Skip to content

[codegen/closures] preserve concrete class info on captured class instances#655

Closed
cs01 wants to merge 0 commit intomainfrom
issue-646-closure-class
Closed

[codegen/closures] preserve concrete class info on captured class instances#655
cs01 wants to merge 0 commit intomainfrom
issue-646-closure-class

Conversation

@cs01
Copy link
Copy Markdown
Owner

@cs01 cs01 commented Apr 22, 2026

Before

A closure that captured a class instance by value lost the concrete class name. Inside the lambda body, capturedVar.field couldn't find the class struct for GEP, so the load used the field's nominal type against whatever alloca held the capture. Pointer/string fields segfaulted; number fields returned garbage.

class T { h: string = "hello"; }
const t = new T();
setTimeout(() => { console.log(t.h); }, 10); // printed garbage

After

Captured class instances retain their concrete class in the inner scope, so capturedVar.field generates the correct GEP + load. The repro above prints hello.

Description

Closes #646. Step 3b of #640.

Threads the concreteClass of outer-scope vars from the symbol table through ClosureAnalyzer and into CapturedVariable records, then — inside the lambda body — calls symbolTable.setConcreteClass(name, className) on the re-bound capture after the normal defineVariable call.

Why this isn't PR #644 (closed)

PR #644 took the same plumbing path but re-bound captures via defineVariableWithMetadata(..., createClassMetadata(...)) instead of defineVariable. That completely swapped the symbol's metadata object — losing fields like isPointerAlloca that other codegen paths depended on — and stage 1 self-hosting silently stopped rejecting "hello" - 5 in the binary-type-in-function fixture.

This PR keeps the existing defineVariable call untouched and only adds the concreteClass field to the already-defined symbol via the existing setConcreteClass setter. No metadata is replaced. The binary-type-in-function fixture still fails to compile as expected on stages 0/1/2.

~82 LOC across 10 files.

Verification

  • Full npm run verify (stages 0/1/2) green.
  • tests/fixtures/semantic/binary-type-in-function.ts still emits the cannot use '-' between 'string' and 'number' compile error.
  • New fixture tests/fixtures/closures-cabi/closure-captures-class-field-string.ts prints TEST_PASSED on stages 0/1/2.

@github-actions
Copy link
Copy Markdown
Contributor

Benchmark Results (Linux x86-64)

Benchmark C ChadScript Go Node Place
Fibonacci 0.816s 0.765s 1.562s 3.168s 🥇
Hash Map Lookup 0.091s 0.062s 0.090s 0.118s 🥇
Binary Trees 1.358s 1.241s 2.827s 1.200s 🥈
Cold Start 0.8ms 0.9ms 1.2ms 27.0ms 🥈
File I/O 0.118s 0.091s 0.086s 0.200s 🥈
JSON Parse/Stringify 0.037s 0.051s 0.175s 0.133s 🥈
N-Body Simulation 1.670s 2.118s 2.210s 2.394s 🥈
Regex Match 0.016s 0.005s 0.021s 0.004s 🥈
SQLite 0.052s 0.369s 0.490s 0.409s 🥈
Monte Carlo Pi 0.389s 0.412s 0.405s 2.251s 🥉
Quicksort 0.214s 0.247s 0.213s 0.262s 🥉
Sieve of Eratosthenes 0.014s 0.027s 0.018s 0.039s 🥉
String Manipulation 0.008s 0.019s 0.017s 0.037s 🥉
Matrix Multiply 0.439s 0.715s 0.609s 0.377s #4

CLI Tool Benchmarks

Benchmark ChadScript grep node xxd Place
Hex Dump 0.645s 0.881s 0.130s 🥈
Recursive Grep 0.022s 0.011s 0.106s 🥈

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[codegen] concreteClass propagation through closure capture breaks stage1 binary-type check

1 participant