we (web engine): Experimental web browser project to understand the limits of Claude
3
fork

Configure Feed

Select the types of activity you want to include in your feed.

Fix closure capture for destructuring, catch params, and class decls

Remaining define_local() calls in destructuring patterns, catch
parameters, and class declarations did not check captured_names,
causing closures that capture these variables to fail at runtime.
Replace all with define_local_ext() + proper cell allocation, and
remove the now-unused define_local() method.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

+34 -13
+34 -13
crates/js/src/compiler.rs
··· 107 107 .unwrap_or(false) 108 108 } 109 109 110 - /// Define a local variable. 111 - fn define_local(&mut self, name: &str) -> Reg { 112 - self.define_local_ext(name, false, false) 113 - } 114 - 115 110 /// Define a local variable with capture and const flags. 116 111 fn define_local_ext(&mut self, name: &str, is_captured: bool, is_const: bool) -> Reg { 117 112 let reg = self.alloc_reg(); ··· 1018 1013 // Bind the catch parameter if present. 1019 1014 if let Some(param) = &catch.param { 1020 1015 if let PatternKind::Identifier(name) = &param.kind { 1021 - let local = fc.define_local(name); 1022 - fc.builder.emit_reg_reg(Op::Move, local, catch_reg); 1016 + let is_captured = fc.captured_names.contains(name.as_str()); 1017 + let local = fc.define_local_ext(name, is_captured, false); 1018 + if is_captured { 1019 + fc.builder.emit_reg(Op::NewCell, local); 1020 + fc.builder.emit_reg_reg(Op::CellStore, local, catch_reg); 1021 + } else { 1022 + fc.builder.emit_reg_reg(Op::Move, local, catch_reg); 1023 + } 1023 1024 } 1024 1025 } 1025 1026 ··· 1129 1130 ) -> Result<(), JsError> { 1130 1131 match &pattern.kind { 1131 1132 PatternKind::Identifier(name) => { 1132 - let reg = fc.define_local(name); 1133 - fc.builder.emit_reg_reg(Op::Move, reg, src); 1133 + let is_captured = fc.captured_names.contains(name.as_str()); 1134 + let reg = fc.define_local_ext(name, is_captured, false); 1135 + if is_captured { 1136 + fc.builder.emit_reg(Op::NewCell, reg); 1137 + fc.builder.emit_reg_reg(Op::CellStore, reg, src); 1138 + } else { 1139 + fc.builder.emit_reg_reg(Op::Move, reg, src); 1140 + } 1134 1141 } 1135 1142 PatternKind::Object { 1136 1143 properties, ··· 1342 1349 1343 1350 fn compile_class_decl(fc: &mut FunctionCompiler, class_def: &ClassDef) -> Result<(), JsError> { 1344 1351 let name = class_def.id.clone().unwrap_or_default(); 1345 - let reg = fc.define_local(&name); 1352 + let is_captured = fc.captured_names.contains(name.as_str()); 1353 + let reg = fc.define_local_ext(&name, is_captured, false); 1354 + 1355 + // For captured classes, build the constructor into a temp register so we can 1356 + // set prototype methods on it before wrapping it in a cell. 1357 + let ctor_reg = if is_captured { fc.alloc_reg() } else { reg }; 1346 1358 1347 1359 // Find constructor or create empty one. 1348 1360 let ctor = class_def.body.iter().find(|m| { ··· 1359 1371 if let ClassMemberKind::Method { value, .. } = &member.kind { 1360 1372 let inner = compile_function_body_with_captures(fc, value)?; 1361 1373 let func_idx = fc.builder.add_function(inner); 1362 - fc.builder.emit_reg_u16(Op::CreateClosure, reg, func_idx); 1374 + fc.builder 1375 + .emit_reg_u16(Op::CreateClosure, ctor_reg, func_idx); 1363 1376 } 1364 1377 } else { 1365 1378 // No constructor: create a minimal function that returns undefined. ··· 1369 1382 empty.emit_reg(Op::LoadUndefined, r); 1370 1383 empty.emit_reg(Op::Return, r); 1371 1384 let func_idx = fc.builder.add_function(empty.finish()); 1372 - fc.builder.emit_reg_u16(Op::CreateClosure, reg, func_idx); 1385 + fc.builder 1386 + .emit_reg_u16(Op::CreateClosure, ctor_reg, func_idx); 1373 1387 } 1374 1388 1375 1389 // Compile methods: set them as properties on the constructor's prototype. ··· 1396 1410 fc.builder 1397 1411 .emit_reg_u16(Op::CreateClosure, method_reg, func_idx); 1398 1412 let name_idx = fc.builder.add_name(&method_name); 1399 - fc.builder.emit_set_prop_name(reg, name_idx, method_reg); 1413 + fc.builder 1414 + .emit_set_prop_name(ctor_reg, name_idx, method_reg); 1400 1415 fc.free_reg(method_reg); 1401 1416 } 1402 1417 ClassMemberKind::Property { .. } => { 1403 1418 // Class fields are set in constructor; skip here. 1404 1419 } 1405 1420 } 1421 + } 1422 + 1423 + if is_captured { 1424 + fc.builder.emit_reg(Op::NewCell, reg); 1425 + fc.builder.emit_reg_reg(Op::CellStore, reg, ctor_reg); 1426 + fc.free_reg(ctor_reg); 1406 1427 } 1407 1428 1408 1429 Ok(())