Require type and expected indices in equal_types constraints

This commit is contained in:
Ayaz Hafiz 2022-10-24 14:05:19 -05:00
parent 35a4781045
commit 55d7f3f658
No known key found for this signature in database
GPG Key ID: 0E2A37416A25EF58
4 changed files with 189 additions and 104 deletions

View File

@ -211,7 +211,7 @@ impl Constraints {
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))
}
@ -256,13 +256,11 @@ impl Constraints {
pub fn equal_types(
&mut self,
typ: Type,
expected: Expected<Type>,
type_index: TypeOrVar,
expected_index: ExpectedTypeIndex,
category: Category,
region: Region,
) -> 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);
Constraint::Eq(Eq(type_index, expected_index, category_index, region))

View File

@ -32,8 +32,10 @@ pub fn add_numeric_bound_constr(
NumericBound::FloatExact(width) => {
let actual_type = Variable(float_width_to_variable(width));
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 =
constraints.equal_types(Variable(num_var), expected, category, region);
constraints.equal_types(type_index, expected_index, category, region);
num_constraints.extend([because_suffix]);
@ -42,8 +44,10 @@ pub fn add_numeric_bound_constr(
NumericBound::IntExact(width) => {
let actual_type = Variable(int_lit_width_to_variable(width));
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 =
constraints.equal_types(Variable(num_var), expected, category, region);
constraints.equal_types(type_index, expected_index, category, region);
num_constraints.extend([because_suffix]);
@ -52,7 +56,9 @@ pub fn add_numeric_bound_constr(
NumericBound::Range(range) => {
let actual_type = Variable(precision_var);
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]);
@ -84,14 +90,19 @@ pub fn int_literal(
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([
constraints.equal_types(
num_type.clone(),
ForReason(reason, num_int(Type::Variable(precision_var)), region),
Category::Int,
region,
),
constraints.equal_types(num_type, expected, Category::Int, region),
constraints.equal_types(num_type_index, expect_precision_var, Category::Int, region),
{
let expected_index = constraints.push_expected_type(expected);
constraints.equal_types(num_type_index, expected_index, Category::Int, region)
},
]);
// TODO the precision_var is not part of the exists here; for float it is. Which is correct?
@ -122,13 +133,20 @@ pub fn single_quote_literal(
);
constrs.extend([
constraints.equal_types(
num_type.clone(),
ForReason(reason, num_int(Type::Variable(precision_var)), region),
Category::Character,
region,
),
constraints.equal_types(num_type, expected, Category::Character, region),
{
let type_index = constraints.push_type(num_type.clone());
let expected_index = constraints.push_expected_type(ForReason(
reason,
num_int(Type::Variable(precision_var)),
region,
));
constraints.equal_types(type_index, expected_index, Category::Character, region)
},
{
let type_index = constraints.push_type(num_type);
let expected_index = constraints.push_expected_type(expected);
constraints.equal_types(type_index, expected_index, Category::Character, region)
},
]);
let and_constraint = constraints.and_constraint(constrs);
@ -158,13 +176,20 @@ pub fn float_literal(
);
constrs.extend([
constraints.equal_types(
num_type.clone(),
ForReason(reason, num_float(Type::Variable(precision_var)), region),
Category::Frac,
region,
),
constraints.equal_types(num_type, expected, Category::Frac, region),
{
let type_index = constraints.push_type(num_type.clone());
let expected_index = constraints.push_expected_type(ForReason(
reason,
num_float(Type::Variable(precision_var)),
region,
));
constraints.equal_types(type_index, expected_index, Category::Frac, region)
},
{
let type_index = constraints.push_type(num_type);
let expected_index = constraints.push_expected_type(expected);
constraints.equal_types(type_index, expected_index, Category::Frac, region)
},
]);
let and_constraint = constraints.and_constraint(constrs);
@ -190,7 +215,9 @@ pub fn num_literal(
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);
constraints.exists([num_var], and_constraint)

View File

@ -292,7 +292,11 @@ pub fn constrain_expr(
let and_constraint = constraints.and_constraint(cons);
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(
constraints,
*num_var,
@ -306,9 +310,11 @@ pub fn constrain_expr(
loc_elems,
} => {
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(
empty_list_type(*elem_var),
expected,
elem_type_index,
expected_index,
Category::List,
region,
);
@ -336,9 +342,11 @@ pub fn constrain_expr(
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_type(list_elem_type),
expected,
elem_type_index,
expected_index,
Category::List,
region,
));
@ -1005,13 +1013,17 @@ pub fn constrain_expr(
category.clone(),
region,
),
constraints.equal_types(function_type.clone(), expected, category.clone(), region),
constraints.equal_types(
function_type,
NoExpectation(Variable(*function_var)),
category,
region,
),
{
let type_index = constraints.push_type(function_type.clone());
let expected_index = constraints.push_expected_type(expected);
constraints.equal_types(type_index, expected_index, category.clone(), region)
},
{
let type_index = constraints.push_type(function_type);
let expected_index =
constraints.push_expected_type(NoExpectation(Variable(*function_var)));
constraints.equal_types(type_index, expected_index, category, region)
},
record_con,
];
@ -1173,12 +1185,17 @@ pub fn constrain_expr(
// Link the entire wrapped opaque type (with the now-constrained argument) to the type
// variables of the opaque type
// TODO: better expectation here
let link_type_variables_con = constraints.equal_types(
arg_type,
Expected::NoExpectation((**specialized_def_type).clone()),
Category::OpaqueArg,
arg_loc_expr.region,
);
let link_type_variables_con = {
let type_index = constraints.push_type(arg_type);
let expected_index = constraints
.push_expected_type(Expected::NoExpectation((**specialized_def_type).clone()));
constraints.equal_types(
type_index,
expected_index,
Category::OpaqueArg,
arg_loc_expr.region,
)
};
let mut vars = vec![*arg_var, *opaque_var];
// Also add the fresh variables we created for the type argument and lambda sets
@ -1225,12 +1242,17 @@ pub fn constrain_expr(
);
// Tie the type of the value wrapped by the opaque to the opaque's type variables.
let link_type_variables_con = constraints.equal_types(
argument_type.clone(),
Expected::NoExpectation((*specialized_def_type).clone()),
Category::OpaqueArg,
region,
);
let link_type_variables_con = {
let arg_type_index = constraints.push_type(argument_type.clone());
let expected_specialized = constraints
.push_expected_type(Expected::NoExpectation((*specialized_def_type).clone()));
constraints.equal_types(
arg_type_index,
expected_specialized,
Category::OpaqueArg,
region,
)
};
let lambda_set = Type::ClosureTag {
name: *function_name,
@ -1441,12 +1463,17 @@ fn constrain_function_def(
signature.clone(),
);
def_pattern_state.constraints.push(constraints.equal_types(
Type::Variable(expr_var),
annotation_expected,
Category::Storage(std::file!(), std::line!()),
Region::span_across(&annotation.region, &loc_body_expr.region),
));
{
let expr_type_index = constraints.push_type(Type::Variable(expr_var));
let expected_index =
constraints.push_expected_type(annotation_expected);
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
};
@ -1544,12 +1571,16 @@ fn constrain_function_def(
signature.clone(),
);
def_pattern_state.constraints.push(constraints.equal_types(
Type::Variable(expr_var),
annotation_expected,
Category::Storage(std::file!(), std::line!()),
Region::span_across(&annotation.region, &loc_body_expr.region),
));
{
let expr_type_index = constraints.push_type(Type::Variable(expr_var));
let expected_index = constraints.push_expected_type(annotation_expected);
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),
));
}
constrain_typed_function_arguments_simple(
constraints,
@ -1929,9 +1960,12 @@ fn constrain_when_branch_help(
// Make sure the bound variables in the patterns on the same branch agree in their types.
for (sym, typ1) in state.headers.iter() {
if let Some(typ2) = partial_state.headers.get(sym) {
let type_index = constraints.push_type(typ1.value.clone());
let expected_index =
constraints.push_expected_type(Expected::NoExpectation(typ2.value.clone()));
state.constraints.push(constraints.equal_types(
typ1.value.clone(),
Expected::NoExpectation(typ2.value.clone()),
type_index,
expected_index,
Category::When,
typ2.region,
));
@ -2016,7 +2050,9 @@ fn constrain_empty_record(
region: Region,
expected: Expected<Type>,
) -> 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
@ -2214,12 +2250,16 @@ fn constrain_typed_def(
signature.clone(),
);
def_pattern_state.constraints.push(constraints.equal_types(
expr_type.clone(),
annotation_expected,
Category::Storage(std::file!(), std::line!()),
Region::span_across(&annotation.region, &def.loc_expr.region),
));
{
let type_index = constraints.push_type(expr_type.clone());
let expected_index = constraints.push_expected_type(annotation_expected);
def_pattern_state.constraints.push(constraints.equal_types(
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
// as a named function (in elm terms) for error messages.
@ -3072,7 +3112,11 @@ fn constraint_recursive_function(
state_constraints,
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
// 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!()),
@ -3482,12 +3526,17 @@ fn rec_defs_help(
state_constraints,
expr_con,
),
constraints.equal_types(
fn_type.clone(),
expected.clone(),
Category::Lambda,
region,
),
{
let fn_type_index = constraints.push_type(fn_type.clone());
let expected_index =
constraints.push_expected_type(expected.clone());
constraints.equal_types(
fn_type_index,
expected_index,
Category::Lambda,
region,
)
},
// "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
constraints.store_index(

View File

@ -263,12 +263,12 @@ pub fn constrain_pattern(
// Link the free num var with the int var and our expectation.
let int_type = builtins::num_int(Type::Variable(precision_var));
state.constraints.push(constraints.equal_types(
num_type.clone(), // TODO check me if something breaks!
Expected::NoExpectation(int_type),
Category::Int,
region,
));
state.constraints.push({
let type_index = constraints.push_type(num_type.clone()); // TODO check me if something breaks!
let expected_index =
constraints.push_expected_type(Expected::NoExpectation(int_type));
constraints.equal_types(type_index, expected_index, Category::Int, region)
});
// Also constrain the pattern against the num var, again to reuse aliases if they're present.
state.constraints.push(constraints.equal_pattern_types(
@ -295,12 +295,12 @@ pub fn constrain_pattern(
// Link the free num var with the float var and our expectation.
let float_type = builtins::num_float(Type::Variable(precision_var));
state.constraints.push(constraints.equal_types(
num_type.clone(), // TODO check me if something breaks!
Expected::NoExpectation(float_type),
Category::Frac,
region,
));
state.constraints.push({
let type_index = constraints.push_type(num_type.clone()); // TODO check me if something breaks!
let expected_index =
constraints.push_expected_type(Expected::NoExpectation(float_type));
constraints.equal_types(type_index, expected_index, Category::Frac, region)
});
// Also constrain the pattern against the num var, again to reuse aliases if they're present.
state.constraints.push(constraints.equal_pattern_types(
@ -336,12 +336,17 @@ pub fn constrain_pattern(
// Link the free num var with the int var and our expectation.
let int_type = builtins::num_int(Type::Variable(precision_var));
state.constraints.push(constraints.equal_types(
num_type.clone(), // TODO check me if something breaks!
Expected::NoExpectation(int_type),
Category::Int,
region,
));
state.constraints.push({
let type_index = constraints.push_type(num_type.clone());
let expected_index =
constraints.push_expected_type(Expected::NoExpectation(int_type));
constraints.equal_types(
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.
state.constraints.push(constraints.equal_pattern_types(
@ -452,9 +457,12 @@ pub fn constrain_pattern(
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(
Type::Variable(*whole_var),
Expected::NoExpectation(record_type),
whole_var_index,
expected_record,
Category::Storage(std::file!(), std::line!()),
region,
);
@ -561,9 +569,12 @@ pub fn constrain_pattern(
);
// 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(
Type::Variable(*whole_var),
Expected::NoExpectation(opaque_type),
whole_var_index,
expected_opaque,
Category::Storage(std::file!(), std::line!()),
region,
);