Skip to content

Commit

Permalink
Added const-generics
Browse files Browse the repository at this point in the history
  • Loading branch information
adam-mcdaniel committed Sep 6, 2024
1 parent c899528 commit 7d48232
Show file tree
Hide file tree
Showing 16 changed files with 301 additions and 187 deletions.
2 changes: 1 addition & 1 deletion src/frontend/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ pub fn parse(
use crate::side_effects::Output;
if include_std {
let std_lib = parse_module("std", &without_comments(include_str!("std_lib.sg")))?;
expr = expr.with(std_lib)
expr = expr.hard_with(std_lib)
}
if include_builtins {
let alloc = crate::lir::ConstExpr::StandardBuiltin(crate::lir::StandardBuiltin {
Expand Down
4 changes: 2 additions & 2 deletions src/frontend/parse.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4475,7 +4475,7 @@ mod tests {
assert_parse_type(
"fun<T>(Option<T>) -> Bool",
Some(Type::Poly(
vec!["T".to_string()],
vec![("T".to_string(), None)],
Type::Proc(
vec![Type::Apply(
Box::new(Type::Symbol("Option".to_string())),
Expand All @@ -4490,7 +4490,7 @@ mod tests {
assert_parse_type(
"fun<T>(Option<T>, Int) -> Bool",
Some(Type::Poly(
vec!["T".to_string()],
vec![("T".to_string(), None)],
Type::Proc(
vec![
Type::Apply(
Expand Down
10 changes: 5 additions & 5 deletions src/lir/compile.rs
Original file line number Diff line number Diff line change
Expand Up @@ -548,7 +548,7 @@ impl Compile for Expr {
Self::EnumUnion(t, variant, val) => {
// Get the size of the tagged union.
let result_size = t.get_size(env)?;
let t = t.simplify_until_concrete(env)?;
let t = t.simplify_until_concrete(env, false)?;
if let Type::EnumUnion(fields) = t {
// Get the list of possible variant names.
let variants = fields.clone().into_keys().collect::<Vec<_>>();
Expand Down Expand Up @@ -843,7 +843,7 @@ impl Compile for Expr {
// val_type.add_monomorphized_associated_consts(env)?;

// Push the address of the struct, tuple, or union onto the stack.
match val_type.simplify_until_has_members(env)? {
match val_type.simplify_until_has_members(env, false)? {
// If the value is a struct, tuple, or union:
Type::Struct(_) | Type::Tuple(_) | Type::Union(_) => {
// Compile a reference to the inner value with the expected mutability.
Expand Down Expand Up @@ -928,7 +928,7 @@ impl Compile for Expr {
// val_type.add_monomorphized_associated_consts(env)?;

// Push the address of the struct, tuple, or union onto the stack.
match val_type.simplify_until_has_members(env)? {
match val_type.simplify_until_has_members(env, false)? {
// If the value is a struct, tuple, or union:
Type::Struct(_) | Type::Tuple(_) | Type::Union(_) => {
// Compile a reference to the inner value with the expected mutability.
Expand Down Expand Up @@ -1389,7 +1389,7 @@ impl Compile for ConstExpr {
Self::EnumUnion(t, variant, val) => {
// Get the size of the tagged union.
let result_size = t.get_size(env)?;
let t = t.simplify_until_has_variants(env)?;
let t = t.simplify_until_has_variants(env, false)?;

// Get the inner list of variants and compile the expression using this information.
if let Type::EnumUnion(variants) = t.clone().simplify(env)? {
Expand Down Expand Up @@ -1463,7 +1463,7 @@ impl Compile for ConstExpr {
Self::Of(enum_type, variant) => {
// Only try to simplify the type 50 times at most.
// This is to prevent infinite loops and to keep recursion under control.
match enum_type.simplify_until_has_variants(env)? {
match enum_type.simplify_until_has_variants(env, false)? {
// If the type is an enum, we can continue.
Type::Enum(variants) => {
// Get the index of the variant.
Expand Down
63 changes: 36 additions & 27 deletions src/lir/env.rs
Original file line number Diff line number Diff line change
Expand Up @@ -252,7 +252,10 @@ impl Env {
// Go through all the types and see if any equals the given type.
for (other_ty, consts) in associated_constants.iter() {
if matches!(ty.is_monomorph_of(other_ty, self), Ok(true)) {
debug!("Type {ty} is monomorph of {other_ty}");
info!("Type {ty} is monomorph of {other_ty}");
for (name, (constant, ty)) in consts {
debug!(" {name}: {ty} = {constant}")
}
let template = other_ty.clone();

let ty_params = template.get_template_params(self);
Expand Down Expand Up @@ -285,11 +288,11 @@ impl Env {
}
}

if ty_args.len() != ty_params.len() {
debug!("Mismatched number of template arguments for {monomorph} of {template}");
debug!("Expected {ty_params:?}, found {ty_args:?}");
continue;
}
// if ty_args.len() != ty_params.len() {
// error!("Mismatched number of template arguments for {monomorph} of {template}");
// error!("Expected {ty_params:?}, found {ty_args:?}");
// continue;
// }

debug!(
"Associated constants for {monomorph} are {:?}",
Expand All @@ -301,7 +304,7 @@ impl Env {
// let result = const_ty.apply(ty_args.clone()).simplify_until_simple(self).ok()?;
// let result = const_ty.apply(ty_args.clone());
let result = const_ty.apply(ty_args.clone().into_iter().map(|x|x.0).collect());
match result.simplify_until_simple(self) {
match result.simplify_until_simple(self, false) {
Ok(result) => {
debug!("Found associated const (type) {name} of type {ty} = {result}");
return Some(result);
Expand All @@ -314,19 +317,23 @@ impl Env {
// continue;
}
}
// info!("Found associated const (type) {name} of type {ty} = {result}");
// debug!("Found associated const (type) {name} of type {ty} = {result}");
// return Some(result);
}

debug!("Could not find associated const {name} of type {ty} in {template}");
for template_const_name in template_associated_consts.keys() {
debug!(" {template_const_name} != {name}");
}
} else {
debug!("Type {ty} is not monomorph of {other_ty}");
}

if !ty.can_decay_to(other_ty, self).unwrap_or(false) {
// trace!("Type {other_ty} does not equal {ty}");
debug!("Type {other_ty} does not equal {ty}");
continue;
} else {
debug!("Type {other_ty} equals {ty}");
}
if let Some((constant, expr_ty)) = consts.get(name) {
let constant = constant.clone();
Expand All @@ -337,7 +344,6 @@ impl Env {
return Some(expr_ty);
}
}
trace!("Could not find associated const {name} of type {ty} in {self}");
drop(associated_constants);

if let Type::Type(inner_ty) = ty {
Expand All @@ -355,11 +361,12 @@ impl Env {
return Some(ty);
}
}
error!("Could not find associated const {name} of type {ty} in {self}");
None
}

pub fn get_associated_const(&self, ty: &Type, name: &str) -> Option<(ConstExpr, Type)> {
trace!(
info!(
"Getting associated const {name} of type {ty} in {self} with types {:?}",
self.types
);
Expand Down Expand Up @@ -394,16 +401,16 @@ impl Env {
debug!("Failed to get monomorph template args for {monomorph} of {template}");
continue;
}
// for (symbol, ty) in &symbols {
// debug!("----> {symbol} == {ty}");
// }
for (symbol, (ty, expected)) in &symbols {
debug!("----> {symbol} == {ty}, {expected:?}");
}
let template_associated_consts = consts.clone();
let mut ty_args = Vec::new();
for (ty_param, _) in &ty_params {
if let Some((arg, _)) = symbols.get(ty_param) {
ty_args.push(arg.clone());
} else {
continue;
debug!("Could not find symbol {ty_param}");
}
}

Expand All @@ -416,7 +423,7 @@ impl Env {
if let Some((const_expr, const_ty)) = template_associated_consts.get(name) {
debug!("Found cached associated const pair: {const_expr} with type {const_ty}");
let mut result_ty = const_ty.apply(ty_args.clone());
result_ty = match result_ty.simplify_until_simple(self) {
result_ty = match result_ty.simplify_until_simple(self, true) {
Ok(result) => {
debug!("Found associated const {name} of type {ty} = {result}");
result
Expand All @@ -436,7 +443,7 @@ impl Env {
debug!("Could not find associated const {name} of type {ty} in {template}");
// return self.get_associated_const(&monomorph, name);
} else {
// info!("Type {ty} is not monomorph of {other_ty}");
debug!("Type {ty} is not monomorph of {other_ty}");
}

if !ty.can_decay_to(other_ty, self).unwrap_or(false) {
Expand Down Expand Up @@ -573,7 +580,7 @@ impl Env {
) -> Result<(), Error> {
debug!("Adding monomorphized associated constants of type {template} to {monomorph} with type arguments {ty_args:?} to environment");

let monomorph = if let Ok(simplified) = monomorph.simplify_until_simple(self) {
let monomorph = if let Ok(simplified) = monomorph.simplify_until_simple(self, false) {
debug!("Simplified {monomorph} to {simplified}");
simplified
} else {
Expand Down Expand Up @@ -665,7 +672,7 @@ impl Env {
expr: ConstExpr,
) -> Result<(), Error> {
let associated_const_name = associated_const_name.to_string();
trace!("Defining associated const {associated_const_name} as {expr} to type {ty}");
info!("Defining associated const {associated_const_name} as {expr} to type {ty}");
let expr_ty = expr.get_type(self)?;
let mut associated_constants = self.associated_constants.write().unwrap();
associated_constants
Expand Down Expand Up @@ -852,7 +859,9 @@ impl Env {

for (name, associated_const) in impls {
let templated_const =
associated_const.template(template_params.clone());
// associated_const.template(supplied_param_symbols.clone().into_iter().map(|x| (x, None)).collect());
// associated_const.template(template_params.clone());
associated_const.template(template_params.clone().into_iter().zip(supplied_param_symbols.clone().into_iter()).map(|((_, ty), param)| (param, ty)).collect());
self.add_associated_const(*template.clone(), name, templated_const)?;
}
} else {
Expand Down Expand Up @@ -1008,7 +1017,7 @@ impl Env {
Arc::make_mut(&mut self.consts).insert(name.clone(), ConstExpr::Type(ty.clone()));
Arc::make_mut(&mut self.types).insert(name.clone(), ty.clone());

if let Ok(simplified) = ty.simplify_until_concrete(self) {
if let Ok(simplified) = ty.simplify_until_concrete(self, false) {
if let Ok(size) = simplified.get_size(self) {
self.set_precalculated_size(simplified.clone(), size);
}
Expand Down Expand Up @@ -1048,7 +1057,7 @@ impl Env {
}

for (_, ty) in types {
if let Ok(simplified) = ty.simplify_until_concrete(self) {
if let Ok(simplified) = ty.simplify_until_concrete(self, false) {
if let Ok(size) = simplified.get_size(self) {
self.set_precalculated_size(simplified, size);
} else {
Expand Down Expand Up @@ -1283,7 +1292,7 @@ impl Env {

impl Display for Env {
fn fmt(&self, f: &mut Formatter) -> FmtResult {
// return Ok(());
return Ok(());
writeln!(f, "Env")?;
writeln!(f, " Types:")?;
for (name, ty) in self.types.iter() {
Expand All @@ -1292,10 +1301,10 @@ impl Display for Env {
if constants.is_empty() {
continue;
}
// writeln!(f, " Associated constants:")?;
// for (name, cexpr) in constants {
// writeln!(f, " {}: {}", name, cexpr)?;
// }
writeln!(f, " Associated constants:")?;
for (name, cexpr) in constants {
writeln!(f, " {}: {}", name, cexpr)?;
}
}
// writeln!(f, " Constants:")?;
// for (i, (name, e)) in self.consts.iter().enumerate() {
Expand Down
39 changes: 29 additions & 10 deletions src/lir/expr/const_expr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -105,9 +105,18 @@ impl ConstExpr {
Self::Monomorphize(Box::new(self), ty_args)
}

pub fn equals(&self, other: &Self) -> bool {
pub fn equals(&self, other: &Self, env: &Env) -> bool {
info!("{self} == {other} in const?");
match (self, other) {
(Self::Any, _) | (_, Self::Any) => true,
(Self::Type(Type::Any), _) | (_, Self::Type(Type::Any)) => true,
(Self::Symbol(name), other) | (other, Self::Symbol(name)) => {
if let Some(c) = env.get_const(name) {
c.equals(other, env)
} else {
&Self::Symbol(name.clone()) == other
}
}
(a, b) => a == b,
}
}
Expand Down Expand Up @@ -391,7 +400,9 @@ impl ConstExpr {
}
*ret
}
Self::PolyProc(proc) => Self::Proc(proc.monomorphize(ty_args.clone(), env)?),
Self::PolyProc(proc) => {
Self::Proc(proc.monomorphize(ty_args.clone(), env)?)
},
Self::Declare(bindings, expr) => {
let mut new_env = env.clone();
new_env.add_compile_time_declaration(&bindings)?;
Expand All @@ -403,6 +414,7 @@ impl ConstExpr {
.monomorphize(ty_args.clone())
.eval_checked(env, i)
.map_err(|x| x.annotate(metadata))?,

_other => {
Self::Monomorphize(Box::new(expr.eval_checked(env, i)?), ty_args.clone())
}
Expand Down Expand Up @@ -580,7 +592,7 @@ impl GetType for ConstExpr {
debug!("Got type of container access {val} . {field}\nContainer: {val_type}");
// val_type.add_monomorphized_associated_consts(env)?;
// Get the type of the value to get the member of.
match &val_type.simplify_until_concrete(env)? {
match &val_type.simplify_until_concrete(env, false)? {
Type::Unit(_unit_name, inner_ty) => {
// Get the type of the field.
env.get_type_of_associated_const(inner_ty, &as_symbol?)
Expand All @@ -589,7 +601,7 @@ impl GetType for ConstExpr {

Type::Pointer(_found_mutability, t) => {
let val = &Expr::ConstExpr(*val);
let t = t.clone().simplify_until_concrete(env)?;
let t = t.clone().simplify_until_concrete(env, false)?;
match t.get_member_offset(&field, val, env) {
Ok((t, _)) => t,
Err(_) => {
Expand Down Expand Up @@ -736,6 +748,7 @@ impl GetType for ConstExpr {
.simplify_until_type_checks(env);
}
Self::Template(params, ret) => {
debug!("Getting type of monomorphized template {self}");
if params.len() != ty_args.len() {
return Err(Error::InvalidMonomorphize(expr));
}
Expand All @@ -748,19 +761,25 @@ impl GetType for ConstExpr {
let expected = expected_ty.clone();
let found = cexpr.get_type_checked(env, i)?;
if !found.equals(expected_ty, env)? {
error!("Mismatch in expected type for constant parameter");
return Err(Error::MismatchedTypes { expected, found, expr: (*cexpr.clone()).into() })
}
ret.substitute(param, ty_arg)
}
ret.substitute(param, ty_arg);
new_env.define_const(param, *cexpr.clone());
} else {
ret.substitute(param, ty_arg)
ret.substitute(param, ty_arg);
new_env.define_type(param, ty_arg.clone());
}
}
ret.get_type_checked(&new_env, i)?
.simplify_until_type_checks(env)?
debug!("Result: {ret}");
let ret = ret.get_type_checked(&new_env, i)?
.simplify_until_poly(&new_env, false)?;
ret
}
_ => {
// warn!("Monomorphizing non-template: {expr}");
// debug!("Monomorphizing non-template: {expr}");
Type::Apply(Box::new(template_ty.clone()), ty_args.clone())
}
};
Expand Down Expand Up @@ -942,9 +961,9 @@ impl GetType for ConstExpr {
}
Self::Symbol(symbol_name) if symbol_name == name => {
// A constant symbol cannot be substituted for a type variable.
warn!("Subbing {self} for {substitution}");
// debug!("Subbing {self} for {substitution}");
*self = ConstExpr::Type(substitution.clone());
warn!("Subbed into {self}");
// debug!("Subbed into {self}");
}
_ => {}
}
Expand Down
4 changes: 3 additions & 1 deletion src/lir/expr/declaration.rs
Original file line number Diff line number Diff line change
Expand Up @@ -571,7 +571,9 @@ impl TypeCheck for Declaration {

for (name, associated_const) in impls {
let templated_const =
associated_const.template(supplied_param_symbols.clone().into_iter().map(|x| (x, None)).collect());
// associated_const.template(supplied_param_symbols.clone().into_iter().map(|x| (x, None)).collect());
// associated_const.template(template_params.clone());
associated_const.template(template_params.clone().into_iter().zip(supplied_param_symbols.clone().into_iter()).map(|((_, ty), param)| (param, ty)).collect());
new_env.add_associated_const(
*template.clone(),
name,
Expand Down
Loading

0 comments on commit 7d48232

Please sign in to comment.