use snapshots for inner scopes

This commit is contained in:
Folkert 2022-04-28 20:01:01 +02:00
parent 70844b1218
commit 5a613db7b6
No known key found for this signature in database
GPG key ID: 1F17F6FFD112B97C
4 changed files with 54 additions and 51 deletions

View file

@ -208,10 +208,10 @@ pub(crate) fn canonicalize_defs<'a>(
env: &mut Env<'a>, env: &mut Env<'a>,
mut output: Output, mut output: Output,
var_store: &mut VarStore, var_store: &mut VarStore,
mut scope: Scope, scope: &mut Scope,
loc_defs: &'a [&'a Loc<ast::Def<'a>>], loc_defs: &'a [&'a Loc<ast::Def<'a>>],
pattern_type: PatternType, pattern_type: PatternType,
) -> (CanDefs, Scope, Output, MutMap<Symbol, Region>) { ) -> (CanDefs, Output, MutMap<Symbol, Region>) {
// Canonicalizing defs while detecting shadowing involves a multi-step process: // Canonicalizing defs while detecting shadowing involves a multi-step process:
// //
// 1. Go through each of the patterns. // 1. Go through each of the patterns.
@ -236,7 +236,7 @@ pub(crate) fn canonicalize_defs<'a>(
for loc_def in loc_defs { for loc_def in loc_defs {
match loc_def.value.unroll_def() { match loc_def.value.unroll_def() {
Ok(type_def) => { Ok(type_def) => {
pending_type_defs.push(to_pending_type_def(env, type_def, &mut scope, pattern_type)) pending_type_defs.push(to_pending_type_def(env, type_def, scope, pattern_type))
} }
Err(value_def) => value_defs.push(Loc::at(loc_def.region, value_def)), Err(value_def) => value_defs.push(Loc::at(loc_def.region, value_def)),
} }
@ -322,7 +322,7 @@ pub(crate) fn canonicalize_defs<'a>(
let symbol = name.value; let symbol = name.value;
let can_ann = canonicalize_annotation( let can_ann = canonicalize_annotation(
env, env,
&mut scope, scope,
&ann.value, &ann.value,
ann.region, ann.region,
var_store, var_store,
@ -446,7 +446,7 @@ pub(crate) fn canonicalize_defs<'a>(
env, env,
&mut output, &mut output,
var_store, var_store,
&mut scope, scope,
abilities, abilities,
&abilities_in_scope, &abilities_in_scope,
pattern_type, pattern_type,
@ -465,7 +465,7 @@ pub(crate) fn canonicalize_defs<'a>(
env, env,
var_store, var_store,
loc_def.value, loc_def.value,
&mut scope, scope,
&mut new_output, &mut new_output,
pattern_type, pattern_type,
) { ) {
@ -512,7 +512,7 @@ pub(crate) fn canonicalize_defs<'a>(
env, env,
pending_def, pending_def,
output, output,
&mut scope, scope,
var_store, var_store,
&mut aliases, &mut aliases,
&abilities_in_scope, &abilities_in_scope,
@ -525,13 +525,6 @@ pub(crate) fn canonicalize_defs<'a>(
def_ordering.insert_symbol_references(def_id as u32, &temp_output.references) def_ordering.insert_symbol_references(def_id as u32, &temp_output.references)
} }
// This returns both the defs info as well as the new scope.
//
// We have to return the new scope because we added defs to it
// (and those lookups shouldn't fail later, e.g. when canonicalizing
// the return expr), but we didn't want to mutate the original scope
// directly because we wanted to keep a clone of it around to diff
// when looking for unused idents.
( (
CanDefs { CanDefs {
defs, defs,
@ -539,7 +532,6 @@ pub(crate) fn canonicalize_defs<'a>(
// The result needs a thread-safe `SendMap` // The result needs a thread-safe `SendMap`
aliases, aliases,
}, },
scope,
output, output,
symbols_introduced, symbols_introduced,
) )
@ -1278,11 +1270,11 @@ fn canonicalize_pending_body<'a>(
pub fn can_defs_with_return<'a>( pub fn can_defs_with_return<'a>(
env: &mut Env<'a>, env: &mut Env<'a>,
var_store: &mut VarStore, var_store: &mut VarStore,
scope: Scope, scope: &mut Scope,
loc_defs: &'a [&'a Loc<ast::Def<'a>>], loc_defs: &'a [&'a Loc<ast::Def<'a>>],
loc_ret: &'a Loc<ast::Expr<'a>>, loc_ret: &'a Loc<ast::Expr<'a>>,
) -> (Expr, Output) { ) -> (Expr, Output) {
let (unsorted, mut scope, defs_output, symbols_introduced) = canonicalize_defs( let (unsorted, defs_output, symbols_introduced) = canonicalize_defs(
env, env,
Output::default(), Output::default(),
var_store, var_store,
@ -1294,7 +1286,7 @@ pub fn can_defs_with_return<'a>(
// The def as a whole is a tail call iff its return expression is a tail call. // The def as a whole is a tail call iff its return expression is a tail call.
// Use its output as a starting point because its tail_call already has the right answer! // Use its output as a starting point because its tail_call already has the right answer!
let (ret_expr, mut output) = let (ret_expr, mut output) =
canonicalize_expr(env, var_store, &mut scope, loc_ret.region, &loc_ret.value); canonicalize_expr(env, var_store, scope, loc_ret.region, &loc_ret.value);
output output
.introduced_variables .introduced_variables

View file

@ -654,15 +654,10 @@ pub fn canonicalize_expr<'a>(
(RuntimeError(problem), Output::default()) (RuntimeError(problem), Output::default())
} }
ast::Expr::Defs(loc_defs, loc_ret) => { ast::Expr::Defs(loc_defs, loc_ret) => {
can_defs_with_return( // The body expression gets a new scope for canonicalization,
env, scope.inner_scope(|inner_scope| {
var_store, can_defs_with_return(env, var_store, inner_scope, loc_defs, loc_ret)
// The body expression gets a new scope for canonicalization, })
// so clone it.
scope.clone(),
loc_defs,
loc_ret,
)
} }
ast::Expr::Backpassing(_, _, _) => { ast::Expr::Backpassing(_, _, _) => {
unreachable!("Backpassing should have been desugared by now") unreachable!("Backpassing should have been desugared by now")
@ -685,14 +680,16 @@ pub fn canonicalize_expr<'a>(
let mut can_branches = Vec::with_capacity(branches.len()); let mut can_branches = Vec::with_capacity(branches.len());
for branch in branches.iter() { for branch in branches.iter() {
let (can_when_branch, branch_references) = canonicalize_when_branch( let (can_when_branch, branch_references) = scope.inner_scope(|inner_scope| {
env, canonicalize_when_branch(
var_store, env,
scope.clone(), var_store,
region, inner_scope,
*branch, region,
&mut output, *branch,
); &mut output,
)
});
output.references.union_mut(&branch_references); output.references.union_mut(&branch_references);
@ -956,17 +953,31 @@ pub fn canonicalize_closure<'a>(
loc_arg_patterns: &'a [Loc<ast::Pattern<'a>>], loc_arg_patterns: &'a [Loc<ast::Pattern<'a>>],
loc_body_expr: &'a Loc<ast::Expr<'a>>, loc_body_expr: &'a Loc<ast::Expr<'a>>,
opt_def_name: Option<Symbol>, opt_def_name: Option<Symbol>,
) -> (ClosureData, Output) {
scope.inner_scope(|inner_scope| {
canonicalize_closure_inner_scope(
env,
var_store,
inner_scope,
loc_arg_patterns,
loc_body_expr,
opt_def_name,
)
})
}
fn canonicalize_closure_inner_scope<'a>(
env: &mut Env<'a>,
var_store: &mut VarStore,
scope: &mut Scope,
loc_arg_patterns: &'a [Loc<ast::Pattern<'a>>],
loc_body_expr: &'a Loc<ast::Expr<'a>>,
opt_def_name: Option<Symbol>,
) -> (ClosureData, Output) { ) -> (ClosureData, Output) {
// The globally unique symbol that will refer to this closure once it gets converted // The globally unique symbol that will refer to this closure once it gets converted
// into a top-level procedure for code gen. // into a top-level procedure for code gen.
let symbol = opt_def_name.unwrap_or_else(|| env.gen_unique_symbol()); let symbol = opt_def_name.unwrap_or_else(|| env.gen_unique_symbol());
// The body expression gets a new scope for canonicalization.
// Shadow `scope` to make sure we don't accidentally use the original one for the
// rest of this block, but keep the original around for later diffing.
let original_scope = scope;
let mut scope = original_scope.clone();
let mut can_args = Vec::with_capacity(loc_arg_patterns.len()); let mut can_args = Vec::with_capacity(loc_arg_patterns.len());
let mut output = Output::default(); let mut output = Output::default();
@ -974,7 +985,7 @@ pub fn canonicalize_closure<'a>(
let can_argument_pattern = canonicalize_pattern( let can_argument_pattern = canonicalize_pattern(
env, env,
var_store, var_store,
&mut scope, scope,
&mut output, &mut output,
FunctionArg, FunctionArg,
&loc_pattern.value, &loc_pattern.value,
@ -990,7 +1001,7 @@ pub fn canonicalize_closure<'a>(
let (loc_body_expr, new_output) = canonicalize_expr( let (loc_body_expr, new_output) = canonicalize_expr(
env, env,
var_store, var_store,
&mut scope, scope,
loc_body_expr.region, loc_body_expr.region,
&loc_body_expr.value, &loc_body_expr.value,
); );
@ -1062,7 +1073,7 @@ pub fn canonicalize_closure<'a>(
fn canonicalize_when_branch<'a>( fn canonicalize_when_branch<'a>(
env: &mut Env<'a>, env: &mut Env<'a>,
var_store: &mut VarStore, var_store: &mut VarStore,
mut scope: Scope, scope: &mut Scope,
_region: Region, _region: Region,
branch: &'a ast::WhenBranch<'a>, branch: &'a ast::WhenBranch<'a>,
output: &mut Output, output: &mut Output,
@ -1074,7 +1085,7 @@ fn canonicalize_when_branch<'a>(
let can_pattern = canonicalize_pattern( let can_pattern = canonicalize_pattern(
env, env,
var_store, var_store,
&mut scope, scope,
output, output,
WhenBranch, WhenBranch,
&loc_pattern.value, &loc_pattern.value,
@ -1087,7 +1098,7 @@ fn canonicalize_when_branch<'a>(
let (value, mut branch_output) = canonicalize_expr( let (value, mut branch_output) = canonicalize_expr(
env, env,
var_store, var_store,
&mut scope, scope,
branch.value.region, branch.value.region,
&branch.value.value, &branch.value.value,
); );
@ -1096,7 +1107,7 @@ fn canonicalize_when_branch<'a>(
None => None, None => None,
Some(loc_expr) => { Some(loc_expr) => {
let (can_guard, guard_branch_output) = let (can_guard, guard_branch_output) =
canonicalize_expr(env, var_store, &mut scope, loc_expr.region, &loc_expr.value); canonicalize_expr(env, var_store, scope, loc_expr.region, &loc_expr.value);
branch_output.union(guard_branch_output); branch_output.union(guard_branch_output);
Some(can_guard) Some(can_guard)

View file

@ -285,11 +285,11 @@ pub fn canonicalize_module_defs<'a>(
} }
} }
let (defs, mut scope, output, symbols_introduced) = canonicalize_defs( let (defs, output, symbols_introduced) = canonicalize_defs(
&mut env, &mut env,
Output::default(), Output::default(),
var_store, var_store,
scope, &mut scope,
&desugared, &desugared,
PatternType::TopLevelDef, PatternType::TopLevelDef,
); );

View file

@ -355,7 +355,7 @@ impl Scope {
result result
} }
pub fn snapshot(&self) -> ScopeSnapshot { fn snapshot(&self) -> ScopeSnapshot {
ScopeSnapshot { ScopeSnapshot {
idents: self.idents.clone(), idents: self.idents.clone(),
aliases: self.aliases.clone(), aliases: self.aliases.clone(),
@ -364,7 +364,7 @@ impl Scope {
} }
} }
pub fn rollback(snapshot: ScopeSnapshot) -> Scope { fn rollback(snapshot: ScopeSnapshot) -> Scope {
Scope { Scope {
idents: snapshot.idents, idents: snapshot.idents,
aliases: snapshot.aliases, aliases: snapshot.aliases,