refactor it all again

This commit is contained in:
Folkert 2022-04-27 17:01:18 +02:00
parent 6783b66db7
commit 465fad9da1
No known key found for this signature in database
GPG key ID: 1F17F6FFD112B97C

View file

@ -1020,12 +1020,12 @@ fn canonicalize_pending_value_def<'a>(
) -> DefOutput { ) -> DefOutput {
use PendingValueDef::*; use PendingValueDef::*;
match pending_def {
AnnotationOnly(_, loc_can_pattern, loc_ann) => {
// Make types for the body expr, even if we won't end up having a body. // Make types for the body expr, even if we won't end up having a body.
let expr_var = var_store.fresh(); let expr_var = var_store.fresh();
let mut vars_by_symbol = SendMap::default(); let mut vars_by_symbol = SendMap::default();
match pending_def {
AnnotationOnly(_, loc_can_pattern, loc_ann) => {
// annotation sans body cannot introduce new rigids that are visible in other annotations // annotation sans body cannot introduce new rigids that are visible in other annotations
// but the rigids can show up in type error messages, so still register them // but the rigids can show up in type error messages, so still register them
let type_annotation = canonicalize_annotation( let type_annotation = canonicalize_annotation(
@ -1146,6 +1146,49 @@ fn canonicalize_pending_value_def<'a>(
.introduced_variables .introduced_variables
.union(&type_annotation.introduced_variables); .union(&type_annotation.introduced_variables);
canonicalize_pending_body(
env,
output,
scope,
var_store,
loc_can_pattern,
loc_expr,
Some(Loc::at(loc_ann.region, type_annotation)),
)
}
Body(_loc_pattern, loc_can_pattern, loc_expr) => {
//
canonicalize_pending_body(
env,
output,
scope,
var_store,
loc_can_pattern,
loc_expr,
None,
)
}
}
}
// TODO trim down these arguments!
#[allow(clippy::too_many_arguments)]
#[allow(clippy::cognitive_complexity)]
fn canonicalize_pending_body<'a>(
env: &mut Env<'a>,
mut output: Output,
scope: &mut Scope,
var_store: &mut VarStore,
loc_can_pattern: Loc<Pattern>,
loc_expr: &'a Loc<ast::Expr>,
opt_loc_annotation: Option<Loc<crate::annotation::Annotation>>,
) -> DefOutput {
// Make types for the body expr, even if we won't end up having a body.
let expr_var = var_store.fresh();
let mut vars_by_symbol = SendMap::default();
pattern_to_vars_by_symbol(&mut vars_by_symbol, &loc_can_pattern.value, expr_var); 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. // First, make sure we are actually assigning an identifier instead of (for example) a tag.
@ -1156,24 +1199,20 @@ fn canonicalize_pending_value_def<'a>(
// Only defs of the form (foo = ...) can be closure declarations or self tail calls. // Only defs of the form (foo = ...) can be closure declarations or self tail calls.
match (&loc_can_pattern.value, &loc_expr.value) { match (&loc_can_pattern.value, &loc_expr.value) {
( (
Pattern::Identifier(symbol) Pattern::Identifier(defined_symbol)
| Pattern::AbilityMemberSpecialization { ident: symbol, .. }, | Pattern::AbilityMemberSpecialization {
ident: defined_symbol,
..
},
ast::Expr::Closure(arguments, body), 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;
if let Pattern::Identifier(ref defined_symbol) = &loc_can_pattern.value {
env.tailcallable_symbol = Some(*defined_symbol); env.tailcallable_symbol = Some(*defined_symbol);
};
// register the name of this closure, to make sure the closure won't capture it's own name // register the name of this closure, to make sure the closure won't capture it's own name
if let (Pattern::Identifier(ref defined_symbol), &ast::Expr::Closure(_, _)) =
(&loc_can_pattern.value, &loc_expr.value)
{
env.closure_name_symbol = Some(*defined_symbol); env.closure_name_symbol = Some(*defined_symbol);
};
let (mut closure_data, can_output) = let (mut closure_data, can_output) =
crate::expr::canonicalize_closure(env, var_store, scope, arguments, body); crate::expr::canonicalize_closure(env, var_store, scope, arguments, body);
@ -1186,12 +1225,12 @@ fn canonicalize_pending_value_def<'a>(
// The closure is self tail recursive iff it tail calls itself (by defined name). // The closure is self tail recursive iff it tail calls itself (by defined name).
let is_recursive = match can_output.tail_call { let is_recursive = match can_output.tail_call {
Some(tail_symbol) if tail_symbol == *symbol => Recursive::TailRecursive, Some(tail_symbol) if tail_symbol == *defined_symbol => Recursive::TailRecursive,
_ => Recursive::NotRecursive, _ => Recursive::NotRecursive,
}; };
closure_data.recursive = is_recursive; closure_data.recursive = is_recursive;
closure_data.name = *symbol; closure_data.name = *defined_symbol;
let loc_can_expr = Loc::at(loc_expr.region, Expr::Closure(closure_data)); let loc_can_expr = Loc::at(loc_expr.region, Expr::Closure(closure_data));
@ -1199,8 +1238,8 @@ fn canonicalize_pending_value_def<'a>(
loc_can_pattern, loc_can_pattern,
loc_can_expr, loc_can_expr,
expr_var, expr_var,
Some(Loc::at(loc_ann.region, type_annotation)), opt_loc_annotation,
vars_by_symbol.clone(), vars_by_symbol,
); );
output.union(can_output); output.union(can_output);
@ -1216,18 +1255,15 @@ fn canonicalize_pending_value_def<'a>(
let (loc_can_expr, can_output) = let (loc_can_expr, can_output) =
canonicalize_expr(env, var_store, scope, loc_expr.region, &loc_expr.value); 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 def = single_can_def( let def = single_can_def(
loc_can_pattern, loc_can_pattern,
loc_can_expr, loc_can_expr,
expr_var, expr_var,
Some(Loc::at(loc_ann.region, type_annotation)), opt_loc_annotation,
vars_by_symbol.clone(), vars_by_symbol,
); );
let refs = can_output.references.clone();
output.union(can_output); output.union(can_output);
DefOutput { DefOutput {
@ -1238,122 +1274,6 @@ fn canonicalize_pending_value_def<'a>(
} }
} }
} }
// If we have a pattern, then the def has a body (that is, it's not a
// standalone annotation), so we need to canonicalize the pattern and expr.
Body(loc_pattern, loc_can_pattern, loc_expr) => {
// bookkeeping for tail-call detection. If we're assigning to an
// identifier (e.g. `f = \x -> ...`), then this symbol can be tail-called.
let outer_identifier = env.tailcallable_symbol;
if let (&ast::Pattern::Identifier(_name), &Pattern::Identifier(ref defined_symbol)) =
(&loc_pattern.value, &loc_can_pattern.value)
{
env.tailcallable_symbol = Some(*defined_symbol);
// TODO isn't types_by_symbol enough? Do we need vars_by_symbol too?
vars_by_symbol.insert(*defined_symbol, expr_var);
};
// register the name of this closure, to make sure the closure won't capture it's own name
if let (Pattern::Identifier(ref defined_symbol), &ast::Expr::Closure(_, _)) =
(&loc_can_pattern.value, &loc_expr.value)
{
env.closure_name_symbol = Some(*defined_symbol);
};
let (mut loc_can_expr, can_output) =
canonicalize_expr(env, var_store, scope, loc_expr.region, &loc_expr.value);
// reset the tailcallable_symbol
env.tailcallable_symbol = outer_identifier;
// 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_can_expr.value) {
(
Pattern::Identifier(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,
// 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(|| {
panic!(
"Tried to remove symbol {:?} from procedures, but it was not found: {:?}",
closure_name, env.closures
)
});
// The closure is self tail recursive iff it tail calls itself (by defined name).
let is_recursive = match can_output.tail_call {
Some(tail_symbol) if tail_symbol == *symbol => Recursive::TailRecursive,
_ => Recursive::NotRecursive,
};
loc_can_expr.value = Closure(ClosureData {
function_type: *function_type,
closure_type: *closure_type,
closure_ext_var: *closure_ext_var,
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(
loc_can_pattern,
loc_can_expr,
expr_var,
None,
vars_by_symbol.clone(),
);
output.union(can_output);
DefOutput {
output,
references: DefReferences::Function(closure_references),
def,
}
}
_ => {
let refs = can_output.references.clone();
let def = single_can_def(
loc_can_pattern,
loc_can_expr,
expr_var,
None,
vars_by_symbol.clone(),
);
output.union(can_output);
DefOutput {
output,
references: DefReferences::Value(refs),
def,
}
}
}
}
}
}
#[inline(always)] #[inline(always)]
pub fn can_defs_with_return<'a>( pub fn can_defs_with_return<'a>(