mirror of
https://github.com/roc-lang/roc.git
synced 2025-10-01 07:41:12 +00:00
fix bug with imported values
This commit is contained in:
parent
173f84400e
commit
879cbfabe4
1 changed files with 82 additions and 49 deletions
|
@ -2653,24 +2653,25 @@ pub fn with_hole<'a>(
|
||||||
let mut can_fields = Vec::with_capacity_in(fields.len(), env.arena);
|
let mut can_fields = Vec::with_capacity_in(fields.len(), env.arena);
|
||||||
|
|
||||||
enum Field {
|
enum Field {
|
||||||
Imported(Symbol, Variable),
|
Function(Symbol, Variable),
|
||||||
NakedSymbol,
|
ValueSymbol,
|
||||||
Field(roc_can::expr::Field),
|
Field(roc_can::expr::Field),
|
||||||
}
|
}
|
||||||
|
|
||||||
for (label, variable, _) in sorted_fields.into_iter() {
|
for (label, variable, _) in sorted_fields.into_iter() {
|
||||||
// TODO how should function pointers be handled here?
|
// TODO how should function pointers be handled here?
|
||||||
|
use ReuseSymbol::*;
|
||||||
match fields.remove(&label) {
|
match fields.remove(&label) {
|
||||||
Some(field) => match can_reuse_symbol(procs, &field.loc_expr.value) {
|
Some(field) => match can_reuse_symbol(env, procs, &field.loc_expr.value) {
|
||||||
Some(reusable) if env.is_imported_symbol(reusable) => {
|
Imported(symbol) | LocalFunction(symbol) => {
|
||||||
field_symbols.push(reusable);
|
field_symbols.push(symbol);
|
||||||
can_fields.push(Field::Imported(reusable, variable));
|
can_fields.push(Field::Function(symbol, variable));
|
||||||
}
|
}
|
||||||
Some(reusable) => {
|
Value(reusable) => {
|
||||||
field_symbols.push(reusable);
|
field_symbols.push(reusable);
|
||||||
can_fields.push(Field::NakedSymbol);
|
can_fields.push(Field::ValueSymbol);
|
||||||
}
|
}
|
||||||
None => {
|
NotASymbol => {
|
||||||
field_symbols.push(env.unique_symbol());
|
field_symbols.push(env.unique_symbol());
|
||||||
can_fields.push(Field::Field(field));
|
can_fields.push(Field::Field(field));
|
||||||
}
|
}
|
||||||
|
@ -2693,17 +2694,19 @@ pub fn with_hole<'a>(
|
||||||
for (opt_field, symbol) in can_fields.into_iter().rev().zip(field_symbols.iter().rev())
|
for (opt_field, symbol) in can_fields.into_iter().rev().zip(field_symbols.iter().rev())
|
||||||
{
|
{
|
||||||
match opt_field {
|
match opt_field {
|
||||||
Field::NakedSymbol => {}
|
Field::ValueSymbol => {
|
||||||
Field::Imported(symbol, variable) => {
|
// this symbol is already defined; nothing to do
|
||||||
// make sure this symbol is specialized appropriately in its source module
|
}
|
||||||
add_needed_external(procs, env, variable, symbol);
|
Field::Function(symbol, variable) => {
|
||||||
|
stmt = reuse_function_symbol(
|
||||||
let layout = layout_cache
|
env,
|
||||||
.from_var(env.arena, variable, env.subs)
|
procs,
|
||||||
.expect("creating layout does not fail");
|
layout_cache,
|
||||||
let expr = Expr::FunctionPointer(symbol, layout.clone());
|
Some(variable),
|
||||||
|
symbol,
|
||||||
stmt = Stmt::Let(symbol, expr, layout, env.arena.alloc(stmt));
|
stmt,
|
||||||
|
symbol,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
Field::Field(field) => {
|
Field::Field(field) => {
|
||||||
stmt = with_hole(
|
stmt = with_hole(
|
||||||
|
@ -2714,7 +2717,7 @@ pub fn with_hole<'a>(
|
||||||
layout_cache,
|
layout_cache,
|
||||||
*symbol,
|
*symbol,
|
||||||
env.arena.alloc(stmt),
|
env.arena.alloc(stmt),
|
||||||
)
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3382,8 +3385,15 @@ pub fn with_hole<'a>(
|
||||||
// if the function expression (loc_expr) is already a symbol,
|
// if the function expression (loc_expr) is already a symbol,
|
||||||
// re-use that symbol, and don't define its value again
|
// re-use that symbol, and don't define its value again
|
||||||
let mut result;
|
let mut result;
|
||||||
match can_reuse_symbol(procs, &loc_expr.value) {
|
use ReuseSymbol::*;
|
||||||
Some(function_symbol) => {
|
match can_reuse_symbol(env, procs, &loc_expr.value) {
|
||||||
|
LocalFunction(_) => {
|
||||||
|
unreachable!("if this was known to be a function, we would not be here")
|
||||||
|
}
|
||||||
|
Imported(_) => {
|
||||||
|
unreachable!("an imported value is never an anonymous function")
|
||||||
|
}
|
||||||
|
Value(function_symbol) => {
|
||||||
if let Layout::Closure(_, closure_fields, _) = full_layout {
|
if let Layout::Closure(_, closure_fields, _) = full_layout {
|
||||||
// we're invoking a closure
|
// we're invoking a closure
|
||||||
let closure_record_symbol = env.unique_symbol();
|
let closure_record_symbol = env.unique_symbol();
|
||||||
|
@ -3476,7 +3486,7 @@ pub fn with_hole<'a>(
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
None => {
|
NotASymbol => {
|
||||||
let function_symbol = env.unique_symbol();
|
let function_symbol = env.unique_symbol();
|
||||||
|
|
||||||
result = Stmt::Let(
|
result = Stmt::Let(
|
||||||
|
@ -4717,15 +4727,33 @@ fn store_record_destruct<'a>(
|
||||||
/// We want to re-use symbols that are not function symbols
|
/// We want to re-use symbols that are not function symbols
|
||||||
/// for any other expression, we create a new symbol, and will
|
/// for any other expression, we create a new symbol, and will
|
||||||
/// later make sure it gets assigned the correct value.
|
/// later make sure it gets assigned the correct value.
|
||||||
fn can_reuse_symbol<'a>(procs: &Procs<'a>, expr: &roc_can::expr::Expr) -> Option<Symbol> {
|
|
||||||
|
enum ReuseSymbol {
|
||||||
|
Imported(Symbol),
|
||||||
|
LocalFunction(Symbol),
|
||||||
|
Value(Symbol),
|
||||||
|
NotASymbol,
|
||||||
|
}
|
||||||
|
|
||||||
|
fn can_reuse_symbol<'a>(
|
||||||
|
env: &mut Env<'a, '_>,
|
||||||
|
procs: &Procs<'a>,
|
||||||
|
expr: &roc_can::expr::Expr,
|
||||||
|
) -> ReuseSymbol {
|
||||||
|
use ReuseSymbol::*;
|
||||||
|
|
||||||
if let roc_can::expr::Expr::Var(symbol) = expr {
|
if let roc_can::expr::Expr::Var(symbol) = expr {
|
||||||
if procs.partial_procs.contains_key(&symbol) {
|
let symbol = *symbol;
|
||||||
None
|
|
||||||
|
if env.is_imported_symbol(symbol) {
|
||||||
|
Imported(symbol)
|
||||||
|
} else if procs.partial_procs.contains_key(&symbol) {
|
||||||
|
LocalFunction(symbol)
|
||||||
} else {
|
} else {
|
||||||
Some(*symbol)
|
Value(symbol)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
None
|
NotASymbol
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4734,9 +4762,9 @@ fn possible_reuse_symbol<'a>(
|
||||||
procs: &Procs<'a>,
|
procs: &Procs<'a>,
|
||||||
expr: &roc_can::expr::Expr,
|
expr: &roc_can::expr::Expr,
|
||||||
) -> Symbol {
|
) -> Symbol {
|
||||||
match can_reuse_symbol(procs, expr) {
|
match can_reuse_symbol(env, procs, expr) {
|
||||||
Some(s) => s,
|
ReuseSymbol::Value(s) => s,
|
||||||
None => env.unique_symbol(),
|
_ => env.unique_symbol(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4792,8 +4820,7 @@ fn reuse_function_symbol<'a>(
|
||||||
) -> Stmt<'a> {
|
) -> Stmt<'a> {
|
||||||
match procs.partial_procs.get(&original) {
|
match procs.partial_procs.get(&original) {
|
||||||
None => {
|
None => {
|
||||||
let is_imported =
|
let is_imported = env.is_imported_symbol(original);
|
||||||
!(env.home == original.module_id() || original.module_id() == ModuleId::ATTR);
|
|
||||||
|
|
||||||
match arg_var {
|
match arg_var {
|
||||||
Some(arg_var) if is_imported => {
|
Some(arg_var) if is_imported => {
|
||||||
|
@ -4814,7 +4841,7 @@ fn reuse_function_symbol<'a>(
|
||||||
// an imported symbol is always a function pointer:
|
// an imported symbol is always a function pointer:
|
||||||
// either it's a function, or a top-level 0-argument thunk
|
// either it's a function, or a top-level 0-argument thunk
|
||||||
let expr = Expr::FunctionPointer(original, layout.clone());
|
let expr = Expr::FunctionPointer(original, layout.clone());
|
||||||
return Stmt::Let(original, expr, layout, env.arena.alloc(result));
|
return Stmt::Let(symbol, expr, layout, env.arena.alloc(result));
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
// danger: a foreign symbol may not be specialized!
|
// danger: a foreign symbol may not be specialized!
|
||||||
|
@ -4954,19 +4981,25 @@ fn assign_to_symbol<'a>(
|
||||||
symbol: Symbol,
|
symbol: Symbol,
|
||||||
result: Stmt<'a>,
|
result: Stmt<'a>,
|
||||||
) -> Stmt<'a> {
|
) -> Stmt<'a> {
|
||||||
// if this argument is already a symbol, we don't need to re-define it
|
use ReuseSymbol::*;
|
||||||
if let roc_can::expr::Expr::Var(original) = loc_arg.value {
|
match can_reuse_symbol(env, procs, &loc_arg.value) {
|
||||||
reuse_function_symbol(
|
Imported(original) | LocalFunction(original) => {
|
||||||
env,
|
// for functions we must make sure they are specialized correctly
|
||||||
procs,
|
reuse_function_symbol(
|
||||||
layout_cache,
|
env,
|
||||||
Some(arg_var),
|
procs,
|
||||||
symbol,
|
layout_cache,
|
||||||
result,
|
Some(arg_var),
|
||||||
original,
|
symbol,
|
||||||
)
|
result,
|
||||||
} else {
|
original,
|
||||||
with_hole(
|
)
|
||||||
|
}
|
||||||
|
Value(_) => {
|
||||||
|
// symbol is already defined; nothing else to do here
|
||||||
|
result
|
||||||
|
}
|
||||||
|
NotASymbol => with_hole(
|
||||||
env,
|
env,
|
||||||
loc_arg.value,
|
loc_arg.value,
|
||||||
arg_var,
|
arg_var,
|
||||||
|
@ -4974,7 +5007,7 @@ fn assign_to_symbol<'a>(
|
||||||
layout_cache,
|
layout_cache,
|
||||||
symbol,
|
symbol,
|
||||||
env.arena.alloc(result),
|
env.arena.alloc(result),
|
||||||
)
|
),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue