about summary refs log tree commit diff
path: root/boot/lower.c
diff options
context:
space:
mode:
Diffstat (limited to 'boot/lower.c')
-rw-r--r--boot/lower.c18
1 files changed, 13 insertions, 5 deletions
diff --git a/boot/lower.c b/boot/lower.c
index 81f39a5..4d00c5d 100644
--- a/boot/lower.c
+++ b/boot/lower.c
@@ -41,8 +41,8 @@ struct Lower_Local_Lookup_Capture
     bool captured;
     // the captured local's declared type
     struct Type_Ref type;
-    // which function does this capture belong to?
-    struct Function* captured_into;
+    // the function the local lives in.
+    struct Function* owner;
 };
 
 // what kind of scope is this?
@@ -924,6 +924,7 @@ void lower_record_capture(struct Function* fn, struct String name, struct Type_R
 void lower_push_scope_function(struct Lower_Context* ctx, struct Function* owner);
 void lower_pop_scope(struct Lower_Context* ctx, enum Scope_Type expected);
 void lower_declare_local(struct Lower_Context* ctx, struct String name, struct Type_Ref type);
+struct Function* lower_current_function(struct Lower_Context* ctx);
 
 struct Expression*
 lower_expression_integer_literal(struct Lower_Context* ctx, struct Tree_Expression* tree_expr)
@@ -971,7 +972,12 @@ lower_expression_name(struct Lower_Context* ctx, struct Tree_Expression* tree_ex
     // locals that were defined in an upper function scope are captured.
     struct Lower_Local_Lookup_Capture lookup = lower_local_lookup_capturing(ctx, name);
     if (lookup.captured) {
-        lower_record_capture(lookup.captured_into, name, lookup.type);
+        struct Function* fn = lower_current_function(ctx);
+        // we walk the enclosing function chain to record every in-between capture.
+        while (fn && fn != lookup.owner) {
+            lower_record_capture(fn, name, lookup.type);
+            fn = fn->parent_function;
+        }
         return ir_make_capture_ref(name, tree_expr->span);
     }
 
@@ -1318,6 +1324,7 @@ lower_expression_function(struct Lower_Context* ctx, struct Tree_Expression* tre
 
     struct Function* fn = *array_at(struct Function*, &ctx->unit->functions.entries, id);
     fn->synthetic = true;
+    fn->parent_function = lower_current_function(ctx);
     lower_fill_function_signature(ctx, fn, tree_expr);
 
     // lower the body inline so name lookups inside see the enclosing
@@ -1507,7 +1514,8 @@ lower_local_lookup(struct Lower_Context* ctx, struct String name, struct Type_Re
 
 // walk the scope stack looking for a local, which could be captured.
 // if the local was declared in some enclosing function that's not us,
-// the local becomes captured by our closure function.
+// the local becomes captured by our closure function (and any lambdas
+// nested between us and the local's owner).
 struct Lower_Local_Lookup_Capture
 lower_local_lookup_capturing(struct Lower_Context* ctx, struct String name)
 {
@@ -1522,7 +1530,7 @@ lower_local_lookup_capturing(struct Lower_Context* ctx, struct String name)
             return (struct Lower_Local_Lookup_Capture){
                 .captured = from_enclosing,
                 .type = var->type,
-                .captured_into = from_enclosing ? current : nil,
+                .owner = scope->containing_function,
             };
         }
     }