Skip to content

fs: compiled callback-async parity (readFile/writeFile/stat/… with callbacks) #970

Description

@nickna

Part of #968.

Problem

Callback-style async fs (fs.readFile(path, cb), fs.writeFile, fs.stat, fs.mkdir, fs.readdir, … ~20 functions) works in the interpreter but does not compile. FsModuleEmitter.TryEmitMethod's switch only lists sync methods, streams, watchers, and the constants/promises property-gets; the callback forms fall through to _ => false. This is a real interpreter↔compiled parity bug — code that runs interpreted silently fails to compile.

Reference (the interpreter already does this correctly)

FsModuleInterpreter.cs + FsAsyncHelpers.cs: extract callback → Ref()Task.Run(real async BCL I/O) → on completion ScheduleTimer(0, …) to invoke the callback with marshalled (err, result)Unref(). Callback is deferred to the next tick (Node-correct), never called synchronously.

The compiled event loop has the same capability, proven by timers: $EventLoop.Schedule(Action) + InvokeValue(callback, args) (RuntimeEmitter.TSEventLoop.cs, RuntimeEmitter.VirtualTimers.cs).

Scope

  • Add callback-form dispatch in FsModuleEmitter (detect trailing callback arg) for the full set the interpreter supports.
  • Emit/route through a runtime helper that runs the op, then $EventLoop.Schedule(() => InvokeValue(cb, [err, result])), with Ref/Unref bracketing.
  • Normalize errors to Node shape (err.code e.g. ENOENT) in the err argument.

Approach B note: if the primitive:fs facade lands first, this closes for free — the TS facade's callback wrapping compiles identically in both modes. Prefer doing the facade first; otherwise implement the emitter here.

Acceptance

  • Dual-mode tests: every callback-async fs function produces identical observable results interpreted vs compiled, including error (err.code) cases and next-tick ordering.
  • No regression in dotnet test / Test262 / conformance.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingenhancementNew feature or request

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions