Skip to content

Commit

Permalink
fix incorrect behavior of nested lambdas capturing non-captures of th…
Browse files Browse the repository at this point in the history
…eir parent
  • Loading branch information
simvux committed Dec 8, 2024
1 parent 7b4dc20 commit e10122b
Show file tree
Hide file tree
Showing 3 changed files with 7 additions and 39 deletions.
5 changes: 2 additions & 3 deletions lumina-compiler/src/hir/expr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -416,20 +416,19 @@ impl<'t, 'a, 's> FuncLower<'t, 'a, 's> {
let lkey = self
.lambdas
.create_placeholder(body.span, Forall::new(0), typing);
self.bindings.reference_lambda(lkey);

self.bindings.enter();
self.type_info.enter_lambda(lkey, Forall::new(0));

let patterns = self.patterns(apatterns);
let expr = self.expr(body);

let (captures, lcaptures) = self.bindings.leave();
let captures = self.bindings.leave();
let forall = self.type_info.leave_function();
assert!(forall.generics.is_empty());

self.lambdas
.complete_lambda("lambda", lkey, expr, patterns, captures, lcaptures);
.complete_lambda("lambda", lkey, expr, patterns, captures);

lkey
}
Expand Down
27 changes: 2 additions & 25 deletions lumina-compiler/src/hir/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -549,9 +549,6 @@ pub struct Lambdas<'s> {
pub params: Map<key::Lambda, Vec<Tr<Pattern<'s>>>>,
pub bodies: Map<key::Lambda, Tr<Expr<'s>>>,
pub captures: Map<key::Lambda, Vec<key::Bind>>,
// If this lambda references other lambdas, it'll need to inherit it's captures even though
// they aren't directly references. (Since they will be references in the next lower)
pub capture_lambdas: Map<key::Lambda, Vec<key::Lambda>>,
}

impl<'s> Lambdas<'s> {
Expand All @@ -569,7 +566,6 @@ impl<'s> Lambdas<'s> {
self.params.push_as(lkey, vec![]);
self.bodies.push_as(lkey, Expr::Poison.tr(span));
self.captures.push_as(lkey, vec![]);
self.capture_lambdas.push_as(lkey, vec![]);
lkey
}

Expand All @@ -580,13 +576,11 @@ impl<'s> Lambdas<'s> {
expr: Tr<Expr<'s>>,
patterns: Vec<Tr<Pattern<'s>>>,
captures: Vec<key::Bind>,
capture_lambdas: Vec<key::Lambda>,
) {
self.names[key] = name;
self.bodies[key] = expr;
self.params[key] = patterns;
self.captures[key] = captures;
self.capture_lambdas[key] = capture_lambdas;
}

pub fn is_empty(&self) -> bool {
Expand Down Expand Up @@ -699,22 +693,6 @@ impl<'t, 'a, 's> FuncLower<'t, 'a, 's> {
let mut func = FuncDef::new(RefCell::new(forall), typing, list, params, expr, no_mangle);
func.lambdas = self.lambdas;

// Copy all captures used by child lambda into the captures of the parent lambda for nesting
for lambda in func.lambdas.keys() {
for child in std::mem::take(&mut func.lambdas.capture_lambdas[lambda]) {
if lambda == child {
continue;
}

let [lcap, ccap] = func.lambdas.captures.get_many_mut([lambda, child]);
for bind in ccap {
if !lcap.contains(bind) {
lcap.push(*bind);
}
}
}
}

info!(
"func lowered to:\n {} {} {} {func}",
"fn".keyword(),
Expand Down Expand Up @@ -784,10 +762,10 @@ impl<'t, 'a, 's> FuncLower<'t, 'a, 's> {
);

let expr = self.expr(lbody.expr.as_ref());
let (captures, lcaptures) = self.bindings.leave();
let captures = self.bindings.leave();
let name = *fdecl.header.name;
self.lambdas
.complete_lambda(name, lkey, expr, patterns, captures, lcaptures);
.complete_lambda(name, lkey, expr, patterns, captures);
}

(params, expr)
Expand All @@ -810,7 +788,6 @@ impl<'t, 'a, 's> FuncLower<'t, 'a, 's> {
.position(|decl| *decl.header.name == name)
{
let lkey = key::Lambda::from(i);
self.bindings.reference_lambda(lkey);
return Some((Callable::Lambda(lkey), ToAnnotate::Some(None)));
}

Expand Down
14 changes: 3 additions & 11 deletions lumina-compiler/src/hir/scope.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ pub struct Bindings<'s> {
struct Scope<'s> {
binds: Vec<(key::Bind, &'s str)>,
captures: Vec<key::Bind>,
references_lambdas: Vec<key::Lambda>,
}

impl<'s> Default for Bindings<'s> {
Expand All @@ -29,17 +28,9 @@ impl<'s> Bindings<'s> {
pub fn enter(&mut self) {
self.scopes.push(Scope::default());
}
pub fn leave(&mut self) -> (Captures, Vec<key::Lambda>) {
pub fn leave(&mut self) -> Captures {
let scope = self.scopes.pop().unwrap();
(scope.captures, scope.references_lambdas)
}

pub fn reference_lambda(&mut self, lambda: key::Lambda) {
self.scopes
.last_mut()
.unwrap()
.references_lambdas
.push(lambda);
scope.captures
}

pub fn declare_nameless(&mut self) -> key::Bind {
Expand Down Expand Up @@ -73,6 +64,7 @@ impl<'s> Bindings<'s> {
.or_else(|| {
Self::resolve_in(xs, name).map(|bind| {
if !scope.captures.contains(&bind) {
trace!("capturing {bind}");
scope.captures.push(bind);
}
bind
Expand Down

0 comments on commit e10122b

Please sign in to comment.