Merge pull request #4354 from roc-lang/var-has-variable

Resolve ability specializations looked up in expects
This commit is contained in:
Folkert de Vries 2022-10-18 23:28:17 +02:00 committed by GitHub
commit e90ddcd7d1
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
15 changed files with 340 additions and 194 deletions

1
Cargo.lock generated
View file

@ -3959,6 +3959,7 @@ dependencies = [
"pretty_assertions", "pretty_assertions",
"roc_build", "roc_build",
"roc_builtins", "roc_builtins",
"roc_can",
"roc_collections", "roc_collections",
"roc_gen_llvm", "roc_gen_llvm",
"roc_intern", "roc_intern",

View file

@ -247,7 +247,7 @@ fn lowlevel_1(symbol: Symbol, op: LowLevel, var_store: &mut VarStore) -> Def {
let body = RunLowLevel { let body = RunLowLevel {
op, op,
args: vec![(arg1_var, Var(Symbol::ARG_1))], args: vec![(arg1_var, Var(Symbol::ARG_1, arg1_var))],
ret_var, ret_var,
}; };
@ -268,8 +268,8 @@ fn lowlevel_2(symbol: Symbol, op: LowLevel, var_store: &mut VarStore) -> Def {
let body = RunLowLevel { let body = RunLowLevel {
op, op,
args: vec![ args: vec![
(arg1_var, Var(Symbol::ARG_1)), (arg1_var, Var(Symbol::ARG_1, arg1_var)),
(arg2_var, Var(Symbol::ARG_2)), (arg2_var, Var(Symbol::ARG_2, arg2_var)),
], ],
ret_var, ret_var,
}; };
@ -292,9 +292,9 @@ fn lowlevel_3(symbol: Symbol, op: LowLevel, var_store: &mut VarStore) -> Def {
let body = RunLowLevel { let body = RunLowLevel {
op, op,
args: vec![ args: vec![
(arg1_var, Var(Symbol::ARG_1)), (arg1_var, Var(Symbol::ARG_1, arg1_var)),
(arg2_var, Var(Symbol::ARG_2)), (arg2_var, Var(Symbol::ARG_2, arg2_var)),
(arg3_var, Var(Symbol::ARG_3)), (arg3_var, Var(Symbol::ARG_3, arg3_var)),
], ],
ret_var, ret_var,
}; };
@ -322,10 +322,10 @@ fn lowlevel_4(symbol: Symbol, op: LowLevel, var_store: &mut VarStore) -> Def {
let body = RunLowLevel { let body = RunLowLevel {
op, op,
args: vec![ args: vec![
(arg1_var, Var(Symbol::ARG_1)), (arg1_var, Var(Symbol::ARG_1, arg1_var)),
(arg2_var, Var(Symbol::ARG_2)), (arg2_var, Var(Symbol::ARG_2, arg2_var)),
(arg3_var, Var(Symbol::ARG_3)), (arg3_var, Var(Symbol::ARG_3, arg3_var)),
(arg4_var, Var(Symbol::ARG_4)), (arg4_var, Var(Symbol::ARG_4, arg4_var)),
], ],
ret_var, ret_var,
}; };
@ -355,11 +355,11 @@ fn lowlevel_5(symbol: Symbol, op: LowLevel, var_store: &mut VarStore) -> Def {
let body = RunLowLevel { let body = RunLowLevel {
op, op,
args: vec![ args: vec![
(arg1_var, Var(Symbol::ARG_1)), (arg1_var, Var(Symbol::ARG_1, arg1_var)),
(arg2_var, Var(Symbol::ARG_2)), (arg2_var, Var(Symbol::ARG_2, arg2_var)),
(arg3_var, Var(Symbol::ARG_3)), (arg3_var, Var(Symbol::ARG_3, arg3_var)),
(arg4_var, Var(Symbol::ARG_4)), (arg4_var, Var(Symbol::ARG_4, arg4_var)),
(arg5_var, Var(Symbol::ARG_5)), (arg5_var, Var(Symbol::ARG_5, arg5_var)),
], ],
ret_var, ret_var,
}; };
@ -486,7 +486,7 @@ fn to_num_checked(symbol: Symbol, var_store: &mut VarStore, lowlevel: LowLevel)
ext_var: var_store.fresh(), ext_var: var_store.fresh(),
field: "b".into(), field: "b".into(),
field_var: var_store.fresh(), field_var: var_store.fresh(),
loc_expr: Box::new(no_region(Var(Symbol::ARG_2))), loc_expr: Box::new(no_region(Var(Symbol::ARG_2, var_store.fresh()))),
}, },
), ),
// out of bounds! // out of bounds!
@ -509,7 +509,7 @@ fn to_num_checked(symbol: Symbol, var_store: &mut VarStore, lowlevel: LowLevel)
ext_var: var_store.fresh(), ext_var: var_store.fresh(),
field: "a".into(), field: "a".into(),
field_var: num_var_2, field_var: num_var_2,
loc_expr: Box::new(no_region(Var(Symbol::ARG_2))), loc_expr: Box::new(no_region(Var(Symbol::ARG_2, var_store.fresh()))),
}, },
], ],
var_store, var_store,
@ -523,7 +523,7 @@ fn to_num_checked(symbol: Symbol, var_store: &mut VarStore, lowlevel: LowLevel)
loc_pattern: no_region(Pattern::Identifier(Symbol::ARG_2)), loc_pattern: no_region(Pattern::Identifier(Symbol::ARG_2)),
loc_expr: no_region(RunLowLevel { loc_expr: no_region(RunLowLevel {
op: lowlevel, op: lowlevel,
args: vec![(num_var_1, Var(Symbol::ARG_1))], args: vec![(num_var_1, Var(Symbol::ARG_1, var_store.fresh()))],
ret_var: record_var, ret_var: record_var,
}), }),
expr_var: record_var, expr_var: record_var,
@ -549,7 +549,7 @@ fn to_num_is_zero(symbol: Symbol, var_store: &mut VarStore) -> Def {
let body = Expr::RunLowLevel { let body = Expr::RunLowLevel {
op: LowLevel::Eq, op: LowLevel::Eq,
args: vec![ args: vec![
(num_var, Var(Symbol::ARG_1)), (num_var, Var(Symbol::ARG_1, num_var)),
( (
num_var, num_var,
Num( Num(

View file

@ -255,9 +255,9 @@ fn deep_copy_expr_help<C: CopyEnv>(env: &mut C, copied: &mut Vec<Variable>, expr
elem_var: sub!(*elem_var), elem_var: sub!(*elem_var),
loc_elems: loc_elems.iter().map(|le| le.map(|e| go_help!(e))).collect(), loc_elems: loc_elems.iter().map(|le| le.map(|e| go_help!(e))).collect(),
}, },
Var(sym) => Var(*sym), Var(sym, var) => Var(*sym, sub!(*var)),
&AbilityMember(sym, specialization, specialization_var) => { &AbilityMember(sym, specialization, specialization_var) => {
AbilityMember(sym, specialization, specialization_var) AbilityMember(sym, specialization, sub!(specialization_var))
} }
When { When {
loc_cond, loc_cond,

View file

@ -124,14 +124,15 @@ fn build_effect_always(
Loc::at_zero(empty_record_pattern(var_store)), Loc::at_zero(empty_record_pattern(var_store)),
)]; )];
let body = Expr::Var(value_symbol); let value_var = var_store.fresh();
let body = Expr::Var(value_symbol, value_var);
Expr::Closure(ClosureData { Expr::Closure(ClosureData {
function_type: var_store.fresh(), function_type: var_store.fresh(),
closure_type: var_store.fresh(), closure_type: var_store.fresh(),
return_type: var_store.fresh(), return_type: var_store.fresh(),
name: inner_closure_symbol, name: inner_closure_symbol,
captured_symbols: vec![(value_symbol, var_store.fresh())], captured_symbols: vec![(value_symbol, value_var)],
recursive: Recursive::NotRecursive, recursive: Recursive::NotRecursive,
arguments, arguments,
loc_body: Box::new(Loc::at_zero(body)), loc_body: Box::new(Loc::at_zero(body)),
@ -231,20 +232,22 @@ fn build_effect_map(
.introduce("effect_map_thunk".into(), Region::zero()) .introduce("effect_map_thunk".into(), Region::zero())
.unwrap() .unwrap()
}; };
let thunk_var = var_store.fresh();
let mapper_symbol = { let mapper_symbol = {
scope scope
.introduce("effect_map_mapper".into(), Region::zero()) .introduce("effect_map_mapper".into(), Region::zero())
.unwrap() .unwrap()
}; };
let mapper_var = var_store.fresh();
let map_symbol = { scope.introduce("map".into(), Region::zero()).unwrap() }; let map_symbol = { scope.introduce("map".into(), Region::zero()).unwrap() };
// `thunk {}` // `thunk {}`
let force_thunk_call = { let force_thunk_call = {
let boxed = ( let boxed = (
var_store.fresh(), thunk_var,
Loc::at_zero(Expr::Var(thunk_symbol)), Loc::at_zero(Expr::Var(thunk_symbol, thunk_var)),
var_store.fresh(), var_store.fresh(),
var_store.fresh(), var_store.fresh(),
); );
@ -256,8 +259,8 @@ fn build_effect_map(
// `toEffect (thunk {})` // `toEffect (thunk {})`
let mapper_call = { let mapper_call = {
let boxed = ( let boxed = (
var_store.fresh(), mapper_var,
Loc::at_zero(Expr::Var(mapper_symbol)), Loc::at_zero(Expr::Var(mapper_symbol, mapper_var)),
var_store.fresh(), var_store.fresh(),
var_store.fresh(), var_store.fresh(),
); );
@ -411,9 +414,9 @@ fn build_effect_map(
(map_symbol, def) (map_symbol, def)
} }
fn force_thunk(expr: Expr, var_store: &mut VarStore) -> Expr { fn force_thunk(expr: Expr, thunk_var: Variable, var_store: &mut VarStore) -> Expr {
let boxed = ( let boxed = (
var_store.fresh(), thunk_var,
Loc::at_zero(expr), Loc::at_zero(expr),
var_store.fresh(), var_store.fresh(),
var_store.fresh(), var_store.fresh(),
@ -441,13 +444,19 @@ fn build_effect_after(
let outer_closure_symbol = new_symbol!(scope, "effect_after_inner"); let outer_closure_symbol = new_symbol!(scope, "effect_after_inner");
// `effect {}` // `effect {}`
let force_effect_call = force_thunk(Expr::Var(effect_symbol), var_store); let force_effect_var = var_store.fresh();
let force_effect_call = force_thunk(
Expr::Var(effect_symbol, force_effect_var),
force_effect_var,
var_store,
);
// `toEffect (effect {})` // `toEffect (effect {})`
let to_effect_var = var_store.fresh();
let to_effect_call = { let to_effect_call = {
let boxed = ( let boxed = (
var_store.fresh(), to_effect_var,
Loc::at_zero(Expr::Var(to_effect_symbol)), Loc::at_zero(Expr::Var(to_effect_symbol, to_effect_var)),
var_store.fresh(), var_store.fresh(),
var_store.fresh(), var_store.fresh(),
); );
@ -459,7 +468,12 @@ fn build_effect_after(
// let @Effect thunk = toEffect (effect {}) in thunk {} // let @Effect thunk = toEffect (effect {}) in thunk {}
let let_effect_thunk = { let let_effect_thunk = {
// `thunk {}` // `thunk {}`
let force_inner_thunk_call = force_thunk(Expr::Var(thunk_symbol), var_store); let force_inner_thunk_var = var_store.fresh();
let force_inner_thunk_call = force_thunk(
Expr::Var(thunk_symbol, force_inner_thunk_var),
force_inner_thunk_var,
var_store,
);
let (specialized_def_type, type_arguments, lambda_set_variables) = let (specialized_def_type, type_arguments, lambda_set_variables) =
build_fresh_opaque_variables(var_store); build_fresh_opaque_variables(var_store);
@ -702,9 +716,10 @@ fn force_effect(
let ret_var = var_store.fresh(); let ret_var = var_store.fresh();
let force_thunk_call = { let force_thunk_call = {
let thunk_var = var_store.fresh();
let boxed = ( let boxed = (
var_store.fresh(), thunk_var,
Loc::at_zero(Expr::Var(thunk_symbol)), Loc::at_zero(Expr::Var(thunk_symbol, thunk_var)),
var_store.fresh(), var_store.fresh(),
ret_var, ret_var,
); );
@ -884,6 +899,7 @@ fn build_effect_forever_inner_body(
effect: Symbol, effect: Symbol,
var_store: &mut VarStore, var_store: &mut VarStore,
) -> Expr { ) -> Expr {
let thunk1_var = var_store.fresh();
let thunk1_symbol = { scope.introduce("thunk1".into(), Region::zero()).unwrap() }; let thunk1_symbol = { scope.introduce("thunk1".into(), Region::zero()).unwrap() };
let thunk2_symbol = { scope.introduce("thunk2".into(), Region::zero()).unwrap() }; let thunk2_symbol = { scope.introduce("thunk2".into(), Region::zero()).unwrap() };
@ -909,7 +925,7 @@ fn build_effect_forever_inner_body(
Def { Def {
loc_pattern: Loc::at_zero(pattern), loc_pattern: Loc::at_zero(pattern),
loc_expr: Loc::at_zero(Expr::Var(effect)), loc_expr: Loc::at_zero(Expr::Var(effect, var_store.fresh())),
expr_var: var_store.fresh(), expr_var: var_store.fresh(),
pattern_vars, pattern_vars,
annotation: None, annotation: None,
@ -920,8 +936,8 @@ fn build_effect_forever_inner_body(
let force_thunk_call = { let force_thunk_call = {
let ret_var = var_store.fresh(); let ret_var = var_store.fresh();
let boxed = ( let boxed = (
var_store.fresh(), thunk1_var,
Loc::at_zero(Expr::Var(thunk1_symbol)), Loc::at_zero(Expr::Var(thunk1_symbol, thunk1_var)),
var_store.fresh(), var_store.fresh(),
ret_var, ret_var,
); );
@ -945,12 +961,13 @@ fn build_effect_forever_inner_body(
let forever_effect = { let forever_effect = {
let boxed = ( let boxed = (
var_store.fresh(), var_store.fresh(),
Loc::at_zero(Expr::Var(forever_symbol)), Loc::at_zero(Expr::Var(forever_symbol, var_store.fresh())),
var_store.fresh(), var_store.fresh(),
var_store.fresh(), var_store.fresh(),
); );
let arguments = vec![(var_store.fresh(), Loc::at_zero(Expr::Var(effect)))]; let effect_var = var_store.fresh();
let arguments = vec![(effect_var, Loc::at_zero(Expr::Var(effect, effect_var)))];
Expr::Call(Box::new(boxed), arguments, CalledVia::Space) Expr::Call(Box::new(boxed), arguments, CalledVia::Space)
}; };
@ -1198,14 +1215,16 @@ fn build_effect_loop_inner_body(
// `step state` // `step state`
let rhs = { let rhs = {
let step_var = var_store.fresh();
let boxed = ( let boxed = (
var_store.fresh(), step_var,
Loc::at_zero(Expr::Var(step_symbol)), Loc::at_zero(Expr::Var(step_symbol, step_var)),
var_store.fresh(), var_store.fresh(),
var_store.fresh(), var_store.fresh(),
); );
let arguments = vec![(var_store.fresh(), Loc::at_zero(Expr::Var(state_symbol)))]; let state_var = var_store.fresh();
let arguments = vec![(state_var, Loc::at_zero(Expr::Var(state_symbol, state_var)))];
Expr::Call(Box::new(boxed), arguments, CalledVia::Space) Expr::Call(Box::new(boxed), arguments, CalledVia::Space)
}; };
@ -1220,10 +1239,11 @@ fn build_effect_loop_inner_body(
// thunk1 {} // thunk1 {}
let force_thunk_call = { let force_thunk_call = {
let thunk1_var = var_store.fresh();
let ret_var = var_store.fresh(); let ret_var = var_store.fresh();
let boxed = ( let boxed = (
var_store.fresh(), thunk1_var,
Loc::at_zero(Expr::Var(thunk1_symbol)), Loc::at_zero(Expr::Var(thunk1_symbol, thunk1_var)),
var_store.fresh(), var_store.fresh(),
ret_var, ret_var,
); );
@ -1236,16 +1256,22 @@ fn build_effect_loop_inner_body(
// recursive call `loop newState step` // recursive call `loop newState step`
let loop_new_state_step = { let loop_new_state_step = {
let loop_var = var_store.fresh();
let boxed = ( let boxed = (
var_store.fresh(), loop_var,
Loc::at_zero(Expr::Var(loop_symbol)), Loc::at_zero(Expr::Var(loop_symbol, loop_var)),
var_store.fresh(), var_store.fresh(),
var_store.fresh(), var_store.fresh(),
); );
let new_state_var = var_store.fresh();
let step_var = var_store.fresh();
let arguments = vec![ let arguments = vec![
(var_store.fresh(), Loc::at_zero(Expr::Var(new_state_symbol))), (
(var_store.fresh(), Loc::at_zero(Expr::Var(step_symbol))), new_state_var,
Loc::at_zero(Expr::Var(new_state_symbol, new_state_var)),
),
(step_var, Loc::at_zero(Expr::Var(step_symbol, step_var))),
]; ];
Expr::Call(Box::new(boxed), arguments, CalledVia::Space) Expr::Call(Box::new(boxed), arguments, CalledVia::Space)
}; };
@ -1283,7 +1309,7 @@ fn build_effect_loop_inner_body(
crate::expr::WhenBranch { crate::expr::WhenBranch {
patterns: vec![done_pattern], patterns: vec![done_pattern],
value: Loc::at_zero(Expr::Var(done_symbol)), value: Loc::at_zero(Expr::Var(done_symbol, var_store.fresh())),
guard: None, guard: None,
redundant: RedundantMark::new(var_store), redundant: RedundantMark::new(var_store),
} }
@ -1351,7 +1377,7 @@ pub fn build_host_exposed_def(
)); ));
captured_symbols.push((arg_symbol, arg_var)); captured_symbols.push((arg_symbol, arg_var));
linked_symbol_arguments.push((arg_var, Expr::Var(arg_symbol))); linked_symbol_arguments.push((arg_var, Expr::Var(arg_symbol, arg_var)));
} }
let foreign_symbol_name = format!("roc_fx_{}", ident); let foreign_symbol_name = format!("roc_fx_{}", ident);

View file

@ -100,7 +100,7 @@ pub enum Expr {
}, },
// Lookups // Lookups
Var(Symbol), Var(Symbol, Variable),
AbilityMember( AbilityMember(
/// Actual member name /// Actual member name
Symbol, Symbol,
@ -230,14 +230,14 @@ pub enum Expr {
Expect { Expect {
loc_condition: Box<Loc<Expr>>, loc_condition: Box<Loc<Expr>>,
loc_continuation: Box<Loc<Expr>>, loc_continuation: Box<Loc<Expr>>,
lookups_in_cond: Vec<(Symbol, Variable)>, lookups_in_cond: Vec<ExpectLookup>,
}, },
// not parsed, but is generated when lowering toplevel effectful expects // not parsed, but is generated when lowering toplevel effectful expects
ExpectFx { ExpectFx {
loc_condition: Box<Loc<Expr>>, loc_condition: Box<Loc<Expr>>,
loc_continuation: Box<Loc<Expr>>, loc_continuation: Box<Loc<Expr>>,
lookups_in_cond: Vec<(Symbol, Variable)>, lookups_in_cond: Vec<ExpectLookup>,
}, },
/// Rendered as empty box in editor /// Rendered as empty box in editor
@ -247,6 +247,13 @@ pub enum Expr {
RuntimeError(RuntimeError), RuntimeError(RuntimeError),
} }
#[derive(Clone, Copy, Debug)]
pub struct ExpectLookup {
pub symbol: Symbol,
pub var: Variable,
pub ability_info: Option<SpecializationId>,
}
impl Expr { impl Expr {
pub fn category(&self) -> Category { pub fn category(&self) -> Category {
match self { match self {
@ -256,7 +263,7 @@ impl Expr {
Self::Str(..) => Category::Str, Self::Str(..) => Category::Str,
Self::SingleQuote(..) => Category::Character, Self::SingleQuote(..) => Category::Character,
Self::List { .. } => Category::List, Self::List { .. } => Category::List,
&Self::Var(sym) => Category::Lookup(sym), &Self::Var(sym, _) => Category::Lookup(sym),
&Self::AbilityMember(sym, _, _) => Category::Lookup(sym), &Self::AbilityMember(sym, _, _) => Category::Lookup(sym),
Self::When { .. } => Category::When, Self::When { .. } => Category::When,
Self::If { .. } => Category::If, Self::If { .. } => Category::If,
@ -372,7 +379,7 @@ impl AccessorData {
record_var, record_var,
ext_var, ext_var,
field_var, field_var,
loc_expr: Box::new(Loc::at_zero(Expr::Var(record_symbol))), loc_expr: Box::new(Loc::at_zero(Expr::Var(record_symbol, record_var))),
field, field,
}; };
@ -440,7 +447,10 @@ impl OpaqueWrapFunctionData {
let body = Expr::OpaqueRef { let body = Expr::OpaqueRef {
opaque_var, opaque_var,
name: opaque_name, name: opaque_name,
argument: Box::new((argument_var, Loc::at_zero(Expr::Var(argument_symbol)))), argument: Box::new((
argument_var,
Loc::at_zero(Expr::Var(argument_symbol, argument_var)),
)),
specialized_def_type: Box::new(specialized_def_type), specialized_def_type: Box::new(specialized_def_type),
type_arguments, type_arguments,
lambda_set_variables, lambda_set_variables,
@ -592,7 +602,7 @@ pub fn canonicalize_expr<'a>(
} => { } => {
let (can_update, update_out) = let (can_update, update_out) =
canonicalize_expr(env, var_store, scope, loc_update.region, &loc_update.value); canonicalize_expr(env, var_store, scope, loc_update.region, &loc_update.value);
if let Var(symbol) = &can_update.value { if let Var(symbol, _) = &can_update.value {
match canonicalize_fields(env, var_store, scope, region, fields.items) { match canonicalize_fields(env, var_store, scope, region, fields.items) {
Ok((can_fields, mut output)) => { Ok((can_fields, mut output)) => {
output.references.union_mut(&update_out.references); output.references.union_mut(&update_out.references);
@ -765,7 +775,7 @@ pub fn canonicalize_expr<'a>(
output.tail_call = None; output.tail_call = None;
let expr = match fn_expr.value { let expr = match fn_expr.value {
Var(symbol) => { Var(symbol, _) => {
output.references.insert_call(symbol); output.references.insert_call(symbol);
// we're tail-calling a symbol by name, check if it's the tail-callable symbol // we're tail-calling a symbol by name, check if it's the tail-callable symbol
@ -994,7 +1004,7 @@ pub fn canonicalize_expr<'a>(
// Get all the lookups that were referenced in the condition, // Get all the lookups that were referenced in the condition,
// so we can print their values later. // so we can print their values later.
let lookups_in_cond = get_lookup_symbols(&loc_condition.value, var_store); let lookups_in_cond = get_lookup_symbols(&loc_condition.value);
let (loc_continuation, output2) = canonicalize_expr( let (loc_continuation, output2) = canonicalize_expr(
env, env,
@ -1600,7 +1610,7 @@ fn canonicalize_var_lookup(
var_store.fresh(), var_store.fresh(),
) )
} else { } else {
Var(symbol) Var(symbol, var_store.fresh())
} }
} }
Err(problem) => { Err(problem) => {
@ -1623,7 +1633,7 @@ fn canonicalize_var_lookup(
var_store.fresh(), var_store.fresh(),
) )
} else { } else {
Var(symbol) Var(symbol, var_store.fresh())
} }
} }
Err(problem) => { Err(problem) => {
@ -1657,7 +1667,7 @@ pub fn inline_calls(var_store: &mut VarStore, scope: &mut Scope, expr: Expr) ->
| other @ EmptyRecord | other @ EmptyRecord
| other @ Accessor { .. } | other @ Accessor { .. }
| other @ Update { .. } | other @ Update { .. }
| other @ Var(_) | other @ Var(..)
| other @ AbilityMember(..) | other @ AbilityMember(..)
| other @ RunLowLevel { .. } | other @ RunLowLevel { .. }
| other @ TypedHole { .. } | other @ TypedHole { .. }
@ -1960,7 +1970,8 @@ pub fn inline_calls(var_store: &mut VarStore, scope: &mut Scope, expr: Expr) ->
let (fn_var, loc_expr, closure_var, expr_var) = *boxed_tuple; let (fn_var, loc_expr, closure_var, expr_var) = *boxed_tuple;
match loc_expr.value { match loc_expr.value {
Var(symbol) if symbol.is_builtin() => match builtin_defs_map(symbol, var_store) { Var(symbol, _) if symbol.is_builtin() => {
match builtin_defs_map(symbol, var_store) {
Some(Def { Some(Def {
loc_expr: loc_expr:
Loc { Loc {
@ -1988,8 +1999,10 @@ pub fn inline_calls(var_store: &mut VarStore, scope: &mut Scope, expr: Expr) ->
// Wrap the body in one LetNonRec for each argument, // Wrap the body in one LetNonRec for each argument,
// such that at the end we have all the arguments in // such that at the end we have all the arguments in
// scope with the values the caller provided. // scope with the values the caller provided.
for ((_param_var, _exhaustive_mark, loc_pattern), (expr_var, loc_expr)) in for (
params.iter().cloned().zip(args.into_iter()).rev() (_param_var, _exhaustive_mark, loc_pattern),
(expr_var, loc_expr),
) in params.iter().cloned().zip(args.into_iter()).rev()
{ {
// TODO get the correct vars into here. // TODO get the correct vars into here.
// Not sure if param_var should be involved. // Not sure if param_var should be involved.
@ -2020,7 +2033,8 @@ pub fn inline_calls(var_store: &mut VarStore, scope: &mut Scope, expr: Expr) ->
symbol symbol
); );
} }
}, }
}
_ => { _ => {
// For now, we only inline calls to builtins. Leave this alone! // For now, we only inline calls to builtins. Leave this alone!
Call( Call(
@ -2172,7 +2186,10 @@ fn desugar_str_segments(var_store: &mut VarStore, segments: Vec<StrSegment>) ->
Interpolation(loc_interpolated_expr) => loc_interpolated_expr, Interpolation(loc_interpolated_expr) => loc_interpolated_expr,
}; };
let fn_expr = Loc::at(Region::zero(), Expr::Var(Symbol::STR_CONCAT)); let fn_expr = Loc::at(
Region::zero(),
Expr::Var(Symbol::STR_CONCAT, var_store.fresh()),
);
let expr = Expr::Call( let expr = Expr::Call(
Box::new(( Box::new((
var_store.fresh(), var_store.fresh(),
@ -2531,7 +2548,7 @@ impl Declarations {
}) })
} }
pub fn expects(&self) -> VecMap<Region, Vec<(Symbol, Variable)>> { pub fn expects(&self) -> VecMap<Region, Vec<ExpectLookup>> {
let mut collector = ExpectCollector { let mut collector = ExpectCollector {
expects: VecMap::default(), expects: VecMap::default(),
}; };
@ -2615,16 +2632,34 @@ pub struct DestructureDef {
pub pattern_vars: VecMap<Symbol, Variable>, pub pattern_vars: VecMap<Symbol, Variable>,
} }
fn get_lookup_symbols(expr: &Expr, var_store: &mut VarStore) -> Vec<(Symbol, Variable)> { fn get_lookup_symbols(expr: &Expr) -> Vec<ExpectLookup> {
let mut stack: Vec<&Expr> = vec![expr]; let mut stack: Vec<&Expr> = vec![expr];
let mut symbols = Vec::new(); let mut lookups: Vec<ExpectLookup> = Vec::new();
while let Some(expr) = stack.pop() { while let Some(expr) = stack.pop() {
match expr { match expr {
Expr::Var(symbol) | Expr::Update { symbol, .. } | Expr::AbilityMember(symbol, _, _) => { Expr::Var(symbol, var)
| Expr::Update {
symbol,
record_var: var,
..
} => {
// Don't introduce duplicates, or make unused variables // Don't introduce duplicates, or make unused variables
if !symbols.iter().any(|(sym, _)| sym == symbol) { if !lookups.iter().any(|l| l.symbol == *symbol) {
symbols.push((*symbol, var_store.fresh())); lookups.push(ExpectLookup {
symbol: *symbol,
var: *var,
ability_info: None,
});
}
}
Expr::AbilityMember(symbol, spec_id, var) => {
if !lookups.iter().any(|l| l.symbol == *symbol) {
lookups.push(ExpectLookup {
symbol: *symbol,
var: *var,
ability_info: *spec_id,
});
} }
} }
Expr::List { loc_elems, .. } => { Expr::List { loc_elems, .. } => {
@ -2665,7 +2700,7 @@ fn get_lookup_symbols(expr: &Expr, var_store: &mut VarStore) -> Vec<(Symbol, Var
stack.reserve(1 + args.len()); stack.reserve(1 + args.len());
match &boxed_expr.1.value { match &boxed_expr.1.value {
Expr::Var(_) => { Expr::Var(_, _) => {
// do nothing // do nothing
} }
function_expr => { function_expr => {
@ -2721,7 +2756,7 @@ fn get_lookup_symbols(expr: &Expr, var_store: &mut VarStore) -> Vec<(Symbol, Var
} }
} }
symbols lookups
} }
/// Here we transform /// Here we transform
@ -2768,14 +2803,22 @@ fn toplevel_expect_to_inline_expect_help(mut loc_expr: Loc<Expr>, has_effects: b
loop { loop {
match loc_expr.value { match loc_expr.value {
Expr::LetNonRec(boxed_def, remainder) => { Expr::LetNonRec(boxed_def, remainder) => {
lookups_in_cond.extend(boxed_def.pattern_vars.iter().map(|(a, b)| (*a, *b))); lookups_in_cond.extend(boxed_def.pattern_vars.iter().map(|(a, b)| ExpectLookup {
symbol: *a,
var: *b,
ability_info: None,
}));
stack.push(StoredDef::NonRecursive(loc_expr.region, boxed_def)); stack.push(StoredDef::NonRecursive(loc_expr.region, boxed_def));
loc_expr = *remainder; loc_expr = *remainder;
} }
Expr::LetRec(defs, remainder, mark) => { Expr::LetRec(defs, remainder, mark) => {
for def in &defs { for def in &defs {
lookups_in_cond.extend(def.pattern_vars.iter().map(|(a, b)| (*a, *b))); lookups_in_cond.extend(def.pattern_vars.iter().map(|(a, b)| ExpectLookup {
symbol: *a,
var: *b,
ability_info: None,
}));
} }
stack.push(StoredDef::Recursive(loc_expr.region, defs, mark)); stack.push(StoredDef::Recursive(loc_expr.region, defs, mark));
@ -2818,7 +2861,7 @@ fn toplevel_expect_to_inline_expect_help(mut loc_expr: Loc<Expr>, has_effects: b
} }
struct ExpectCollector { struct ExpectCollector {
expects: VecMap<Region, Vec<(Symbol, Variable)>>, expects: VecMap<Region, Vec<ExpectLookup>>,
} }
impl crate::traverse::Visitor for ExpectCollector { impl crate::traverse::Visitor for ExpectCollector {

View file

@ -3,7 +3,7 @@ use crate::annotation::canonicalize_annotation;
use crate::def::{canonicalize_defs, Def}; use crate::def::{canonicalize_defs, Def};
use crate::effect_module::HostedGeneratedFunctions; use crate::effect_module::HostedGeneratedFunctions;
use crate::env::Env; use crate::env::Env;
use crate::expr::{ClosureData, Declarations, Expr, Output, PendingDerives}; use crate::expr::{ClosureData, Declarations, ExpectLookup, Expr, Output, PendingDerives};
use crate::pattern::{BindingsFromPattern, Pattern}; use crate::pattern::{BindingsFromPattern, Pattern};
use crate::scope::Scope; use crate::scope::Scope;
use bumpalo::Bump; use bumpalo::Bump;
@ -130,7 +130,7 @@ pub struct Module {
pub aliases: MutMap<Symbol, (bool, Alias)>, pub aliases: MutMap<Symbol, (bool, Alias)>,
pub rigid_variables: RigidVariables, pub rigid_variables: RigidVariables,
pub abilities_store: PendingAbilitiesStore, pub abilities_store: PendingAbilitiesStore,
pub loc_expects: VecMap<Region, Vec<(Symbol, Variable)>>, pub loc_expects: VecMap<Region, Vec<ExpectLookup>>,
} }
#[derive(Debug, Default)] #[derive(Debug, Default)]
@ -152,7 +152,7 @@ pub struct ModuleOutput {
pub symbols_from_requires: Vec<(Loc<Symbol>, Loc<Type>)>, pub symbols_from_requires: Vec<(Loc<Symbol>, Loc<Type>)>,
pub pending_derives: PendingDerives, pub pending_derives: PendingDerives,
pub scope: Scope, pub scope: Scope,
pub loc_expects: VecMap<Region, Vec<(Symbol, Variable)>>, pub loc_expects: VecMap<Region, Vec<ExpectLookup>>,
} }
fn validate_generate_with<'a>( fn validate_generate_with<'a>(
@ -1040,7 +1040,7 @@ fn fix_values_captured_in_closure_expr(
| Float(..) | Float(..)
| Str(_) | Str(_)
| SingleQuote(..) | SingleQuote(..)
| Var(_) | Var(..)
| AbilityMember(..) | AbilityMember(..)
| EmptyRecord | EmptyRecord
| TypedHole { .. } | TypedHole { .. }

View file

@ -13,8 +13,8 @@ use roc_can::expected::Expected::{self, *};
use roc_can::expected::PExpected; use roc_can::expected::PExpected;
use roc_can::expr::Expr::{self, *}; use roc_can::expr::Expr::{self, *};
use roc_can::expr::{ use roc_can::expr::{
AccessorData, AnnotatedMark, ClosureData, DeclarationTag, Declarations, DestructureDef, Field, AccessorData, AnnotatedMark, ClosureData, DeclarationTag, Declarations, DestructureDef,
FunctionDef, OpaqueWrapFunctionData, WhenBranch, ExpectLookup, Field, FunctionDef, OpaqueWrapFunctionData, WhenBranch,
}; };
use roc_can::pattern::Pattern; use roc_can::pattern::Pattern;
use roc_can::traverse::symbols_introduced_from_pattern; use roc_can::traverse::symbols_introduced_from_pattern;
@ -351,7 +351,7 @@ pub fn constrain_expr(
let (fn_var, loc_fn, closure_var, ret_var) = &**boxed; let (fn_var, loc_fn, closure_var, ret_var) = &**boxed;
// The expression that evaluates to the function being called, e.g. `foo` in // The expression that evaluates to the function being called, e.g. `foo` in
// (foo) bar baz // (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) Some(symbol)
} else { } else {
None None
@ -425,9 +425,13 @@ pub fn constrain_expr(
let and_constraint = constraints.and_constraint(and_cons); let and_constraint = constraints.and_constraint(and_cons);
constraints.exists(vars, and_constraint) constraints.exists(vars, and_constraint)
} }
Var(symbol) => { Var(symbol, variable) => {
// make lookup constraint to lookup this symbol's type in the environment // Save the expectation in the variable, then lookup the symbol's type in the environment
constraints.lookup(*symbol, expected, region) let store_expected =
constraints.store(expected.get_type_ref().clone(), *variable, file!(), line!());
let lookup_constr =
constraints.lookup(*symbol, expected.replace(Type::Variable(*variable)), region);
constraints.and_constraint([store_expected, lookup_constr])
} }
&AbilityMember(symbol, specialization_id, specialization_var) => { &AbilityMember(symbol, specialization_id, specialization_var) => {
// Save the expectation in the `specialization_var` so we know what to specialize, then // Save the expectation in the `specialization_var` so we know what to specialize, then
@ -515,7 +519,12 @@ pub fn constrain_expr(
let mut vars = Vec::with_capacity(lookups_in_cond.len()); let mut vars = Vec::with_capacity(lookups_in_cond.len());
for (symbol, var) in lookups_in_cond.iter() { for ExpectLookup {
symbol,
var,
ability_info: _,
} in lookups_in_cond.iter()
{
vars.push(*var); vars.push(*var);
all_constraints.push(constraints.lookup( all_constraints.push(constraints.lookup(
@ -562,7 +571,12 @@ pub fn constrain_expr(
let mut vars = Vec::with_capacity(lookups_in_cond.len()); let mut vars = Vec::with_capacity(lookups_in_cond.len());
for (symbol, var) in lookups_in_cond.iter() { for ExpectLookup {
symbol,
var,
ability_info: _,
} in lookups_in_cond.iter()
{
vars.push(*var); vars.push(*var);
all_constraints.push(constraints.lookup( all_constraints.push(constraints.lookup(

View file

@ -357,7 +357,7 @@ fn decoder_record_step_field(
name: "Ok".into(), name: "Ok".into(),
arguments: vec![( arguments: vec![(
field_var, field_var,
Loc::at_zero(Expr::Var(ok_val_symbol)), Loc::at_zero(Expr::Var(ok_val_symbol, field_var)),
)], )],
})), })),
}, },
@ -417,7 +417,7 @@ fn decoder_record_step_field(
name: "Err".into(), name: "Err".into(),
arguments: vec![( arguments: vec![(
decode_err_var, decode_err_var,
Loc::at_zero(Expr::Var(err_val_symbol)), Loc::at_zero(Expr::Var(err_val_symbol, decode_err_var)),
)], )],
}), }),
guard: None, guard: None,
@ -433,7 +433,7 @@ fn decoder_record_step_field(
record_var: rec_var, record_var: rec_var,
ext_var: env.new_ext_var(ExtensionKind::Record), ext_var: env.new_ext_var(ExtensionKind::Record),
field_var: rec_dot_result, field_var: rec_dot_result,
loc_expr: Box::new(Loc::at_zero(Expr::Var(rec_symbol))), loc_expr: Box::new(Loc::at_zero(Expr::Var(rec_symbol, rec_var))),
field: "result".into(), field: "result".into(),
})), })),
cond_var: rec_dot_result, cond_var: rec_dot_result,
@ -462,7 +462,7 @@ fn decoder_record_step_field(
record_var: rec_var, record_var: rec_var,
ext_var: env.new_ext_var(ExtensionKind::Record), ext_var: env.new_ext_var(ExtensionKind::Record),
field_var: Variable::LIST_U8, field_var: Variable::LIST_U8,
loc_expr: Box::new(Loc::at_zero(Expr::Var(rec_symbol))), loc_expr: Box::new(Loc::at_zero(Expr::Var(rec_symbol, rec_var))),
field: "rest".into(), field: "rest".into(),
})), })),
}, },
@ -499,12 +499,15 @@ fn decoder_record_step_field(
let condition_expr = Expr::Call( let condition_expr = Expr::Call(
Box::new(( Box::new((
this_decode_with_var, this_decode_with_var,
Loc::at_zero(Expr::Var(Symbol::DECODE_DECODE_WITH)), Loc::at_zero(Expr::Var(Symbol::DECODE_DECODE_WITH, this_decode_with_var)),
lambda_set_var, lambda_set_var,
rec_var, rec_var,
)), )),
vec![ vec![
(Variable::LIST_U8, Loc::at_zero(Expr::Var(bytes_arg_symbol))), (
Variable::LIST_U8,
Loc::at_zero(Expr::Var(bytes_arg_symbol, Variable::LIST_U8)),
),
( (
decoder_var, decoder_var,
Loc::at_zero(Expr::AbilityMember( Loc::at_zero(Expr::AbilityMember(
@ -513,7 +516,10 @@ fn decoder_record_step_field(
decoder_var, decoder_var,
)), )),
), ),
(fmt_arg_var, Loc::at_zero(Expr::Var(fmt_arg_symbol))), (
fmt_arg_var,
Loc::at_zero(Expr::Var(fmt_arg_symbol, fmt_arg_var)),
),
], ],
CalledVia::Space, CalledVia::Space,
); );
@ -600,7 +606,7 @@ fn decoder_record_step_field(
Expr::Call( Expr::Call(
Box::new(( Box::new((
this_decode_custom_var, this_decode_custom_var,
Loc::at_zero(Expr::Var(Symbol::DECODE_CUSTOM)), Loc::at_zero(Expr::Var(Symbol::DECODE_CUSTOM, this_decode_custom_var)),
decode_custom_closure_var, decode_custom_closure_var,
decode_custom_ret_var, decode_custom_ret_var,
)), )),
@ -676,7 +682,7 @@ fn decoder_record_step_field(
// when field is // when field is
let body = Expr::When { let body = Expr::When {
loc_cond: Box::new(Loc::at_zero(Expr::Var(field_arg_symbol))), loc_cond: Box::new(Loc::at_zero(Expr::Var(field_arg_symbol, Variable::STR))),
cond_var: Variable::STR, cond_var: Variable::STR,
expr_var: keep_or_skip_var, expr_var: keep_or_skip_var,
region: Region::zero(), region: Region::zero(),
@ -764,7 +770,7 @@ fn decoder_record_finalizer(
pattern_symbols.push(symbol); pattern_symbols.push(symbol);
let field_expr = Expr::Var(symbol); let field_expr = Expr::Var(symbol, field_var);
let field = Field { let field = Field {
var: field_var, var: field_var,
region: Region::zero(), region: Region::zero(),
@ -827,7 +833,7 @@ fn decoder_record_finalizer(
record_var: state_record_var, record_var: state_record_var,
ext_var: env.new_ext_var(ExtensionKind::Record), ext_var: env.new_ext_var(ExtensionKind::Record),
field_var: result_field_var, field_var: result_field_var,
loc_expr: Box::new(Loc::at_zero(Expr::Var(state_arg_symbol))), loc_expr: Box::new(Loc::at_zero(Expr::Var(state_arg_symbol, state_record_var))),
field: field_name.clone(), field: field_name.clone(),
}; };
@ -1126,7 +1132,7 @@ fn wrap_in_decode_custom_decode_with(
// ~ bytes, Decoder (List elem) fmt, fmt -> DecoderResult (List val) // ~ bytes, Decoder (List elem) fmt, fmt -> DecoderResult (List val)
env.unify(decode_with_type, this_decode_with_fn_var); env.unify(decode_with_type, this_decode_with_fn_var);
let decode_with_var = Var(Symbol::DECODE_DECODE_WITH); let decode_with_var = Var(Symbol::DECODE_DECODE_WITH, this_decode_with_fn_var);
let decode_with_fn = Box::new(( let decode_with_fn = Box::new((
this_decode_with_fn_var, this_decode_with_fn_var,
Loc::at_zero(decode_with_var), Loc::at_zero(decode_with_var),
@ -1137,9 +1143,9 @@ fn wrap_in_decode_custom_decode_with(
decode_with_fn, decode_with_fn,
vec![ vec![
// bytes inner_decoder fmt // bytes inner_decoder fmt
(bytes_var, Loc::at_zero(Var(bytes_sym))), (bytes_var, Loc::at_zero(Var(bytes_sym, bytes_var))),
(inner_decoder_var, Loc::at_zero(inner_decoder)), (inner_decoder_var, Loc::at_zero(inner_decoder)),
(fmt_var, Loc::at_zero(Var(fmt_sym))), (fmt_var, Loc::at_zero(Var(fmt_sym, fmt_var))),
], ],
CalledVia::Space, CalledVia::Space,
); );
@ -1231,7 +1237,7 @@ fn wrap_in_decode_custom_decode_with(
// ~ (List U8, fmt -> DecodeResult (List elem)) -> Decoder (List elem) fmt // ~ (List U8, fmt -> DecodeResult (List elem)) -> Decoder (List elem) fmt
env.unify(decode_custom_type, this_decode_custom_fn_var); env.unify(decode_custom_type, this_decode_custom_fn_var);
let decode_custom_var = Var(Symbol::DECODE_CUSTOM); let decode_custom_var = Var(Symbol::DECODE_CUSTOM, this_decode_custom_fn_var);
let decode_custom_fn = Box::new(( let decode_custom_fn = Box::new((
this_decode_custom_fn_var, this_decode_custom_fn_var,
Loc::at_zero(decode_custom_var), Loc::at_zero(decode_custom_var),

View file

@ -134,7 +134,7 @@ fn to_encoder_list(env: &mut Env<'_>, fn_name: Symbol) -> (Expr, Variable) {
// toEncoder elem // toEncoder elem
let to_encoder_call = Call( let to_encoder_call = Call(
to_encoder_fn, to_encoder_fn,
vec![(elem_var, Loc::at_zero(Var(elem_sym)))], vec![(elem_var, Loc::at_zero(Var(elem_sym, elem_var)))],
CalledVia::Space, CalledVia::Space,
); );
@ -217,7 +217,7 @@ fn to_encoder_list(env: &mut Env<'_>, fn_name: Symbol) -> (Expr, Variable) {
let encode_list_call = Call( let encode_list_call = Call(
encode_list_fn, encode_list_fn,
vec![ vec![
(list_var, Loc::at_zero(Var(lst_sym))), (list_var, Loc::at_zero(Var(lst_sym, list_var))),
(to_elem_encoder_fn_var, Loc::at_zero(to_elem_encoder)), (to_elem_encoder_fn_var, Loc::at_zero(to_elem_encoder)),
], ],
CalledVia::Space, CalledVia::Space,
@ -314,7 +314,10 @@ fn to_encoder_record(
record_var, record_var,
ext_var: env.subs.fresh_unnamed_flex_var(), ext_var: env.subs.fresh_unnamed_flex_var(),
field_var, field_var,
loc_expr: Box::new(Loc::at_zero(Var(rcd_sym))), loc_expr: Box::new(Loc::at_zero(Var(
rcd_sym,
env.subs.fresh_unnamed_flex_var(),
))),
field: field_name, field: field_name,
}; };
@ -572,7 +575,7 @@ fn to_encoder_tag_union(
// toEncoder rcd.a // toEncoder rcd.a
let to_encoder_call = Call( let to_encoder_call = Call(
to_encoder_fn, to_encoder_fn,
vec![(sym_var, Loc::at_zero(Var(sym)))], vec![(sym_var, Loc::at_zero(Var(sym, sym_var)))],
CalledVia::Space, CalledVia::Space,
); );
@ -662,7 +665,7 @@ fn to_encoder_tag_union(
// A v1 v2 -> Encode.tag "A" [ Encode.toEncoder v1, Encode.toEncoder v2 ] // A v1 v2 -> Encode.tag "A" [ Encode.toEncoder v1, Encode.toEncoder v2 ]
// B v3 -> Encode.tag "B" [ Encode.toEncoder v3 ] // B v3 -> Encode.tag "B" [ Encode.toEncoder v3 ]
let when_branches = When { let when_branches = When {
loc_cond: Box::new(Loc::at_zero(Var(tag_sym))), loc_cond: Box::new(Loc::at_zero(Var(tag_sym, tag_union_var))),
cond_var: tag_union_var, cond_var: tag_union_var,
expr_var: whole_tag_encoders_var, expr_var: whole_tag_encoders_var,
region: Region::zero(), region: Region::zero(),
@ -778,7 +781,7 @@ fn wrap_in_encode_custom(
// Encode.appendWith : List U8, encoder_var, fmt -[appendWith]-> List U8 | fmt has EncoderFormatting // Encode.appendWith : List U8, encoder_var, fmt -[appendWith]-> List U8 | fmt has EncoderFormatting
let append_with_fn = Box::new(( let append_with_fn = Box::new((
this_append_with_fn_var, this_append_with_fn_var,
Loc::at_zero(Var(Symbol::ENCODE_APPEND_WITH)), Loc::at_zero(Var(Symbol::ENCODE_APPEND_WITH, this_append_with_fn_var)),
this_append_with_clos_var, this_append_with_clos_var,
Variable::LIST_U8, Variable::LIST_U8,
)); ));
@ -788,11 +791,11 @@ fn wrap_in_encode_custom(
append_with_fn, append_with_fn,
vec![ vec![
// (bytes_var, bytes) // (bytes_var, bytes)
(bytes_var, Loc::at_zero(Var(bytes_sym))), (bytes_var, Loc::at_zero(Var(bytes_sym, bytes_var))),
// (encoder_var, encoder) // (encoder_var, encoder)
(encoder_var, Loc::at_zero(encoder)), (encoder_var, Loc::at_zero(encoder)),
// (fmt, fmt_var) // (fmt, fmt_var)
(fmt_var, Loc::at_zero(Var(fmt_sym))), (fmt_var, Loc::at_zero(Var(fmt_sym, fmt_var))),
], ],
CalledVia::Space, CalledVia::Space,
); );
@ -869,7 +872,7 @@ fn wrap_in_encode_custom(
// Encode.custom : (List U8, fmt -> List U8) -> Encoder fmt | fmt has EncoderFormatting // Encode.custom : (List U8, fmt -> List U8) -> Encoder fmt | fmt has EncoderFormatting
let custom_fn = Box::new(( let custom_fn = Box::new((
this_custom_fn_var, this_custom_fn_var,
Loc::at_zero(Var(Symbol::ENCODE_CUSTOM)), Loc::at_zero(Var(Symbol::ENCODE_CUSTOM, this_custom_fn_var)),
this_custom_clos_var, // -[clos]-> this_custom_clos_var, // -[clos]->
this_custom_encoder_var, // t' ~ Encoder fmt this_custom_encoder_var, // t' ~ Encoder fmt
)); ));

View file

@ -90,7 +90,7 @@ fn hash_record(env: &mut Env<'_>, fn_name: Symbol, fields: Vec<Lowercase>) -> (V
let hasher_var = synth_var(env.subs, Content::FlexAbleVar(None, Symbol::HASH_HASHER)); let hasher_var = synth_var(env.subs, Content::FlexAbleVar(None, Symbol::HASH_HASHER));
let (body_var, body) = record_fields.iter_all().fold( let (body_var, body) = record_fields.iter_all().fold(
(hasher_var, Expr::Var(hasher_sym)), (hasher_var, Expr::Var(hasher_sym, hasher_var)),
|total_hasher, (field_name, field_var, _)| { |total_hasher, (field_name, field_var, _)| {
let field_name = env.subs[field_name].clone(); let field_name = env.subs[field_name].clone();
let field_var = env.subs[field_var]; let field_var = env.subs[field_var];
@ -99,7 +99,10 @@ fn hash_record(env: &mut Env<'_>, fn_name: Symbol, fields: Vec<Lowercase>) -> (V
record_var, record_var,
field_var, field_var,
ext_var: env.subs.fresh_unnamed_flex_var(), ext_var: env.subs.fresh_unnamed_flex_var(),
loc_expr: Box::new(Loc::at_zero(Expr::Var(rcd_sym))), loc_expr: Box::new(Loc::at_zero(Expr::Var(
rcd_sym,
env.subs.fresh_unnamed_flex_var(),
))),
field: field_name, field: field_name,
}; };
@ -215,7 +218,7 @@ fn hash_tag_union(
let (discr_hasher_var, disc_hasher_expr) = call_hash_ability_member( let (discr_hasher_var, disc_hasher_expr) = call_hash_ability_member(
env, env,
hash_discr_member, hash_discr_member,
(hasher_var, Expr::Var(hasher_sym)), (hasher_var, Expr::Var(hasher_sym, hasher_var)),
( (
discr_num_var, discr_num_var,
Expr::Int( Expr::Int(
@ -232,7 +235,11 @@ fn hash_tag_union(
let (body_var, body_expr) = (payload_vars.into_iter()).zip(payload_syms).fold( let (body_var, body_expr) = (payload_vars.into_iter()).zip(payload_syms).fold(
(discr_hasher_var, disc_hasher_expr), (discr_hasher_var, disc_hasher_expr),
|total_hasher, (payload_var, payload_sym)| { |total_hasher, (payload_var, payload_sym)| {
call_hash_hash(env, total_hasher, (payload_var, Expr::Var(payload_sym))) call_hash_hash(
env,
total_hasher,
(payload_var, Expr::Var(payload_sym, payload_var)),
)
}, },
); );
@ -251,7 +258,7 @@ fn hash_tag_union(
// ... // ...
let when_var = whole_hasher_var; let when_var = whole_hasher_var;
let when_expr = Expr::When { let when_expr = Expr::When {
loc_cond: Box::new(Loc::at_zero(Expr::Var(union_sym))), loc_cond: Box::new(Loc::at_zero(Expr::Var(union_sym, union_var))),
cond_var: union_var, cond_var: union_var,
expr_var: when_var, expr_var: when_var,
region: Region::zero(), region: Region::zero(),
@ -338,9 +345,13 @@ fn hash_newtype_tag_union(
// Fold up `Hash.hash (... (Hash.hash discrHasher x11) ...) x1n` // Fold up `Hash.hash (... (Hash.hash discrHasher x11) ...) x1n`
let (body_var, body_expr) = (payload_vars.into_iter()).zip(payload_syms).fold( let (body_var, body_expr) = (payload_vars.into_iter()).zip(payload_syms).fold(
(hasher_var, Expr::Var(hasher_sym)), (hasher_var, Expr::Var(hasher_sym, hasher_var)),
|total_hasher, (payload_var, payload_sym)| { |total_hasher, (payload_var, payload_sym)| {
call_hash_hash(env, total_hasher, (payload_var, Expr::Var(payload_sym))) call_hash_hash(
env,
total_hasher,
(payload_var, Expr::Var(payload_sym, payload_var)),
)
}, },
); );

View file

@ -7,8 +7,8 @@ use parking_lot::Mutex;
use roc_builtins::roc::module_source; use roc_builtins::roc::module_source;
use roc_can::abilities::{AbilitiesStore, PendingAbilitiesStore, ResolvedImpl}; use roc_can::abilities::{AbilitiesStore, PendingAbilitiesStore, ResolvedImpl};
use roc_can::constraint::{Constraint as ConstraintSoa, Constraints}; use roc_can::constraint::{Constraint as ConstraintSoa, Constraints};
use roc_can::expr::Declarations;
use roc_can::expr::PendingDerives; use roc_can::expr::PendingDerives;
use roc_can::expr::{Declarations, ExpectLookup};
use roc_can::module::{ use roc_can::module::{
canonicalize_module_defs, ExposedByModule, ExposedForModule, ExposedModuleTypes, Module, canonicalize_module_defs, ExposedByModule, ExposedForModule, ExposedModuleTypes, Module,
ResolvedImplementations, TypeState, ResolvedImplementations, TypeState,
@ -719,7 +719,7 @@ pub enum EntryPoint<'a> {
pub struct Expectations { pub struct Expectations {
pub subs: roc_types::subs::Subs, pub subs: roc_types::subs::Subs,
pub path: PathBuf, pub path: PathBuf,
pub expectations: VecMap<Region, Vec<(Symbol, Variable)>>, pub expectations: VecMap<Region, Vec<ExpectLookup>>,
pub ident_ids: IdentIds, pub ident_ids: IdentIds,
} }
@ -763,7 +763,7 @@ struct ParsedModule<'a> {
header_for: HeaderFor<'a>, header_for: HeaderFor<'a>,
} }
type LocExpects = VecMap<Region, Vec<(Symbol, Variable)>>; type LocExpects = VecMap<Region, Vec<ExpectLookup>>;
/// A message sent out _from_ a worker thread, /// A message sent out _from_ a worker thread,
/// representing a result of work done, or a request for further work /// representing a result of work done, or a request for further work

View file

@ -9,7 +9,7 @@ use bumpalo::collections::{CollectIn, Vec};
use bumpalo::Bump; use bumpalo::Bump;
use roc_builtins::bitcode::{FloatWidth, IntWidth}; use roc_builtins::bitcode::{FloatWidth, IntWidth};
use roc_can::abilities::SpecializationId; use roc_can::abilities::SpecializationId;
use roc_can::expr::{AnnotatedMark, ClosureData, IntValue}; use roc_can::expr::{AnnotatedMark, ClosureData, ExpectLookup, IntValue};
use roc_can::module::ExposedByModule; use roc_can::module::ExposedByModule;
use roc_collections::all::{default_hasher, BumpMap, BumpMapDefault, MutMap}; use roc_collections::all::{default_hasher, BumpMap, BumpMapDefault, MutMap};
use roc_collections::VecMap; use roc_collections::VecMap;
@ -2376,7 +2376,7 @@ fn from_can_let<'a>(
lower_rest!(variable, cont.value) lower_rest!(variable, cont.value)
} }
Var(original) | AbilityMember(original, _, _) => { Var(original, _) | AbilityMember(original, _, _) => {
// a variable is aliased, e.g. // a variable is aliased, e.g.
// //
// foo = bar // foo = bar
@ -2605,7 +2605,7 @@ fn from_can_let<'a>(
} }
match def.loc_expr.value { match def.loc_expr.value {
roc_can::expr::Expr::Var(outer_symbol) if !procs.is_module_thunk(outer_symbol) => { roc_can::expr::Expr::Var(outer_symbol, _) if !procs.is_module_thunk(outer_symbol) => {
store_pattern(env, procs, layout_cache, &mono_pattern, outer_symbol, stmt) store_pattern(env, procs, layout_cache, &mono_pattern, outer_symbol, stmt)
} }
_ => { _ => {
@ -2747,7 +2747,7 @@ fn pattern_to_when<'a>(
cond_var: pattern_var, cond_var: pattern_var,
expr_var: body_var, expr_var: body_var,
region: Region::zero(), region: Region::zero(),
loc_cond: Box::new(Loc::at_zero(Var(symbol))), loc_cond: Box::new(Loc::at_zero(Var(symbol, pattern_var))),
branches: vec![WhenBranch { branches: vec![WhenBranch {
patterns: vec![WhenBranchPattern { patterns: vec![WhenBranchPattern {
pattern, pattern,
@ -4074,11 +4074,14 @@ pub fn with_hole<'a>(
hole, hole,
) )
} }
Var(mut symbol) => { Var(mut symbol, _) => {
// If this symbol is a raw value, find the real name we gave to its specialized usage. // If this symbol is a raw value, find the real name we gave to its specialized usage.
if let ReuseSymbol::Value(_symbol) = if let ReuseSymbol::Value(_symbol) = can_reuse_symbol(
can_reuse_symbol(env, procs, &roc_can::expr::Expr::Var(symbol), variable) env,
{ procs,
&roc_can::expr::Expr::Var(symbol, variable),
variable,
) {
let real_symbol = let real_symbol =
procs procs
.symbol_specializations .symbol_specializations
@ -5046,7 +5049,7 @@ pub fn with_hole<'a>(
}; };
match loc_expr.value { match loc_expr.value {
roc_can::expr::Expr::Var(proc_name) if is_known(proc_name) => { roc_can::expr::Expr::Var(proc_name, _) if is_known(proc_name) => {
// a call by a known name // a call by a known name
call_by_name( call_by_name(
env, env,
@ -6010,7 +6013,7 @@ fn tag_union_to_function<'a>(
let loc_pattern = Loc::at_zero(roc_can::pattern::Pattern::Identifier(arg_symbol)); let loc_pattern = Loc::at_zero(roc_can::pattern::Pattern::Identifier(arg_symbol));
let loc_expr = Loc::at_zero(roc_can::expr::Expr::Var(arg_symbol)); let loc_expr = Loc::at_zero(roc_can::expr::Expr::Var(arg_symbol, arg_var));
loc_pattern_args.push((arg_var, AnnotatedMark::known_exhaustive(), loc_pattern)); loc_pattern_args.push((arg_var, AnnotatedMark::known_exhaustive(), loc_pattern));
loc_expr_args.push((arg_var, loc_expr)); loc_expr_args.push((arg_var, loc_expr));
@ -6347,11 +6350,25 @@ pub fn from_can<'a>(
let rest = from_can(env, variable, loc_continuation.value, procs, layout_cache); let rest = from_can(env, variable, loc_continuation.value, procs, layout_cache);
let cond_symbol = env.unique_symbol(); let cond_symbol = env.unique_symbol();
let lookups = Vec::from_iter_in(lookups_in_cond.iter().map(|t| t.0), env.arena); let mut lookups = Vec::with_capacity_in(lookups_in_cond.len(), env.arena);
let mut layouts = Vec::with_capacity_in(lookups_in_cond.len(), env.arena); let mut layouts = Vec::with_capacity_in(lookups_in_cond.len(), env.arena);
for (_, var) in lookups_in_cond { for ExpectLookup {
symbol,
var,
ability_info,
} in lookups_in_cond
{
let symbol = match ability_info {
Some(specialization_id) => late_resolve_ability_specialization(
env,
symbol,
Some(specialization_id),
var,
),
None => symbol,
};
lookups.push(symbol);
let res_layout = layout_cache.from_var(env.arena, var, env.subs); let res_layout = layout_cache.from_var(env.arena, var, env.subs);
let layout = return_on_layout_error!(env, res_layout, "Expect"); let layout = return_on_layout_error!(env, res_layout, "Expect");
layouts.push(layout); layouts.push(layout);
@ -6386,11 +6403,25 @@ pub fn from_can<'a>(
let rest = from_can(env, variable, loc_continuation.value, procs, layout_cache); let rest = from_can(env, variable, loc_continuation.value, procs, layout_cache);
let cond_symbol = env.unique_symbol(); let cond_symbol = env.unique_symbol();
let lookups = Vec::from_iter_in(lookups_in_cond.iter().map(|t| t.0), env.arena); let mut lookups = Vec::with_capacity_in(lookups_in_cond.len(), env.arena);
let mut layouts = Vec::with_capacity_in(lookups_in_cond.len(), env.arena); let mut layouts = Vec::with_capacity_in(lookups_in_cond.len(), env.arena);
for (_, var) in lookups_in_cond { for ExpectLookup {
symbol,
var,
ability_info,
} in lookups_in_cond
{
let symbol = match ability_info {
Some(specialization_id) => late_resolve_ability_specialization(
env,
symbol,
Some(specialization_id),
var,
),
None => symbol,
};
lookups.push(symbol);
let res_layout = layout_cache.from_var(env.arena, var, env.subs); let res_layout = layout_cache.from_var(env.arena, var, env.subs);
let layout = return_on_layout_error!(env, res_layout, "Expect"); let layout = return_on_layout_error!(env, res_layout, "Expect");
layouts.push(layout); layouts.push(layout);
@ -7513,7 +7544,7 @@ fn can_reuse_symbol<'a>(
AbilityMember(member, specialization_id, _) => { AbilityMember(member, specialization_id, _) => {
late_resolve_ability_specialization(env, *member, *specialization_id, expr_var) late_resolve_ability_specialization(env, *member, *specialization_id, expr_var)
} }
Var(symbol) => *symbol, Var(symbol, _) => *symbol,
_ => return NotASymbol, _ => return NotASymbol,
}; };

View file

@ -87,7 +87,7 @@ fn expr<'a>(c: &Ctx, p: EPrec, f: &'a Arena<'a>, e: &'a Expr) -> DocBuilder<'a,
.append("]") .append("]")
.group(), .group(),
), ),
Var(sym) | AbilityMember(sym, _, _) => f.text(format!( Var(sym, _) | AbilityMember(sym, _, _) => f.text(format!(
"{}.{}", "{}.{}",
sym.module_string(c.interns), sym.module_string(c.interns),
sym.as_str(c.interns), sym.as_str(c.interns),

View file

@ -10,6 +10,7 @@ bumpalo = {version = "3.11.0", features = ["collections"]}
target-lexicon = "0.12.2" target-lexicon = "0.12.2"
roc_builtins = {path = "../compiler/builtins"} roc_builtins = {path = "../compiler/builtins"}
roc_can = {path = "../compiler/can"}
roc_collections = {path = "../compiler/collections"} roc_collections = {path = "../compiler/collections"}
roc_intern = {path = "../compiler/intern"} roc_intern = {path = "../compiler/intern"}
roc_load = {path = "../compiler/load"} roc_load = {path = "../compiler/load"}

View file

@ -4,6 +4,7 @@ use bumpalo::collections::Vec as BumpVec;
use bumpalo::Bump; use bumpalo::Bump;
use inkwell::context::Context; use inkwell::context::Context;
use roc_build::link::llvm_module_to_dylib; use roc_build::link::llvm_module_to_dylib;
use roc_can::expr::ExpectLookup;
use roc_collections::{MutSet, VecMap}; use roc_collections::{MutSet, VecMap};
use roc_gen_llvm::{ use roc_gen_llvm::{
llvm::{build::LlvmBackendMode, externs::add_default_roc_externs}, llvm::{build::LlvmBackendMode, externs::add_default_roc_externs},
@ -389,7 +390,16 @@ fn render_expect_failure<'a>(
}; };
let subs = arena.alloc(&mut data.subs); let subs = arena.alloc(&mut data.subs);
let (symbols, variables): (Vec<_>, Vec<_>) = current.iter().map(|(a, b)| (*a, *b)).unzip(); let (symbols, variables): (Vec<_>, Vec<_>) = current
.iter()
.map(
|ExpectLookup {
symbol,
var,
ability_info: _,
}| (*symbol, *var),
)
.unzip();
let (offset, expressions) = crate::get_values( let (offset, expressions) = crate::get_values(
target_info, target_info,