Environment
- scriptc: 0.0.36
- OS: macOS 26.5 (arm64), Darwin 25.5.0
- Node: v24.20.0
- Install:
npm install scriptc@0.0.36 (bin: node_modules/scriptc/dist/bootstrap.js)
Summary
An any-typed local variable used with an operator inside a function body is rejected by scriptc build --dynamic with SC2011, even though scriptc coverage --dynamic on the same file classifies that exact statement as a "runs with --dynamic" (dynamically-eligible) site rather than a rejected blocker. The identical operation on an any-typed function parameter builds and runs correctly under --dynamic. coverage and build --dynamic disagree about whether the local-variable site is coverable.
Repro — failing shape (local variable)
local-any.ts:
function f(): number {
const x: any = JSON.parse("41");
return x + 1;
}
console.log(f());
$ scriptc build local-any.ts --dynamic
local-any.ts:3:10 - error SC2011: the '+' operator on 'any'-typed values runs in the embedded dynamic engine, which this build does not include
2 | const x: any = JSON.parse("41");
3 | return x + 1;
| ^~~~~
4 | }
hint: build with --dynamic to run 'any'-typed code in the embedded engine (adds ~620KB to the binary), or stay static with 'unknown' and a checked cast ('x as T')
1 error.
scriptc run local-any.ts --dynamic fails identically.
$ scriptc coverage local-any.ts --dynamic
scriptc coverage local-any.ts
statements analyzed 3
compile statically 2 (66%)
compile dynamically 0 (0%) (island sites — the embedded engine runs them)
runs with --dynamic 1 site (embeds a JS engine, ~620KB — static stays the default)
×1 the '+' operator on 'any'-typed values runs in the embedded dynamic engine, which this build does not include SC2011
coverage puts this SC2011 site under "runs with --dynamic" (the dynamically-capable bucket, not the "blockers:" section) — i.e. it reports the site as coverable by --dynamic. build --dynamic rejects the same site with the same SC2011 instead of lowering it to the embedded engine.
Working shape (function parameter) — for comparison
param-any.ts:
function dynamicProof(v: any): number {
return v + 1;
}
console.log(dynamicProof(JSON.parse("41")));
$ scriptc build param-any.ts --dynamic -o param-any.exe
param-any.exe
$ ./param-any.exe
42
$ scriptc coverage param-any.ts --dynamic
scriptc coverage param-any.ts
statements analyzed 2
compile statically 1 (50%)
compile dynamically 1 (50%) (island sites — the embedded engine runs them)
builds with --dynamic — no remaining blockers (the island sites above run in the embedded engine).
Here the any value crosses a function-parameter boundary instead of staying in a local, coverage reports "no remaining blockers", and build --dynamic builds and runs correctly (prints 42).
Expected
For the local-variable shape, either:
build --dynamic lowers the x + 1 site to the embedded dynamic engine and builds/runs successfully (matching what coverage --dynamic reports), or
coverage --dynamic lists the site under blockers: (not under "runs with --dynamic") so the two commands agree that the site is not actually dynamically coverable.
Actual
coverage --dynamic classifies the site as dynamically-eligible ("runs with --dynamic", SC2011 in the dynamic-capable bucket), but build --dynamic (and run --dynamic) reject the exact same statement with SC2011, saying the operator "runs in the embedded dynamic engine, which this build does not include" — despite --dynamic being passed and the engine being embedded (as proven by the parameter-boundary shape building and running with the same flag).
Workaround
Move the any value across a function-parameter boundary (pass it into a function that takes an any parameter and operate on the parameter there) instead of binding it to a local const/let before operating on it. This builds and runs correctly under --dynamic.
Environment
npm install scriptc@0.0.36(bin:node_modules/scriptc/dist/bootstrap.js)Summary
An
any-typed local variable used with an operator inside a function body is rejected byscriptc build --dynamicwithSC2011, even thoughscriptc coverage --dynamicon the same file classifies that exact statement as a "runs with --dynamic" (dynamically-eligible) site rather than a rejected blocker. The identical operation on anany-typed function parameter builds and runs correctly under--dynamic.coverageandbuild --dynamicdisagree about whether the local-variable site is coverable.Repro — failing shape (local variable)
local-any.ts:scriptc run local-any.ts --dynamicfails identically.coverageputs this SC2011 site under "runs with --dynamic" (the dynamically-capable bucket, not the "blockers:" section) — i.e. it reports the site as coverable by--dynamic.build --dynamicrejects the same site with the same SC2011 instead of lowering it to the embedded engine.Working shape (function parameter) — for comparison
param-any.ts:Here the
anyvalue crosses a function-parameter boundary instead of staying in a local,coveragereports "no remaining blockers", andbuild --dynamicbuilds and runs correctly (prints42).Expected
For the local-variable shape, either:
build --dynamiclowers thex + 1site to the embedded dynamic engine and builds/runs successfully (matching whatcoverage --dynamicreports), orcoverage --dynamiclists the site underblockers:(not under "runs with --dynamic") so the two commands agree that the site is not actually dynamically coverable.Actual
coverage --dynamicclassifies the site as dynamically-eligible ("runs with --dynamic",SC2011in the dynamic-capable bucket), butbuild --dynamic(andrun --dynamic) reject the exact same statement withSC2011, saying the operator "runs in the embedded dynamic engine, which this build does not include" — despite--dynamicbeing passed and the engine being embedded (as proven by the parameter-boundary shape building and running with the same flag).Workaround
Move the
anyvalue across a function-parameter boundary (pass it into a function that takes ananyparameter and operate on the parameter there) instead of binding it to a localconst/letbefore operating on it. This builds and runs correctly under--dynamic.