for-in rejects records that may be null or undefined
维护者通常 1 天内回复
评估
- 难度
- 4/5
- 预计耗时
- 3-5 天
- 新手友好度
- 25/100
- Issue 类型
- 功能
- 描述清晰度
- 描述清楚
- 活跃度
- 活跃
- 技术栈
- node.js, typescript
- 领域
- compilers
调研方向
A pull request (#2406) already proposes a fix, so pick this up from that branch rather than starting fresh. Read lowerForIn in packages/compiler/src/frontend/lowering/lower-stmts.ts and note how it dispatches on the receiver's IR kind before reaching the unsupported-receiver branch that emits SC1052; the approach is to bind the receiver once, branch on the present record tag and reuse the existing typed record walk. Reproduce with the repro.ts snippet and node packages/cli/dist/main.js coverage repro.ts --print diagnostics, and check that coverage treats the loop as a runtime fence rather than a preflight error. Done means null and undefined iterate zero times, a side-effecting receiver evaluates once, and the listed regression cases (deletion during enumeration, labels, shared cursor bindings, per-iteration closures) pass with unchanged codegen for existing typed loops.
由索引模型根据 Issue 内容生成。
描述
We are trying to compile a complete Node.js CLI and its existing JavaScript dependencies with scriptc. One remaining language gap is a loop over an object that may be missing.
JavaScript allows for-in over null or undefined: the loop simply runs zero times. scriptc can already enumerate the object itself, but rejects a parameter whose type also allows either missing value.
Reproduction
Save as repro.ts:
function keys(value: { a: number } | null | undefined): string {
let result = "";
for (const key in value) result += key;
return result;
}
console.log("[" + keys(null) + "] [" + keys(undefined) + "] [" + keys({ a: 1 }) + "]");
Node executes it successfully:
$ node repro.ts
[] [] [a]
After building the scriptc workspace, run:
node packages/cli/dist/main.js coverage repro.ts --print diagnostics
The loop reports:
SC1052: for-in over '{ a: number; } | null | undefined' receivers (records, index-signature shapes, arrays, and globalThis enumerate) are not supported yet
The same refusal occurs with { a: number } | null and { a: number } | undefined. Coverage can report this as a runtime fence rather than a preflight error, so a successful frontend result alone does not mean the loop will execute.
Expected behavior
Null and undefined should perform zero iterations. A present record should use the existing record enumeration behavior. The receiver expression must be evaluated exactly once, including when it returns a nullish value.
Where the boundary occurs
lowerForIn in packages/compiler/src/frontend/lowering/lower-stmts.ts dispatches directly on the receiver's IR kind. It handles records, arrays and checked-dynamic values, but a union with one record arm and only nullish alternatives reaches the unsupported-receiver branch.
A narrow fix can bind the receiver once, branch on the present record tag, then reuse the existing typed record walk. That would preserve live deletion checks, loop binding forms, labels and per-iteration captures without introducing new runtime semantics. Tuples and other unsupported union families can retain their current fences.
Scope and regression coverage
This reproduction uses an explicitly typed parameter. It does not depend on hoisted locals or widening a JavaScript binding after assignment, the neighboring work in #1907.
Useful regression cases include null/undefined no-ops, a side-effecting receiver expression, fixed and index-signature records, deletion/addition during enumeration, shared cursor bindings, labeled break/continue, and closures capturing each iteration's key. Existing typed loops should retain the same generated code.
Proposed fix and regression tests: #2406.
Tested environment
Reproduced with a source build from scriptc’s main development branch on macOS arm64, using Node 24.22.0 and matching native compiler/runtime packages. The source build reports version 0.4.5. The original gap was also checked against later main changes before opening the linked PR.
- 主要语言
- TypeScript
- 星标
- 6.4k
- 派生
- 204
- 平均合并
- 7 小时 23 分钟
- 30 天内合并 PR
- 887
环境准备
- 没有 Dockerfile 或 Docker Compose 文件
- 没有 Pull Request 模板
- 阅读贡献指南
从这里开始
- 先读完整个 Issue,再读项目的贡献指南。
- 在 Issue 下留言说明你要接手 —— 这能避免两个人做同样的事。
- Fork 仓库,在一个分支上完成修改。
- 提交 Pull Request,并在描述里引用这个 Issue 编号。
vercel-labs/scriptc 的其他 Issue
-
难度 5/5 一周以上 新手友好度 20/100
vercel-labs/scriptc#2209 ·
维护者通常 1 天内回复
-
难度 4/5 3-5 天 新手友好度 49/100
vercel-labs/scriptc#2143 ·
维护者通常 1 天内回复
-
难度 4/5 3-5 天 新手友好度 56/100
vercel-labs/scriptc#1993 ·
维护者通常 1 天内回复
-
难度 5/5 一周以上 新手友好度 32/100
vercel-labs/scriptc#1777 · 1 条评论 ·
维护者通常 1 天内回复
-
Support WebAssembly SIMD instructions in ahead-of-time translation可能已有人在做 @jlucaso1 于 7 天前认领。 未关闭
难度 5/5 一周以上 新手友好度 45/100
vercel-labs/scriptc#1679 ·
维护者通常 1 天内回复
查看 vercel-labs/scriptc 的全部 Issue
相似的 Issue
-
难度 2/5 1-3 小时 新手友好度 72/100
维护者通常 1 天内回复
-
enhancement tech debt
难度 2/5 1-3 小时 新手友好度 78/100
维护者通常 1 天内回复
-
难度 2/5 1-3 小时 新手友好度 68/100
privatenumber/tsx#866 ·
-
难度 2/5 1-3 小时 新手友好度 62/100
danielmiessler/LifeOS#2533 ·
维护者通常 9 天内回复
-
auto:producer auto:uiux
难度 2/5 1-3 小时 新手友好度 78/100
fritzprix/libr-agent#2447 ·
维护者通常 1 天内回复