denoland / deno

A modern runtime for JavaScript and TypeScript.
https://deno.com
MIT License
94.49k stars 5.24k forks source link

`using` in a `for... of` loop fails to call `Symbol.dispose` method (+ same problem for `async` versions) #25757

Open lionel-rowe opened 1 week ago

lionel-rowe commented 1 week ago

Version: Deno 1.46.3

I initially thought this was a bug with TS, but compiling TS via the playground and running it in Chrome works correctly, as does running it in Bun.

Using using within a for... of loop fails to call the Symbol.dispose method. The same problem occurs when using awaiting using using await using using Symbol.asyncDispose:

class Disposable {
    disposed = false;

    [Symbol.dispose]() {
        this.disposed = true
    }
}

const disposables = [new Disposable()]

for (using _ of disposables) {/* ... */}

if (disposables[0]!.disposed) {
    console.log("✅ dispose ok")
} else {
    console.error("💥 failed to dispose")
}

class AsyncDisposable {
    disposed = false;

    [Symbol.asyncDispose]() {
        this.disposed = true
    }
}

const asyncDisposables = [new AsyncDisposable()]

for (await using _ of asyncDisposables) {/* ... */}

if (asyncDisposables[0]!.disposed) {
    console.log("✅ async dispose ok")
} else {
    console.error("💥 failed to async dispose")
}

Keywords: using, using using, using await using, awaiting using await using

marvinhagemeister commented 1 week ago

Seems like an SWC transpilation issue. I've put the reproduction code into their playground and the transpiled output matches exactly what we run in Deno. Running the transpiled output on its own inhibits the described error and the dispose hooks aren't called.

Filed an upstream issue here https://github.com/swc-project/swc/issues/9576