From a34b399c3a7df49baf4c9ce6a581de5b22fe342b Mon Sep 17 00:00:00 2001 From: Mel Date: Tue, 26 May 2026 04:31:41 +0200 Subject: Support multi-level closure captures Signed-off-by: Mel --- boot/lower.c | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) (limited to 'boot/lower.c') 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, }; } } -- cgit 1.4.1