First pass at expectations taking a type index

This commit is contained in:
Ayaz Hafiz 2022-10-25 11:01:53 -05:00
parent 6dc6386f77
commit 2a4fca7034
No known key found for this signature in database
GPG key ID: 0E2A37416A25EF58
7 changed files with 379 additions and 272 deletions

View file

@ -19,7 +19,7 @@ pub struct Constraints {
pub let_constraints: Vec<LetConstraint>,
pub categories: Vec<Category>,
pub pattern_categories: Vec<PatternCategory>,
pub expectations: Vec<Expected<Cell<Type>>>,
pub expectations: Vec<Expected<TypeOrVar>>,
pub pattern_expectations: Vec<PExpected<Cell<Type>>>,
pub includes_tags: Vec<IncludesTag>,
pub strings: Vec<&'static str>,
@ -59,7 +59,7 @@ impl Default for Constraints {
}
pub type TypeIndex = Index<Cell<Type>>;
pub type ExpectedTypeIndex = Index<Expected<Cell<Type>>>;
pub type ExpectedTypeIndex = Index<Expected<TypeOrVar>>;
pub type PExpectedTypeIndex = Index<PExpected<Cell<Type>>>;
pub type TypeOrVar = EitherIndex<Cell<Type>, Variable>;
@ -215,8 +215,8 @@ impl Constraints {
EitherIndex::from_right(index)
}
pub fn push_expected_type(&mut self, expected: Expected<Type>) -> ExpectedTypeIndex {
Index::push_new(&mut self.expectations, expected.map(Cell::new))
pub fn push_expected_type(&mut self, expected: Expected<TypeOrVar>) -> ExpectedTypeIndex {
Index::push_new(&mut self.expectations, expected)
}
pub fn push_pat_expected_type(&mut self, expected: PExpected<Type>) -> PExpectedTypeIndex {
@ -464,7 +464,7 @@ impl Constraints {
where
I1: IntoIterator<Item = Variable>,
I2: IntoIterator<Item = Variable>,
I3: IntoIterator<Item = (Symbol, Loc<Type>)>,
I3: IntoIterator<Item = (Symbol, Loc<TypeOrVar>)>,
I3::IntoIter: ExactSizeIterator,
{
// defs and ret constraint are stored consequtively, so we only need to store one index
@ -473,27 +473,10 @@ impl Constraints {
self.constraints.push(defs_constraint);
self.constraints.push(ret_constraint);
let def_types = {
let types = def_types
.into_iter()
.map(|(sym, Loc { region, value })| {
let type_index = self.push_type(value);
(
sym,
Loc {
region,
value: type_index,
},
)
})
.collect::<Vec<_>>();
self.def_types_slice(types)
};
let let_constraint = LetConstraint {
rigid_vars: self.variable_slice(rigid_vars),
flex_vars: self.variable_slice(flex_vars),
def_types,
def_types: self.def_types_slice(def_types),
defs_and_ret_constraint,
};
@ -714,7 +697,7 @@ roc_error_macros::assert_sizeof_aarch64!(Constraint, 3 * 8);
#[derive(Clone, Copy, Debug)]
pub struct Eq(
pub TypeOrVar,
pub Index<Expected<Cell<Type>>>,
pub ExpectedTypeIndex,
pub Index<Category>,
pub Region,
);

View file

@ -1,5 +1,5 @@
use arrayvec::ArrayVec;
use roc_can::constraint::{Constraint, Constraints};
use roc_can::constraint::{Constraint, Constraints, TypeOrVar};
use roc_can::expected::Expected::{self, *};
use roc_can::num::{FloatBound, FloatWidth, IntBound, IntLitWidth, NumBound, SignDemand};
use roc_module::symbol::Symbol;
@ -30,7 +30,7 @@ pub fn add_numeric_bound_constr(
num_num(Variable(num_var))
}
NumericBound::FloatExact(width) => {
let actual_type = Variable(float_width_to_variable(width));
let actual_type = constraints.push_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);
@ -42,7 +42,7 @@ pub fn add_numeric_bound_constr(
Variable(num_var)
}
NumericBound::IntExact(width) => {
let actual_type = Variable(int_lit_width_to_variable(width));
let actual_type = constraints.push_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);
@ -54,11 +54,10 @@ pub fn add_numeric_bound_constr(
Variable(num_var)
}
NumericBound::Range(range) => {
let actual_type = Variable(precision_var);
let expected = Expected::NoExpectation(RangedNumber(range));
let type_index = constraints.push_type(actual_type);
let precision_type = constraints.push_type(Variable(precision_var));
let expected = Expected::NoExpectation(constraints.push_type(RangedNumber(range)));
let expected_index = constraints.push_expected_type(expected);
let constr = constraints.equal_types(type_index, expected_index, category, region);
let constr = constraints.equal_types(precision_type, expected_index, category, region);
num_constraints.extend([constr]);
@ -72,7 +71,7 @@ pub fn int_literal(
constraints: &mut Constraints,
num_var: Variable,
precision_var: Variable,
expected: Expected<Type>,
expected: Expected<TypeOrVar>,
region: Region,
bound: IntBound,
) -> Constraint {
@ -91,11 +90,10 @@ pub fn int_literal(
);
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,
));
let int_precision_type = constraints.push_type(num_int(Type::Variable(precision_var)));
let expect_precision_var =
constraints.push_expected_type(ForReason(reason, int_precision_type, region));
constrs.extend([
constraints.equal_types(num_type_index, expect_precision_var, Category::Int, region),
@ -114,7 +112,7 @@ pub fn single_quote_literal(
constraints: &mut Constraints,
num_var: Variable,
precision_var: Variable,
expected: Expected<Type>,
expected: Expected<TypeOrVar>,
region: Region,
bound: SingleQuoteBound,
) -> Constraint {
@ -133,11 +131,10 @@ pub fn single_quote_literal(
);
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,
));
let int_precision_type = constraints.push_type(num_int(Type::Variable(precision_var)));
let expect_precision_var =
constraints.push_expected_type(ForReason(reason, int_precision_type, region));
constrs.extend([
constraints.equal_types(
@ -161,7 +158,7 @@ pub fn float_literal(
constraints: &mut Constraints,
num_var: Variable,
precision_var: Variable,
expected: Expected<Type>,
expected: Expected<TypeOrVar>,
region: Region,
bound: FloatBound,
) -> Constraint {
@ -179,11 +176,10 @@ pub fn float_literal(
);
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,
));
let float_precision_type = constraints.push_type(num_float(Type::Variable(precision_var)));
let expect_precision_var =
constraints.push_expected_type(ForReason(reason, float_precision_type, region));
constrs.extend([
constraints.equal_types(num_type_index, expect_precision_var, Category::Frac, region),
@ -201,7 +197,7 @@ pub fn float_literal(
pub fn num_literal(
constraints: &mut Constraints,
num_var: Variable,
expected: Expected<Type>,
expected: Expected<TypeOrVar>,
region: Region,
bound: NumBound,
) -> Constraint {

File diff suppressed because it is too large Load diff

View file

@ -69,13 +69,15 @@ fn constrain_symbols_from_requires(
// 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.
let arity = loc_type.value.arity();
let typ = loc_type.value;
let type_index = constraints.push_type(typ);
let expected = constraints.push_expected_type(Expected::FromAnnotation(
loc_symbol.map(|&s| Pattern::Identifier(s)),
arity,
AnnotationSource::RequiredSymbol {
region: loc_type.region,
},
loc_type.value,
type_index,
));
let provided_eq_requires_constr =
constraints.lookup(loc_symbol.value, expected, loc_type.region);
@ -120,8 +122,9 @@ pub fn frontload_ability_constraints(
let rigid_variables = vars.rigid_vars.iter().chain(vars.able_vars.iter()).copied();
let infer_variables = vars.flex_vars.iter().copied();
let signature_index = constraints.push_type(signature.clone());
let signature_expectation =
constraints.push_expected_type(Expected::NoExpectation(signature.clone()));
constraints.push_expected_type(Expected::NoExpectation(signature_index));
def_pattern_state
.constraints

View file

@ -1,6 +1,6 @@
use crate::builtins;
use crate::expr::{constrain_expr, Env};
use roc_can::constraint::{Constraint, Constraints};
use roc_can::constraint::{Constraint, Constraints, TypeOrVar};
use roc_can::expected::{Expected, PExpected};
use roc_can::pattern::Pattern::{self, *};
use roc_can::pattern::{DestructType, ListPatterns, RecordDestruct};
@ -17,7 +17,7 @@ use roc_types::types::{
#[derive(Default, Debug)]
pub struct PatternState {
pub headers: VecMap<Symbol, Loc<Type>>,
pub headers: VecMap<Symbol, Loc<TypeOrVar>>,
pub vars: Vec<Variable>,
pub constraints: Vec<Constraint>,
pub delayed_is_open_constraints: Vec<Constraint>,
@ -31,14 +31,16 @@ pub struct PatternState {
/// Would add `x => <42>` to the headers (i.e., symbol points to a type variable). If the
/// definition has an annotation, we instead now add `x => Int`.
pub fn headers_from_annotation(
constraints: &mut Constraints,
pattern: &Pattern,
annotation: &Loc<&Type>,
) -> Option<VecMap<Symbol, Loc<Type>>> {
) -> Option<VecMap<Symbol, Loc<TypeOrVar>>> {
let mut headers = VecMap::default();
// Check that the annotation structurally agrees with the pattern, preventing e.g. `{ x, y } : Int`
// in such incorrect cases we don't put the full annotation in headers, just a variable, and let
// inference generate a proper error.
let is_structurally_valid = headers_from_annotation_help(pattern, annotation, &mut headers);
let is_structurally_valid =
headers_from_annotation_help(constraints, pattern, annotation, &mut headers);
if is_structurally_valid {
Some(headers)
@ -48,9 +50,10 @@ pub fn headers_from_annotation(
}
fn headers_from_annotation_help(
constraints: &mut Constraints,
pattern: &Pattern,
annotation: &Loc<&Type>,
headers: &mut VecMap<Symbol, Loc<Type>>,
headers: &mut VecMap<Symbol, Loc<TypeOrVar>>,
) -> bool {
match pattern {
Identifier(symbol)
@ -60,7 +63,8 @@ fn headers_from_annotation_help(
ident: symbol,
specializes: _,
} => {
let typ = Loc::at(annotation.region, annotation.value.clone());
let annotation_index = constraints.push_type(annotation.value.clone());
let typ = Loc::at(annotation.region, annotation_index);
headers.insert(*symbol, typ);
true
}
@ -87,9 +91,10 @@ fn headers_from_annotation_help(
// `{ x ? 0 } = rec` or `{ x: 5 } -> ...` in all cases
// the type of `x` within the binding itself is the same.
if let Some(field_type) = fields.get(&destruct.label) {
let field_type_index = constraints.push_type(field_type.as_inner().clone());
headers.insert(
destruct.symbol,
Loc::at(annotation.region, field_type.clone().into_inner()),
Loc::at(annotation.region, field_type_index),
);
} else {
return false;
@ -125,6 +130,7 @@ fn headers_from_annotation_help(
.zip(arg_types.iter())
.all(|(arg_pattern, arg_type)| {
headers_from_annotation_help(
constraints,
&arg_pattern.1.value,
&Loc::at(annotation.region, arg_type),
headers,
@ -156,11 +162,13 @@ fn headers_from_annotation_help(
&& type_arguments.len() == pat_type_arguments.len()
&& lambda_set_variables.len() == pat_lambda_set_variables.len() =>
{
let typ = Loc::at(annotation.region, annotation.value.clone());
let annotation_index = constraints.push_type(annotation.value.clone());
let typ = Loc::at(annotation.region, annotation_index);
headers.insert(*opaque, typ);
let (_, argument_pat) = &**argument;
headers_from_annotation_help(
constraints,
&argument_pat.value,
&Loc::at(annotation.region, actual),
headers,
@ -203,9 +211,9 @@ pub fn constrain_pattern(
}
Identifier(symbol) | Shadowed(_, _, symbol) => {
if could_be_a_tag_union(expected.get_type_ref()) {
let type_index = constraints.push_type(expected.get_type_ref().clone());
if could_be_a_tag_union(expected.get_type_ref()) {
state
.delayed_is_open_constraints
.push(constraints.is_open_type(type_index));
@ -215,7 +223,7 @@ pub fn constrain_pattern(
*symbol,
Loc {
region,
value: expected.get_type(),
value: type_index,
},
);
}
@ -224,9 +232,9 @@ pub fn constrain_pattern(
ident: symbol,
specializes: _,
} => {
if could_be_a_tag_union(expected.get_type_ref()) {
let type_index = constraints.push_type(expected.get_type_ref().clone());
if could_be_a_tag_union(expected.get_type_ref()) {
state.constraints.push(constraints.is_open_type(type_index));
}
@ -234,7 +242,7 @@ pub fn constrain_pattern(
*symbol,
Loc {
region,
value: expected.get_type(),
value: type_index,
},
);
}
@ -278,7 +286,7 @@ pub fn constrain_pattern(
let num_type = constraints.push_type(num_type);
// 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 = constraints.push_type(builtins::num_int(Type::Variable(precision_var)));
state.constraints.push({
let expected_index =
@ -308,10 +316,11 @@ pub fn constrain_pattern(
region,
Category::Frac,
);
let num_type_index = constraints.push_type(num_type); // TODO check me if something breaks!
// Link the free num var with the float var and our expectation.
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!
let float_type =
constraints.push_type(builtins::num_float(Type::Variable(precision_var)));
state.constraints.push({
let expected_index =
@ -353,11 +362,11 @@ pub fn constrain_pattern(
Category::Int,
);
// Link the free num var with the int var and our expectation.
let int_type = builtins::num_int(Type::Variable(precision_var));
let num_type_index = constraints.push_type(num_type);
// Link the free num var with the int var and our expectation.
let int_type = constraints.push_type(builtins::num_int(Type::Variable(precision_var)));
state.constraints.push({
let expected_index =
constraints.push_expected_type(Expected::NoExpectation(int_type));
@ -402,12 +411,13 @@ pub fn constrain_pattern(
} in destructs
{
let pat_type = Type::Variable(*var);
let pat_type_index = constraints.push_type(pat_type.clone());
let expected = PExpected::NoExpectation(pat_type.clone());
if !state.headers.contains_key(symbol) {
state
.headers
.insert(*symbol, Loc::at(region, pat_type.clone()));
.insert(*symbol, Loc::at(region, pat_type_index));
}
let field_type = match typ {
@ -459,7 +469,7 @@ pub fn constrain_pattern(
let expr_expected = Expected::ForReason(
Reason::RecordDefaultField(label.clone()),
pat_type.clone(),
pat_type_index,
loc_expr.region,
);
@ -485,7 +495,10 @@ pub fn constrain_pattern(
state.vars.push(*var);
}
let record_type = Type::Record(field_types, TypeExtension::from_type(ext_type));
let record_type = constraints.push_type(Type::Record(
field_types,
TypeExtension::from_type(ext_type),
));
let whole_var_index = constraints.push_type(Type::Variable(*whole_var));
let expected_record =
@ -623,7 +636,7 @@ pub fn constrain_pattern(
let (arg_pattern_var, loc_arg_pattern) = &**argument;
let arg_pattern_type = Type::Variable(*arg_pattern_var);
let opaque_type = Type::Alias {
let opaque_type = constraints.push_type(Type::Alias {
symbol: *opaque,
type_arguments: type_arguments
.iter()
@ -636,7 +649,7 @@ pub fn constrain_pattern(
infer_ext_in_output_types: vec![],
actual: Box::new(arg_pattern_type.clone()),
kind: AliasKind::Opaque,
};
});
// First, add a constraint for the argument "who"
let arg_pattern_expected = PExpected::NoExpectation(arg_pattern_type.clone());

View file

@ -947,15 +947,16 @@ fn solve(
);
let expectation = &constraints.expectations[expectation_index.index()];
let expected = type_cell_to_var(
let expected = either_type_index_to_var(
constraints,
subs,
rank,
pools,
problems,
abilities_store,
obligation_cache,
pools,
aliases,
expectation.get_type_ref(),
*expectation.get_type_ref(),
);
match unify(
@ -1065,15 +1066,16 @@ fn solve(
let actual = deep_copy_var_in(subs, rank, pools, var, arena);
let expectation = &constraints.expectations[expectation_index.index()];
let expected = type_cell_to_var(
let expected = either_type_index_to_var(
constraints,
subs,
rank,
pools,
problems,
abilities_store,
obligation_cache,
pools,
aliases,
expectation.get_type_ref(),
*expectation.get_type_ref(),
);
match unify(
@ -1487,15 +1489,28 @@ fn solve(
// 4. Condition and branch types aren't "almost equal", this is just a normal type
// error.
let (real_var, real_region, expected_type, category_and_expected) = match eq {
let (real_var, real_region, branches_var, category_and_expected) = match eq {
Ok(eq) => {
let roc_can::constraint::Eq(real_var, expected, category, real_region) =
constraints.eq[eq.index()];
let expected = &constraints.expectations[expected.index()];
let branches_var = either_type_index_to_var(
constraints,
subs,
rank,
pools,
problems,
abilities_store,
obligation_cache,
aliases,
*expected.get_type_ref(),
);
(
real_var,
real_region,
expected.get_type_ref(),
branches_var,
Ok((category, expected)),
)
}
@ -1507,10 +1522,22 @@ fn solve(
real_region,
) = constraints.pattern_eq[peq.index()];
let expected = &constraints.pattern_expectations[expected.index()];
let branches_var = type_cell_to_var(
subs,
rank,
problems,
abilities_store,
obligation_cache,
pools,
aliases,
expected.get_type_ref(),
);
(
real_var,
real_region,
expected.get_type_ref(),
branches_var,
Err((category, expected)),
)
}

View file

@ -140,9 +140,12 @@ pub fn can_expr_with<'a>(
}
};
let mut constraints = Constraints::new();
let mut var_store = VarStore::default();
let var = var_store.fresh();
let expected = Expected::NoExpectation(Type::Variable(var));
let var_index = constraints.push_type(Type::Variable(var));
let expected = Expected::NoExpectation(var_index);
let mut module_ids = ModuleIds::default();
// ensure the Test module is accessible in our tests
@ -169,7 +172,6 @@ pub fn can_expr_with<'a>(
&loc_expr.value,
);
let mut constraints = Constraints::new();
let constraint = constrain_expr(
&mut constraints,
&mut roc_constrain::expr::Env {