add record_var to Access and Accessor

This commit is contained in:
Folkert 2020-03-14 01:13:44 +01:00
parent e62ddc9ef5
commit b43be95b19
5 changed files with 67 additions and 35 deletions

View File

@ -95,6 +95,7 @@ pub enum Expr {
/// Look up exactly one field on a record, e.g. (expr).foo. /// Look up exactly one field on a record, e.g. (expr).foo.
Access { Access {
record_var: Variable,
ext_var: Variable, ext_var: Variable,
field_var: Variable, field_var: Variable,
loc_expr: Box<Located<Expr>>, loc_expr: Box<Located<Expr>>,
@ -102,6 +103,7 @@ pub enum Expr {
}, },
/// field accessor as a function, e.g. (.foo) expr /// field accessor as a function, e.g. (.foo) expr
Accessor { Accessor {
record_var: Variable,
ext_var: Variable, ext_var: Variable,
field_var: Variable, field_var: Variable,
field: Lowercase, field: Lowercase,
@ -488,6 +490,7 @@ pub fn canonicalize_expr<'a>(
( (
Access { Access {
record_var: var_store.fresh(),
field_var: var_store.fresh(), field_var: var_store.fresh(),
ext_var: var_store.fresh(), ext_var: var_store.fresh(),
loc_expr: Box::new(loc_expr), loc_expr: Box::new(loc_expr),
@ -496,20 +499,15 @@ pub fn canonicalize_expr<'a>(
output, output,
) )
} }
ast::Expr::AccessorFunction(field) => { ast::Expr::AccessorFunction(field) => (
let ext_var = var_store.fresh(); Accessor {
let field_var = var_store.fresh(); record_var: var_store.fresh(),
let field_name: Lowercase = (*field).into(); ext_var: var_store.fresh(),
field_var: var_store.fresh(),
( field: (*field).into(),
Accessor { },
field: field_name, Output::default(),
ext_var, ),
field_var,
},
Output::default(),
)
}
ast::Expr::GlobalTag(tag) => { ast::Expr::GlobalTag(tag) => {
let variant_var = var_store.fresh(); let variant_var = var_store.fresh();
let ext_var = var_store.fresh(); let ext_var = var_store.fresh();

View File

@ -515,6 +515,7 @@ pub fn constrain_expr(
exists(vec![cond_var, *expr_var], And(constraints)) exists(vec![cond_var, *expr_var], And(constraints))
} }
Access { Access {
record_var,
ext_var, ext_var,
field_var, field_var,
loc_expr, loc_expr,
@ -533,6 +534,8 @@ pub fn constrain_expr(
let record_type = Type::Record(rec_field_types, Box::new(ext_type)); let record_type = Type::Record(rec_field_types, Box::new(ext_type));
let record_expected = Expected::NoExpectation(record_type); let record_expected = Expected::NoExpectation(record_type);
let record_con = Eq(Type::Variable(*record_var), record_expected.clone(), region);
let constraint = constrain_expr( let constraint = constrain_expr(
&Env { &Env {
home: env.home, home: env.home,
@ -544,12 +547,17 @@ pub fn constrain_expr(
); );
exists( exists(
vec![field_var, ext_var], vec![*record_var, field_var, ext_var],
And(vec![constraint, Eq(field_type, expected, region)]), And(vec![
constraint,
Eq(field_type, expected, region),
record_con,
]),
) )
} }
Accessor { Accessor {
field, field,
record_var,
ext_var, ext_var,
field_var, field_var,
} => { } => {
@ -563,13 +571,19 @@ pub fn constrain_expr(
field_types.insert(label, field_type.clone()); field_types.insert(label, field_type.clone());
let record_type = Type::Record(field_types, Box::new(ext_type)); let record_type = Type::Record(field_types, Box::new(ext_type));
let record_expected = Expected::NoExpectation(record_type.clone());
let record_con = Eq(Type::Variable(*record_var), record_expected, region);
exists( exists(
vec![field_var, ext_var], vec![*record_var, field_var, ext_var],
Eq( And(vec![
Type::Function(vec![record_type], Box::new(field_type)), Eq(
expected, Type::Function(vec![record_type], Box::new(field_type)),
region, expected,
), region,
),
record_con,
]),
) )
} }
LetRec(defs, loc_ret, var, aliases) => { LetRec(defs, loc_ret, var, aliases) => {

View File

@ -1141,6 +1141,7 @@ pub fn constrain_expr(
} }
Access { Access {
record_var,
ext_var, ext_var,
field_var, field_var,
loc_expr, loc_expr,
@ -1163,6 +1164,8 @@ pub fn constrain_expr(
); );
let record_expected = Expected::NoExpectation(record_type); let record_expected = Expected::NoExpectation(record_type);
let record_con = Eq(Type::Variable(*record_var), record_expected.clone(), region);
let inner_constraint = constrain_expr( let inner_constraint = constrain_expr(
env, env,
var_store, var_store,
@ -1174,13 +1177,24 @@ pub fn constrain_expr(
); );
exists( exists(
vec![*field_var, *ext_var, field_uniq_var, record_uniq_var], vec![
And(vec![Eq(field_type, expected, region), inner_constraint]), *record_var,
*field_var,
*ext_var,
field_uniq_var,
record_uniq_var,
],
And(vec![
Eq(field_type, expected, region),
inner_constraint,
record_con,
]),
) )
} }
Accessor { Accessor {
field, field,
record_var,
field_var, field_var,
ext_var, ext_var,
} => { } => {
@ -1200,6 +1214,9 @@ pub fn constrain_expr(
Type::Record(field_types, Box::new(Type::Variable(*ext_var))), Type::Record(field_types, Box::new(Type::Variable(*ext_var))),
); );
let record_expected = Expected::NoExpectation(record_type.clone());
let record_con = Eq(Type::Variable(*record_var), record_expected, region);
let fn_uniq_var = var_store.fresh(); let fn_uniq_var = var_store.fresh();
let fn_type = attr_type( let fn_type = attr_type(
Bool::variable(fn_uniq_var), Bool::variable(fn_uniq_var),
@ -1208,13 +1225,14 @@ pub fn constrain_expr(
exists( exists(
vec![ vec![
*record_var,
*field_var, *field_var,
*ext_var, *ext_var,
fn_uniq_var, fn_uniq_var,
field_uniq_var, field_uniq_var,
record_uniq_var, record_uniq_var,
], ],
And(vec![Eq(fn_type, expected, region)]), And(vec![Eq(fn_type, expected, region), record_con]),
) )
} }
RuntimeError(_) => True, RuntimeError(_) => True,

View File

@ -681,20 +681,22 @@ fn from_can<'a>(
} }
Access { Access {
ext_var, record_var,
field_var, field_var,
field, field,
loc_expr, loc_expr,
..
} => { } => {
let arena = env.arena; let arena = env.arena;
let struct_layout = match Layout::from_var(arena, ext_var, env.subs, env.pointer_size) { let struct_layout =
Ok(layout) => layout, match Layout::from_var(arena, record_var, env.subs, env.pointer_size) {
Err(()) => { Ok(layout) => layout,
// Invalid field! Err(()) => {
panic!("TODO gracefully handle Access with invalid struct_layout"); // Invalid field!
} panic!("TODO gracefully handle Access with invalid struct_layout");
}; }
};
let field_layout = match Layout::from_var(arena, field_var, env.subs, env.pointer_size) let field_layout = match Layout::from_var(arena, field_var, env.subs, env.pointer_size)
{ {

View File

@ -2116,8 +2116,8 @@ mod test_uniq_solve {
f f
"# "#
), ),
"Attr * (Attr (* | a | b) { p : (Attr a *), q : (Attr b *) }* -> Attr * (Num (Attr * *)))", //"Attr * (Attr (* | a | b) { p : (Attr a *), q : (Attr b *) }* -> Attr * (Num (Attr * *)))",
//"Attr * (Attr (* | a | b) { p : (Attr b *), q : (Attr a *) }* -> Attr * (Num (Attr * *)))" "Attr * (Attr (* | a | b) { p : (Attr b *), q : (Attr a *) }* -> Attr * (Num (Attr * *)))"
); );
} }