mirror of
https://github.com/roc-lang/roc.git
synced 2025-09-26 13:29:12 +00:00
Address PR comments, add syntax tests
This commit is contained in:
parent
b3e60f9d3a
commit
7518a2c5ab
28 changed files with 772 additions and 34 deletions
|
@ -2640,7 +2640,13 @@ fn canonicalize_pending_body<'a>(
|
|||
|
||||
// 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 == *defined_symbol => Recursive::TailRecursive,
|
||||
Some(tail_symbol) if tail_symbol == *defined_symbol => {
|
||||
if closure_data.early_returns.is_empty() {
|
||||
Recursive::TailRecursive
|
||||
} else {
|
||||
Recursive::Recursive
|
||||
}
|
||||
}
|
||||
_ => Recursive::NotRecursive,
|
||||
};
|
||||
|
||||
|
|
|
@ -1017,7 +1017,7 @@ pub fn canonicalize_expr<'a>(
|
|||
}
|
||||
ast::Expr::Defs(loc_defs, loc_ret) => {
|
||||
// The body expression gets a new scope for canonicalization,
|
||||
scope.inner_scope(false, |inner_scope| {
|
||||
scope.inner_def_scope(|inner_scope| {
|
||||
let defs: Defs = (*loc_defs).clone();
|
||||
can_defs_with_return(env, var_store, inner_scope, env.arena.alloc(defs), loc_ret)
|
||||
})
|
||||
|
@ -1049,17 +1049,16 @@ pub fn canonicalize_expr<'a>(
|
|||
let mut can_branches = Vec::with_capacity(branches.len());
|
||||
|
||||
for branch in branches.iter() {
|
||||
let (can_when_branch, branch_references) =
|
||||
scope.inner_scope(false, |inner_scope| {
|
||||
canonicalize_when_branch(
|
||||
env,
|
||||
var_store,
|
||||
inner_scope,
|
||||
region,
|
||||
branch,
|
||||
&mut output,
|
||||
)
|
||||
});
|
||||
let (can_when_branch, branch_references) = scope.inner_def_scope(|inner_scope| {
|
||||
canonicalize_when_branch(
|
||||
env,
|
||||
var_store,
|
||||
inner_scope,
|
||||
region,
|
||||
branch,
|
||||
&mut output,
|
||||
)
|
||||
});
|
||||
|
||||
output.references.union_mut(&branch_references);
|
||||
|
||||
|
@ -1534,7 +1533,7 @@ pub fn canonicalize_closure<'a>(
|
|||
loc_body_expr: &'a Loc<ast::Expr<'a>>,
|
||||
opt_def_name: Option<Symbol>,
|
||||
) -> (ClosureData, Output) {
|
||||
scope.inner_scope(true, |inner_scope| {
|
||||
scope.inner_function_scope(|inner_scope| {
|
||||
canonicalize_closure_body(
|
||||
env,
|
||||
var_store,
|
||||
|
|
|
@ -432,7 +432,8 @@ impl Scope {
|
|||
self.aliases.contains_key(&name)
|
||||
}
|
||||
|
||||
pub fn inner_scope<F, T>(&mut self, entering_function: bool, f: F) -> T
|
||||
/// Enter an inner scope within a definition, e.g. a def or when block.
|
||||
pub fn inner_def_scope<F, T>(&mut self, f: F) -> T
|
||||
where
|
||||
F: FnOnce(&mut Scope) -> T,
|
||||
{
|
||||
|
@ -449,11 +450,6 @@ impl Scope {
|
|||
let locals_snapshot = self.locals.in_scope.len();
|
||||
let imported_symbols_snapshot = self.imported_symbols.len();
|
||||
let imported_modules_snapshot = self.modules.len();
|
||||
let early_returns_snapshot = if entering_function {
|
||||
std::mem::replace(&mut self.early_returns, Vec::new())
|
||||
} else {
|
||||
Vec::new()
|
||||
};
|
||||
|
||||
let result = f(self);
|
||||
|
||||
|
@ -461,9 +457,6 @@ impl Scope {
|
|||
self.ignored_locals.truncate(ignored_locals_count);
|
||||
self.imported_symbols.truncate(imported_symbols_snapshot);
|
||||
self.modules.truncate(imported_modules_snapshot);
|
||||
if entering_function {
|
||||
self.early_returns = early_returns_snapshot;
|
||||
}
|
||||
|
||||
// anything added in the inner scope is no longer in scope now
|
||||
for i in locals_snapshot..self.locals.in_scope.len() {
|
||||
|
@ -473,6 +466,20 @@ impl Scope {
|
|||
result
|
||||
}
|
||||
|
||||
/// Enter an inner scope within a child function, e.g. a closure body.
|
||||
pub fn inner_function_scope<F, T>(&mut self, f: F) -> T
|
||||
where
|
||||
F: FnOnce(&mut Scope) -> T,
|
||||
{
|
||||
let early_returns_snapshot = std::mem::replace(&mut self.early_returns, Vec::new());
|
||||
|
||||
let result = self.inner_def_scope(f);
|
||||
|
||||
self.early_returns = early_returns_snapshot;
|
||||
|
||||
result
|
||||
}
|
||||
|
||||
pub fn register_debug_idents(&self) {
|
||||
self.home.register_debug_idents(&self.locals.ident_ids)
|
||||
}
|
||||
|
@ -879,7 +886,7 @@ mod test {
|
|||
}
|
||||
|
||||
#[test]
|
||||
fn inner_scope_does_not_influence_outer() {
|
||||
fn inner_def_scope_does_not_influence_outer() {
|
||||
let _register_module_debug_names = ModuleIds::default();
|
||||
let mut scope = Scope::new(
|
||||
ModuleId::ATTR,
|
||||
|
@ -893,7 +900,7 @@ mod test {
|
|||
|
||||
assert!(scope.lookup(&ident, region).is_err());
|
||||
|
||||
scope.inner_scope(false, |inner| {
|
||||
scope.inner_def_scope(|inner| {
|
||||
assert!(inner.introduce(ident.clone(), region).is_ok());
|
||||
});
|
||||
|
||||
|
@ -919,7 +926,7 @@ mod test {
|
|||
}
|
||||
|
||||
#[test]
|
||||
fn idents_with_inner_scope() {
|
||||
fn idents_with_inner_def_scope() {
|
||||
let _register_module_debug_names = ModuleIds::default();
|
||||
let mut scope = Scope::new(
|
||||
ModuleId::ATTR,
|
||||
|
@ -954,7 +961,7 @@ mod test {
|
|||
&[ident1.clone(), ident2.clone(), ident3.clone(),]
|
||||
);
|
||||
|
||||
scope.inner_scope(false, |inner| {
|
||||
scope.inner_def_scope(|inner| {
|
||||
let ident4 = Ident::from("Ångström");
|
||||
let ident5 = Ident::from("Sirály");
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue