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

Configure Feed

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

Review fixes: clean up comments, fix test names, add arrow tests, guard throw_into_generator

- Remove stream-of-consciousness comments in async_resume_callback, replace
with concise doc explaining the actual mechanism
- Rename misleading test_async_arrow_* tests to test_async_function_expression*
(they tested function expressions, not arrows)
- Add real async arrow function tests using `async x => ...` syntax
- Add Executing state guard to throw_into_generator for consistency with
run_generator (prevents re-entrancy)

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

+37 -23
+37 -23
crates/js/src/vm.rs
··· 1486 1486 if gen.state == GeneratorState::Completed { 1487 1487 return Ok(self.make_iterator_result(Value::Undefined, true)); 1488 1488 } 1489 + if gen.state == GeneratorState::Executing { 1490 + return Err(RuntimeError::type_error("Generator is already executing")); 1491 + } 1489 1492 ( 1490 1493 gen.func.clone(), 1491 1494 gen.upvalues.clone(), ··· 3412 3415 /// Native callback for async function resume. Called from microtask drain. 3413 3416 /// Returns a marker object with `__async_resume__` so the VM can detect it 3414 3417 /// and call `drive_async_step`. 3418 + /// 3419 + /// The resume data (gen_ref, result_promise, is_throw) is stored on the 3420 + /// function's `__async_data__` property. The VM extracts it into the 3421 + /// `ASYNC_RESUME_DATA` thread-local before invoking this callback. 3415 3422 fn async_resume_callback(args: &[Value], ctx: &mut NativeContext) -> Result<Value, RuntimeError> { 3416 - // The resume data is stored on the function's own properties. 3417 - // We need to find the function ref from the calling convention. 3418 - // Since NativeContext doesn't provide function-self, we store data on the 3419 - // function object's properties and read them from global __async_current_fn__. 3420 - // 3421 - // Alternative approach: the callback itself reads from ctx.gc using a 3422 - // known __async_data__ property on the function. However, we don't have 3423 - // the function's GcRef here. 3424 - // 3425 - // Workaround: store the data in a global variable set before calling. 3426 - 3427 - // Actually, the simplest approach: pass the data as extra information. 3428 - // We set __async_data__ as a property of the function, and the VM's 3429 - // call_function / Call handler extracts it from the function before 3430 - // calling the native callback. 3431 - 3432 - // For now, use a sentinel return value that the VM intercepts. 3433 3423 let value = args.first().cloned().unwrap_or(Value::Undefined); 3434 - 3435 - // We need the async data (gen_ref, result_promise, is_throw). 3436 - // The data was stored on the function's properties. We read from 3437 - // a thread-local set by the VM before calling us. 3438 3424 let data_ref = ASYNC_RESUME_DATA.with(|cell| cell.take()); 3439 3425 if let Some(data) = data_ref { 3440 3426 let gen_ref = match gc_get_property(ctx.gc, data, "__gen_ref__") { ··· 7340 7326 } 7341 7327 7342 7328 #[test] 7343 - fn test_async_arrow_function() { 7329 + fn test_async_function_expression() { 7344 7330 match eval_global( 7345 7331 "var f = async function() { var x = await Promise.resolve(99); return x; }; 7346 7332 f().then(function(v) { result = v; });", ··· 7354 7340 } 7355 7341 7356 7342 #[test] 7357 - fn test_async_arrow_concise_body() { 7343 + fn test_async_function_expression_with_args() { 7358 7344 match eval_global( 7359 7345 "var f = async function(x) { return x * 2; }; 7360 7346 f(21).then(function(v) { result = v; });", ··· 7364 7350 { 7365 7351 Value::Number(n) => assert_eq!(n, 42.0), 7366 7352 v => panic!("expected 42, got {v:?}"), 7353 + } 7354 + } 7355 + 7356 + #[test] 7357 + fn test_async_arrow_function() { 7358 + match eval_global( 7359 + "var f = async x => { var y = await Promise.resolve(x); return y + 1; }; 7360 + f(10).then(function(v) { result = v; });", 7361 + "result", 7362 + ) 7363 + .unwrap() 7364 + { 7365 + Value::Number(n) => assert_eq!(n, 11.0), 7366 + v => panic!("expected 11, got {v:?}"), 7367 + } 7368 + } 7369 + 7370 + #[test] 7371 + fn test_async_arrow_concise_body() { 7372 + match eval_global( 7373 + "var f = async x => x * 3; 7374 + f(7).then(function(v) { result = v; });", 7375 + "result", 7376 + ) 7377 + .unwrap() 7378 + { 7379 + Value::Number(n) => assert_eq!(n, 21.0), 7380 + v => panic!("expected 21, got {v:?}"), 7367 7381 } 7368 7382 } 7369 7383