mirror of
https://github.com/roc-lang/roc.git
synced 2025-09-30 23:31:12 +00:00
use snapshots for inner scopes
This commit is contained in:
parent
70844b1218
commit
5a613db7b6
4 changed files with 54 additions and 51 deletions
|
@ -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
|
||||||
|
|
|
@ -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(
|
|
||||||
env,
|
|
||||||
var_store,
|
|
||||||
// The body expression gets a new scope for canonicalization,
|
// The body expression gets a new scope for canonicalization,
|
||||||
// so clone it.
|
scope.inner_scope(|inner_scope| {
|
||||||
scope.clone(),
|
can_defs_with_return(env, var_store, inner_scope, loc_defs, loc_ret)
|
||||||
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| {
|
||||||
|
canonicalize_when_branch(
|
||||||
env,
|
env,
|
||||||
var_store,
|
var_store,
|
||||||
scope.clone(),
|
inner_scope,
|
||||||
region,
|
region,
|
||||||
*branch,
|
*branch,
|
||||||
&mut output,
|
&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)
|
||||||
|
|
|
@ -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,
|
||||||
);
|
);
|
||||||
|
|
|
@ -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,
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue