From 02b2e944475f3790be1bd0bc61070a2707c5b306 Mon Sep 17 00:00:00 2001 From: Charles Lowell Date: Thu, 31 Jul 2025 14:43:16 -0500 Subject: [PATCH] =?UTF-8?q?=E2=9C=A8=20properly=20propagate=20errors=20fro?= =?UTF-8?q?m=20nested=20scopes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit There was a problem where raising errors within nested scopes was causing the outermost delimiter to have its outcome overwritten by its children propagating up. This changes delimiters so that their outcomes cannot be overwritten unless that outcome is, in fact, an error. --- lib/delimiter.ts | 9 ++++++--- test/scoped.test.ts | 17 +++++++++-------- test/spawn.test.ts | 1 - 3 files changed, 15 insertions(+), 12 deletions(-) diff --git a/lib/delimiter.ts b/lib/delimiter.ts index a9cd804af..c224410d7 100644 --- a/lib/delimiter.ts +++ b/lib/delimiter.ts @@ -50,13 +50,16 @@ export class Delimiter if (this.finalized) { return; } - this.outcome = outcome; + this.outcome = + (this.outcome && this.outcome.exists && !this.outcome.value.ok) + ? this.outcome + : outcome; this.level++; if (!this.routine) { this.finalized = true; - this.future.resolve(outcome); + this.future.resolve(this.outcome); } else { - this.routine.return(Ok(outcome)); + this.routine.return(Ok(this.outcome)); } } diff --git a/test/scoped.test.ts b/test/scoped.test.ts index c79b57c6a..3d8df697b 100644 --- a/test/scoped.test.ts +++ b/test/scoped.test.ts @@ -1,3 +1,4 @@ +import { box } from "../lib/box.ts"; import { createContext, resource, @@ -157,7 +158,7 @@ describe("scoped", () => { })); }); - it.skip("throws errors at the correct point when there are multiple nested scopes", async () => { + it("throws errors at the correct point when there are multiple nested scopes", async () => { let task = run(function* () { return yield* scoped(function* () { yield* spawn(function* () { @@ -165,13 +166,13 @@ describe("scoped", () => { throw new Error("boom!"); }); - try { - return yield* scoped(function* () { - yield* suspend(); - }); - } catch (error) { - return error; - } + yield* box(() => + scoped(function* () { + yield* scoped(function* () { + yield* suspend(); + }); + }) + ); }); }); diff --git a/test/spawn.test.ts b/test/spawn.test.ts index bf2545d1d..7469dd45c 100644 --- a/test/spawn.test.ts +++ b/test/spawn.test.ts @@ -122,7 +122,6 @@ describe("spawn", () => { await expect(root.halt()).rejects.toHaveProperty("message", "moo"); await expect(child!.halt()).rejects.toHaveProperty("message", "moo"); - await expect(root.halt()).rejects.toHaveProperty("message", "moo"); }); it("halts when child finishes during asynchronous halt", async () => {