refactor: special-case the canonicalization of a Closure def

This commit is contained in:
Folkert 2022-04-27 16:39:21 +02:00
parent 41ee2c3e6a
commit c28a0af932
No known key found for this signature in database
GPG key ID: 1F17F6FFD112B97C

View file

@ -1146,6 +1146,20 @@ fn canonicalize_pending_value_def<'a>(
.introduced_variables .introduced_variables
.union(&type_annotation.introduced_variables); .union(&type_annotation.introduced_variables);
pattern_to_vars_by_symbol(&mut vars_by_symbol, &loc_can_pattern.value, expr_var);
// First, make sure we are actually assigning an identifier instead of (for example) a tag.
//
// If we're assigning (UserId userId) = ... then this is certainly not a closure declaration,
// which also implies it's not a self tail call!
//
// Only defs of the form (foo = ...) can be closure declarations or self tail calls.
match (&loc_can_pattern.value, &loc_expr.value) {
(
Pattern::Identifier(symbol)
| Pattern::AbilityMemberSpecialization { ident: symbol, .. },
ast::Expr::Closure(arguments, body),
) => {
// bookkeeping for tail-call detection. If we're assigning to an // bookkeeping for tail-call detection. If we're assigning to an
// identifier (e.g. `f = \x -> ...`), then this symbol can be tail-called. // identifier (e.g. `f = \x -> ...`), then this symbol can be tail-called.
let outer_identifier = env.tailcallable_symbol; let outer_identifier = env.tailcallable_symbol;
@ -1161,45 +1175,20 @@ fn canonicalize_pending_value_def<'a>(
env.closure_name_symbol = Some(*defined_symbol); env.closure_name_symbol = Some(*defined_symbol);
}; };
pattern_to_vars_by_symbol(&mut vars_by_symbol, &loc_can_pattern.value, expr_var); let (mut closure_data, can_output) =
crate::expr::canonicalize_closure(env, var_store, scope, arguments, body);
let (mut loc_can_expr, can_output) =
canonicalize_expr(env, var_store, scope, loc_expr.region, &loc_expr.value);
output.references.union_mut(&can_output.references);
// reset the tailcallable_symbol // reset the tailcallable_symbol
env.tailcallable_symbol = outer_identifier; env.tailcallable_symbol = outer_identifier;
// First, make sure we are actually assigning an identifier instead of (for example) a tag. output.references.union_mut(&can_output.references);
//
// If we're assigning (UserId userId) = ... then this is certainly not a closure declaration,
// which also implies it's not a self tail call!
//
// Only defs of the form (foo = ...) can be closure declarations or self tail calls.
match (&loc_can_pattern.value, &loc_can_expr.value) {
(
Pattern::Identifier(symbol)
| Pattern::AbilityMemberSpecialization { ident: symbol, .. },
Closure(ClosureData {
function_type,
closure_type,
closure_ext_var,
return_type,
name: closure_name,
arguments,
loc_body: body,
captured_symbols,
..
}),
) => {
// Since everywhere in the code it'll be referred to by its defined name, // Since everywhere in the code it'll be referred to by its defined name,
// remove its generated name from the closure map. (We'll re-insert it later.) // remove its generated name from the closure map. (We'll re-insert it later.)
let closure_references = env.closures.remove(closure_name).unwrap_or_else(|| { let closure_references = env.closures.remove(&closure_data.name).unwrap_or_else(|| {
panic!( panic!(
"Tried to remove symbol {:?} from procedures, but it was not found: {:?}", "Tried to remove symbol {:?} from procedures, but it was not found: {:?}",
closure_name, env.closures closure_data.name, env.closures
) )
}); });
@ -1209,17 +1198,10 @@ fn canonicalize_pending_value_def<'a>(
_ => Recursive::NotRecursive, _ => Recursive::NotRecursive,
}; };
loc_can_expr.value = Closure(ClosureData { closure_data.recursive = is_recursive;
function_type: *function_type, closure_data.name = *symbol;
closure_type: *closure_type,
closure_ext_var: *closure_ext_var, let loc_can_expr = Loc::at(loc_expr.region, Expr::Closure(closure_data));
return_type: *return_type,
name: *symbol,
captured_symbols: captured_symbols.clone(),
recursive: is_recursive,
arguments: arguments.clone(),
loc_body: body.clone(),
});
let def = single_can_def( let def = single_can_def(
loc_can_pattern, loc_can_pattern,
@ -1237,7 +1219,13 @@ fn canonicalize_pending_value_def<'a>(
def, def,
} }
} }
_ => { _ => {
let (loc_can_expr, can_output) =
canonicalize_expr(env, var_store, scope, loc_expr.region, &loc_expr.value);
output.references.union_mut(&can_output.references);
let refs = can_output.references.clone(); let refs = can_output.references.clone();
let def = single_can_def( let def = single_can_def(