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",
"roc_build",
"roc_builtins",
"roc_can",
"roc_collections",
"roc_gen_llvm",
"roc_intern",

View file

@ -247,7 +247,7 @@ fn lowlevel_1(symbol: Symbol, op: LowLevel, var_store: &mut VarStore) -> Def {
let body = RunLowLevel {
op,
args: vec![(arg1_var, Var(Symbol::ARG_1))],
args: vec![(arg1_var, Var(Symbol::ARG_1, arg1_var))],
ret_var,
};
@ -268,8 +268,8 @@ fn lowlevel_2(symbol: Symbol, op: LowLevel, var_store: &mut VarStore) -> Def {
let body = RunLowLevel {
op,
args: vec![
(arg1_var, Var(Symbol::ARG_1)),
(arg2_var, Var(Symbol::ARG_2)),
(arg1_var, Var(Symbol::ARG_1, arg1_var)),
(arg2_var, Var(Symbol::ARG_2, arg2_var)),
],
ret_var,
};
@ -292,9 +292,9 @@ fn lowlevel_3(symbol: Symbol, op: LowLevel, var_store: &mut VarStore) -> Def {
let body = RunLowLevel {
op,
args: vec![
(arg1_var, Var(Symbol::ARG_1)),
(arg2_var, Var(Symbol::ARG_2)),
(arg3_var, Var(Symbol::ARG_3)),
(arg1_var, Var(Symbol::ARG_1, arg1_var)),
(arg2_var, Var(Symbol::ARG_2, arg2_var)),
(arg3_var, Var(Symbol::ARG_3, arg3_var)),
],
ret_var,
};
@ -322,10 +322,10 @@ fn lowlevel_4(symbol: Symbol, op: LowLevel, var_store: &mut VarStore) -> Def {
let body = RunLowLevel {
op,
args: vec![
(arg1_var, Var(Symbol::ARG_1)),
(arg2_var, Var(Symbol::ARG_2)),
(arg3_var, Var(Symbol::ARG_3)),
(arg4_var, Var(Symbol::ARG_4)),
(arg1_var, Var(Symbol::ARG_1, arg1_var)),
(arg2_var, Var(Symbol::ARG_2, arg2_var)),
(arg3_var, Var(Symbol::ARG_3, arg3_var)),
(arg4_var, Var(Symbol::ARG_4, arg4_var)),
],
ret_var,
};
@ -355,11 +355,11 @@ fn lowlevel_5(symbol: Symbol, op: LowLevel, var_store: &mut VarStore) -> Def {
let body = RunLowLevel {
op,
args: vec![
(arg1_var, Var(Symbol::ARG_1)),
(arg2_var, Var(Symbol::ARG_2)),
(arg3_var, Var(Symbol::ARG_3)),
(arg4_var, Var(Symbol::ARG_4)),
(arg5_var, Var(Symbol::ARG_5)),
(arg1_var, Var(Symbol::ARG_1, arg1_var)),
(arg2_var, Var(Symbol::ARG_2, arg2_var)),
(arg3_var, Var(Symbol::ARG_3, arg3_var)),
(arg4_var, Var(Symbol::ARG_4, arg4_var)),
(arg5_var, Var(Symbol::ARG_5, arg5_var)),
],
ret_var,
};
@ -486,7 +486,7 @@ fn to_num_checked(symbol: Symbol, var_store: &mut VarStore, lowlevel: LowLevel)
ext_var: var_store.fresh(),
field: "b".into(),
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!
@ -509,7 +509,7 @@ fn to_num_checked(symbol: Symbol, var_store: &mut VarStore, lowlevel: LowLevel)
ext_var: var_store.fresh(),
field: "a".into(),
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,
@ -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_expr: no_region(RunLowLevel {
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,
}),
expr_var: record_var,
@ -549,7 +549,7 @@ fn to_num_is_zero(symbol: Symbol, var_store: &mut VarStore) -> Def {
let body = Expr::RunLowLevel {
op: LowLevel::Eq,
args: vec![
(num_var, Var(Symbol::ARG_1)),
(num_var, Var(Symbol::ARG_1, num_var)),
(
num_var,
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),
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, sub!(specialization_var))
}
When {
loc_cond,

View file

@ -124,14 +124,15 @@ fn build_effect_always(
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 {
function_type: var_store.fresh(),
closure_type: var_store.fresh(),
return_type: var_store.fresh(),
name: inner_closure_symbol,
captured_symbols: vec![(value_symbol, var_store.fresh())],
captured_symbols: vec![(value_symbol, value_var)],
recursive: Recursive::NotRecursive,
arguments,
loc_body: Box::new(Loc::at_zero(body)),
@ -231,20 +232,22 @@ fn build_effect_map(
.introduce("effect_map_thunk".into(), Region::zero())
.unwrap()
};
let thunk_var = var_store.fresh();
let mapper_symbol = {
scope
.introduce("effect_map_mapper".into(), Region::zero())
.unwrap()
};
let mapper_var = var_store.fresh();
let map_symbol = { scope.introduce("map".into(), Region::zero()).unwrap() };
// `thunk {}`
let force_thunk_call = {
let boxed = (
var_store.fresh(),
Loc::at_zero(Expr::Var(thunk_symbol)),
thunk_var,
Loc::at_zero(Expr::Var(thunk_symbol, thunk_var)),
var_store.fresh(),
var_store.fresh(),
);
@ -256,8 +259,8 @@ fn build_effect_map(
// `toEffect (thunk {})`
let mapper_call = {
let boxed = (
var_store.fresh(),
Loc::at_zero(Expr::Var(mapper_symbol)),
mapper_var,
Loc::at_zero(Expr::Var(mapper_symbol, mapper_var)),
var_store.fresh(),
var_store.fresh(),
);
@ -411,9 +414,9 @@ fn build_effect_map(
(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 = (
var_store.fresh(),
thunk_var,
Loc::at_zero(expr),
var_store.fresh(),
var_store.fresh(),
@ -441,13 +444,19 @@ fn build_effect_after(
let outer_closure_symbol = new_symbol!(scope, "effect_after_inner");
// `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 {})`
let to_effect_var = var_store.fresh();
let to_effect_call = {
let boxed = (
var_store.fresh(),
Loc::at_zero(Expr::Var(to_effect_symbol)),
to_effect_var,
Loc::at_zero(Expr::Var(to_effect_symbol, to_effect_var)),
var_store.fresh(),
var_store.fresh(),
);
@ -459,7 +468,12 @@ fn build_effect_after(
// let @Effect thunk = toEffect (effect {}) in thunk {}
let let_effect_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) =
build_fresh_opaque_variables(var_store);
@ -702,9 +716,10 @@ fn force_effect(
let ret_var = var_store.fresh();
let force_thunk_call = {
let thunk_var = var_store.fresh();
let boxed = (
var_store.fresh(),
Loc::at_zero(Expr::Var(thunk_symbol)),
thunk_var,
Loc::at_zero(Expr::Var(thunk_symbol, thunk_var)),
var_store.fresh(),
ret_var,
);
@ -884,6 +899,7 @@ fn build_effect_forever_inner_body(
effect: Symbol,
var_store: &mut VarStore,
) -> Expr {
let thunk1_var = var_store.fresh();
let thunk1_symbol = { scope.introduce("thunk1".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 {
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(),
pattern_vars,
annotation: None,
@ -920,8 +936,8 @@ fn build_effect_forever_inner_body(
let force_thunk_call = {
let ret_var = var_store.fresh();
let boxed = (
var_store.fresh(),
Loc::at_zero(Expr::Var(thunk1_symbol)),
thunk1_var,
Loc::at_zero(Expr::Var(thunk1_symbol, thunk1_var)),
var_store.fresh(),
ret_var,
);
@ -945,12 +961,13 @@ fn build_effect_forever_inner_body(
let forever_effect = {
let boxed = (
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(),
);
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)
};
@ -1198,14 +1215,16 @@ fn build_effect_loop_inner_body(
// `step state`
let rhs = {
let step_var = var_store.fresh();
let boxed = (
var_store.fresh(),
Loc::at_zero(Expr::Var(step_symbol)),
step_var,
Loc::at_zero(Expr::Var(step_symbol, step_var)),
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)
};
@ -1220,10 +1239,11 @@ fn build_effect_loop_inner_body(
// thunk1 {}
let force_thunk_call = {
let thunk1_var = var_store.fresh();
let ret_var = var_store.fresh();
let boxed = (
var_store.fresh(),
Loc::at_zero(Expr::Var(thunk1_symbol)),
thunk1_var,
Loc::at_zero(Expr::Var(thunk1_symbol, thunk1_var)),
var_store.fresh(),
ret_var,
);
@ -1236,16 +1256,22 @@ fn build_effect_loop_inner_body(
// recursive call `loop newState step`
let loop_new_state_step = {
let loop_var = var_store.fresh();
let boxed = (
var_store.fresh(),
Loc::at_zero(Expr::Var(loop_symbol)),
loop_var,
Loc::at_zero(Expr::Var(loop_symbol, loop_var)),
var_store.fresh(),
var_store.fresh(),
);
let new_state_var = var_store.fresh();
let step_var = var_store.fresh();
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)
};
@ -1283,7 +1309,7 @@ fn build_effect_loop_inner_body(
crate::expr::WhenBranch {
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,
redundant: RedundantMark::new(var_store),
}
@ -1351,7 +1377,7 @@ pub fn build_host_exposed_def(
));
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);

View file

@ -100,7 +100,7 @@ pub enum Expr {
},
// Lookups
Var(Symbol),
Var(Symbol, Variable),
AbilityMember(
/// Actual member name
Symbol,
@ -230,14 +230,14 @@ pub enum Expr {
Expect {
loc_condition: 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
ExpectFx {
loc_condition: 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
@ -247,6 +247,13 @@ pub enum Expr {
RuntimeError(RuntimeError),
}
#[derive(Clone, Copy, Debug)]
pub struct ExpectLookup {
pub symbol: Symbol,
pub var: Variable,
pub ability_info: Option<SpecializationId>,
}
impl Expr {
pub fn category(&self) -> Category {
match self {
@ -256,7 +263,7 @@ impl Expr {
Self::Str(..) => Category::Str,
Self::SingleQuote(..) => Category::Character,
Self::List { .. } => Category::List,
&Self::Var(sym) => Category::Lookup(sym),
&Self::Var(sym, _) => Category::Lookup(sym),
&Self::AbilityMember(sym, _, _) => Category::Lookup(sym),
Self::When { .. } => Category::When,
Self::If { .. } => Category::If,
@ -372,7 +379,7 @@ impl AccessorData {
record_var,
ext_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,
};
@ -440,7 +447,10 @@ impl OpaqueWrapFunctionData {
let body = Expr::OpaqueRef {
opaque_var,
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),
type_arguments,
lambda_set_variables,
@ -592,7 +602,7 @@ pub fn canonicalize_expr<'a>(
} => {
let (can_update, update_out) =
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) {
Ok((can_fields, mut output)) => {
output.references.union_mut(&update_out.references);
@ -765,7 +775,7 @@ pub fn canonicalize_expr<'a>(
output.tail_call = None;
let expr = match fn_expr.value {
Var(symbol) => {
Var(symbol, _) => {
output.references.insert_call(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,
// 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(
env,
@ -1600,7 +1610,7 @@ fn canonicalize_var_lookup(
var_store.fresh(),
)
} else {
Var(symbol)
Var(symbol, var_store.fresh())
}
}
Err(problem) => {
@ -1623,7 +1633,7 @@ fn canonicalize_var_lookup(
var_store.fresh(),
)
} else {
Var(symbol)
Var(symbol, var_store.fresh())
}
}
Err(problem) => {
@ -1657,7 +1667,7 @@ pub fn inline_calls(var_store: &mut VarStore, scope: &mut Scope, expr: Expr) ->
| other @ EmptyRecord
| other @ Accessor { .. }
| other @ Update { .. }
| other @ Var(_)
| other @ Var(..)
| other @ AbilityMember(..)
| other @ RunLowLevel { .. }
| other @ TypedHole { .. }
@ -1960,67 +1970,71 @@ pub fn inline_calls(var_store: &mut VarStore, scope: &mut Scope, expr: Expr) ->
let (fn_var, loc_expr, closure_var, expr_var) = *boxed_tuple;
match loc_expr.value {
Var(symbol) if symbol.is_builtin() => match builtin_defs_map(symbol, var_store) {
Some(Def {
loc_expr:
Loc {
value:
Closure(ClosureData {
recursive,
arguments: params,
loc_body: boxed_body,
..
}),
..
},
..
}) => {
debug_assert_eq!(recursive, Recursive::NotRecursive);
Var(symbol, _) if symbol.is_builtin() => {
match builtin_defs_map(symbol, var_store) {
Some(Def {
loc_expr:
Loc {
value:
Closure(ClosureData {
recursive,
arguments: params,
loc_body: boxed_body,
..
}),
..
},
..
}) => {
debug_assert_eq!(recursive, Recursive::NotRecursive);
// Since this is a canonicalized Expr, we should have
// already detected any arity mismatches and replaced this
// with a RuntimeError if there was a mismatch.
debug_assert_eq!(params.len(), args.len());
// Since this is a canonicalized Expr, we should have
// already detected any arity mismatches and replaced this
// with a RuntimeError if there was a mismatch.
debug_assert_eq!(params.len(), args.len());
// Start with the function's body as the answer.
let mut loc_answer = *boxed_body;
// Start with the function's body as the answer.
let mut loc_answer = *boxed_body;
// Wrap the body in one LetNonRec for each argument,
// such that at the end we have all the arguments in
// scope with the values the caller provided.
for ((_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.
// Not sure if param_var should be involved.
let pattern_vars = SendMap::default();
// Wrap the body in one LetNonRec for each argument,
// such that at the end we have all the arguments in
// scope with the values the caller provided.
for (
(_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.
// Not sure if param_var should be involved.
let pattern_vars = SendMap::default();
let def = Def {
loc_pattern,
loc_expr,
expr_var,
pattern_vars,
annotation: None,
};
let def = Def {
loc_pattern,
loc_expr,
expr_var,
pattern_vars,
annotation: None,
};
loc_answer = Loc {
region: Region::zero(),
value: LetNonRec(Box::new(def), Box::new(loc_answer)),
};
loc_answer = Loc {
region: Region::zero(),
value: LetNonRec(Box::new(def), Box::new(loc_answer)),
};
}
loc_answer.value
}
Some(_) => {
unreachable!("Tried to inline a non-function");
}
None => {
unreachable!(
"Tried to inline a builtin that wasn't registered: {:?}",
symbol
);
}
loc_answer.value
}
Some(_) => {
unreachable!("Tried to inline a non-function");
}
None => {
unreachable!(
"Tried to inline a builtin that wasn't registered: {:?}",
symbol
);
}
},
}
_ => {
// For now, we only inline calls to builtins. Leave this alone!
Call(
@ -2172,7 +2186,10 @@ fn desugar_str_segments(var_store: &mut VarStore, segments: Vec<StrSegment>) ->
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(
Box::new((
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 {
expects: VecMap::default(),
};
@ -2615,16 +2632,34 @@ pub struct DestructureDef {
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 symbols = Vec::new();
let mut lookups: Vec<ExpectLookup> = Vec::new();
while let Some(expr) = stack.pop() {
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
if !symbols.iter().any(|(sym, _)| sym == symbol) {
symbols.push((*symbol, var_store.fresh()));
if !lookups.iter().any(|l| l.symbol == *symbol) {
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, .. } => {
@ -2665,7 +2700,7 @@ fn get_lookup_symbols(expr: &Expr, var_store: &mut VarStore) -> Vec<(Symbol, Var
stack.reserve(1 + args.len());
match &boxed_expr.1.value {
Expr::Var(_) => {
Expr::Var(_, _) => {
// do nothing
}
function_expr => {
@ -2721,7 +2756,7 @@ fn get_lookup_symbols(expr: &Expr, var_store: &mut VarStore) -> Vec<(Symbol, Var
}
}
symbols
lookups
}
/// Here we transform
@ -2768,14 +2803,22 @@ fn toplevel_expect_to_inline_expect_help(mut loc_expr: Loc<Expr>, has_effects: b
loop {
match loc_expr.value {
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));
loc_expr = *remainder;
}
Expr::LetRec(defs, remainder, mark) => {
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));
@ -2818,7 +2861,7 @@ fn toplevel_expect_to_inline_expect_help(mut loc_expr: Loc<Expr>, has_effects: b
}
struct ExpectCollector {
expects: VecMap<Region, Vec<(Symbol, Variable)>>,
expects: VecMap<Region, Vec<ExpectLookup>>,
}
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::effect_module::HostedGeneratedFunctions;
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::scope::Scope;
use bumpalo::Bump;
@ -130,7 +130,7 @@ pub struct Module {
pub aliases: MutMap<Symbol, (bool, Alias)>,
pub rigid_variables: RigidVariables,
pub abilities_store: PendingAbilitiesStore,
pub loc_expects: VecMap<Region, Vec<(Symbol, Variable)>>,
pub loc_expects: VecMap<Region, Vec<ExpectLookup>>,
}
#[derive(Debug, Default)]
@ -152,7 +152,7 @@ pub struct ModuleOutput {
pub symbols_from_requires: Vec<(Loc<Symbol>, Loc<Type>)>,
pub pending_derives: PendingDerives,
pub scope: Scope,
pub loc_expects: VecMap<Region, Vec<(Symbol, Variable)>>,
pub loc_expects: VecMap<Region, Vec<ExpectLookup>>,
}
fn validate_generate_with<'a>(
@ -1040,7 +1040,7 @@ fn fix_values_captured_in_closure_expr(
| Float(..)
| Str(_)
| SingleQuote(..)
| Var(_)
| Var(..)
| AbilityMember(..)
| EmptyRecord
| TypedHole { .. }

View file

@ -13,8 +13,8 @@ use roc_can::expected::Expected::{self, *};
use roc_can::expected::PExpected;
use roc_can::expr::Expr::{self, *};
use roc_can::expr::{
AccessorData, AnnotatedMark, ClosureData, DeclarationTag, Declarations, DestructureDef, Field,
FunctionDef, OpaqueWrapFunctionData, WhenBranch,
AccessorData, AnnotatedMark, ClosureData, DeclarationTag, Declarations, DestructureDef,
ExpectLookup, Field, FunctionDef, OpaqueWrapFunctionData, WhenBranch,
};
use roc_can::pattern::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;
// 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
@ -425,9 +425,13 @@ pub fn constrain_expr(
let and_constraint = constraints.and_constraint(and_cons);
constraints.exists(vars, and_constraint)
}
Var(symbol) => {
// make lookup constraint to lookup this symbol's type in the environment
constraints.lookup(*symbol, expected, region)
Var(symbol, variable) => {
// Save the expectation in the variable, then lookup the symbol's type in the environment
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) => {
// 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());
for (symbol, var) in lookups_in_cond.iter() {
for ExpectLookup {
symbol,
var,
ability_info: _,
} in lookups_in_cond.iter()
{
vars.push(*var);
all_constraints.push(constraints.lookup(
@ -562,7 +571,12 @@ pub fn constrain_expr(
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);
all_constraints.push(constraints.lookup(

View file

@ -357,7 +357,7 @@ fn decoder_record_step_field(
name: "Ok".into(),
arguments: vec![(
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(),
arguments: vec![(
decode_err_var,
Loc::at_zero(Expr::Var(err_val_symbol)),
Loc::at_zero(Expr::Var(err_val_symbol, decode_err_var)),
)],
}),
guard: None,
@ -433,7 +433,7 @@ fn decoder_record_step_field(
record_var: rec_var,
ext_var: env.new_ext_var(ExtensionKind::Record),
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(),
})),
cond_var: rec_dot_result,
@ -462,7 +462,7 @@ fn decoder_record_step_field(
record_var: rec_var,
ext_var: env.new_ext_var(ExtensionKind::Record),
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(),
})),
},
@ -499,12 +499,15 @@ fn decoder_record_step_field(
let condition_expr = Expr::Call(
Box::new((
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,
rec_var,
)),
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,
Loc::at_zero(Expr::AbilityMember(
@ -513,7 +516,10 @@ fn decoder_record_step_field(
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,
);
@ -600,7 +606,7 @@ fn decoder_record_step_field(
Expr::Call(
Box::new((
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_ret_var,
)),
@ -676,7 +682,7 @@ fn decoder_record_step_field(
// when field is
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,
expr_var: keep_or_skip_var,
region: Region::zero(),
@ -764,7 +770,7 @@ fn decoder_record_finalizer(
pattern_symbols.push(symbol);
let field_expr = Expr::Var(symbol);
let field_expr = Expr::Var(symbol, field_var);
let field = Field {
var: field_var,
region: Region::zero(),
@ -827,7 +833,7 @@ fn decoder_record_finalizer(
record_var: state_record_var,
ext_var: env.new_ext_var(ExtensionKind::Record),
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(),
};
@ -1126,7 +1132,7 @@ fn wrap_in_decode_custom_decode_with(
// ~ bytes, Decoder (List elem) fmt, fmt -> DecoderResult (List val)
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((
this_decode_with_fn_var,
Loc::at_zero(decode_with_var),
@ -1137,9 +1143,9 @@ fn wrap_in_decode_custom_decode_with(
decode_with_fn,
vec![
// 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)),
(fmt_var, Loc::at_zero(Var(fmt_sym))),
(fmt_var, Loc::at_zero(Var(fmt_sym, fmt_var))),
],
CalledVia::Space,
);
@ -1231,7 +1237,7 @@ fn wrap_in_decode_custom_decode_with(
// ~ (List U8, fmt -> DecodeResult (List elem)) -> Decoder (List elem) fmt
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((
this_decode_custom_fn_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
let to_encoder_call = Call(
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,
);
@ -217,7 +217,7 @@ fn to_encoder_list(env: &mut Env<'_>, fn_name: Symbol) -> (Expr, Variable) {
let encode_list_call = Call(
encode_list_fn,
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)),
],
CalledVia::Space,
@ -314,7 +314,10 @@ fn to_encoder_record(
record_var,
ext_var: env.subs.fresh_unnamed_flex_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,
};
@ -572,7 +575,7 @@ fn to_encoder_tag_union(
// toEncoder rcd.a
let to_encoder_call = Call(
to_encoder_fn,
vec![(sym_var, Loc::at_zero(Var(sym)))],
vec![(sym_var, Loc::at_zero(Var(sym, sym_var)))],
CalledVia::Space,
);
@ -662,7 +665,7 @@ fn to_encoder_tag_union(
// A v1 v2 -> Encode.tag "A" [ Encode.toEncoder v1, Encode.toEncoder v2 ]
// B v3 -> Encode.tag "B" [ Encode.toEncoder v3 ]
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,
expr_var: whole_tag_encoders_var,
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
let append_with_fn = Box::new((
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,
Variable::LIST_U8,
));
@ -788,11 +791,11 @@ fn wrap_in_encode_custom(
append_with_fn,
vec![
// (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, Loc::at_zero(encoder)),
// (fmt, fmt_var)
(fmt_var, Loc::at_zero(Var(fmt_sym))),
(fmt_var, Loc::at_zero(Var(fmt_sym, fmt_var))),
],
CalledVia::Space,
);
@ -869,7 +872,7 @@ fn wrap_in_encode_custom(
// Encode.custom : (List U8, fmt -> List U8) -> Encoder fmt | fmt has EncoderFormatting
let custom_fn = Box::new((
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_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 (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, _)| {
let field_name = env.subs[field_name].clone();
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,
field_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,
};
@ -215,7 +218,7 @@ fn hash_tag_union(
let (discr_hasher_var, disc_hasher_expr) = call_hash_ability_member(
env,
hash_discr_member,
(hasher_var, Expr::Var(hasher_sym)),
(hasher_var, Expr::Var(hasher_sym, hasher_var)),
(
discr_num_var,
Expr::Int(
@ -232,7 +235,11 @@ fn hash_tag_union(
let (body_var, body_expr) = (payload_vars.into_iter()).zip(payload_syms).fold(
(discr_hasher_var, disc_hasher_expr),
|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_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,
expr_var: when_var,
region: Region::zero(),
@ -338,9 +345,13 @@ fn hash_newtype_tag_union(
// Fold up `Hash.hash (... (Hash.hash discrHasher x11) ...) x1n`
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)| {
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_can::abilities::{AbilitiesStore, PendingAbilitiesStore, ResolvedImpl};
use roc_can::constraint::{Constraint as ConstraintSoa, Constraints};
use roc_can::expr::Declarations;
use roc_can::expr::PendingDerives;
use roc_can::expr::{Declarations, ExpectLookup};
use roc_can::module::{
canonicalize_module_defs, ExposedByModule, ExposedForModule, ExposedModuleTypes, Module,
ResolvedImplementations, TypeState,
@ -719,7 +719,7 @@ pub enum EntryPoint<'a> {
pub struct Expectations {
pub subs: roc_types::subs::Subs,
pub path: PathBuf,
pub expectations: VecMap<Region, Vec<(Symbol, Variable)>>,
pub expectations: VecMap<Region, Vec<ExpectLookup>>,
pub ident_ids: IdentIds,
}
@ -763,7 +763,7 @@ struct ParsedModule<'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,
/// 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 roc_builtins::bitcode::{FloatWidth, IntWidth};
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_collections::all::{default_hasher, BumpMap, BumpMapDefault, MutMap};
use roc_collections::VecMap;
@ -2376,7 +2376,7 @@ fn from_can_let<'a>(
lower_rest!(variable, cont.value)
}
Var(original) | AbilityMember(original, _, _) => {
Var(original, _) | AbilityMember(original, _, _) => {
// a variable is aliased, e.g.
//
// foo = bar
@ -2605,7 +2605,7 @@ fn from_can_let<'a>(
}
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)
}
_ => {
@ -2747,7 +2747,7 @@ fn pattern_to_when<'a>(
cond_var: pattern_var,
expr_var: body_var,
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 {
patterns: vec![WhenBranchPattern {
pattern,
@ -4074,11 +4074,14 @@ pub fn with_hole<'a>(
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 let ReuseSymbol::Value(_symbol) =
can_reuse_symbol(env, procs, &roc_can::expr::Expr::Var(symbol), variable)
{
if let ReuseSymbol::Value(_symbol) = can_reuse_symbol(
env,
procs,
&roc_can::expr::Expr::Var(symbol, variable),
variable,
) {
let real_symbol =
procs
.symbol_specializations
@ -5046,7 +5049,7 @@ pub fn with_hole<'a>(
};
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
call_by_name(
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_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_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 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);
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 layout = return_on_layout_error!(env, res_layout, "Expect");
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 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);
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 layout = return_on_layout_error!(env, res_layout, "Expect");
layouts.push(layout);
@ -7513,7 +7544,7 @@ fn can_reuse_symbol<'a>(
AbilityMember(member, specialization_id, _) => {
late_resolve_ability_specialization(env, *member, *specialization_id, expr_var)
}
Var(symbol) => *symbol,
Var(symbol, _) => *symbol,
_ => 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("]")
.group(),
),
Var(sym) | AbilityMember(sym, _, _) => f.text(format!(
Var(sym, _) | AbilityMember(sym, _, _) => f.text(format!(
"{}.{}",
sym.module_string(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"
roc_builtins = {path = "../compiler/builtins"}
roc_can = {path = "../compiler/can"}
roc_collections = {path = "../compiler/collections"}
roc_intern = {path = "../compiler/intern"}
roc_load = {path = "../compiler/load"}

View file

@ -4,6 +4,7 @@ use bumpalo::collections::Vec as BumpVec;
use bumpalo::Bump;
use inkwell::context::Context;
use roc_build::link::llvm_module_to_dylib;
use roc_can::expr::ExpectLookup;
use roc_collections::{MutSet, VecMap};
use roc_gen_llvm::{
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 (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(
target_info,