we are compiling

This commit is contained in:
Folkert 2022-03-02 18:48:34 +01:00
parent 01a7fe77d4
commit a4889fd571
No known key found for this signature in database
GPG key ID: 1F17F6FFD112B97C
6 changed files with 406 additions and 297 deletions

View file

@ -1,5 +1,6 @@
use crate::expected::{Expected, PExpected}; use crate::expected::{Expected, PExpected};
use roc_collections::soa::{Index, Slice}; use roc_collections::soa::{Index, Slice};
use roc_module::ident::TagName;
use roc_module::symbol::Symbol; use roc_module::symbol::Symbol;
use roc_region::all::{Loc, Region}; use roc_region::all::{Loc, Region};
use roc_types::types::{Category, PatternCategory, Type}; use roc_types::types::{Category, PatternCategory, Type};
@ -15,6 +16,7 @@ pub struct Constraints {
pattern_categories: Vec<PatternCategory>, pattern_categories: Vec<PatternCategory>,
expectations: Vec<Expected<Type>>, expectations: Vec<Expected<Type>>,
pattern_expectations: Vec<PExpected<Type>>, pattern_expectations: Vec<PExpected<Type>>,
includes_tags: Vec<IncludesTag>,
} }
impl Constraints { impl Constraints {
@ -52,13 +54,9 @@ impl Constraints {
category: Category, category: Category,
region: Region, region: Region,
) -> Constraint { ) -> Constraint {
let type_index = Index::new(self.types.len() as _); let type_index = Index::push_new(&mut self.types, typ);
let expected_index = Index::new(self.expectations.len() as _); let expected_index = Index::push_new(&mut self.expectations, expected);
let category_index = Index::new(self.categories.len() as _); let category_index = Index::push_new(&mut self.categories, category);
self.types.push(typ);
self.expectations.push(expected);
self.categories.push(category);
Constraint::Eq(type_index, expected_index, category_index, region) Constraint::Eq(type_index, expected_index, category_index, region)
} }
@ -70,17 +68,61 @@ impl Constraints {
category: PatternCategory, category: PatternCategory,
region: Region, region: Region,
) -> Constraint { ) -> Constraint {
let type_index = Index::new(self.types.len() as _); let type_index = Index::push_new(&mut self.types, typ);
let expected_index = Index::new(self.pattern_expectations.len() as _); let expected_index = Index::push_new(&mut self.pattern_expectations, expected);
let category_index = Index::new(self.pattern_categories.len() as _); let category_index = Index::push_new(&mut self.pattern_categories, category);
self.types.push(typ);
self.pattern_expectations.push(expected);
self.pattern_categories.push(category);
Constraint::Pattern(type_index, expected_index, category_index, region) Constraint::Pattern(type_index, expected_index, category_index, region)
} }
pub fn pattern_presence(
&mut self,
typ: Type,
expected: PExpected<Type>,
category: PatternCategory,
region: Region,
) -> Constraint {
let type_index = Index::push_new(&mut self.types, typ);
let expected_index = Index::push_new(&mut self.pattern_expectations, expected);
let category_index = Index::push_new(&mut self.pattern_categories, category);
Constraint::PatternPresence(type_index, expected_index, category_index, region)
}
pub fn is_open_type(&mut self, typ: Type) -> Constraint {
let type_index = Index::push_new(&mut self.types, typ);
Constraint::IsOpenType(type_index)
}
pub fn includes_tag<I>(
&mut self,
typ: Type,
tag_name: TagName,
types: I,
category: PatternCategory,
region: Region,
) -> Constraint
where
I: IntoIterator<Item = Type>,
{
let type_index = Index::push_new(&mut self.types, typ);
let category_index = Index::push_new(&mut self.pattern_categories, category);
let types_slice = Slice::extend_new(&mut self.types, types);
let includes_tag = IncludesTag {
type_index,
tag_name,
types: types_slice,
pattern_category: category_index,
region,
};
let includes_tag_index = Index::push_new(&mut self.includes_tags, includes_tag);
Constraint::IncludesTag(includes_tag_index)
}
fn variable_slice<I>(&mut self, it: I) -> Slice<Variable> fn variable_slice<I>(&mut self, it: I) -> Slice<Variable>
where where
I: IntoIterator<Item = Variable>, I: IntoIterator<Item = Variable>,
@ -133,6 +175,29 @@ impl Constraints {
Constraint::Let(let_index) Constraint::Let(let_index)
} }
pub fn exists_many<I, C>(&mut self, flex_vars: I, defs_constraint: C) -> Constraint
where
I: IntoIterator<Item = Variable>,
C: IntoIterator<Item = Constraint>,
{
let defs_and_ret_constraint = Index::new(self.constraints.len() as _);
self.and_constraint(defs_constraint);
self.constraints.push(Constraint::True);
let let_contraint = LetConstraint {
rigid_vars: Slice::default(),
flex_vars: self.variable_slice(flex_vars),
def_types: Slice::default(),
defs_and_ret_constraint,
};
let let_index = Index::new(self.let_constraints.len() as _);
self.let_constraints.push(let_contraint);
Constraint::Let(let_index)
}
pub fn let_constraint<I1, I2, I3>( pub fn let_constraint<I1, I2, I3>(
&mut self, &mut self,
rigid_vars: I1, rigid_vars: I1,
@ -191,7 +256,7 @@ impl Constraints {
region, region,
) )
} }
pub fn contains_save_the_environment(&self, constraint: Constraint) -> bool { pub fn contains_save_the_environment(&self, constraint: &Constraint) -> bool {
todo!() todo!()
} }
@ -228,6 +293,15 @@ pub enum Constraint {
SaveTheEnvironment, SaveTheEnvironment,
Let(Index<LetConstraint>), Let(Index<LetConstraint>),
And(Slice<Constraint>), And(Slice<Constraint>),
/// Presence constraints
IsOpenType(Index<Type>), // Theory; always applied to a variable? if yes the use that
IncludesTag(Index<IncludesTag>),
PatternPresence(
Index<Type>,
Index<PExpected<Type>>,
Index<PatternCategory>,
Region,
),
} }
#[derive(Debug, Clone, PartialEq)] #[derive(Debug, Clone, PartialEq)]
@ -237,3 +311,12 @@ pub struct LetConstraint {
pub def_types: Slice<(Symbol, Loc<Type>)>, pub def_types: Slice<(Symbol, Loc<Type>)>,
pub defs_and_ret_constraint: Index<(Constraint, Constraint)>, pub defs_and_ret_constraint: Index<(Constraint, Constraint)>,
} }
#[derive(Debug, Clone, PartialEq)]
pub struct IncludesTag {
pub type_index: Index<Type>,
pub tag_name: TagName,
pub types: Slice<Type>,
pub pattern_category: Index<PatternCategory>,
pub region: Region,
}

View file

@ -47,6 +47,19 @@ impl<T> Slice<T> {
} }
} }
pub fn extend_new<I>(vector: &mut Vec<T>, values: I) -> Slice<T>
where
I: IntoIterator<Item = T>,
{
let start = vector.len() as u32;
vector.extend(values);
let end = vector.len() as u32;
Self::new(start, (end - start) as u16)
}
pub const fn len(&self) -> usize { pub const fn len(&self) -> usize {
self.length as _ self.length as _
} }

View file

@ -61,7 +61,8 @@ pub fn add_numeric_bound_constr_soa(
1 => { 1 => {
let actual_type = Variable(range[0]); let actual_type = Variable(range[0]);
let expected = Expected::ForReason(Reason::NumericLiteralSuffix, actual_type, region); let expected = Expected::ForReason(Reason::NumericLiteralSuffix, actual_type, region);
let because_suffix = constraints.equal_types(actual_type, expected, category, region); let because_suffix =
constraints.equal_types(total_num_type.clone(), expected, category, region);
num_constraints.extend([because_suffix]); num_constraints.extend([because_suffix]);

View file

@ -411,23 +411,17 @@ pub fn constrain_expr(
&mut vars, &mut vars,
); );
constraints.exists( let pattern_state_constraints = constraints.and_constraint(pattern_state.constraints);
vars, let cons = [
constraints.and_constraint([
constraints.let_constraint( constraints.let_constraint(
Vec::new(), [],
pattern_state.vars, pattern_state.vars,
pattern_state.headers, pattern_state.headers,
constraints.and_constraint(pattern_state.constraints), pattern_state_constraints,
ret_constraint, ret_constraint,
), ),
// "the closure's type is equal to expected type" // "the closure's type is equal to expected type"
constraints.equal_types( constraints.equal_types(function_type.clone(), expected, Category::Lambda, region),
function_type.clone(),
expected,
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
constraints.equal_types( constraints.equal_types(
Type::Variable(*fn_var), Type::Variable(*fn_var),
@ -436,8 +430,9 @@ pub fn constrain_expr(
region, region,
), ),
closure_constraint, closure_constraint,
]), ];
)
constraints.exists_many(vars, cons)
} }
Expect(loc_cond, continuation) => { Expect(loc_cond, continuation) => {
@ -462,7 +457,7 @@ pub fn constrain_expr(
expected, expected,
); );
constraints.exists([], constraints.and_constraint([cond_con, continuation_con])) constraints.exists_many([], [cond_con, continuation_con])
} }
If { If {
@ -548,10 +543,7 @@ pub fn constrain_expr(
branch_cons.push(ast_con); branch_cons.push(ast_con);
branch_cons.push(else_con); branch_cons.push(else_con);
constraints.exists( constraints.exists_many([*cond_var, *branch_var], branch_cons)
[*cond_var, *branch_var],
constraints.and_constraint(branch_cons),
)
} }
_ => { _ => {
for (index, (loc_cond, loc_body)) in branches.iter().enumerate() { for (index, (loc_cond, loc_body)) in branches.iter().enumerate() {
@ -604,10 +596,7 @@ pub fn constrain_expr(
)); ));
branch_cons.push(else_con); branch_cons.push(else_con);
constraints.exists( constraints.exists_many([*cond_var, *branch_var], branch_cons)
[*cond_var, *branch_var],
constraints.and_constraint(branch_cons),
)
} }
} }
} }
@ -677,10 +666,7 @@ pub fn constrain_expr(
region, region,
)); ));
return constraints.exists( return constraints.exists_many([cond_var, *expr_var], branch_constraints);
[cond_var, *expr_var],
constraints.and_constraint(branch_constraints),
);
} }
_ => { _ => {
@ -691,6 +677,7 @@ pub fn constrain_expr(
let pattern_region = let pattern_region =
Region::across_all(when_branch.patterns.iter().map(|v| &v.region)); Region::across_all(when_branch.patterns.iter().map(|v| &v.region));
let branch_con = constrain_when_branch( let branch_con = constrain_when_branch(
constraints,
env, env,
region, region,
when_branch, when_branch,
@ -713,23 +700,26 @@ pub fn constrain_expr(
branch_cons.push(branch_con); branch_cons.push(branch_con);
} }
branch_constraints.push(constraints.and_constraint([ // Deviation: elm adds another layer of And nesting
//
// Record the original conditional expression's constraint. // Record the original conditional expression's constraint.
// Each branch's pattern must have the same type // Each branch's pattern must have the same type
// as the condition expression did. // as the condition expression did.
constraints.and_constraint(branch_cons), //
// The return type of each branch must equal // The return type of each branch must equal the return type of
// the return type of the entire when-expression. // the entire when-expression.
constraints.equal_types(branch_type, expected, Category::When, region), branch_cons.push(constraints.equal_types(
])); branch_type,
expected,
Category::When,
region,
));
branch_constraints.push(constraints.and_constraint(branch_cons));
} }
} }
// exhautiveness checking happens when converting to mono::Expr // exhautiveness checking happens when converting to mono::Expr
constraints.exists( constraints.exists_many([cond_var, *expr_var], branch_constraints)
[cond_var, *expr_var],
constraints.and_constraint(branch_constraints),
)
} }
Access { Access {
record_var, record_var,
@ -771,13 +761,10 @@ pub fn constrain_expr(
record_expected, record_expected,
); );
constraints.exists( let eq = constraints.equal_types(field_type, expected, category, region);
constraints.exists_many(
[*record_var, field_var, ext_var], [*record_var, field_var, ext_var],
constraints.and_constraint([ [constraint, eq, record_con],
constraint,
constraints.equal_types(field_type, expected, category, region),
record_con,
]),
) )
} }
Accessor { Accessor {
@ -820,15 +807,8 @@ pub fn constrain_expr(
Box::new(field_type), Box::new(field_type),
); );
constraints.exists( let cons = [
[*record_var, *function_var, *closure_var, field_var, ext_var], constraints.equal_types(function_type.clone(), expected, category.clone(), region),
constraints.and_constraint([
constraints.equal_types(
function_type.clone(),
expected,
category.clone(),
region,
),
constraints.equal_types( constraints.equal_types(
function_type, function_type,
NoExpectation(Variable(*function_var)), NoExpectation(Variable(*function_var)),
@ -836,7 +816,11 @@ pub fn constrain_expr(
region, region,
), ),
record_con, record_con,
]), ];
constraints.exists_many(
[*record_var, *function_var, *closure_var, field_var, ext_var],
cons,
) )
} }
LetRec(defs, loc_ret, var) => { LetRec(defs, loc_ret, var) => {
@ -848,10 +832,8 @@ pub fn constrain_expr(
expected.clone(), expected.clone(),
); );
constraints.exists( let cons = [
[*var], constrain_recursive_defs(constraints, env, defs, body_con),
constraints.and_constraint([
constrain_recursive_defs(env, defs, body_con),
// Record the type of tne entire def-expression in the variable. // Record the type of tne entire def-expression in the variable.
// Code gen will need that later! // Code gen will need that later!
constraints.equal_types( constraints.equal_types(
@ -860,8 +842,9 @@ pub fn constrain_expr(
Category::Storage(std::file!(), std::line!()), Category::Storage(std::file!(), std::line!()),
loc_ret.region, loc_ret.region,
), ),
]), ];
)
constraints.exists_many([*var], cons)
} }
LetNonRec(def, loc_ret, var) => { LetNonRec(def, loc_ret, var) => {
let mut stack = Vec::with_capacity(1); let mut stack = Vec::with_capacity(1);
@ -884,10 +867,8 @@ pub fn constrain_expr(
); );
while let Some((def, var, ret_region)) = stack.pop() { while let Some((def, var, ret_region)) = stack.pop() {
body_con = constraints.exists( let cons = [
[*var], constrain_def(constraints, env, def, body_con),
constraints.and_constraint([
constrain_def(env, def, body_con),
// Record the type of the entire def-expression in the variable. // Record the type of the entire def-expression in the variable.
// Code gen will need that later! // Code gen will need that later!
constraints.equal_types( constraints.equal_types(
@ -896,8 +877,9 @@ pub fn constrain_expr(
Category::Storage(std::file!(), std::line!()), Category::Storage(std::file!(), std::line!()),
ret_region, ret_region,
), ),
]), ];
)
body_con = constraints.exists_many([*var], cons)
} }
body_con body_con
@ -950,7 +932,7 @@ pub fn constrain_expr(
arg_cons.push(union_con); arg_cons.push(union_con);
arg_cons.push(ast_con); arg_cons.push(ast_con);
constraints.exists(vars, constraints.and_constraint(arg_cons)) constraints.exists_many(vars, arg_cons)
} }
ZeroArgumentTag { ZeroArgumentTag {
variant_var, variant_var,
@ -1002,7 +984,7 @@ pub fn constrain_expr(
arg_cons.push(union_con); arg_cons.push(union_con);
arg_cons.push(ast_con); arg_cons.push(ast_con);
constraints.exists(vars, constraints.and_constraint(arg_cons)) constraints.exists_many(vars, arg_cons)
} }
OpaqueRef { OpaqueRef {
@ -1069,9 +1051,9 @@ pub fn constrain_expr(
v.0.expect_variable("all lambda sets should be fresh variables here") v.0.expect_variable("all lambda sets should be fresh variables here")
})); }));
constraints.exists( constraints.exists_many(
vars, vars,
constraints.and([arg_con, opaque_con, link_type_variables_con, storage_con]), [arg_con, opaque_con, link_type_variables_con, storage_con],
) )
} }
@ -1109,12 +1091,8 @@ pub fn constrain_expr(
let category = Category::LowLevelOpResult(*op); let category = Category::LowLevelOpResult(*op);
constraints.exists( let eq = constraints.equal_types(ret_type, expected, category, region);
vars, constraints.exists_many(vars, arg_cons.into_iter().chain(std::iter::once(eq)))
constraints.and_constraint(arg_cons.into_iter().chain(std::iter::once(
constraints.equal_types(ret_type, expected, category, region),
))),
)
} }
ForeignCall { ForeignCall {
args, args,
@ -1154,12 +1132,8 @@ pub fn constrain_expr(
let category = Category::ForeignCall; let category = Category::ForeignCall;
constraints.exists( let eq = constraints.equal_types(ret_type, expected, category, region);
vars, constraints.exists_many(vars, arg_cons.into_iter().chain(std::iter::once(eq)))
constraints.and_constraint(arg_cons.into_iter().chain(std::iter::once(
constraints.equal_types(ret_type, expected, category, region),
))),
)
} }
RuntimeError(_) => { RuntimeError(_) => {
// Runtime Errors have no constraints because they're going to crash. // Runtime Errors have no constraints because they're going to crash.
@ -1195,6 +1169,7 @@ fn constrain_when_branch(
// then unify that variable with the expectation? // then unify that variable with the expectation?
for loc_pattern in &when_branch.patterns { for loc_pattern in &when_branch.patterns {
constrain_pattern( constrain_pattern(
constraints,
env, env,
&loc_pattern.value, &loc_pattern.value,
loc_pattern.region, loc_pattern.region,
@ -1217,25 +1192,23 @@ fn constrain_when_branch(
); );
// must introduce the headers from the pattern before constraining the guard // must introduce the headers from the pattern before constraining the guard
constraints.let_constraint( let state_constraints = constraints.and_constraint(state.constraints);
[], let inner = constraints.let_constraint(
state.vars,
state.headers,
constraints.and_constraint(state.constraints),
constraints.let_constraint(
[], [],
[], [],
SendMap::default(), SendMap::default(),
guard_constraint, guard_constraint,
ret_constraint, ret_constraint,
), );
)
constraints.let_constraint([], state.vars, state.headers, state_constraints, inner)
} else { } else {
let state_constraints = constraints.and_constraint(state.constraints);
constraints.let_constraint( constraints.let_constraint(
[], [],
state.vars, state.vars,
state.headers, state.headers,
constraints.and_constraint(state.constraints), state_constraints,
ret_constraint, ret_constraint,
) )
} }
@ -1300,7 +1273,7 @@ pub fn constrain_decls(
constraint = constrain_def(constraints, &env, def, constraint); constraint = constrain_def(constraints, &env, def, constraint);
} }
Declaration::DeclareRec(defs) => { Declaration::DeclareRec(defs) => {
constraint = constrain_recursive_defs(&env, defs, constraint); constraint = constrain_recursive_defs(constraints, &env, defs, constraint);
} }
Declaration::InvalidCycle(_) => { Declaration::InvalidCycle(_) => {
// invalid cycles give a canonicalization error. we skip them here. // invalid cycles give a canonicalization error. we skip them here.
@ -1310,7 +1283,7 @@ pub fn constrain_decls(
} }
// this assert make the "root" of the constraint wasn't dropped // this assert make the "root" of the constraint wasn't dropped
debug_assert!(constraints.contains_save_the_environment(constraint)); debug_assert!(constraints.contains_save_the_environment(&constraint));
constraint constraint
} }
@ -1484,6 +1457,7 @@ fn constrain_def(
} }
let closure_constraint = constrain_closure_size( let closure_constraint = constrain_closure_size(
constraints,
*name, *name,
region, region,
captured_symbols, captured_symbols,
@ -1512,9 +1486,7 @@ fn constrain_def(
vars.push(*fn_var); vars.push(*fn_var);
let defs_constraint = constraints.and_constraint(state.constraints); let defs_constraint = constraints.and_constraint(state.constraints);
constraints.exists( let cons = [
vars,
constraints.and_constraint([
constraints.let_constraint( constraints.let_constraint(
[], [],
state.vars, state.vars,
@ -1535,17 +1507,14 @@ fn constrain_def(
Category::ClosureSize, Category::ClosureSize,
region, region,
), ),
constraints.store( constraints.store(signature.clone(), *fn_var, std::file!(), std::line!()),
signature.clone(),
*fn_var,
std::file!(),
std::line!(),
),
constraints.store(signature, expr_var, std::file!(), std::line!()), constraints.store(signature, expr_var, std::file!(), std::line!()),
constraints.store(ret_type, ret_var, std::file!(), std::line!()), constraints.store(ret_type, ret_var, std::file!(), std::line!()),
closure_constraint, closure_constraint,
]), ];
)
let and_constraint = constraints.and_constraint(cons);
constraints.exists(vars, and_constraint)
} }
_ => { _ => {
@ -1559,7 +1528,7 @@ fn constrain_def(
expected, expected,
); );
constraints.and_constraint([ let cons = [
constraints.let_constraint( constraints.let_constraint(
[], [],
[], [],
@ -1569,7 +1538,8 @@ fn constrain_def(
), ),
// 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, expr_var, std::file!(), std::line!()),
]) ];
constraints.and_constraint(cons)
} }
} }
} }
@ -1586,17 +1556,21 @@ fn constrain_def(
} }
}; };
let and_constraint = constraints.and_constraint(def_pattern_state.constraints);
let def_con = constraints.let_constraint(
[],
[],
SendMap::default(), // empty, because our functions have no arguments!
and_constraint,
expr_con,
);
constraints.let_constraint( constraints.let_constraint(
new_rigids, new_rigids,
def_pattern_state.vars, def_pattern_state.vars,
def_pattern_state.headers, def_pattern_state.headers,
constraints.let_constraint( def_con,
[],
[],
SendMap::default(), // empty, because our functions have no arguments!
constraints.and_constraint(def_pattern_state.constraints),
expr_con,
),
body_con, body_con,
) )
} }
@ -1706,8 +1680,14 @@ fn instantiate_rigids(
annotation annotation
} }
fn constrain_recursive_defs(env: &Env, defs: &[Def], body_con: Constraint) -> Constraint { fn constrain_recursive_defs(
constraints: &mut Constraints,
env: &Env,
defs: &[Def],
body_con: Constraint,
) -> Constraint {
rec_defs_help( rec_defs_help(
constraints,
env, env,
defs, defs,
body_con, body_con,
@ -1897,14 +1877,13 @@ pub fn rec_defs_help(
vars.push(*fn_var); vars.push(*fn_var);
let def_con = constraints.exists( let state_constraints = constraints.and_constraint(state.constraints);
vars, let cons = [
constraints.and_constraint([
constraints.let_constraint( constraints.let_constraint(
[], [],
state.vars, state.vars,
state.headers, state.headers,
constraints.and_constraint(state.constraints), state_constraints,
expr_con, expr_con,
), ),
constraints.equal_types( constraints.equal_types(
@ -1924,8 +1903,10 @@ pub fn rec_defs_help(
constraints.store(signature, expr_var, std::file!(), std::line!()), constraints.store(signature, expr_var, std::file!(), std::line!()),
constraints.store(ret_type, ret_var, std::file!(), std::line!()), constraints.store(ret_type, ret_var, std::file!(), std::line!()),
closure_constraint, closure_constraint,
]), ];
);
let and_constraint = constraints.and_constraint(cons);
let def_con = constraints.exists(vars, and_constraint);
rigid_info.vars.extend(&new_rigids); rigid_info.vars.extend(&new_rigids);
@ -1949,7 +1930,7 @@ pub fn rec_defs_help(
expected, expected,
); );
let def_con = constraints.and_constraint([ let cons = [
constraints.let_constraint( constraints.let_constraint(
[], [],
[], [],
@ -1959,7 +1940,8 @@ pub fn rec_defs_help(
), ),
// 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, expr_var, std::file!(), std::line!()),
]); ];
let def_con = constraints.and_constraint(cons);
rigid_info.vars.extend(&new_rigids); rigid_info.vars.extend(&new_rigids);
@ -1977,25 +1959,36 @@ pub fn rec_defs_help(
} }
} }
let flex_constraints = constraints.and_constraint(flex_info.constraints);
let inner_inner = constraints.let_constraint(
[],
[],
flex_info.def_types.clone(),
Constraint::True,
flex_constraints,
);
let rigid_constraints = {
let mut temp = rigid_info.constraints;
temp.push(body_con);
constraints.and_constraint(temp)
};
let inner = constraints.let_constraint(
[],
flex_info.vars,
flex_info.def_types,
inner_inner,
rigid_constraints,
);
constraints.let_constraint( constraints.let_constraint(
rigid_info.vars, rigid_info.vars,
[], [],
rigid_info.def_types, rigid_info.def_types,
Constraint::True, Constraint::True,
constraints.let_constraint( inner,
[],
flex_info.vars,
flex_info.def_types.clone(),
constraints.let_constraint(
[],
[],
flex_info.def_types,
Constraint::True,
constraints.and_constraint(flex_info.constraints),
),
constraints
.and_constraint([constraints.and_constraint(rigid_info.constraints), body_con]),
),
) )
} }

View file

@ -1,6 +1,6 @@
use crate::builtins; use crate::builtins;
use crate::soa_expr::{constrain_expr, Env}; use crate::soa_expr::{constrain_expr, Env};
use roc_can::constraint_soa::{Constraint, Constraints, PresenceConstraint}; use roc_can::constraint_soa::{Constraint, Constraints};
use roc_can::expected::{Expected, PExpected}; use roc_can::expected::{Expected, PExpected};
use roc_can::pattern::Pattern::{self, *}; use roc_can::pattern::Pattern::{self, *};
use roc_can::pattern::{DestructType, RecordDestruct}; use roc_can::pattern::{DestructType, RecordDestruct};
@ -168,20 +168,18 @@ pub fn constrain_pattern(
// A -> "" // A -> ""
// _ -> "" // _ -> ""
// 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.
state.constraints.push(Constraint::Present( state
expected.get_type(), .constraints
PresenceConstraint::IsOpen, .push(constraints.is_open_type(expected.get_type()));
));
} }
UnsupportedPattern(_) | MalformedPattern(_, _) | OpaqueNotInScope(..) => { UnsupportedPattern(_) | MalformedPattern(_, _) | OpaqueNotInScope(..) => {
// Erroneous patterns don't add any constraints. // Erroneous patterns don't add any constraints.
} }
Identifier(symbol) | Shadowed(_, _, symbol) => { Identifier(symbol) | Shadowed(_, _, symbol) => {
state.constraints.push(Constraint::Present( state
expected.get_type_ref().clone(), .constraints
PresenceConstraint::IsOpen, .push(constraints.is_open_type(expected.get_type_ref().clone()));
));
state.headers.insert( state.headers.insert(
*symbol, *symbol,
Loc { Loc {
@ -205,18 +203,19 @@ pub fn constrain_pattern(
Category::Num, Category::Num,
); );
state.constraints.push(Constraint::Pattern( state.constraints.push(constraints.equal_pattern_types(
region,
PatternCategory::Num,
num_type, num_type,
expected, expected,
PatternCategory::Num,
region,
)); ));
} }
&IntLiteral(num_var, precision_var, _, _, bound) => { &IntLiteral(num_var, precision_var, _, _, bound) => {
// First constraint on the free num var; this improves the resolved type quality in // First constraint on the free num var; this improves the resolved type quality in
// case the bound is an alias. // case the bound is an alias.
let num_type = builtins::add_numeric_bound_constr( let num_type = builtins::add_numeric_bound_constr_soa(
constraints,
&mut state.constraints, &mut state.constraints,
Type::Variable(num_var), Type::Variable(num_var),
bound, bound,
@ -266,29 +265,29 @@ pub fn constrain_pattern(
)); ));
// 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.
state.constraints.push(Constraint::Pattern( state.constraints.push(constraints.equal_pattern_types(
region,
PatternCategory::Float,
num_type, // TODO check me if something breaks! num_type, // TODO check me if something breaks!
expected, expected,
PatternCategory::Float,
region,
)); ));
} }
StrLiteral(_) => { StrLiteral(_) => {
state.constraints.push(Constraint::Pattern( state.constraints.push(constraints.equal_pattern_types(
region,
PatternCategory::Str,
builtins::str_type(), builtins::str_type(),
expected, expected,
PatternCategory::Str,
region,
)); ));
} }
SingleQuote(_) => { SingleQuote(_) => {
state.constraints.push(Constraint::Pattern( state.constraints.push(constraints.equal_pattern_types(
region,
PatternCategory::Character,
builtins::num_u32(), builtins::num_u32(),
expected, expected,
PatternCategory::Character,
region,
)); ));
} }
@ -325,36 +324,39 @@ 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(Constraint::Present( state.constraints.push(constraints.pattern_presence(
Type::Variable(*guard_var), Type::Variable(*guard_var),
PresenceConstraint::Pattern(
region,
PatternCategory::PatternGuard,
PExpected::ForReason( PExpected::ForReason(
PReason::PatternGuard, PReason::PatternGuard,
pat_type.clone(), pat_type.clone(),
loc_guard.region, loc_guard.region,
), ),
), PatternCategory::PatternGuard,
region,
)); ));
state.vars.push(*guard_var); state.vars.push(*guard_var);
constrain_pattern(env, &loc_guard.value, loc_guard.region, expected, state); constrain_pattern(
constraints,
env,
&loc_guard.value,
loc_guard.region,
expected,
state,
);
RecordField::Demanded(pat_type) RecordField::Demanded(pat_type)
} }
DestructType::Optional(expr_var, loc_expr) => { DestructType::Optional(expr_var, loc_expr) => {
state.constraints.push(Constraint::Present( state.constraints.push(constraints.pattern_presence(
Type::Variable(*expr_var), Type::Variable(*expr_var),
PresenceConstraint::Pattern(
region,
PatternCategory::PatternDefault,
PExpected::ForReason( PExpected::ForReason(
PReason::OptionalField, PReason::OptionalField,
pat_type.clone(), pat_type.clone(),
loc_expr.region, loc_expr.region,
), ),
), PatternCategory::PatternDefault,
region,
)); ));
state.vars.push(*expr_var); state.vars.push(*expr_var);
@ -365,8 +367,13 @@ pub fn constrain_pattern(
loc_expr.region, loc_expr.region,
); );
let expr_con = let expr_con = constrain_expr(
constrain_expr(env, loc_expr.region, &loc_expr.value, expr_expected); constraints,
env,
loc_expr.region,
&loc_expr.value,
expr_expected,
);
state.constraints.push(expr_con); state.constraints.push(expr_con);
RecordField::Optional(pat_type) RecordField::Optional(pat_type)
@ -391,9 +398,11 @@ pub fn constrain_pattern(
region, region,
); );
let record_con = Constraint::Present( let record_con = constraints.pattern_presence(
Type::Variable(*whole_var), Type::Variable(*whole_var),
PresenceConstraint::Pattern(region, PatternCategory::Record, expected), expected,
PatternCategory::Record,
region,
); );
state.constraints.push(whole_con); state.constraints.push(whole_con);
@ -420,24 +429,31 @@ pub fn constrain_pattern(
pattern_type, pattern_type,
region, region,
); );
constrain_pattern(env, &loc_pattern.value, loc_pattern.region, expected, state); constrain_pattern(
constraints,
env,
&loc_pattern.value,
loc_pattern.region,
expected,
state,
);
} }
let pat_category = PatternCategory::Ctor(tag_name.clone()); let pat_category = PatternCategory::Ctor(tag_name.clone());
let whole_con = Constraint::Present( let whole_con = constraints.includes_tag(
expected.clone().get_type(), expected.clone().get_type(),
PresenceConstraint::IncludesTag(
tag_name.clone(), tag_name.clone(),
argument_types.clone(), argument_types.clone(),
region,
pat_category.clone(), pat_category.clone(),
), region,
); );
let tag_con = Constraint::Present( let tag_con = constraints.pattern_presence(
Type::Variable(*whole_var), Type::Variable(*whole_var),
PresenceConstraint::Pattern(region, pat_category, expected), expected,
pat_category,
region,
); );
state.vars.push(*whole_var); state.vars.push(*whole_var);
@ -469,6 +485,7 @@ pub fn constrain_pattern(
// First, add a constraint for the argument "who" // First, add a constraint for the argument "who"
let arg_pattern_expected = PExpected::NoExpectation(arg_pattern_type.clone()); let arg_pattern_expected = PExpected::NoExpectation(arg_pattern_type.clone());
constrain_pattern( constrain_pattern(
constraints,
env, env,
&loc_arg_pattern.value, &loc_arg_pattern.value,
loc_arg_pattern.region, loc_arg_pattern.region,
@ -495,9 +512,11 @@ pub fn constrain_pattern(
); );
// 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 opaque_pattern_con = Constraint::Present( let opaque_pattern_con = constraints.pattern_presence(
Type::Variable(*whole_var), Type::Variable(*whole_var),
PresenceConstraint::Pattern(region, PatternCategory::Opaque(*opaque), expected), expected,
PatternCategory::Opaque(*opaque),
region,
); );
state state

View file

@ -1372,7 +1372,7 @@ fn to_pattern_report<'b>(
} }
} }
PReason::WhenMatch { index } => { PReason::WhenMatch { index } => {
if index == Index::FIRST { if index == HumanIndex::FIRST {
let doc = alloc.stack(vec![ let doc = alloc.stack(vec![
alloc alloc
.text("The 1st pattern in this ") .text("The 1st pattern in this ")
@ -1384,7 +1384,7 @@ fn to_pattern_report<'b>(
found, found,
expected_type, expected_type,
add_pattern_category( add_pattern_category(
HumanIndexlloc, alloc,
alloc.text("The first pattern is trying to match"), alloc.text("The first pattern is trying to match"),
&category, &category,
), ),