Merge pull request #4399 from roc-lang/no-types-in-constraining-api

Have most constraining APIs take a type index rather than `Type`
This commit is contained in:
Folkert de Vries 2022-10-26 19:45:55 +02:00 committed by GitHub
commit 02a76bb8bd
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 485 additions and 366 deletions

View file

@ -211,10 +211,14 @@ impl Constraints {
EitherIndex::from_right(index) EitherIndex::from_right(index)
} }
pub fn push_expected_type(&mut self, expected: Expected<Type>) -> Index<Expected<Cell<Type>>> { pub fn push_expected_type(&mut self, expected: Expected<Type>) -> ExpectedTypeIndex {
Index::push_new(&mut self.expectations, expected.map(Cell::new)) Index::push_new(&mut self.expectations, expected.map(Cell::new))
} }
pub fn push_pat_expected_type(&mut self, expected: PExpected<Type>) -> PExpectedTypeIndex {
Index::push_new(&mut self.pattern_expectations, expected.map(Cell::new))
}
#[inline(always)] #[inline(always)]
pub fn push_category(&mut self, category: Category) -> Index<Category> { pub fn push_category(&mut self, category: Category) -> Index<Category> {
match category { match category {
@ -256,13 +260,11 @@ impl Constraints {
pub fn equal_types( pub fn equal_types(
&mut self, &mut self,
typ: Type, type_index: TypeOrVar,
expected: Expected<Type>, expected_index: ExpectedTypeIndex,
category: Category, category: Category,
region: Region, region: Region,
) -> Constraint { ) -> Constraint {
let type_index = self.push_type(typ);
let expected_index = Index::push_new(&mut self.expectations, expected.map(Cell::new));
let category_index = Self::push_category(self, category); let category_index = Self::push_category(self, category);
Constraint::Eq(Eq(type_index, expected_index, category_index, region)) Constraint::Eq(Eq(type_index, expected_index, category_index, region))
@ -271,12 +273,11 @@ impl Constraints {
pub fn equal_types_var( pub fn equal_types_var(
&mut self, &mut self,
var: Variable, var: Variable,
expected: Expected<Type>, expected_index: ExpectedTypeIndex,
category: Category, category: Category,
region: Region, region: Region,
) -> Constraint { ) -> Constraint {
let type_index = Self::push_type_variable(var); let type_index = Self::push_type_variable(var);
let expected_index = Index::push_new(&mut self.expectations, expected.map(Cell::new));
let category_index = Self::push_category(self, category); let category_index = Self::push_category(self, category);
Constraint::Eq(Eq(type_index, expected_index, category_index, region)) Constraint::Eq(Eq(type_index, expected_index, category_index, region))
@ -284,14 +285,12 @@ impl Constraints {
pub fn equal_types_with_storage( pub fn equal_types_with_storage(
&mut self, &mut self,
typ: Type, type_index: TypeOrVar,
expected: Expected<Type>, expected_index: ExpectedTypeIndex,
category: Category, category: Category,
region: Region, region: Region,
storage_var: Variable, storage_var: Variable,
) -> Constraint { ) -> Constraint {
let type_index = self.push_type(typ);
let expected_index = Index::push_new(&mut self.expectations, expected.map(Cell::new));
let category_index = Self::push_category(self, category); let category_index = Self::push_category(self, category);
let equal = Constraint::Eq(Eq(type_index, expected_index, category_index, region)); let equal = Constraint::Eq(Eq(type_index, expected_index, category_index, region));
@ -311,14 +310,11 @@ impl Constraints {
pub fn equal_pattern_types( pub fn equal_pattern_types(
&mut self, &mut self,
typ: Type, type_index: TypeOrVar,
expected: PExpected<Type>, expected_index: PExpectedTypeIndex,
category: PatternCategory, category: PatternCategory,
region: Region, region: Region,
) -> Constraint { ) -> Constraint {
let type_index = self.push_type(typ);
let expected_index =
Index::push_new(&mut self.pattern_expectations, expected.map(Cell::new));
let category_index = Self::push_pattern_category(self, category); let category_index = Self::push_pattern_category(self, category);
Constraint::Pattern(type_index, expected_index, category_index, region) Constraint::Pattern(type_index, expected_index, category_index, region)
@ -326,44 +322,34 @@ impl Constraints {
pub fn pattern_presence( pub fn pattern_presence(
&mut self, &mut self,
typ: Type, type_index: TypeOrVar,
expected: PExpected<Type>, expected_index: PExpectedTypeIndex,
category: PatternCategory, category: PatternCategory,
region: Region, region: Region,
) -> Constraint { ) -> Constraint {
let type_index = self.push_type(typ);
let expected_index =
Index::push_new(&mut self.pattern_expectations, expected.map(Cell::new));
let category_index = Index::push_new(&mut self.pattern_categories, category); let category_index = Index::push_new(&mut self.pattern_categories, category);
Constraint::PatternPresence(type_index, expected_index, category_index, region) Constraint::PatternPresence(type_index, expected_index, category_index, region)
} }
pub fn is_open_type(&mut self, typ: Type) -> Constraint { pub fn is_open_type(&mut self, type_index: TypeOrVar) -> Constraint {
let type_index = self.push_type(typ);
Constraint::IsOpenType(type_index) Constraint::IsOpenType(type_index)
} }
pub fn includes_tag<I>( pub fn includes_tag(
&mut self, &mut self,
typ: Type, type_index: TypeOrVar,
tag_name: TagName, tag_name: TagName,
types: I, payloads: Slice<Variable>,
category: PatternCategory, category: PatternCategory,
region: Region, region: Region,
) -> Constraint ) -> Constraint {
where
I: IntoIterator<Item = Type>,
{
let type_index = Index::push_new(&mut self.types, Cell::new(typ));
let category_index = Index::push_new(&mut self.pattern_categories, category); let category_index = Index::push_new(&mut self.pattern_categories, category);
let types_slice = Slice::extend_new(&mut self.types, types.into_iter().map(Cell::new));
let includes_tag = IncludesTag { let includes_tag = IncludesTag {
type_index, type_index,
tag_name, tag_name,
types: types_slice, types: payloads,
pattern_category: category_index, pattern_category: category_index,
region, region,
}; };
@ -373,7 +359,7 @@ impl Constraints {
Constraint::IncludesTag(includes_tag_index) Constraint::IncludesTag(includes_tag_index)
} }
fn variable_slice<I>(&mut self, it: I) -> Slice<Variable> pub fn variable_slice<I>(&mut self, it: I) -> Slice<Variable>
where where
I: IntoIterator<Item = Variable>, I: IntoIterator<Item = Variable>,
{ {
@ -572,14 +558,10 @@ impl Constraints {
pub fn lookup( pub fn lookup(
&mut self, &mut self,
symbol: Symbol, symbol: Symbol,
expected: Expected<Type>, expected_index: ExpectedTypeIndex,
region: Region, region: Region,
) -> Constraint { ) -> Constraint {
Constraint::Lookup( Constraint::Lookup(symbol, expected_index, region)
symbol,
Index::push_new(&mut self.expectations, expected.map(Cell::new)),
region,
)
} }
pub fn contains_save_the_environment(&self, constraint: &Constraint) -> bool { pub fn contains_save_the_environment(&self, constraint: &Constraint) -> bool {
@ -617,19 +599,6 @@ impl Constraints {
} }
pub fn store( pub fn store(
&mut self,
typ: Type,
variable: Variable,
filename: &'static str,
line_number: u32,
) -> Constraint {
let type_index = self.push_type(typ);
let string_index = Index::push_new(&mut self.strings, filename);
Constraint::Store(type_index, variable, string_index, line_number)
}
pub fn store_index(
&mut self, &mut self,
type_index: TypeOrVar, type_index: TypeOrVar,
variable: Variable, variable: Variable,
@ -804,9 +773,9 @@ pub struct LetConstraint {
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct IncludesTag { pub struct IncludesTag {
pub type_index: TypeIndex, pub type_index: TypeOrVar,
pub tag_name: TagName, pub tag_name: TagName,
pub types: Slice<Cell<Type>>, pub types: Slice<Variable>,
pub pattern_category: Index<PatternCategory>, pub pattern_category: Index<PatternCategory>,
pub region: Region, pub region: Region,
} }

View file

@ -32,8 +32,10 @@ pub fn add_numeric_bound_constr(
NumericBound::FloatExact(width) => { NumericBound::FloatExact(width) => {
let actual_type = Variable(float_width_to_variable(width)); let actual_type = Variable(float_width_to_variable(width));
let expected = Expected::ForReason(Reason::NumericLiteralSuffix, actual_type, region); let expected = Expected::ForReason(Reason::NumericLiteralSuffix, actual_type, region);
let type_index = constraints.push_type(Variable(num_var));
let expected_index = constraints.push_expected_type(expected);
let because_suffix = let because_suffix =
constraints.equal_types(Variable(num_var), expected, category, region); constraints.equal_types(type_index, expected_index, category, region);
num_constraints.extend([because_suffix]); num_constraints.extend([because_suffix]);
@ -42,8 +44,10 @@ pub fn add_numeric_bound_constr(
NumericBound::IntExact(width) => { NumericBound::IntExact(width) => {
let actual_type = Variable(int_lit_width_to_variable(width)); let actual_type = Variable(int_lit_width_to_variable(width));
let expected = Expected::ForReason(Reason::NumericLiteralSuffix, actual_type, region); let expected = Expected::ForReason(Reason::NumericLiteralSuffix, actual_type, region);
let type_index = constraints.push_type(Variable(num_var));
let expected_index = constraints.push_expected_type(expected);
let because_suffix = let because_suffix =
constraints.equal_types(Variable(num_var), expected, category, region); constraints.equal_types(type_index, expected_index, category, region);
num_constraints.extend([because_suffix]); num_constraints.extend([because_suffix]);
@ -52,7 +56,9 @@ pub fn add_numeric_bound_constr(
NumericBound::Range(range) => { NumericBound::Range(range) => {
let actual_type = Variable(precision_var); let actual_type = Variable(precision_var);
let expected = Expected::NoExpectation(RangedNumber(range)); let expected = Expected::NoExpectation(RangedNumber(range));
let constr = constraints.equal_types(actual_type, expected, category, region); let type_index = constraints.push_type(actual_type);
let expected_index = constraints.push_expected_type(expected);
let constr = constraints.equal_types(type_index, expected_index, category, region);
num_constraints.extend([constr]); num_constraints.extend([constr]);
@ -84,14 +90,19 @@ pub fn int_literal(
Category::Num, Category::Num,
); );
let num_type_index = constraints.push_type(num_type);
let expect_precision_var = constraints.push_expected_type(ForReason(
reason,
num_int(Type::Variable(precision_var)),
region,
));
constrs.extend([ constrs.extend([
constraints.equal_types( constraints.equal_types(num_type_index, expect_precision_var, Category::Int, region),
num_type.clone(), {
ForReason(reason, num_int(Type::Variable(precision_var)), region), let expected_index = constraints.push_expected_type(expected);
Category::Int, constraints.equal_types(num_type_index, expected_index, Category::Int, region)
region, },
),
constraints.equal_types(num_type, expected, Category::Int, region),
]); ]);
// TODO the precision_var is not part of the exists here; for float it is. Which is correct? // TODO the precision_var is not part of the exists here; for float it is. Which is correct?
@ -121,14 +132,24 @@ pub fn single_quote_literal(
Category::Character, Category::Character,
); );
let num_type_index = constraints.push_type(num_type);
let expect_precision_var = constraints.push_expected_type(ForReason(
reason,
num_int(Type::Variable(precision_var)),
region,
));
constrs.extend([ constrs.extend([
constraints.equal_types( constraints.equal_types(
num_type.clone(), num_type_index,
ForReason(reason, num_int(Type::Variable(precision_var)), region), expect_precision_var,
Category::Character, Category::Character,
region, region,
), ),
constraints.equal_types(num_type, expected, Category::Character, region), {
let expected_index = constraints.push_expected_type(expected);
constraints.equal_types(num_type_index, expected_index, Category::Character, region)
},
]); ]);
let and_constraint = constraints.and_constraint(constrs); let and_constraint = constraints.and_constraint(constrs);
@ -157,14 +178,19 @@ pub fn float_literal(
Category::Frac, Category::Frac,
); );
let num_type_index = constraints.push_type(num_type);
let expect_precision_var = constraints.push_expected_type(ForReason(
reason,
num_float(Type::Variable(precision_var)),
region,
));
constrs.extend([ constrs.extend([
constraints.equal_types( constraints.equal_types(num_type_index, expect_precision_var, Category::Frac, region),
num_type.clone(), {
ForReason(reason, num_float(Type::Variable(precision_var)), region), let expected_index = constraints.push_expected_type(expected);
Category::Frac, constraints.equal_types(num_type_index, expected_index, Category::Frac, region)
region, },
),
constraints.equal_types(num_type, expected, Category::Frac, region),
]); ]);
let and_constraint = constraints.and_constraint(constrs); let and_constraint = constraints.and_constraint(constrs);
@ -190,7 +216,9 @@ pub fn num_literal(
Category::Num, Category::Num,
); );
constrs.extend([constraints.equal_types(num_type, expected, Category::Num, region)]); let type_index = constraints.push_type(num_type);
let expected_index = constraints.push_expected_type(expected);
constrs.extend([constraints.equal_types(type_index, expected_index, Category::Num, region)]);
let and_constraint = constraints.and_constraint(constrs); let and_constraint = constraints.and_constraint(constrs);
constraints.exists([num_var], and_constraint) constraints.exists([num_var], and_constraint)

View file

@ -151,6 +151,10 @@ fn constrain_untyped_closure(
); );
let pattern_state_constraints = constraints.and_constraint(pattern_state.constraints); let pattern_state_constraints = constraints.and_constraint(pattern_state.constraints);
let function_type = constraints.push_type(function_type);
let expected = constraints.push_expected_type(expected);
let cons = [ let cons = [
constraints.let_constraint( constraints.let_constraint(
[], [],
@ -211,7 +215,9 @@ pub fn constrain_expr(
rec_constraints.push(field_con); rec_constraints.push(field_con);
} }
let record_type = Type::Record(field_types, TypeExtension::Closed); let record_type =
constraints.push_type(Type::Record(field_types, TypeExtension::Closed));
let expected = constraints.push_expected_type(expected);
let record_con = constraints.equal_types_with_storage( let record_con = constraints.equal_types_with_storage(
record_type, record_type,
@ -256,33 +262,33 @@ pub fn constrain_expr(
let record_type = Type::Variable(*record_var); let record_type = Type::Variable(*record_var);
// NOTE from elm compiler: fields_type is separate so that Error propagates better // NOTE from elm compiler: fields_type is separate so that Error propagates better
let fields_type_expected = constraints.push_expected_type(NoExpectation(fields_type));
let fields_con = constraints.equal_types_var( let fields_con = constraints.equal_types_var(
*record_var, *record_var,
NoExpectation(fields_type), fields_type_expected,
Category::Record, Category::Record,
region, region,
); );
let expected_record = constraints.push_expected_type(expected);
let record_con = let record_con =
constraints.equal_types_var(*record_var, expected, Category::Record, region); constraints.equal_types_var(*record_var, expected_record, Category::Record, region);
vars.push(*record_var); vars.push(*record_var);
vars.push(*ext_var); vars.push(*ext_var);
let con = constraints.lookup( let record_being_updated_expectation = constraints.push_expected_type(ForReason(
*symbol, Reason::RecordUpdateKeys(
ForReason( *symbol,
Reason::RecordUpdateKeys( updates
*symbol, .iter()
updates .map(|(key, field)| (key.clone(), field.region))
.iter() .collect(),
.map(|(key, field)| (key.clone(), field.region))
.collect(),
),
record_type,
region,
), ),
record_type,
region, region,
); ));
let con = constraints.lookup(*symbol, record_being_updated_expectation, region);
// ensure constraints are solved in this order, gives better errors // ensure constraints are solved in this order, gives better errors
cons.insert(0, fields_con); cons.insert(0, fields_con);
@ -292,7 +298,11 @@ pub fn constrain_expr(
let and_constraint = constraints.and_constraint(cons); let and_constraint = constraints.and_constraint(cons);
constraints.exists(vars, and_constraint) constraints.exists(vars, and_constraint)
} }
Str(_) => constraints.equal_types(str_type(), expected, Category::Str, region), Str(_) => {
let str_index = constraints.push_type(str_type());
let expected_index = constraints.push_expected_type(expected);
constraints.equal_types(str_index, expected_index, Category::Str, region)
}
SingleQuote(num_var, precision_var, _, bound) => single_quote_literal( SingleQuote(num_var, precision_var, _, bound) => single_quote_literal(
constraints, constraints,
*num_var, *num_var,
@ -306,9 +316,11 @@ pub fn constrain_expr(
loc_elems, loc_elems,
} => { } => {
if loc_elems.is_empty() { if loc_elems.is_empty() {
let elem_type_index = constraints.push_type(empty_list_type(*elem_var));
let expected_index = constraints.push_expected_type(expected);
let eq = constraints.equal_types( let eq = constraints.equal_types(
empty_list_type(*elem_var), elem_type_index,
expected, expected_index,
Category::List, Category::List,
region, region,
); );
@ -336,9 +348,11 @@ pub fn constrain_expr(
list_constraints.push(constraint); list_constraints.push(constraint);
} }
let elem_type_index = constraints.push_type(list_type(list_elem_type));
let expected_index = constraints.push_expected_type(expected);
list_constraints.push(constraints.equal_types( list_constraints.push(constraints.equal_types(
list_type(list_elem_type), elem_type_index,
expected, expected_index,
Category::List, Category::List,
region, region,
)); ));
@ -407,11 +421,13 @@ pub fn constrain_expr(
arg_cons.push(arg_con); arg_cons.push(arg_con);
} }
let expected_fn_type = ForReason( let expected_fn_type = constraints.push_expected_type(ForReason(
fn_reason, fn_reason,
Function(arg_types, Box::new(closure_type), Box::new(ret_type)), Function(arg_types, Box::new(closure_type), Box::new(ret_type)),
region, region,
); ));
let expected_final_type = constraints.push_expected_type(expected);
let category = Category::CallResult(opt_symbol, *called_via); let category = Category::CallResult(opt_symbol, *called_via);
@ -419,7 +435,7 @@ pub fn constrain_expr(
fn_con, fn_con,
constraints.equal_types_var(*fn_var, expected_fn_type, category.clone(), fn_region), constraints.equal_types_var(*fn_var, expected_fn_type, category.clone(), fn_region),
constraints.and_constraint(arg_cons), constraints.and_constraint(arg_cons),
constraints.equal_types_var(*ret_var, expected, category, region), constraints.equal_types_var(*ret_var, expected_final_type, category, region),
]; ];
let and_constraint = constraints.and_constraint(and_cons); let and_constraint = constraints.and_constraint(and_cons);
@ -427,26 +443,25 @@ pub fn constrain_expr(
} }
Var(symbol, variable) => { Var(symbol, variable) => {
// Save the expectation in the variable, then lookup the symbol's type in the environment // Save the expectation in the variable, then lookup the symbol's type in the environment
let store_expected = let expected_type = constraints.push_type(expected.get_type_ref().clone());
constraints.store(expected.get_type_ref().clone(), *variable, file!(), line!()); let store_expected = constraints.store(expected_type, *variable, file!(), line!());
let lookup_constr =
constraints.lookup(*symbol, expected.replace(Type::Variable(*variable)), region); let store_into_var =
constraints.push_expected_type(expected.replace(Type::Variable(*variable)));
let lookup_constr = constraints.lookup(*symbol, store_into_var, region);
constraints.and_constraint([store_expected, lookup_constr]) constraints.and_constraint([store_expected, lookup_constr])
} }
&AbilityMember(symbol, specialization_id, specialization_var) => { &AbilityMember(symbol, specialization_id, specialization_var) => {
// Save the expectation in the `specialization_var` so we know what to specialize, then // Save the expectation in the `specialization_var` so we know what to specialize, then
// lookup the member in the environment. // lookup the member in the environment.
let store_expected = constraints.store( let expected_type = constraints.push_type(expected.get_type_ref().clone());
expected.get_type_ref().clone(), let store_expected =
specialization_var, constraints.store(expected_type, specialization_var, file!(), line!());
file!(), let store_specialization_var = constraints
line!(), .push_expected_type(Expected::NoExpectation(Type::Variable(specialization_var)));
); let lookup_constr = constraints.lookup(symbol, store_specialization_var, region);
let lookup_constr = constraints.lookup(
symbol,
Expected::NoExpectation(Type::Variable(specialization_var)),
region,
);
// Make sure we attempt to resolve the specialization, if we can. // Make sure we attempt to resolve the specialization, if we can.
if let Some(specialization_id) = specialization_id { if let Some(specialization_id) = specialization_id {
@ -527,11 +542,9 @@ pub fn constrain_expr(
{ {
vars.push(*var); vars.push(*var);
all_constraints.push(constraints.lookup( let store_into =
*symbol, constraints.push_expected_type(NoExpectation(Type::Variable(*var)));
NoExpectation(Type::Variable(*var)), all_constraints.push(constraints.lookup(*symbol, store_into, Region::zero()));
Region::zero(),
));
} }
constraints.exists_many(vars, all_constraints) constraints.exists_many(vars, all_constraints)
@ -579,11 +592,10 @@ pub fn constrain_expr(
{ {
vars.push(*var); vars.push(*var);
all_constraints.push(constraints.lookup( let store_into =
*symbol, constraints.push_expected_type(NoExpectation(Type::Variable(*var)));
NoExpectation(Type::Variable(*var)),
Region::zero(), all_constraints.push(constraints.lookup(*symbol, store_into, Region::zero()));
));
} }
constraints.exists_many(vars, all_constraints) constraints.exists_many(vars, all_constraints)
@ -603,9 +615,10 @@ pub fn constrain_expr(
// TODO why does this cond var exist? is it for error messages? // TODO why does this cond var exist? is it for error messages?
let first_cond_region = branches[0].0.region; let first_cond_region = branches[0].0.region;
let expected_bool = constraints.push_expected_type(expect_bool(first_cond_region));
let cond_var_is_bool_con = constraints.equal_types_var( let cond_var_is_bool_con = constraints.equal_types_var(
*cond_var, *cond_var,
expect_bool(first_cond_region), expected_bool,
Category::If, Category::If,
first_cond_region, first_cond_region,
); );
@ -662,9 +675,11 @@ pub fn constrain_expr(
), ),
); );
let expected_result_type = constraints.push_expected_type(NoExpectation(tipe));
let ast_con = constraints.equal_types_var( let ast_con = constraints.equal_types_var(
*branch_var, *branch_var,
NoExpectation(tipe), expected_result_type,
Category::Storage(std::file!(), std::line!()), Category::Storage(std::file!(), std::line!()),
region, region,
); );
@ -717,6 +732,8 @@ pub fn constrain_expr(
), ),
); );
let expected = constraints.push_expected_type(expected);
branch_cons.push(constraints.equal_types_var( branch_cons.push(constraints.equal_types_var(
*branch_var, *branch_var,
expected, expected,
@ -910,6 +927,8 @@ pub fn constrain_expr(
body_constraints, body_constraints,
); );
let expected = constraints.push_expected_type(expected);
let result_con = let result_con =
constraints.equal_types_var(body_var, expected, Category::When, region); constraints.equal_types_var(body_var, expected, Category::When, region);
@ -939,19 +958,22 @@ pub fn constrain_expr(
rec_field_types.insert(label, RecordField::Demanded(field_type)); rec_field_types.insert(label, RecordField::Demanded(field_type));
let record_type = Type::Record(rec_field_types, TypeExtension::from_type(ext_type)); let record_type = Type::Record(rec_field_types, TypeExtension::from_type(ext_type));
let record_expected = Expected::NoExpectation(record_type); let record_expected =
constraints.push_expected_type(NoExpectation(record_type.clone()));
let category = Category::Access(field.clone()); let category = Category::Access(field.clone());
let record_con = constraints.equal_types_var( let record_con =
*record_var, constraints.equal_types_var(*record_var, record_expected, category.clone(), region);
record_expected.clone(),
category.clone(),
region,
);
let constraint = let constraint = constrain_expr(
constrain_expr(constraints, env, region, &loc_expr.value, record_expected); constraints,
env,
region,
&loc_expr.value,
NoExpectation(record_type),
);
let expected = constraints.push_expected_type(expected);
let eq = constraints.equal_types_var(field_var, expected, category, region); let eq = constraints.equal_types_var(field_var, expected, category, region);
constraints.exists_many( constraints.exists_many(
@ -980,38 +1002,46 @@ pub fn constrain_expr(
let category = Category::Accessor(field.clone()); let category = Category::Accessor(field.clone());
let record_expected = Expected::NoExpectation(record_type.clone()); let record_expected =
constraints.push_expected_type(NoExpectation(record_type.clone()));
let record_con = let record_con =
constraints.equal_types_var(*record_var, record_expected, category.clone(), region); constraints.equal_types_var(*record_var, record_expected, category.clone(), region);
let lambda_set = Type::ClosureTag { let lambda_set = constraints.push_expected_type(NoExpectation(Type::ClosureTag {
name: *closure_name, name: *closure_name,
captures: vec![], captures: vec![],
ambient_function: *function_var, ambient_function: *function_var,
}; }));
let closure_type = Type::Variable(*closure_var); let closure_type = Type::Variable(*closure_var);
let function_type = Type::Function( let function_type_index = constraints.push_type(Type::Function(
vec![record_type], vec![record_type],
Box::new(closure_type), Box::new(closure_type),
Box::new(field_type), Box::new(field_type),
); ));
let cons = [ let cons = [
constraints.equal_types_var( constraints.equal_types_var(*closure_var, lambda_set, category.clone(), region),
*closure_var, {
NoExpectation(lambda_set), let expected_index = constraints.push_expected_type(expected);
category.clone(), constraints.equal_types(
region, function_type_index,
), expected_index,
constraints.equal_types(function_type.clone(), expected, category.clone(), region), category.clone(),
constraints.equal_types( region,
function_type, )
NoExpectation(Variable(*function_var)), },
category, {
region, let function_var_index =
), constraints.push_expected_type(NoExpectation(Variable(*function_var)));
constraints.equal_types(
function_type_index,
function_var_index,
category,
region,
)
},
record_con, record_con,
]; ];
@ -1083,12 +1113,15 @@ pub fn constrain_expr(
types.push(Type::Variable(*var)); types.push(Type::Variable(*var));
} }
let tag_union_type = constraints.push_type(Type::TagUnion(
vec![(name.clone(), types)],
TypeExtension::from_type(Type::Variable(*ext_var)),
));
let expected = constraints.push_expected_type(expected);
let union_con = constraints.equal_types_with_storage( let union_con = constraints.equal_types_with_storage(
Type::TagUnion( tag_union_type,
vec![(name.clone(), types)], expected,
TypeExtension::from_type(Type::Variable(*ext_var)),
),
expected.clone(),
Category::TagApply { Category::TagApply {
tag_name: name.clone(), tag_name: name.clone(),
args_count: arguments.len(), args_count: arguments.len(),
@ -1109,13 +1142,15 @@ pub fn constrain_expr(
name, name,
closure_name, closure_name,
} => { } => {
let function_or_tag_union = constraints.push_type(Type::FunctionOrTagUnion(
name.clone(),
*closure_name,
TypeExtension::from_type(Type::Variable(*ext_var)),
));
let expected = constraints.push_expected_type(expected);
let union_con = constraints.equal_types_with_storage( let union_con = constraints.equal_types_with_storage(
Type::FunctionOrTagUnion( function_or_tag_union,
name.clone(), expected,
*closure_name,
TypeExtension::from_type(Type::Variable(*ext_var)),
),
expected.clone(),
Category::TagApply { Category::TagApply {
tag_name: name.clone(), tag_name: name.clone(),
args_count: 0, args_count: 0,
@ -1137,7 +1172,7 @@ pub fn constrain_expr(
let (arg_var, arg_loc_expr) = &**argument; let (arg_var, arg_loc_expr) = &**argument;
let arg_type = Type::Variable(*arg_var); let arg_type = Type::Variable(*arg_var);
let opaque_type = Type::Alias { let opaque_type = constraints.push_type(Type::Alias {
symbol: *name, symbol: *name,
type_arguments: type_arguments type_arguments: type_arguments
.iter() .iter()
@ -1149,7 +1184,7 @@ pub fn constrain_expr(
lambda_set_variables: lambda_set_variables.clone(), lambda_set_variables: lambda_set_variables.clone(),
actual: Box::new(arg_type.clone()), actual: Box::new(arg_type.clone()),
kind: AliasKind::Opaque, kind: AliasKind::Opaque,
}; });
// Constrain the argument // Constrain the argument
let arg_con = constrain_expr( let arg_con = constrain_expr(
@ -1162,6 +1197,7 @@ pub fn constrain_expr(
// Link the entire wrapped opaque type (with the now-constrained argument) to the // Link the entire wrapped opaque type (with the now-constrained argument) to the
// expected type // expected type
let expected = constraints.push_expected_type(expected);
let opaque_con = constraints.equal_types_with_storage( let opaque_con = constraints.equal_types_with_storage(
opaque_type, opaque_type,
expected, expected,
@ -1173,12 +1209,17 @@ pub fn constrain_expr(
// Link the entire wrapped opaque type (with the now-constrained argument) to the type // Link the entire wrapped opaque type (with the now-constrained argument) to the type
// variables of the opaque type // variables of the opaque type
// TODO: better expectation here // TODO: better expectation here
let link_type_variables_con = constraints.equal_types( let link_type_variables_con = {
arg_type, let type_index = constraints.push_type(arg_type);
Expected::NoExpectation((**specialized_def_type).clone()), let expected_index = constraints
Category::OpaqueArg, .push_expected_type(Expected::NoExpectation((**specialized_def_type).clone()));
arg_loc_expr.region, constraints.equal_types(
); type_index,
expected_index,
Category::OpaqueArg,
arg_loc_expr.region,
)
};
let mut vars = vec![*arg_var, *opaque_var]; let mut vars = vec![*arg_var, *opaque_var];
// Also add the fresh variables we created for the type argument and lambda sets // Also add the fresh variables we created for the type argument and lambda sets
@ -1216,50 +1257,59 @@ pub fn constrain_expr(
kind: AliasKind::Opaque, kind: AliasKind::Opaque,
}; };
let expected_opaque_type = constraints.push_expected_type(NoExpectation(opaque_type));
// Tie the opaque type to the opaque_var // Tie the opaque type to the opaque_var
let opaque_con = constraints.equal_types_var( let opaque_con = constraints.equal_types_var(
*opaque_var, *opaque_var,
Expected::NoExpectation(opaque_type), expected_opaque_type,
Category::OpaqueWrap(*opaque_name), Category::OpaqueWrap(*opaque_name),
region, region,
); );
// Tie the type of the value wrapped by the opaque to the opaque's type variables. // Tie the type of the value wrapped by the opaque to the opaque's type variables.
let link_type_variables_con = constraints.equal_types( let link_type_variables_con = {
argument_type.clone(), let arg_type_index = constraints.push_type(argument_type.clone());
Expected::NoExpectation((*specialized_def_type).clone()), let expected_specialized = constraints
Category::OpaqueArg, .push_expected_type(Expected::NoExpectation((*specialized_def_type).clone()));
region, constraints.equal_types(
); arg_type_index,
expected_specialized,
Category::OpaqueArg,
region,
)
};
let lambda_set = Type::ClosureTag { let lambda_set = constraints.push_expected_type(NoExpectation(Type::ClosureTag {
name: *function_name, name: *function_name,
captures: vec![], captures: vec![],
ambient_function: *function_var, ambient_function: *function_var,
}; }));
let closure_type = Type::Variable(*closure_var); let closure_type = Type::Variable(*closure_var);
let opaque_type = Type::Variable(*opaque_var); let opaque_type = Type::Variable(*opaque_var);
let function_type = Type::Function( let function_type = constraints.push_expected_type(NoExpectation(Type::Function(
vec![argument_type], vec![argument_type],
Box::new(closure_type), Box::new(closure_type),
Box::new(opaque_type), Box::new(opaque_type),
); )));
let expected = constraints.push_expected_type(expected);
let cons = [ let cons = [
opaque_con, opaque_con,
link_type_variables_con, link_type_variables_con,
constraints.equal_types_var( constraints.equal_types_var(
*closure_var, *closure_var,
NoExpectation(lambda_set), lambda_set,
Category::OpaqueWrap(*opaque_name), Category::OpaqueWrap(*opaque_name),
region, region,
), ),
constraints.equal_types_var( constraints.equal_types_var(
*function_var, *function_var,
Expected::NoExpectation(function_type), function_type,
Category::OpaqueWrap(*opaque_name), Category::OpaqueWrap(*opaque_name),
region, region,
), ),
@ -1314,6 +1364,7 @@ pub fn constrain_expr(
} }
let category = Category::LowLevelOpResult(*op); let category = Category::LowLevelOpResult(*op);
let expected = constraints.push_expected_type(expected);
// Deviation: elm uses an additional And here // Deviation: elm uses an additional And here
let eq = constraints.equal_types_var(*ret_var, expected, category, region); let eq = constraints.equal_types_var(*ret_var, expected, category, region);
@ -1354,6 +1405,7 @@ pub fn constrain_expr(
} }
let category = Category::ForeignCall; let category = Category::ForeignCall;
let expected = constraints.push_expected_type(expected);
// Deviation: elm uses an additional And here // Deviation: elm uses an additional And here
let eq = constraints.equal_types_var(*ret_var, expected, category, region); let eq = constraints.equal_types_var(*ret_var, expected, category, region);
@ -1362,6 +1414,7 @@ pub fn constrain_expr(
} }
TypedHole(var) => { TypedHole(var) => {
// store the expected type for this position // store the expected type for this position
let expected = constraints.push_expected_type(expected);
constraints.equal_types_var( constraints.equal_types_var(
*var, *var,
expected, expected,
@ -1441,12 +1494,17 @@ fn constrain_function_def(
signature.clone(), signature.clone(),
); );
def_pattern_state.constraints.push(constraints.equal_types( {
Type::Variable(expr_var), let expr_type_index = constraints.push_type(Type::Variable(expr_var));
annotation_expected, let expected_index =
Category::Storage(std::file!(), std::line!()), constraints.push_expected_type(annotation_expected);
Region::span_across(&annotation.region, &loc_body_expr.region), def_pattern_state.constraints.push(constraints.equal_types(
)); expr_type_index,
expected_index,
Category::Storage(std::file!(), std::line!()),
Region::span_across(&annotation.region, &loc_body_expr.region),
));
}
def_pattern_state def_pattern_state
}; };
@ -1477,10 +1535,12 @@ fn constrain_function_def(
let ret_constraint = let ret_constraint =
attach_resolution_constraints(constraints, env, ret_constraint); attach_resolution_constraints(constraints, env, ret_constraint);
let signature_index = constraints.push_type(signature);
let cons = [ let cons = [
ret_constraint, ret_constraint,
// Store type into AST vars. We use Store so errors aren't reported twice // Store type into AST vars. We use Store so errors aren't reported twice
constraints.store(signature, expr_var, std::file!(), std::line!()), constraints.store(signature_index, expr_var, std::file!(), std::line!()),
]; ];
let expr_con = constraints.and_constraint(cons); let expr_con = constraints.and_constraint(cons);
@ -1514,6 +1574,7 @@ fn constrain_function_def(
let closure_var = function_def.closure_type; let closure_var = function_def.closure_type;
let ret_type = *ret_type.clone(); let ret_type = *ret_type.clone();
let ret_type_index = constraints.push_type(ret_type.clone());
vars.push(ret_var); vars.push(ret_var);
vars.push(closure_var); vars.push(closure_var);
@ -1544,12 +1605,16 @@ fn constrain_function_def(
signature.clone(), signature.clone(),
); );
def_pattern_state.constraints.push(constraints.equal_types( {
Type::Variable(expr_var), let expr_type_index = constraints.push_type(Type::Variable(expr_var));
annotation_expected, let expected_index = constraints.push_expected_type(annotation_expected);
Category::Storage(std::file!(), std::line!()), def_pattern_state.constraints.push(constraints.equal_types(
Region::span_across(&annotation.region, &loc_body_expr.region), expr_type_index,
)); expected_index,
Category::Storage(std::file!(), std::line!()),
Region::span_across(&annotation.region, &loc_body_expr.region),
));
}
constrain_typed_function_arguments_simple( constrain_typed_function_arguments_simple(
constraints, constraints,
@ -1577,7 +1642,7 @@ fn constrain_function_def(
AnnotationSource::TypedBody { AnnotationSource::TypedBody {
region: annotation.region, region: annotation.region,
}, },
ret_type.clone(), ret_type,
); );
let ret_constraint = constrain_expr( let ret_constraint = constrain_expr(
@ -1592,8 +1657,15 @@ fn constrain_function_def(
vars.push(expr_var); vars.push(expr_var);
let defs_constraint = constraints.and_constraint(argument_pattern_state.constraints); let defs_constraint = constraints.and_constraint(argument_pattern_state.constraints);
let signature_closure_type = *signature_closure_type.clone(); let signature_closure_type = constraints.push_expected_type(Expected::FromAnnotation(
let signature_index = constraints.push_type(signature.clone()); loc_pattern,
arity,
AnnotationSource::TypedBody {
region: annotation.region,
},
*signature_closure_type.clone(),
));
let signature_index = constraints.push_type(signature);
let cons = [ let cons = [
constraints.let_constraint( constraints.let_constraint(
[], [],
@ -1604,19 +1676,12 @@ fn constrain_function_def(
), ),
constraints.equal_types_var( constraints.equal_types_var(
closure_var, closure_var,
Expected::FromAnnotation( signature_closure_type,
loc_pattern,
arity,
AnnotationSource::TypedBody {
region: annotation.region,
},
signature_closure_type,
),
Category::ClosureSize, Category::ClosureSize,
region, region,
), ),
constraints.store_index(signature_index, expr_var, std::file!(), std::line!()), constraints.store(signature_index, expr_var, std::file!(), std::line!()),
constraints.store(ret_type, ret_var, std::file!(), std::line!()), constraints.store(ret_type_index, ret_var, std::file!(), std::line!()),
closure_constraint, closure_constraint,
]; ];
@ -1728,10 +1793,12 @@ fn constrain_destructure_def(
annotation_expected, annotation_expected,
); );
let signature_index = constraints.push_type(signature);
let cons = [ let cons = [
ret_constraint, ret_constraint,
// Store type into AST vars. We use Store so errors aren't reported twice // Store type into AST vars. We use Store so errors aren't reported twice
constraints.store(signature, expr_var, std::file!(), std::line!()), constraints.store(signature_index, expr_var, std::file!(), std::line!()),
]; ];
let expr_con = constraints.and_constraint(cons); let expr_con = constraints.and_constraint(cons);
@ -1824,10 +1891,12 @@ fn constrain_value_def(
); );
let ret_constraint = attach_resolution_constraints(constraints, env, ret_constraint); let ret_constraint = attach_resolution_constraints(constraints, env, ret_constraint);
let signature_index = constraints.push_type(signature.clone());
let cons = [ let cons = [
ret_constraint, ret_constraint,
// Store type into AST vars. We use Store so errors aren't reported twice // Store type into AST vars. We use Store so errors aren't reported twice
constraints.store(signature.clone(), expr_var, std::file!(), std::line!()), constraints.store(signature_index, expr_var, std::file!(), std::line!()),
]; ];
let expr_con = constraints.and_constraint(cons); let expr_con = constraints.and_constraint(cons);
@ -1927,13 +1996,17 @@ fn constrain_when_branch_help(
state.headers.extend(partial_state.headers); state.headers.extend(partial_state.headers);
} else { } else {
// Make sure the bound variables in the patterns on the same branch agree in their types. // Make sure the bound variables in the patterns on the same branch agree in their types.
for (sym, typ1) in state.headers.iter() { for (sym, all_branches_bound_typ) in state.headers.iter() {
if let Some(typ2) = partial_state.headers.get(sym) { if let Some(this_bound_typ) = partial_state.headers.get(sym) {
let whole_typ = constraints.push_type(all_branches_bound_typ.value.clone());
let this_typ = constraints
.push_expected_type(Expected::NoExpectation(this_bound_typ.value.clone()));
state.constraints.push(constraints.equal_types( state.constraints.push(constraints.equal_types(
typ1.value.clone(), whole_typ,
Expected::NoExpectation(typ2.value.clone()), this_typ,
Category::When, Category::When,
typ2.region, this_bound_typ.region,
)); ));
} }
@ -2016,7 +2089,9 @@ fn constrain_empty_record(
region: Region, region: Region,
expected: Expected<Type>, expected: Expected<Type>,
) -> Constraint { ) -> Constraint {
constraints.equal_types(Type::EmptyRec, expected, Category::Record, region) let record_type_index = constraints.push_type(Type::EmptyRec);
let expected_index = constraints.push_expected_type(expected);
constraints.equal_types(record_type_index, expected_index, Category::Record, region)
} }
/// Constrain top-level module declarations /// Constrain top-level module declarations
@ -2214,12 +2289,16 @@ fn constrain_typed_def(
signature.clone(), signature.clone(),
); );
def_pattern_state.constraints.push(constraints.equal_types( {
expr_type.clone(), let type_index = constraints.push_type(expr_type.clone());
annotation_expected, let expected_index = constraints.push_expected_type(annotation_expected);
Category::Storage(std::file!(), std::line!()), def_pattern_state.constraints.push(constraints.equal_types(
Region::span_across(&annotation.region, &def.loc_expr.region), type_index,
)); expected_index,
Category::Storage(std::file!(), std::line!()),
Region::span_across(&annotation.region, &def.loc_expr.region),
));
}
// when a def is annotated, and its body is a closure, treat this // when a def is annotated, and its body is a closure, treat this
// as a named function (in elm terms) for error messages. // as a named function (in elm terms) for error messages.
@ -2256,6 +2335,7 @@ fn constrain_typed_def(
let ret_var = *ret_var; let ret_var = *ret_var;
let closure_var = *closure_var; let closure_var = *closure_var;
let ret_type = *ret_type.clone(); let ret_type = *ret_type.clone();
let ret_type_index = constraints.push_type(ret_type.clone());
vars.push(ret_var); vars.push(ret_var);
vars.push(closure_var); vars.push(closure_var);
@ -2286,7 +2366,7 @@ fn constrain_typed_def(
AnnotationSource::TypedBody { AnnotationSource::TypedBody {
region: annotation.region, region: annotation.region,
}, },
ret_type.clone(), ret_type,
); );
let ret_constraint = constrain_expr( let ret_constraint = constrain_expr(
@ -2301,7 +2381,14 @@ fn constrain_typed_def(
vars.push(*fn_var); vars.push(*fn_var);
let defs_constraint = constraints.and_constraint(argument_pattern_state.constraints); let defs_constraint = constraints.and_constraint(argument_pattern_state.constraints);
let signature_closure_type = *signature_closure_type.clone(); let signature_closure_type = constraints.push_expected_type(Expected::FromAnnotation(
def.loc_pattern.clone(),
arity,
AnnotationSource::TypedBody {
region: annotation.region,
},
*signature_closure_type.clone(),
));
let signature_index = constraints.push_type(signature); let signature_index = constraints.push_type(signature);
let cons = [ let cons = [
constraints.let_constraint( constraints.let_constraint(
@ -2313,20 +2400,13 @@ fn constrain_typed_def(
), ),
constraints.equal_types_var( constraints.equal_types_var(
closure_var, closure_var,
Expected::FromAnnotation( signature_closure_type,
def.loc_pattern.clone(),
arity,
AnnotationSource::TypedBody {
region: annotation.region,
},
signature_closure_type,
),
Category::ClosureSize, Category::ClosureSize,
region, region,
), ),
constraints.store_index(signature_index, *fn_var, std::file!(), std::line!()), constraints.store(signature_index, *fn_var, std::file!(), std::line!()),
constraints.store_index(signature_index, expr_var, std::file!(), std::line!()), constraints.store(signature_index, expr_var, std::file!(), std::line!()),
constraints.store(ret_type, ret_var, std::file!(), std::line!()), constraints.store(ret_type_index, ret_var, std::file!(), std::line!()),
closure_constraint, closure_constraint,
]; ];
@ -2417,9 +2497,11 @@ fn constrain_typed_function_arguments(
// this constraint must be to the def_pattern_state's constraints // this constraint must be to the def_pattern_state's constraints
def_pattern_state.vars.push(*pattern_var); def_pattern_state.vars.push(*pattern_var);
let ann_expected =
constraints.push_expected_type(Expected::NoExpectation(ann.clone()));
let pattern_con = constraints.equal_types_var( let pattern_con = constraints.equal_types_var(
*pattern_var, *pattern_var,
Expected::NoExpectation(ann.clone()), ann_expected,
Category::Storage(std::file!(), std::line!()), Category::Storage(std::file!(), std::line!()),
loc_pattern.region, loc_pattern.region,
); );
@ -2452,11 +2534,13 @@ fn constrain_typed_function_arguments(
{ {
// Store the actual type in a variable. // Store the actual type in a variable.
let ann_expected =
constraints.push_expected_type(Expected::NoExpectation(ann.clone()));
argument_pattern_state argument_pattern_state
.constraints .constraints
.push(constraints.equal_types_var( .push(constraints.equal_types_var(
annotation_var, annotation_var,
Expected::NoExpectation(ann.clone()), ann_expected,
Category::Storage(file!(), line!()), Category::Storage(file!(), line!()),
Region::zero(), Region::zero(),
)); ));
@ -2537,9 +2621,11 @@ fn constrain_typed_function_arguments_simple(
// this constraint must be to the def_pattern_state's constraints // this constraint must be to the def_pattern_state's constraints
def_pattern_state.vars.push(*pattern_var); def_pattern_state.vars.push(*pattern_var);
let ann_expected =
constraints.push_expected_type(Expected::NoExpectation(ann.clone()));
let pattern_con = constraints.equal_types_var( let pattern_con = constraints.equal_types_var(
*pattern_var, *pattern_var,
Expected::NoExpectation(ann.clone()), ann_expected,
Category::Storage(std::file!(), std::line!()), Category::Storage(std::file!(), std::line!()),
loc_pattern.region, loc_pattern.region,
); );
@ -2572,11 +2658,13 @@ fn constrain_typed_function_arguments_simple(
{ {
// Store the actual type in a variable. // Store the actual type in a variable.
let expected_annotation =
constraints.push_expected_type(Expected::NoExpectation(ann.clone()));
argument_pattern_state argument_pattern_state
.constraints .constraints
.push(constraints.equal_types_var( .push(constraints.equal_types_var(
annotation_var, annotation_var,
Expected::NoExpectation(ann.clone()), expected_annotation,
Category::Storage(file!(), line!()), Category::Storage(file!(), line!()),
Region::zero(), Region::zero(),
)); ));
@ -2758,27 +2846,22 @@ fn constrain_closure_size(
captured_types.push(Type::Variable(*var)); captured_types.push(Type::Variable(*var));
// make the variable equal to the looked-up type of symbol // make the variable equal to the looked-up type of symbol
captured_symbols_constraints.push(constraints.lookup( let store_into =
*symbol, constraints.push_expected_type(Expected::NoExpectation(Type::Variable(*var)));
Expected::NoExpectation(Type::Variable(*var)), captured_symbols_constraints.push(constraints.lookup(*symbol, store_into, Region::zero()));
Region::zero(),
));
} }
// pick a more efficient representation if we don't actually capture anything let finalizer = {
let closure_type = Type::ClosureTag { // pick a more efficient representation if we don't actually capture anything
name, let closure_type = Type::ClosureTag {
captures: captured_types, name,
ambient_function, captures: captured_types,
ambient_function,
};
let clos_type = constraints.push_expected_type(NoExpectation(closure_type));
constraints.equal_types_var(closure_var, clos_type, Category::ClosureSize, region)
}; };
let finalizer = constraints.equal_types_var(
closure_var,
NoExpectation(closure_type),
Category::ClosureSize,
region,
);
captured_symbols_constraints.push(finalizer); captured_symbols_constraints.push(finalizer);
constraints.and_constraint(captured_symbols_constraints) constraints.and_constraint(captured_symbols_constraints)
@ -3005,6 +3088,7 @@ fn constraint_recursive_function(
let ret_var = function_def.return_type; let ret_var = function_def.return_type;
let closure_var = function_def.closure_type; let closure_var = function_def.closure_type;
let ret_type = *ret_type.clone(); let ret_type = *ret_type.clone();
let ret_type_index = constraints.push_type(ret_type.clone());
vars.push(ret_var); vars.push(ret_var);
vars.push(closure_var); vars.push(closure_var);
@ -3056,7 +3140,7 @@ fn constraint_recursive_function(
env, env,
loc_body_expr.region, loc_body_expr.region,
&loc_body_expr.value, &loc_body_expr.value,
NoExpectation(ret_type.clone()), NoExpectation(ret_type),
); );
let expr_con = attach_resolution_constraints(constraints, env, expr_con); let expr_con = attach_resolution_constraints(constraints, env, expr_con);
@ -3072,11 +3156,15 @@ fn constraint_recursive_function(
state_constraints, state_constraints,
expr_con, expr_con,
), ),
constraints.equal_types(fn_type, expected, Category::Lambda, region), {
let type_index = constraints.push_type(fn_type);
let expected_index = constraints.push_expected_type(expected);
constraints.equal_types(type_index, expected_index, Category::Lambda, region)
},
// "fn_var is equal to the closure's type" - fn_var is used in code gen // "fn_var is equal to the closure's type" - fn_var is used in code gen
// Store type into AST vars. We use Store so errors aren't reported twice // Store type into AST vars. We use Store so errors aren't reported twice
constraints.store_index(signature_index, expr_var, std::file!(), std::line!()), constraints.store(signature_index, expr_var, std::file!(), std::line!()),
constraints.store(ret_type, ret_var, std::file!(), std::line!()), constraints.store(ret_type_index, ret_var, std::file!(), std::line!()),
closure_constraint, closure_constraint,
]; ];
@ -3197,11 +3285,13 @@ pub fn rec_defs_help_simple(
let ret_constraint = let ret_constraint =
attach_resolution_constraints(constraints, env, ret_constraint); attach_resolution_constraints(constraints, env, ret_constraint);
let signature_index = constraints.push_type(signature.clone());
let cons = [ let cons = [
ret_constraint, ret_constraint,
// Store type into AST vars. We use Store so errors aren't reported twice // Store type into AST vars. We use Store so errors aren't reported twice
constraints.store( constraints.store(
signature.clone(), signature_index,
expr_var, expr_var,
std::file!(), std::file!(),
std::line!(), std::line!(),
@ -3430,6 +3520,7 @@ fn rec_defs_help(
let ret_var = *ret_var; let ret_var = *ret_var;
let closure_var = *closure_var; let closure_var = *closure_var;
let ret_type = *ret_type.clone(); let ret_type = *ret_type.clone();
let ret_type_index = constraints.push_type(ret_type.clone());
vars.push(ret_var); vars.push(ret_var);
vars.push(closure_var); vars.push(closure_var);
@ -3455,11 +3546,11 @@ fn rec_defs_help(
&mut vars, &mut vars,
); );
let fn_type = Type::Function( let fn_type_index = constraints.push_type(Type::Function(
pattern_types, pattern_types,
Box::new(Type::Variable(closure_var)), Box::new(Type::Variable(closure_var)),
Box::new(ret_type.clone()), Box::new(ret_type.clone()),
); ));
let body_type = NoExpectation(ret_type.clone()); let body_type = NoExpectation(ret_type.clone());
let expr_con = constrain_expr( let expr_con = constrain_expr(
constraints, constraints,
@ -3474,6 +3565,7 @@ fn rec_defs_help(
let signature_index = constraints.push_type(signature); let signature_index = constraints.push_type(signature);
let state_constraints = constraints.and_constraint(state.constraints); let state_constraints = constraints.and_constraint(state.constraints);
let expected_index = constraints.push_expected_type(expected);
let cons = [ let cons = [
constraints.let_constraint( constraints.let_constraint(
[], [],
@ -3483,26 +3575,21 @@ fn rec_defs_help(
expr_con, expr_con,
), ),
constraints.equal_types( constraints.equal_types(
fn_type.clone(), fn_type_index,
expected.clone(), expected_index,
Category::Lambda, Category::Lambda,
region, region,
), ),
// "fn_var is equal to the closure's type" - fn_var is used in code gen // "fn_var is equal to the closure's type" - fn_var is used in code gen
// Store type into AST vars. We use Store so errors aren't reported twice // Store type into AST vars. We use Store so errors aren't reported twice
constraints.store_index( constraints.store(signature_index, *fn_var, std::file!(), std::line!()),
signature_index, constraints.store(
*fn_var,
std::file!(),
std::line!(),
),
constraints.store_index(
signature_index, signature_index,
expr_var, expr_var,
std::file!(), std::file!(),
std::line!(), std::line!(),
), ),
constraints.store(ret_type, ret_var, std::file!(), std::line!()), constraints.store(ret_type_index, ret_var, std::file!(), std::line!()),
closure_constraint, closure_constraint,
]; ];
@ -3541,10 +3628,17 @@ fn rec_defs_help(
let ret_constraint = let ret_constraint =
attach_resolution_constraints(constraints, env, ret_constraint); attach_resolution_constraints(constraints, env, ret_constraint);
let signature_index = constraints.push_type(signature);
let cons = [ let cons = [
ret_constraint, ret_constraint,
// Store type into AST vars. We use Store so errors aren't reported twice // Store type into AST vars. We use Store so errors aren't reported twice
constraints.store(signature, expr_var, std::file!(), std::line!()), constraints.store(
signature_index,
expr_var,
std::file!(),
std::line!(),
),
]; ];
let def_con = constraints.and_constraint(cons); let def_con = constraints.and_constraint(cons);

View file

@ -69,18 +69,16 @@ fn constrain_symbols_from_requires(
// Otherwise, this symbol comes from an app module - we want to check that the type // Otherwise, this symbol comes from an app module - we want to check that the type
// provided by the app is in fact what the package module requires. // provided by the app is in fact what the package module requires.
let arity = loc_type.value.arity(); let arity = loc_type.value.arity();
let provided_eq_requires_constr = constraints.lookup( let expected = constraints.push_expected_type(Expected::FromAnnotation(
loc_symbol.value, loc_symbol.map(|&s| Pattern::Identifier(s)),
Expected::FromAnnotation( arity,
loc_symbol.map(|&s| Pattern::Identifier(s)), AnnotationSource::RequiredSymbol {
arity, region: loc_type.region,
AnnotationSource::RequiredSymbol { },
region: loc_type.region, loc_type.value,
}, ));
loc_type.value, let provided_eq_requires_constr =
), constraints.lookup(loc_symbol.value, expected, loc_type.region);
loc_type.region,
);
constraints.and_constraint([provided_eq_requires_constr, constraint]) constraints.and_constraint([provided_eq_requires_constr, constraint])
} }
}) })
@ -122,11 +120,14 @@ pub fn frontload_ability_constraints(
let rigid_variables = vars.rigid_vars.iter().chain(vars.able_vars.iter()).copied(); let rigid_variables = vars.rigid_vars.iter().chain(vars.able_vars.iter()).copied();
let infer_variables = vars.flex_vars.iter().copied(); let infer_variables = vars.flex_vars.iter().copied();
let signature_expectation =
constraints.push_expected_type(Expected::NoExpectation(signature.clone()));
def_pattern_state def_pattern_state
.constraints .constraints
.push(constraints.equal_types_var( .push(constraints.equal_types_var(
signature_var, signature_var,
Expected::NoExpectation(signature.clone()), signature_expectation,
Category::Storage(file!(), line!()), Category::Storage(file!(), line!()),
Region::zero(), Region::zero(),
)); ));

View file

@ -182,9 +182,11 @@ pub fn constrain_pattern(
// _ -> "" // _ -> ""
// so, we know that "x" (in this case, a tag union) must be open. // so, we know that "x" (in this case, a tag union) must be open.
if could_be_a_tag_union(expected.get_type_ref()) { if could_be_a_tag_union(expected.get_type_ref()) {
let type_index = constraints.push_type(expected.get_type());
state state
.delayed_is_open_constraints .delayed_is_open_constraints
.push(constraints.is_open_type(expected.get_type())); .push(constraints.is_open_type(type_index));
} }
} }
UnsupportedPattern(_) | MalformedPattern(_, _) | OpaqueNotInScope(..) => { UnsupportedPattern(_) | MalformedPattern(_, _) | OpaqueNotInScope(..) => {
@ -193,9 +195,11 @@ pub fn constrain_pattern(
Identifier(symbol) | Shadowed(_, _, symbol) => { Identifier(symbol) | Shadowed(_, _, symbol) => {
if could_be_a_tag_union(expected.get_type_ref()) { if could_be_a_tag_union(expected.get_type_ref()) {
let type_index = constraints.push_type(expected.get_type_ref().clone());
state state
.delayed_is_open_constraints .delayed_is_open_constraints
.push(constraints.is_open_type(expected.get_type_ref().clone())); .push(constraints.is_open_type(type_index));
} }
state.headers.insert( state.headers.insert(
@ -212,9 +216,9 @@ pub fn constrain_pattern(
specializes: _, specializes: _,
} => { } => {
if could_be_a_tag_union(expected.get_type_ref()) { if could_be_a_tag_union(expected.get_type_ref()) {
state let type_index = constraints.push_type(expected.get_type_ref().clone());
.constraints
.push(constraints.is_open_type(expected.get_type_ref().clone())); state.constraints.push(constraints.is_open_type(type_index));
} }
state.headers.insert( state.headers.insert(
@ -238,6 +242,9 @@ pub fn constrain_pattern(
region, region,
Category::Num, Category::Num,
); );
let num_type = constraints.push_type(num_type);
let expected = constraints.push_pat_expected_type(expected);
state.constraints.push(constraints.equal_pattern_types( state.constraints.push(constraints.equal_pattern_types(
num_type, num_type,
@ -259,18 +266,19 @@ pub fn constrain_pattern(
region, region,
Category::Int, Category::Int,
); );
let num_type = constraints.push_type(num_type);
// Link the free num var with the int var and our expectation. // Link the free num var with the int var and our expectation.
let int_type = builtins::num_int(Type::Variable(precision_var)); let int_type = builtins::num_int(Type::Variable(precision_var));
state.constraints.push(constraints.equal_types( state.constraints.push({
num_type.clone(), // TODO check me if something breaks! let expected_index =
Expected::NoExpectation(int_type), constraints.push_expected_type(Expected::NoExpectation(int_type));
Category::Int, constraints.equal_types(num_type, expected_index, Category::Int, region)
region, });
));
// Also constrain the pattern against the num var, again to reuse aliases if they're present. // Also constrain the pattern against the num var, again to reuse aliases if they're present.
let expected = constraints.push_pat_expected_type(expected);
state.constraints.push(constraints.equal_pattern_types( state.constraints.push(constraints.equal_pattern_types(
num_type, num_type,
expected, expected,
@ -294,17 +302,18 @@ pub fn constrain_pattern(
// Link the free num var with the float var and our expectation. // Link the free num var with the float var and our expectation.
let float_type = builtins::num_float(Type::Variable(precision_var)); let float_type = builtins::num_float(Type::Variable(precision_var));
let num_type_index = constraints.push_type(num_type); // TODO check me if something breaks!
state.constraints.push(constraints.equal_types( state.constraints.push({
num_type.clone(), // TODO check me if something breaks! let expected_index =
Expected::NoExpectation(float_type), constraints.push_expected_type(Expected::NoExpectation(float_type));
Category::Frac, constraints.equal_types(num_type_index, expected_index, Category::Frac, region)
region, });
));
// Also constrain the pattern against the num var, again to reuse aliases if they're present. // Also constrain the pattern against the num var, again to reuse aliases if they're present.
let expected = constraints.push_pat_expected_type(expected);
state.constraints.push(constraints.equal_pattern_types( state.constraints.push(constraints.equal_pattern_types(
num_type, // TODO check me if something breaks! num_type_index,
expected, expected,
PatternCategory::Float, PatternCategory::Float,
region, region,
@ -312,8 +321,10 @@ pub fn constrain_pattern(
} }
StrLiteral(_) => { StrLiteral(_) => {
let str_type = constraints.push_type(builtins::str_type());
let expected = constraints.push_pat_expected_type(expected);
state.constraints.push(constraints.equal_pattern_types( state.constraints.push(constraints.equal_pattern_types(
builtins::str_type(), str_type,
expected, expected,
PatternCategory::Str, PatternCategory::Str,
region, region,
@ -336,16 +347,23 @@ pub fn constrain_pattern(
// Link the free num var with the int var and our expectation. // Link the free num var with the int var and our expectation.
let int_type = builtins::num_int(Type::Variable(precision_var)); let int_type = builtins::num_int(Type::Variable(precision_var));
state.constraints.push(constraints.equal_types( let num_type_index = constraints.push_type(num_type);
num_type.clone(), // TODO check me if something breaks!
Expected::NoExpectation(int_type), state.constraints.push({
Category::Int, let expected_index =
region, constraints.push_expected_type(Expected::NoExpectation(int_type));
)); constraints.equal_types(
num_type_index, // TODO check me if something breaks!
expected_index,
Category::Int,
region,
)
});
// Also constrain the pattern against the num var, again to reuse aliases if they're present. // Also constrain the pattern against the num var, again to reuse aliases if they're present.
let expected = constraints.push_pat_expected_type(expected);
state.constraints.push(constraints.equal_pattern_types( state.constraints.push(constraints.equal_pattern_types(
num_type, num_type_index,
expected, expected,
PatternCategory::Character, PatternCategory::Character,
region, region,
@ -385,13 +403,17 @@ pub fn constrain_pattern(
let field_type = match typ { let field_type = match typ {
DestructType::Guard(guard_var, loc_guard) => { DestructType::Guard(guard_var, loc_guard) => {
state.constraints.push(constraints.pattern_presence( let guard_type = constraints.push_type(Type::Variable(*guard_var));
Type::Variable(*guard_var), let expected_pat =
PExpected::ForReason( constraints.push_pat_expected_type(PExpected::ForReason(
PReason::PatternGuard, PReason::PatternGuard,
pat_type.clone(), pat_type.clone(),
loc_guard.region, loc_guard.region,
), ));
state.constraints.push(constraints.pattern_presence(
guard_type,
expected_pat,
PatternCategory::PatternGuard, PatternCategory::PatternGuard,
region, region,
)); ));
@ -409,13 +431,17 @@ pub fn constrain_pattern(
RecordField::Demanded(pat_type) RecordField::Demanded(pat_type)
} }
DestructType::Optional(expr_var, loc_expr) => { DestructType::Optional(expr_var, loc_expr) => {
state.constraints.push(constraints.pattern_presence( let expr_type = constraints.push_type(Type::Variable(*expr_var));
Type::Variable(*expr_var), let expected_pat =
PExpected::ForReason( constraints.push_pat_expected_type(PExpected::ForReason(
PReason::OptionalField, PReason::OptionalField,
pat_type.clone(), pat_type.clone(),
loc_expr.region, loc_expr.region,
), ));
state.constraints.push(constraints.pattern_presence(
expr_type,
expected_pat,
PatternCategory::PatternDefault, PatternCategory::PatternDefault,
region, region,
)); ));
@ -452,15 +478,20 @@ pub fn constrain_pattern(
let record_type = Type::Record(field_types, TypeExtension::from_type(ext_type)); let record_type = Type::Record(field_types, TypeExtension::from_type(ext_type));
let whole_var_index = constraints.push_type(Type::Variable(*whole_var));
let expected_record =
constraints.push_expected_type(Expected::NoExpectation(record_type));
let whole_con = constraints.equal_types( let whole_con = constraints.equal_types(
Type::Variable(*whole_var), whole_var_index,
Expected::NoExpectation(record_type), expected_record,
Category::Storage(std::file!(), std::line!()), Category::Storage(std::file!(), std::line!()),
region, region,
); );
let expected = constraints.push_pat_expected_type(expected);
let record_con = constraints.pattern_presence( let record_con = constraints.pattern_presence(
Type::Variable(*whole_var), whole_var_index,
expected, expected,
PatternCategory::Record, PatternCategory::Record,
region, region,
@ -475,12 +506,12 @@ pub fn constrain_pattern(
tag_name, tag_name,
arguments, arguments,
} => { } => {
let mut argument_types = Vec::with_capacity(arguments.len()); let argument_types = constraints.variable_slice(arguments.iter().map(|(var, _)| *var));
for (index, (pattern_var, loc_pattern)) in arguments.iter().enumerate() { for (index, (pattern_var, loc_pattern)) in arguments.iter().enumerate() {
state.vars.push(*pattern_var); state.vars.push(*pattern_var);
let pattern_type = Type::Variable(*pattern_var); let pattern_type = Type::Variable(*pattern_var);
argument_types.push(pattern_type.clone());
let expected = PExpected::ForReason( let expected = PExpected::ForReason(
PReason::TagArg { PReason::TagArg {
@ -501,21 +532,20 @@ pub fn constrain_pattern(
} }
let pat_category = PatternCategory::Ctor(tag_name.clone()); let pat_category = PatternCategory::Ctor(tag_name.clone());
let expected_type = constraints.push_type(expected.get_type_ref().clone());
let whole_con = constraints.includes_tag( let whole_con = constraints.includes_tag(
expected.clone().get_type(), expected_type,
tag_name.clone(), tag_name.clone(),
argument_types.clone(), argument_types,
pat_category.clone(), pat_category.clone(),
region, region,
); );
let tag_con = constraints.pattern_presence( let whole_type = constraints.push_type(Type::Variable(*whole_var));
Type::Variable(*whole_var), let expected = constraints.push_pat_expected_type(expected);
expected,
pat_category, let tag_con = constraints.pattern_presence(whole_type, expected, pat_category, region);
region,
);
state.vars.push(*whole_var); state.vars.push(*whole_var);
state.vars.push(*ext_var); state.vars.push(*ext_var);
@ -561,9 +591,12 @@ pub fn constrain_pattern(
); );
// Next, link `whole_var` to the opaque type of "@Id who" // Next, link `whole_var` to the opaque type of "@Id who"
let whole_var_index = constraints.push_type(Type::Variable(*whole_var));
let expected_opaque =
constraints.push_expected_type(Expected::NoExpectation(opaque_type));
let whole_con = constraints.equal_types( let whole_con = constraints.equal_types(
Type::Variable(*whole_var), whole_var_index,
Expected::NoExpectation(opaque_type), expected_opaque,
Category::Storage(std::file!(), std::line!()), Category::Storage(std::file!(), std::line!()),
region, region,
); );
@ -581,16 +614,21 @@ pub fn constrain_pattern(
// This must **always** be a presence constraint, that is enforcing // This must **always** be a presence constraint, that is enforcing
// `[A k1, B k1] += typeof (A s)`, because we are in a destructure position and not // `[A k1, B k1] += typeof (A s)`, because we are in a destructure position and not
// all constructors are covered in this branch! // all constructors are covered in this branch!
let arg_pattern_type = constraints.push_type(arg_pattern_type);
let specialized_type = constraints
.push_pat_expected_type(PExpected::NoExpectation((**specialized_def_type).clone()));
let link_type_variables_con = constraints.pattern_presence( let link_type_variables_con = constraints.pattern_presence(
arg_pattern_type, arg_pattern_type,
PExpected::NoExpectation((**specialized_def_type).clone()), specialized_type,
PatternCategory::Opaque(*opaque), PatternCategory::Opaque(*opaque),
loc_arg_pattern.region, loc_arg_pattern.region,
); );
// Next, link `whole_var` (the type of "@Id who") to the expected type // Next, link `whole_var` (the type of "@Id who") to the expected type
let whole_type = constraints.push_type(Type::Variable(*whole_var));
let expected = constraints.push_pat_expected_type(expected);
let opaque_pattern_con = constraints.pattern_presence( let opaque_pattern_con = constraints.pattern_presence(
Type::Variable(*whole_var), whole_type,
expected, expected,
PatternCategory::Opaque(*opaque), PatternCategory::Opaque(*opaque),
region, region,

View file

@ -1323,40 +1323,29 @@ fn solve(
region, region,
} = includes_tag; } = includes_tag;
let typ_cell = &constraints.types[type_index.index()];
let tys_cells = &constraints.types[types.indices()];
let pattern_category = &constraints.pattern_categories[pattern_category.index()]; let pattern_category = &constraints.pattern_categories[pattern_category.index()];
let actual = type_cell_to_var( let actual = either_type_index_to_var(
constraints,
subs, subs,
rank, rank,
pools,
problems, problems,
abilities_store, abilities_store,
obligation_cache, obligation_cache,
pools,
aliases, aliases,
typ_cell, *type_index,
); );
let tys = { let payload_types = constraints.variables[types.indices()]
let mut tys = Vec::with_capacity(tys_cells.len()); .iter()
for cell in tys_cells { .map(|v| Type::Variable(*v))
let actual = type_cell_to_var( .collect();
subs,
rank,
problems,
abilities_store,
obligation_cache,
pools,
aliases,
cell,
);
tys.push(Type::Variable(actual));
}
tys
};
let tag_ty = Type::TagUnion(vec![(tag_name.clone(), tys)], TypeExtension::Closed); let tag_ty = Type::TagUnion(
vec![(tag_name.clone(), payload_types)],
TypeExtension::Closed,
);
let includes = type_to_var( let includes = type_to_var(
subs, subs,
rank, rank,