Skip to content

Commit

Permalink
Part of implementing variant
Browse files Browse the repository at this point in the history
  • Loading branch information
JonathanBrouwer committed Apr 21, 2024
1 parent 6061bfc commit 5b1d57b
Show file tree
Hide file tree
Showing 7 changed files with 120 additions and 7 deletions.
7 changes: 6 additions & 1 deletion compiler/src/passes/validate/constrain/expr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ use crate::passes::validate::constrain::seq::constrain_seq;
use crate::passes::validate::constrain::unary_op::constrain_unary_op;
use crate::passes::validate::constrain::uncover_globals::Env;
use crate::passes::validate::constrain::var::constrain_var;
use crate::passes::validate::constrain::variant;
use crate::passes::validate::error::TypeError;
use crate::passes::validate::{ExprConstrained, ExprUniquified};

Expand Down Expand Up @@ -52,7 +53,11 @@ pub fn constrain_expr<'p>(
Expr::Struct { sym, fields } => constrain_struct(env, span, sym, fields),
Expr::AccessField { strct, field } => constrain_access_field(env, span, *strct, field),
Expr::Asm { instrs } => constrain_asm(env, span, instrs),
Expr::Variant { .. } => todo!(),
Expr::Variant {
enum_sym,
variant_sym,
bdy,
} => variant::constraint_variant(env, span, enum_sym, variant_sym, *bdy),
Expr::Switch { .. } => todo!(),
}
}
1 change: 1 addition & 0 deletions compiler/src/passes/validate/constrain/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ mod r#struct;
mod unary_op;
mod uncover_globals;
mod var;
mod variant;

impl<'p> PrgUniquified<'p> {
pub fn constrain(self) -> Result<PrgConstrained<'p>, TypeError> {
Expand Down
65 changes: 65 additions & 0 deletions compiler/src/passes/validate/constrain/variant.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
use crate::passes::parse::{Constrained, Span, Spanned, TypeDef};
use crate::passes::validate::constrain::expr::constrain_expr;
use crate::passes::validate::constrain::uncover_globals::{Env, EnvEntry};
use crate::passes::validate::error::TypeError;
use crate::passes::validate::partial_type::PartialType;
use crate::passes::validate::{ExprConstrained, ExprUniquified, MetaConstrained};
use crate::utils::unique_sym::UniqueSym;

pub fn constraint_variant<'p>(
env: &mut Env<'_, 'p>,
span: Span,
enum_sym: Spanned<UniqueSym<'p>>,
variant_sym: Spanned<&'p str>,
bdy: Spanned<ExprUniquified<'p>>,
) -> Result<Constrained<ExprConstrained<'p>>, TypeError> {
// Get the `EnvEntry` from the scope.
// This should exist after uniquify, but could potentially not be an enum definition.
let EnvEntry::Def {
def: TypeDef::Enum {
variants: def_variants,
},
} = &env.scope[&enum_sym.inner]
else {
return Err(TypeError::SymbolShouldBeEnum { span: enum_sym.meta });
};

// Check if variant_sym exists
let Some((def_span, variant_typ)) = def_variants
.iter()
.find(|(def_variant, _)| def_variant.inner == variant_sym.inner)
else {
return Err(TypeError::UnknownEnumVariant {
sym: variant_sym.inner.to_string(),
span: variant_sym.meta,
});
};
let def_span = def_span.meta;
let variant_typ = variant_typ.clone();

// Check body type
let bdy_typ = constrain_expr(bdy, env)?;
env.uf.expect_type(
bdy_typ.meta.index,
variant_typ,
|field_typ, def_typ| TypeError::MismatchedStructField {
expect: def_typ,
got: field_typ,
span_expected: def_span,
span_got: bdy_typ.meta.span,
},
)?;

let index = env.uf.add(PartialType::Var {
sym: enum_sym.inner,
});

Ok(Constrained {
meta: MetaConstrained { span, index },
inner: ExprConstrained::Variant {
enum_sym,
variant_sym,
bdy: Box::new(bdy_typ),
},
})
}
21 changes: 21 additions & 0 deletions compiler/src/passes/validate/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -53,12 +53,23 @@ pub enum TypeError {
#[label = "This should be a struct."]
span: (usize, usize),
},
#[error("Tried to use variable as type.'")]
SymbolShouldBeEnum {
#[label = "This should be an enum."]
span: (usize, usize),
},
#[error("Unknown struct field.")]
UnknownStructField {
sym: String,
#[label = "The field `{sym}` is not present in the struct definition."]
span: (usize, usize),
},
#[error("Unknown enum variant.")]
UnknownEnumVariant {
sym: String,
#[label = "The variant `{sym}` is not present in the enum definition."]
span: (usize, usize),
},
#[error("Missing struct field.")]
ConstructMissingField {
sym: String,
Expand Down Expand Up @@ -175,6 +186,16 @@ pub enum TypeError {
span_got: (usize, usize),
},
#[error("Types did not match.")]
MismatchedEnumVariant {
expect: String,
got: String,

#[label = "Expected enum variant to have type: `{expect}`"]
span_expected: (usize, usize),
#[label = "But got this type: `{got}`"]
span_got: (usize, usize),
},
#[error("Types did not match.")]
IfExpectBool {
got: String,

Expand Down
6 changes: 5 additions & 1 deletion compiler/src/passes/validate/resolve.rs
Original file line number Diff line number Diff line change
Expand Up @@ -295,7 +295,11 @@ fn resolve_expr<'p>(
strct: Box::new(resolve_expr(*strct, uf)?),
field: field.inner,
},
Expr::Variant { .. } => todo!(),
Expr::Variant { enum_sym, variant_sym, bdy } => Expr::Variant {
enum_sym: enum_sym.inner,
variant_sym: variant_sym.inner,
bdy: Box::new(resolve_expr(*bdy, uf)?),
},
Expr::Switch { .. } => todo!(),
ExprConstrained::Asm { instrs } => ExprValidated::Asm {
instrs: instrs.into_iter().map(resolve_instr).collect(),
Expand Down
18 changes: 13 additions & 5 deletions compiler/src/passes/validate/uniquify/expr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use crate::passes::select::VarArg;
use crate::passes::validate::error::TypeError;
use crate::passes::validate::uniquify::r#type::uniquify_type;
use crate::passes::validate::uniquify::{gen_spanned_sym, try_get};
use crate::passes::validate::{uniquify, ExprUniquified, InstrUniquified};
use crate::passes::validate::{ExprUniquified, InstrUniquified};
use crate::utils::push_map::PushMap;
use crate::utils::unique_sym::UniqueSym;

Expand Down Expand Up @@ -34,14 +34,14 @@ pub fn uniquify_expr<'p>(
}
}
Expr::Var { sym } => Expr::Var {
sym: uniquify::try_get(sym, scope)?,
sym: try_get(sym, scope)?,
},
Expr::Assign { sym, bnd } => Expr::Assign {
sym: uniquify::try_get(sym, scope)?,
sym: try_get(sym, scope)?,
bnd: Box::new(uniquify_expr(*bnd, scope)?),
},
Expr::Struct { sym, fields } => Expr::Struct {
sym: uniquify::try_get(sym, scope)?,
sym: try_get(sym, scope)?,
fields: fields
.into_iter()
.map(|(sym, expr)| uniquify_expr(expr, scope).map(|expr| (sym, expr)))
Expand Down Expand Up @@ -90,7 +90,15 @@ pub fn uniquify_expr<'p>(
strct: Box::new(uniquify_expr(*strct, scope)?),
field,
},
Expr::Variant { .. } => todo!(),
Expr::Variant {
enum_sym,
variant_sym,
bdy,
} => Expr::Variant {
enum_sym: try_get(enum_sym, scope)?,
variant_sym,
bdy: Box::new(uniquify_expr(*bdy, scope)?),
},
Expr::Switch { .. } => todo!(),
ExprParsed::Asm { instrs } => ExprUniquified::Asm {
instrs: instrs
Expand Down
9 changes: 9 additions & 0 deletions programs/good/algebraic/simple_enum_construct.sp
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
enum TestEnum {
Variant1: I64,
Variant2: Bool,
}

fn main() {
let _ = TestEnum::Variant1(15);
unit
}

0 comments on commit 5b1d57b

Please sign in to comment.