remove Output from uniq infer

This commit is contained in:
Folkert 2020-01-06 17:03:31 +01:00
parent ab54e8ad29
commit c665eccf11
3 changed files with 72 additions and 136 deletions

View file

@ -1,11 +1,10 @@
use crate::can::def::Def; use crate::can::def::Def;
use crate::can::expr::Expr; use crate::can::expr::Expr;
use crate::can::expr::Field; use crate::can::expr::Field;
use crate::can::expr::Output;
use crate::can::ident::Lowercase; use crate::can::ident::Lowercase;
use crate::can::pattern; use crate::can::pattern;
use crate::can::pattern::{Pattern, RecordDestruct}; use crate::can::pattern::{Pattern, RecordDestruct};
use crate::can::procedure::{Procedure, References}; use crate::can::procedure::Procedure;
use crate::can::symbol::Symbol; use crate::can::symbol::Symbol;
use crate::collections::{ImMap, SendMap}; use crate::collections::{ImMap, SendMap};
use crate::constrain::expr::{Info, Rigids}; use crate::constrain::expr::{Info, Rigids};
@ -41,7 +40,7 @@ pub fn constrain_declaration(
loc_expr: Located<Expr>, loc_expr: Located<Expr>,
_declared_idents: &ImMap<Ident, (Symbol, Region)>, _declared_idents: &ImMap<Ident, (Symbol, Region)>,
expected: Expected<Type>, expected: Expected<Type>,
) -> (Output, Constraint) { ) -> Constraint {
let rigids = ImMap::default(); let rigids = ImMap::default();
let mut var_usage = VarUsage::default(); let mut var_usage = VarUsage::default();
@ -172,44 +171,32 @@ pub fn constrain_expr(
region: Region, region: Region,
expr: &Expr, expr: &Expr,
expected: Expected<Type>, expected: Expected<Type>,
) -> (Output, Constraint) { ) -> Constraint {
pub use crate::can::expr::Expr::*; pub use crate::can::expr::Expr::*;
match expr { match expr {
Int(_, _) => { Int(_, _) => constrain::int_literal(var_store, expected, region),
let constraint = constrain::int_literal(var_store, expected, region); Float(_, _) => constrain::float_literal(var_store, expected, region),
(Output::default(), constraint)
}
Float(_, _) => {
let constraint = constrain::float_literal(var_store, expected, region);
(Output::default(), constraint)
}
BlockStr(_) | Str(_) => { BlockStr(_) | Str(_) => {
let inferred = constrain::lift(var_store, constrain::str_type()); let inferred = constrain::lift(var_store, constrain::str_type());
let constraint = Eq(inferred, expected, region); Eq(inferred, expected, region)
(Output::default(), constraint)
}
EmptyRecord => {
let constraint = Eq(constrain::lift(var_store, EmptyRec), expected, region);
(Output::default(), constraint)
} }
EmptyRecord => Eq(constrain::lift(var_store, EmptyRec), expected, region),
Record(variable, fields) => { Record(variable, fields) => {
// NOTE: canonicalization guarantees at least one field // NOTE: canonicalization guarantees at least one field
// zero fields generates an EmptyRecord // zero fields generates an EmptyRecord
let mut field_types = SendMap::default(); let mut field_types = SendMap::default();
let mut field_vars = Vec::with_capacity(fields.len()); let mut field_vars = Vec::with_capacity(fields.len());
// Constraints need capacity for each field + 1 for the record itself. // Constraints need capacity for each field + 1 for the record itself + 1 for ext
let mut constraints = Vec::with_capacity(1 + fields.len()); let mut constraints = Vec::with_capacity(2 + fields.len());
let mut output = Output::default();
for (label, ref field) in fields.iter() { for (label, ref field) in fields.iter() {
let field_var = var_store.fresh(); let field_var = var_store.fresh();
let field_type = Variable(field_var); let field_type = Variable(field_var);
let field_expected = Expected::NoExpectation(field_type.clone()); let field_expected = Expected::NoExpectation(field_type.clone());
let loc_expr = &*field.loc_expr; let loc_expr = &*field.loc_expr;
let (field_out, field_con) = constrain_expr( let field_con = constrain_expr(
rigids, rigids,
var_store, var_store,
var_usage, var_usage,
@ -222,7 +209,6 @@ pub fn constrain_expr(
field_types.insert(label.clone(), field_type); field_types.insert(label.clone(), field_type);
constraints.push(field_con); constraints.push(field_con);
output.references = output.references.union(field_out.references);
} }
let record_type = constrain::lift( let record_type = constrain::lift(
@ -243,7 +229,7 @@ pub fn constrain_expr(
let constraint = exists(field_vars, And(constraints)); let constraint = exists(field_vars, And(constraints));
(output, constraint) (constraint)
} }
Tag { .. } => { Tag { .. } => {
panic!("TODO implement tag"); panic!("TODO implement tag");
@ -252,14 +238,12 @@ pub fn constrain_expr(
if loc_elems.is_empty() { if loc_elems.is_empty() {
let list_var = *variable; let list_var = *variable;
let inferred = constrain::lift(var_store, constrain::empty_list_type(list_var)); let inferred = constrain::lift(var_store, constrain::empty_list_type(list_var));
let constraint = Eq(inferred, expected, region); Eq(inferred, expected, region)
(Output::default(), constraint)
} else { } else {
// constrain `expected ~ List a` and that all elements `~ a`. // constrain `expected ~ List a` and that all elements `~ a`.
let list_var = *variable; // `v` in the type (List v) let list_var = *variable; // `v` in the type (List v)
let list_type = Type::Variable(list_var); let list_type = Type::Variable(list_var);
let mut constraints = Vec::with_capacity(1 + (loc_elems.len() * 2)); let mut constraints = Vec::with_capacity(1 + (loc_elems.len() * 2));
let mut references = References::new();
for (elem_var, loc_elem) in loc_elems.iter() { for (elem_var, loc_elem) in loc_elems.iter() {
let elem_type = Variable(*elem_var); let elem_type = Variable(*elem_var);
@ -269,7 +253,7 @@ pub fn constrain_expr(
Expected::ForReason(Reason::ElemInList, elem_type, region), Expected::ForReason(Reason::ElemInList, elem_type, region),
region, region,
); );
let (elem_out, constraint) = constrain_expr( let constraint = constrain_expr(
rigids, rigids,
var_store, var_store,
var_usage, var_usage,
@ -280,20 +264,11 @@ pub fn constrain_expr(
constraints.push(list_elem_constraint); constraints.push(list_elem_constraint);
constraints.push(constraint); constraints.push(constraint);
references = references.union(elem_out.references);
} }
let inferred = constrain::lift(var_store, constrain::list_type(list_type)); let inferred = constrain::lift(var_store, constrain::list_type(list_type));
constraints.push(Eq(inferred, expected, region)); constraints.push(Eq(inferred, expected, region));
let mut output = Output::default(); And(constraints)
output.references = references;
// A list literal is never a tail call!
output.tail_call = None;
(output, And(constraints))
} }
} }
Var { Var {
@ -311,8 +286,6 @@ pub fn constrain_expr(
let attr_type = constrain::attr_type(uniq_type.clone(), val_type); let attr_type = constrain::attr_type(uniq_type.clone(), val_type);
(
Output::default(),
And(vec![ And(vec![
Lookup(symbol_for_lookup.clone(), expected.clone(), region), Lookup(symbol_for_lookup.clone(), expected.clone(), region),
Eq(attr_type, expected, region), Eq(attr_type, expected, region),
@ -321,20 +294,16 @@ pub fn constrain_expr(
Expected::NoExpectation(constrain::shared_type()), Expected::NoExpectation(constrain::shared_type()),
region, region,
), ),
]), ])
)
} }
Some(sharing::ReferenceCount::Unique) => { Some(sharing::ReferenceCount::Unique) => {
// no additional constraints, keep uniqueness unbound // no additional constraints, keep uniqueness unbound
( Lookup(symbol_for_lookup.clone(), expected.clone(), region)
Output::default(),
Lookup(symbol_for_lookup.clone(), expected.clone(), region),
)
} }
None => panic!("symbol not analyzed"), None => panic!("symbol not analyzed"),
} }
} }
Closure(_fn_var, _symbol, _recursion, args, boxed_body) => { Closure(fn_var, _symbol, _recursion, args, boxed_body) => {
let (body, ret_var) = &**boxed_body; let (body, ret_var) = &**boxed_body;
// first, generate constraints for the arguments // first, generate constraints for the arguments
@ -371,7 +340,7 @@ pub fn constrain_expr(
Type::Function(arg_types, Box::new(ret_type.clone())), Type::Function(arg_types, Box::new(ret_type.clone())),
); );
let (output, ret_constraint) = constrain_expr( let ret_constraint = constrain_expr(
rigids, rigids,
var_store, var_store,
var_usage, var_usage,
@ -388,7 +357,7 @@ pub fn constrain_expr(
} }
let defs_constraint = And(state.constraints); let defs_constraint = And(state.constraints);
let constraint = exists( exists(
vars, vars,
And(vec![ And(vec![
Let(Box::new(LetConstraint { Let(Box::new(LetConstraint {
@ -399,11 +368,10 @@ pub fn constrain_expr(
ret_constraint, ret_constraint,
})), })),
// "the closure's type is equal to expected type" // "the closure's type is equal to expected type"
Eq(fn_typ, expected, region), Eq(fn_typ, expected.clone(), region),
Eq(Type::Variable(*fn_var), expected, region),
]), ]),
); )
(output, constraint)
} }
Call(boxed, loc_args, _) => { Call(boxed, loc_args, _) => {
@ -416,7 +384,7 @@ pub fn constrain_expr(
let mut vars = Vec::with_capacity(2 + loc_args.len()); let mut vars = Vec::with_capacity(2 + loc_args.len());
// Canonicalize the function expression and its arguments // Canonicalize the function expression and its arguments
let (_, fn_con) = constrain_expr( let fn_con = constrain_expr(
rigids, rigids,
var_store, var_store,
var_usage, var_usage,
@ -442,7 +410,7 @@ pub fn constrain_expr(
}; };
let expected_arg = Expected::ForReason(reason, arg_type.clone(), region); let expected_arg = Expected::ForReason(reason, arg_type.clone(), region);
let (_, arg_con) = constrain_expr( let arg_con = constrain_expr(
rigids, rigids,
var_store, var_store,
var_usage, var_usage,
@ -462,8 +430,6 @@ pub fn constrain_expr(
region, region,
); );
(
Output::default(),
exists( exists(
vars, vars,
And(vec![ And(vec![
@ -472,13 +438,12 @@ pub fn constrain_expr(
And(arg_cons), And(arg_cons),
Eq(ret_type, expected, region), Eq(ret_type, expected, region),
]), ]),
),
) )
} }
LetRec(defs, loc_ret, _) => { LetRec(defs, loc_ret, _) => {
// NOTE doesn't currently unregister bound symbols // NOTE doesn't currently unregister bound symbols
// may be a problem when symbols are not globally unique // may be a problem when symbols are not globally unique
let (_, body_con) = constrain_expr( let body_con = constrain_expr(
rigids, rigids,
var_store, var_store,
var_usage, var_usage,
@ -486,15 +451,12 @@ pub fn constrain_expr(
&loc_ret.value, &loc_ret.value,
expected, expected,
); );
( constrain_recursive_defs(rigids, var_store, var_usage, defs, body_con)
Output::default(),
constrain_recursive_defs(rigids, var_store, var_usage, defs, body_con),
)
} }
LetNonRec(def, loc_ret, _) => { LetNonRec(def, loc_ret, _) => {
// NOTE doesn't currently unregister bound symbols // NOTE doesn't currently unregister bound symbols
// may be a problem when symbols are not globally unique // may be a problem when symbols are not globally unique
let (_, body_con) = constrain_expr( let body_con = constrain_expr(
rigids, rigids,
var_store, var_store,
var_usage, var_usage,
@ -503,10 +465,7 @@ pub fn constrain_expr(
expected, expected,
); );
( constrain_def(rigids, var_store, var_usage, def, body_con)
Output::default(),
constrain_def(rigids, var_store, var_usage, def, body_con),
)
} }
When { When {
cond_var, cond_var,
@ -516,7 +475,7 @@ pub fn constrain_expr(
} => { } => {
let cond_var = *cond_var; let cond_var = *cond_var;
let cond_type = Variable(cond_var); let cond_type = Variable(cond_var);
let (mut output, expr_con) = constrain_expr( let expr_con = constrain_expr(
rigids, rigids,
var_store, var_store,
var_usage, var_usage,
@ -551,7 +510,6 @@ pub fn constrain_expr(
TypedWhenBranch(index), TypedWhenBranch(index),
typ.clone(), typ.clone(),
), ),
&mut output,
); );
// required for a case like // required for a case like
@ -600,7 +558,6 @@ pub fn constrain_expr(
branch_type.clone(), branch_type.clone(),
region, region,
), ),
&mut output,
); );
// required for a case like // required for a case like
@ -635,7 +592,7 @@ pub fn constrain_expr(
} }
} }
(output, And(constraints)) And(constraints)
} }
Update { Update {
@ -647,7 +604,7 @@ pub fn constrain_expr(
} => { } => {
let mut fields: SendMap<Lowercase, Type> = SendMap::default(); let mut fields: SendMap<Lowercase, Type> = SendMap::default();
let mut vars = Vec::with_capacity(updates.len() + 2); let mut vars = Vec::with_capacity(updates.len() + 2);
let mut cons = Vec::with_capacity(updates.len() + 1); let mut cons = Vec::with_capacity(updates.len() + 3);
for (field_name, Field { var, loc_expr, .. }) in updates.clone() { for (field_name, Field { var, loc_expr, .. }) in updates.clone() {
let (var, tipe, con) = constrain_field_update( let (var, tipe, con) = constrain_field_update(
rigids, rigids,
@ -694,7 +651,7 @@ pub fn constrain_expr(
cons.push(fields_con); cons.push(fields_con);
cons.push(record_con); cons.push(record_con);
(Output::default(), exists(vars, And(cons))) exists(vars, And(cons))
} }
Access { Access {
@ -714,7 +671,7 @@ pub fn constrain_expr(
constrain::lift(var_store, Type::Record(rec_field_types, Box::new(ext_type))); constrain::lift(var_store, Type::Record(rec_field_types, Box::new(ext_type)));
let record_expected = Expected::NoExpectation(record_type); let record_expected = Expected::NoExpectation(record_type);
let (output, mut constraint) = constrain_expr( let mut constraint = constrain_expr(
rigids, rigids,
var_store, var_store,
var_usage, var_usage,
@ -728,7 +685,7 @@ pub fn constrain_expr(
And(vec![constraint, Eq(field_type, expected, region)]), And(vec![constraint, Eq(field_type, expected, region)]),
); );
(output, constraint) constraint
} }
Accessor { Accessor {
@ -745,8 +702,6 @@ pub fn constrain_expr(
let record_type = let record_type =
constrain::lift(var_store, Type::Record(field_types, Box::new(ext_type))); constrain::lift(var_store, Type::Record(field_types, Box::new(ext_type)));
(
Output::default(),
exists( exists(
vec![*field_var, *ext_var], vec![*field_var, *ext_var],
Eq( Eq(
@ -754,11 +709,9 @@ pub fn constrain_expr(
expected, expected,
region, region,
), ),
),
) )
} }
RuntimeError(_) => (Output::default(), True), RuntimeError(_) => True,
// _ => panic!("{:?}", expr),
} }
} }
@ -774,9 +727,8 @@ fn constrain_when_branch(
loc_expr: &Located<Expr>, loc_expr: &Located<Expr>,
pattern_expected: PExpected<Type>, pattern_expected: PExpected<Type>,
expr_expected: Expected<Type>, expr_expected: Expected<Type>,
_output: &mut Output,
) -> Constraint { ) -> Constraint {
let (_, ret_constraint) = constrain_expr( let ret_constraint = constrain_expr(
rigids, rigids,
var_store, var_store,
var_usage, var_usage,
@ -877,19 +829,15 @@ pub fn constrain_def(
&def.loc_expr.value, &def.loc_expr.value,
annotation_expected, annotation_expected,
) )
.1
} }
None => { None => constrain_expr(
constrain_expr(
rigids, rigids,
var_store, var_store,
var_usage, var_usage,
def.loc_expr.region, def.loc_expr.region,
&def.loc_expr.value, &def.loc_expr.value,
Expected::NoExpectation(expr_type), Expected::NoExpectation(expr_type),
) ),
.1
}
}; };
Let(Box::new(LetConstraint { Let(Box::new(LetConstraint {
@ -959,7 +907,7 @@ pub fn rec_defs_help(
let mut new_rigids = Vec::new(); let mut new_rigids = Vec::new();
match &def.annotation { match &def.annotation {
None => { None => {
let (_, expr_con) = constrain_expr( let expr_con = constrain_expr(
rigids, rigids,
var_store, var_store,
var_usage, var_usage,
@ -1002,7 +950,7 @@ pub fn rec_defs_help(
AnnotationSource::TypedBody, AnnotationSource::TypedBody,
annotation.clone(), annotation.clone(),
); );
let (_, expr_con) = constrain_expr( let expr_con = constrain_expr(
&ftv, &ftv,
var_store, var_store,
var_usage, var_usage,
@ -1074,7 +1022,7 @@ fn constrain_field_update(
let field_type = Type::Variable(var); let field_type = Type::Variable(var);
let reason = Reason::RecordUpdateValue(field); let reason = Reason::RecordUpdateValue(field);
let expected = Expected::ForReason(reason, field_type.clone(), region); let expected = Expected::ForReason(reason, field_type.clone(), region);
let (_, con) = constrain_expr( let con = constrain_expr(
rigids, rigids,
var_store, var_store,
var_usage, var_usage,

View file

@ -89,7 +89,6 @@ pub fn can_expr(expr_str: &str) -> (Expr, Output, Vec<Problem>, VarStore, Variab
pub fn uniq_expr( pub fn uniq_expr(
expr_str: &str, expr_str: &str,
) -> ( ) -> (
Output,
Output, Output,
Vec<Problem>, Vec<Problem>,
Subs, Subs,
@ -108,7 +107,6 @@ pub fn uniq_expr_with(
expr_str: &str, expr_str: &str,
declared_idents: &ImMap<Ident, (Symbol, Region)>, declared_idents: &ImMap<Ident, (Symbol, Region)>,
) -> ( ) -> (
Output,
Output, Output,
Vec<Problem>, Vec<Problem>,
Subs, Subs,
@ -129,7 +127,7 @@ pub fn uniq_expr_with(
let variable2 = var_store2.fresh(); let variable2 = var_store2.fresh();
let expected2 = Expected::NoExpectation(Type::Variable(variable2)); let expected2 = Expected::NoExpectation(Type::Variable(variable2));
let (output2, constraint2) = roc::uniqueness::constrain_declaration( let constraint2 = roc::uniqueness::constrain_declaration(
&var_store2, &var_store2,
Region::zero(), Region::zero(),
loc_expr, loc_expr,
@ -140,7 +138,6 @@ pub fn uniq_expr_with(
let subs2 = Subs::new(var_store2.into()); let subs2 = Subs::new(var_store2.into());
( (
output2,
output, output,
problems, problems,
subs1, subs1,

View file

@ -17,17 +17,8 @@ mod test_infer_uniq {
// HELPERS // HELPERS
fn infer_eq(src: &str, expected: &str) { fn infer_eq(src: &str, expected: &str) {
let ( let (_output1, _, mut subs1, variable1, mut subs2, variable2, constraint1, constraint2) =
_output2, uniq_expr(src);
_output1,
_,
mut subs1,
variable1,
mut subs2,
variable2,
constraint1,
constraint2,
) = uniq_expr(src);
let mut unify_problems = Vec::new(); let mut unify_problems = Vec::new();
let content1 = infer_expr(&mut subs1, &mut unify_problems, &constraint1, variable1); let content1 = infer_expr(&mut subs1, &mut unify_problems, &constraint1, variable1);