mirror of
https://github.com/roc-lang/roc.git
synced 2025-10-03 16:44:33 +00:00
Merge remote-tracking branch 'origin/trunk' into flat-declarations
This commit is contained in:
commit
b119986777
65 changed files with 3072 additions and 1287 deletions
|
@ -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,
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue