Merge remote-tracking branch 'origin/trunk' into flat-declarations

This commit is contained in:
Folkert 2022-05-14 15:52:40 +02:00
commit b119986777
No known key found for this signature in database
GPG key ID: 1F17F6FFD112B97C
65 changed files with 3072 additions and 1287 deletions

View file

@ -3,8 +3,8 @@ use crate::builtins::{
};
use crate::pattern::{constrain_pattern, PatternState};
use roc_can::annotation::IntroducedVariables;
use roc_can::constraint::{Constraint, Constraints};
use roc_can::def::{Declaration, Def};
use roc_can::constraint::{Constraint, Constraints, OpportunisticResolve};
use roc_can::def::Def;
use roc_can::exhaustive::{sketch_pattern_to_rows, sketch_when_branches, ExhaustiveContext};
use roc_can::expected::Expected::{self, *};
use roc_can::expected::PExpected;
@ -14,12 +14,13 @@ use roc_can::expr::{
WhenBranch,
};
use roc_can::pattern::Pattern;
use roc_can::traverse::symbols_introduced_from_pattern;
use roc_collections::all::{HumanIndex, MutMap, SendMap};
use roc_collections::soa::{Index, Slice};
use roc_module::ident::{Lowercase, TagName};
use roc_module::symbol::{ModuleId, Symbol};
use roc_region::all::{Loc, Region};
use roc_types::subs::Variable;
use roc_types::subs::{IllegalCycleMark, Variable};
use roc_types::types::Type::{self, *};
use roc_types::types::{
AliasKind, AnnotationSource, Category, OptAbleType, PReason, Reason, RecordField, TypeExtension,
@ -44,16 +45,16 @@ impl Info {
}
pub struct Env {
/// Whenever we encounter a user-defined type variable (a "rigid" var for short),
/// for example `a` in the annotation `identity : a -> a`, we add it to this
/// map so that expressions within that annotation can share these vars.
pub rigids: MutMap<Lowercase, Variable>,
pub resolutions_to_make: Vec<OpportunisticResolve>,
pub home: ModuleId,
}
fn constrain_untyped_args(
constraints: &mut Constraints,
env: &Env,
env: &mut Env,
arguments: &[(Variable, AnnotatedMark, Loc<Pattern>)],
closure_type: Type,
return_type: Type,
@ -93,7 +94,7 @@ fn constrain_untyped_args(
#[allow(clippy::too_many_arguments)]
fn constrain_untyped_closure(
constraints: &mut Constraints,
env: &Env,
env: &mut Env,
region: Region,
expected: Expected<Type>,
@ -171,7 +172,7 @@ fn constrain_untyped_closure(
pub fn constrain_expr(
constraints: &mut Constraints,
env: &Env,
env: &mut Env,
region: Region,
expr: &Expr,
expected: Expected<Type>,
@ -341,7 +342,7 @@ pub fn constrain_expr(
let (fn_var, loc_fn, closure_var, ret_var) = &**boxed;
// The expression that evaluates to the function being called, e.g. `foo` in
// (foo) bar baz
let opt_symbol = if let Var(symbol) | AbilityMember(symbol, _) = loc_fn.value {
let opt_symbol = if let Var(symbol) | AbilityMember(symbol, _, _) = loc_fn.value {
Some(symbol)
} else {
None
@ -419,10 +420,31 @@ pub fn constrain_expr(
// make lookup constraint to lookup this symbol's type in the environment
constraints.lookup(*symbol, expected, region)
}
AbilityMember(symbol, _specialization) => {
&AbilityMember(symbol, specialization_id, specialization_var) => {
// make lookup constraint to lookup this symbol's type in the environment
constraints.lookup(*symbol, expected, region)
// TODO: consider trying to solve `_specialization` here.
let store_expected = constraints.equal_types_var(
specialization_var,
expected,
Category::Storage(file!(), line!()),
region,
);
let lookup_constr = constraints.lookup(
symbol,
Expected::NoExpectation(Type::Variable(specialization_var)),
region,
);
// Make sure we attempt to resolve the specialization.
env.resolutions_to_make.push(OpportunisticResolve {
specialization_variable: specialization_var,
specialization_expectation: constraints.push_expected_type(
Expected::NoExpectation(Type::Variable(specialization_var)),
),
member: symbol,
specialization_id,
});
constraints.and_constraint([store_expected, lookup_constr])
}
Closure(ClosureData {
function_type: fn_var,
@ -829,16 +851,8 @@ pub fn constrain_expr(
region,
);
let constraint = constrain_expr(
constraints,
&Env {
home: env.home,
rigids: MutMap::default(),
},
region,
&loc_expr.value,
record_expected,
);
let constraint =
constrain_expr(constraints, env, region, &loc_expr.value, record_expected);
let eq = constraints.equal_types_var(field_var, expected, category, region);
constraints.exists_many(
@ -914,7 +928,7 @@ pub fn constrain_expr(
cons,
)
}
LetRec(defs, loc_ret) => {
LetRec(defs, loc_ret, cycle_mark) => {
let body_con = constrain_expr(
constraints,
env,
@ -923,7 +937,7 @@ pub fn constrain_expr(
expected.clone(),
);
constrain_recursive_defs(constraints, env, defs, body_con)
constrain_recursive_defs(constraints, env, defs, body_con, *cycle_mark)
}
LetNonRec(def, loc_ret) => {
let mut stack = Vec::with_capacity(1);
@ -1169,7 +1183,7 @@ pub fn constrain_expr(
fn constrain_function_def(
constraints: &mut Constraints,
env: &Env,
env: &mut Env,
declarations: &Declarations,
index: usize,
function_def_index: Index<Loc<FunctionDef>>,
@ -1199,9 +1213,10 @@ fn constrain_function_def(
&mut ftv,
);
let env = &Env {
let env = &mut Env {
home: env.home,
rigids: ftv,
resolutions_to_make: vec![],
};
let loc_pattern = Loc::at(loc_symbol.region, Pattern::Identifier(loc_symbol.value));
@ -1379,7 +1394,7 @@ fn constrain_function_def(
fn constrain_destructure_def(
constraints: &mut Constraints,
env: &Env,
env: &mut Env,
declarations: &Declarations,
index: usize,
destructure_def_index: Index<DestructureDef>,
@ -1416,9 +1431,10 @@ fn constrain_destructure_def(
&mut def_pattern_state.headers,
);
let env = &Env {
let env = &mut Env {
home: env.home,
rigids: ftv,
resolutions_to_make: vec![],
};
let annotation_expected = FromAnnotation(
@ -1482,7 +1498,7 @@ fn constrain_destructure_def(
fn constrain_value_def(
constraints: &mut Constraints,
env: &Env,
env: &mut Env,
declarations: &Declarations,
index: usize,
body_con: Constraint,
@ -1508,9 +1524,10 @@ fn constrain_value_def(
&mut ftv,
);
let env = &Env {
let env = &mut Env {
home: env.home,
rigids: ftv,
resolutions_to_make: vec![],
};
let loc_pattern = Loc::at(loc_symbol.region, Pattern::Identifier(loc_symbol.value));
@ -1583,7 +1600,7 @@ fn constrain_value_def(
#[inline(always)]
fn constrain_when_branch_help(
constraints: &mut Constraints,
env: &Env,
env: &mut Env,
region: Region,
when_branch: &WhenBranch,
pattern_expected: impl Fn(HumanIndex, Region) -> PExpected<Type>,
@ -1663,7 +1680,7 @@ fn constrain_when_branch_help(
fn constrain_field(
constraints: &mut Constraints,
env: &Env,
env: &mut Env,
field_var: Variable,
loc_expr: &Loc<Expr>,
) -> (Type, Constraint) {
@ -1701,6 +1718,7 @@ pub fn constrain_decls(
let mut env = Env {
home,
rigids: MutMap::default(),
resolutions_to_make: vec![],
};
debug_assert_eq!(declarations.declarations.len(), declarations.symbols.len());
@ -1714,12 +1732,12 @@ pub fn constrain_decls(
match tag {
Value => {
constraint =
constrain_value_def(constraints, &env, declarations, index, constraint);
constrain_value_def(constraints, &mut env, declarations, index, constraint);
}
Function(function_def_index) => {
constraint = constrain_function_def(
constraints,
&env,
&mut env,
declarations,
index,
function_def_index,
@ -1730,7 +1748,7 @@ pub fn constrain_decls(
// for the type it does not matter that a recursive call is a tail call
constraint = constrain_recursive_defs_simple(
constraints,
&env,
&mut env,
declarations,
index,
function_def_index.as_slice(),
@ -1740,7 +1758,7 @@ pub fn constrain_decls(
Destructure(destructure_def_index) => {
constrain_destructure_def(
constraints,
&env,
&mut env,
declarations,
index,
destructure_def_index,
@ -1759,7 +1777,7 @@ pub fn constrain_decls(
pub(crate) fn constrain_def_pattern(
constraints: &mut Constraints,
env: &Env,
env: &mut Env,
loc_pattern: &Loc<Pattern>,
expr_type: Type,
) -> PatternState {
@ -1787,7 +1805,7 @@ pub(crate) fn constrain_def_pattern(
/// Generate constraints for a definition with a type signature
fn constrain_typed_def(
constraints: &mut Constraints,
env: &Env,
env: &mut Env,
def: &Def,
body_con: Constraint,
annotation: &roc_can::def::Annotation,
@ -1816,8 +1834,9 @@ fn constrain_typed_def(
&mut def_pattern_state.headers,
);
let env = &Env {
let env = &mut Env {
home: env.home,
resolutions_to_make: vec![],
rigids: ftv,
};
@ -1915,6 +1934,7 @@ fn constrain_typed_def(
&loc_body_expr.value,
body_type,
);
let ret_constraint = attach_resolution_constraints(constraints, env, ret_constraint);
vars.push(*fn_var);
let defs_constraint = constraints.and_constraint(argument_pattern_state.constraints);
@ -1977,6 +1997,7 @@ fn constrain_typed_def(
&def.loc_expr.value,
annotation_expected,
);
let ret_constraint = attach_resolution_constraints(constraints, env, ret_constraint);
let cons = [
ret_constraint,
@ -1999,7 +2020,7 @@ fn constrain_typed_def(
fn constrain_typed_function_arguments(
constraints: &mut Constraints,
env: &Env,
env: &mut Env,
def: &Def,
def_pattern_state: &mut PatternState,
argument_pattern_state: &mut PatternState,
@ -2127,7 +2148,7 @@ fn constrain_typed_function_arguments(
fn constrain_typed_function_arguments_simple(
constraints: &mut Constraints,
env: &Env,
env: &mut Env,
symbol: Symbol,
def_pattern_state: &mut PatternState,
argument_pattern_state: &mut PatternState,
@ -2237,9 +2258,20 @@ fn constrain_typed_function_arguments_simple(
}
}
#[inline(always)]
fn attach_resolution_constraints(
constraints: &mut Constraints,
env: &mut Env,
constraint: Constraint,
) -> Constraint {
let resolution_constrs =
constraints.and_constraint(env.resolutions_to_make.drain(..).map(Constraint::Resolve));
constraints.and_constraint([constraint, resolution_constrs])
}
fn constrain_def(
constraints: &mut Constraints,
env: &Env,
env: &mut Env,
def: &Def,
body_con: Constraint,
) -> Constraint {
@ -2262,6 +2294,7 @@ fn constrain_def(
&def.loc_expr.value,
NoExpectation(expr_type),
);
let expr_con = attach_resolution_constraints(constraints, env, expr_con);
constrain_def_make_constraint(
constraints,
@ -2275,30 +2308,27 @@ fn constrain_def(
}
}
/// Create a let-constraint for a non-recursive def.
/// Recursive defs should always use `constrain_recursive_defs`.
pub(crate) fn constrain_def_make_constraint(
constraints: &mut Constraints,
new_rigid_variables: impl Iterator<Item = Variable>,
new_infer_variables: impl Iterator<Item = Variable>,
expr_con: Constraint,
body_con: Constraint,
annotation_rigid_variables: impl Iterator<Item = Variable>,
annotation_infer_variables: impl Iterator<Item = Variable>,
def_expr_con: Constraint,
after_def_con: Constraint,
def_pattern_state: PatternState,
) -> Constraint {
let and_constraint = constraints.and_constraint(def_pattern_state.constraints);
let all_flex_variables = (def_pattern_state.vars.into_iter()).chain(annotation_infer_variables);
let def_con = constraints.let_constraint(
[],
new_infer_variables,
[], // empty, because our functions have no arguments!
and_constraint,
expr_con,
);
let pattern_constraints = constraints.and_constraint(def_pattern_state.constraints);
let def_pattern_and_body_con = constraints.and_constraint([pattern_constraints, def_expr_con]);
constraints.let_constraint(
new_rigid_variables,
def_pattern_state.vars,
annotation_rigid_variables,
all_flex_variables,
def_pattern_state.headers,
def_con,
body_con,
def_pattern_and_body_con,
after_def_con,
)
}
@ -2524,7 +2554,7 @@ fn instantiate_rigids_simple(
fn constrain_recursive_defs_simple(
constraints: &mut Constraints,
env: &Env,
env: &mut Env,
declarations: &Declarations,
start_index: usize,
defs: Slice<Loc<FunctionDef>>,
@ -2544,7 +2574,7 @@ fn constrain_recursive_defs_simple(
pub fn rec_defs_help_simple(
constraints: &mut Constraints,
env: &Env,
env: &mut Env,
declarations: &Declarations,
defs: Slice<Loc<FunctionDef>>,
start_index: usize,
@ -2773,9 +2803,10 @@ pub fn rec_defs_help_simple(
fn constrain_recursive_defs(
constraints: &mut Constraints,
env: &Env,
env: &mut Env,
defs: &[Def],
body_con: Constraint,
cycle_mark: IllegalCycleMark,
) -> Constraint {
rec_defs_help(
constraints,
@ -2784,16 +2815,18 @@ fn constrain_recursive_defs(
body_con,
Info::with_capacity(defs.len()),
Info::with_capacity(defs.len()),
cycle_mark,
)
}
pub fn rec_defs_help(
constraints: &mut Constraints,
env: &Env,
env: &mut Env,
defs: &[Def],
body_con: Constraint,
mut rigid_info: Info,
mut flex_info: Info,
cycle_mark: IllegalCycleMark,
) -> Constraint {
for def in defs {
let expr_var = def.expr_var;
@ -2813,6 +2846,7 @@ pub fn rec_defs_help(
&def.loc_expr.value,
NoExpectation(expr_type),
);
let expr_con = attach_resolution_constraints(constraints, env, expr_con);
let def_con = expr_con;
@ -2925,6 +2959,7 @@ pub fn rec_defs_help(
&loc_body_expr.value,
body_type,
);
let expr_con = attach_resolution_constraints(constraints, env, expr_con);
vars.push(*fn_var);
@ -2986,6 +3021,8 @@ pub fn rec_defs_help(
&def.loc_expr.value,
expected,
);
let ret_constraint =
attach_resolution_constraints(constraints, env, ret_constraint);
let cons = [
ret_constraint,
@ -3010,30 +3047,60 @@ pub fn rec_defs_help(
}
}
let flex_constraints = constraints.and_constraint(flex_info.constraints);
let inner_inner = constraints.let_constraint(
// Strategy for recursive defs:
// 1. Let-generalize the type annotations we know; these are the source of truth we'll solve
// everything else with. If there are circular type errors here, they will be caught during
// the let-generalization.
// 2. Introduce all symbols of the untyped defs, but don't generalize them yet. Now, solve
// the untyped defs' bodies. This way, when checking something like
// f = \x -> f [ x ]
// we introduce `f: b -> c`, then constrain the call `f [ x ]`,
// forcing `b -> c ~ List b -> c` and correctly picking up a recursion error.
// Had we generalized `b -> c`, the call `f [ x ]` would have been generalized, and this
// error would not be found.
// 3. Now properly let-generalize the untyped body defs, since we now know their types and
// that they don't have circular type errors.
// 4. Solve the bodies of the typed body defs, and check that they agree the types of the type
// annotation.
// 5. Solve the rest of the program that happens after this recursive def block.
// 2. Solve untyped defs without generalization of their symbols.
let untyped_body_constraints = constraints.and_constraint(flex_info.constraints);
let untyped_def_symbols_constr = constraints.let_constraint(
[],
[],
flex_info.def_types.clone(),
Constraint::True,
flex_constraints,
untyped_body_constraints,
);
let rigid_constraints = {
let mut temp = rigid_info.constraints;
temp.push(body_con);
// an extra constraint that propagates information to the solver to check for invalid recursion
// and generate a good error message there.
let (loc_symbols, expr_regions): (Vec<_>, Vec<_>) = defs
.iter()
.flat_map(|def| {
symbols_introduced_from_pattern(&def.loc_pattern)
.map(move |loc_symbol| ((loc_symbol.value, loc_symbol.region), def.loc_expr.region))
})
.unzip();
constraints.and_constraint(temp)
};
let cycle_constraint = constraints.check_cycle(loc_symbols, expr_regions, cycle_mark);
let typed_body_constraints = constraints.and_constraint(rigid_info.constraints);
let typed_body_and_final_constr =
constraints.and_constraint([typed_body_constraints, cycle_constraint, body_con]);
// 3. Properly generalize untyped defs after solving them.
let inner = constraints.let_constraint(
[],
flex_info.vars,
flex_info.def_types,
inner_inner,
rigid_constraints,
untyped_def_symbols_constr,
// 4 + 5. Solve the typed body defs, and the rest of the program.
typed_body_and_final_constr,
);
// 1. Let-generalize annotations we know.
constraints.let_constraint(
rigid_info.vars,
[],
@ -3046,7 +3113,7 @@ pub fn rec_defs_help(
#[inline(always)]
fn constrain_field_update(
constraints: &mut Constraints,
env: &Env,
env: &mut Env,
var: Variable,
region: Region,
field: Lowercase,