Skip to content

SC9001 internal compiler error on Buffer.from(<island call>) where new Uint8Array(...) reports cleanly #35

Description

@vinikjkkj

Summary

Under --dynamic, passing an island call expression directly to Buffer.from() crashes the compiler with an internal error. The equivalent new Uint8Array(...) construction over the same expression emits a clean SC2020 with an actionable hint. Both hit the same underlying situation — a byte-container constructor over an any-typed value returned from the embedded engine — so the Buffer.from path looks like it is missing the guard that the Uint8Array path has.

Environment

scriptc 0.0.17 (@scriptc/compiler 0.0.17)
OS Ubuntu 24.04, x86_64
clang 18.1.3
cmake 3.28.3
Node (baseline) 22.22.2
npm package under test zapo-js@1.6.2 (any package returning a Uint8Array reproduces)

Repro

tsconfig.json:

{
  "compilerOptions": {
    "target": "es2022",
    "module": "nodenext",
    "moduleResolution": "nodenext",
    "strict": true,
    "types": ["node"],
    "skipLibCheck": true
  }
}

repro.ts:

import { sha256 } from "zapo-js/crypto";
console.log(Buffer.from(sha256(Buffer.from("zapo"))).toString("hex"));
$ scriptc build repro.ts --dynamic
error SC9001: internal compiler error: in main: bytesNew source of kind jsval — please report this

  1 | import { sha256 } from "zapo-js/crypto";
  2 | console.log(Buffer.from(sha256(Buffer.from("zapo"))).toString("hex"));
    |             ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Also fires as in %init.0 when the nested call sits in a top-level const.

Contrast: the Uint8Array path

Same shape, no Buffer anywhere:

import { sha256 } from "zapo-js/crypto";
const input = new Uint8Array([122, 97, 112, 111]);
const c = new Uint8Array(sha256(input));
error SC2020: 'new Uint8Array over 'any' values' is part of the standard library types
but has no scriptc lowering yet

  hint: supported: new Uint8Array(), (length), (typedArray) — always a copy — or
  (number[]); ArrayBuffers and views do not exist here (narrow unions first)

Clean diagnostic, code frame, actionable hint. That is the behaviour I would expect from the Buffer.from case too.

Workaround

Binding the call to a const first makes the declared .d.ts type apply instead of any, and both constructors then work:

const r = sha256(input);
const c = new Uint8Array(r);   // ok, copies
const b = Buffer.from(r);      // ok

Notes

Everything else I tried on island-returned Uint8Array values works through an intermediate binding: .length, indexing, .slice(), .subarray(), .set(), and passing to a statically-compiled TS function. The one other rejection I hit was r instanceof Uint8ArraySC1090.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions