@scriptc/compiler 0.2.1 → 0.2.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (193) hide show
  1. package/ambient/scriptc-node-fallback.d.ts +59 -4
  2. package/dist/backend/llvm/dyn.d.ts +3 -0
  3. package/dist/backend/llvm/dyn.js +84 -12
  4. package/dist/backend/llvm/dyn.js.map +1 -1
  5. package/dist/backend/llvm/emitter.d.ts +4 -1
  6. package/dist/backend/llvm/emitter.js +20 -5
  7. package/dist/backend/llvm/emitter.js.map +1 -1
  8. package/dist/backend/llvm/emitter.test.js +9 -1
  9. package/dist/backend/llvm/emitter.test.js.map +1 -1
  10. package/dist/backend/llvm/expr-containers.js +5 -0
  11. package/dist/backend/llvm/expr-containers.js.map +1 -1
  12. package/dist/backend/llvm/expr-dynamic.js +30 -5
  13. package/dist/backend/llvm/expr-dynamic.js.map +1 -1
  14. package/dist/backend/llvm/expr-stream-bridges.js +70 -9
  15. package/dist/backend/llvm/expr-stream-bridges.js.map +1 -1
  16. package/dist/backend/llvm/expr-stream-callbacks.d.ts +2 -2
  17. package/dist/backend/llvm/expr-stream-callbacks.js +7 -57
  18. package/dist/backend/llvm/expr-stream-callbacks.js.map +1 -1
  19. package/dist/backend/llvm/lib-dispatch.js +41 -3
  20. package/dist/backend/llvm/lib-dispatch.js.map +1 -1
  21. package/dist/backend/llvm/lib-filesystem.js +12 -9
  22. package/dist/backend/llvm/lib-filesystem.js.map +1 -1
  23. package/dist/backend/llvm/lib-shared.js +35 -1
  24. package/dist/backend/llvm/lib-shared.js.map +1 -1
  25. package/dist/backend/may-throw.js +4 -0
  26. package/dist/backend/may-throw.js.map +1 -1
  27. package/dist/backend/native-codegen.d.ts +1 -1
  28. package/dist/backend/native-codegen.js +4 -3
  29. package/dist/backend/native-codegen.js.map +1 -1
  30. package/dist/backend/native-codegen.test.js +11 -0
  31. package/dist/backend/native-codegen.test.js.map +1 -1
  32. package/dist/backend/target-diagnostics.d.ts +5 -0
  33. package/dist/backend/target-diagnostics.js +72 -1
  34. package/dist/backend/target-diagnostics.js.map +1 -1
  35. package/dist/backend/target-diagnostics.test.d.ts +1 -0
  36. package/dist/backend/target-diagnostics.test.js +68 -0
  37. package/dist/backend/target-diagnostics.test.js.map +1 -0
  38. package/dist/coverage/surface-manifest.js +5 -3
  39. package/dist/coverage/surface-manifest.js.map +1 -1
  40. package/dist/executable/executable-cache.d.ts +7 -3
  41. package/dist/executable/executable-cache.js +47 -11
  42. package/dist/executable/executable-cache.js.map +1 -1
  43. package/dist/executable/executable-cache.test.js +109 -2
  44. package/dist/executable/executable-cache.test.js.map +1 -1
  45. package/dist/executable/prepare.js +2 -1
  46. package/dist/executable/prepare.js.map +1 -1
  47. package/dist/frontend/builtin-modules.d.ts +1 -1
  48. package/dist/frontend/builtin-modules.js +1 -1
  49. package/dist/frontend/builtin-modules.js.map +1 -1
  50. package/dist/frontend/function-completion.d.ts +6 -0
  51. package/dist/frontend/function-completion.js +50 -0
  52. package/dist/frontend/function-completion.js.map +1 -0
  53. package/dist/frontend/lowering/abstract-equality.js +5 -1
  54. package/dist/frontend/lowering/abstract-equality.js.map +1 -1
  55. package/dist/frontend/lowering/checked-iterable-spread.d.ts +4 -0
  56. package/dist/frontend/lowering/checked-iterable-spread.js +30 -0
  57. package/dist/frontend/lowering/checked-iterable-spread.js.map +1 -0
  58. package/dist/frontend/lowering/checked-promise-all.d.ts +5 -0
  59. package/dist/frontend/lowering/checked-promise-all.js +31 -0
  60. package/dist/frontend/lowering/checked-promise-all.js.map +1 -0
  61. package/dist/frontend/lowering/class-callbacks.d.ts +1 -1
  62. package/dist/frontend/lowering/class-callbacks.js +7 -6
  63. package/dist/frontend/lowering/class-callbacks.js.map +1 -1
  64. package/dist/frontend/lowering/class-construction.d.ts +2 -0
  65. package/dist/frontend/lowering/class-construction.js +34 -5
  66. package/dist/frontend/lowering/class-construction.js.map +1 -1
  67. package/dist/frontend/lowering/class-descriptors.d.ts +1 -1
  68. package/dist/frontend/lowering/class-descriptors.js +12 -5
  69. package/dist/frontend/lowering/class-descriptors.js.map +1 -1
  70. package/dist/frontend/lowering/class-dynamic-dispatch.d.ts +25 -0
  71. package/dist/frontend/lowering/class-dynamic-dispatch.js +597 -78
  72. package/dist/frontend/lowering/class-dynamic-dispatch.js.map +1 -1
  73. package/dist/frontend/lowering/class-dynamic-dispatch.test.js +64 -2
  74. package/dist/frontend/lowering/class-dynamic-dispatch.test.js.map +1 -1
  75. package/dist/frontend/lowering/class-instance-constructor.d.ts +1 -1
  76. package/dist/frontend/lowering/class-instance-constructor.js +11 -41
  77. package/dist/frontend/lowering/class-instance-constructor.js.map +1 -1
  78. package/dist/frontend/lowering/class-method-values.d.ts +16 -0
  79. package/dist/frontend/lowering/class-method-values.js +60 -29
  80. package/dist/frontend/lowering/class-method-values.js.map +1 -1
  81. package/dist/frontend/lowering/class-prototypes.d.ts +5 -1
  82. package/dist/frontend/lowering/class-prototypes.js +69 -10
  83. package/dist/frontend/lowering/class-prototypes.js.map +1 -1
  84. package/dist/frontend/lowering/class-runtime-statics.d.ts +4 -4
  85. package/dist/frontend/lowering/class-runtime-statics.js +26 -8
  86. package/dist/frontend/lowering/class-runtime-statics.js.map +1 -1
  87. package/dist/frontend/lowering/class-static-data.d.ts +1 -0
  88. package/dist/frontend/lowering/class-static-data.js +4 -2
  89. package/dist/frontend/lowering/class-static-data.js.map +1 -1
  90. package/dist/frontend/lowering/containers/bytes.js +17 -4
  91. package/dist/frontend/lowering/containers/bytes.js.map +1 -1
  92. package/dist/frontend/lowering/containers/string-and-regexp.js +6 -1
  93. package/dist/frontend/lowering/containers/string-and-regexp.js.map +1 -1
  94. package/dist/frontend/lowering/deferred-module-initializers.d.ts +13 -0
  95. package/dist/frontend/lowering/deferred-module-initializers.js +410 -0
  96. package/dist/frontend/lowering/deferred-module-initializers.js.map +1 -0
  97. package/dist/frontend/lowering/deferred-module-initializers.test.d.ts +1 -0
  98. package/dist/frontend/lowering/deferred-module-initializers.test.js +92 -0
  99. package/dist/frontend/lowering/deferred-module-initializers.test.js.map +1 -0
  100. package/dist/frontend/lowering/expressions/object-literals.js +31 -1
  101. package/dist/frontend/lowering/expressions/object-literals.js.map +1 -1
  102. package/dist/frontend/lowering/expressions/optional-chains.js +3 -3
  103. package/dist/frontend/lowering/expressions/optional-chains.js.map +1 -1
  104. package/dist/frontend/lowering/lower-builtins.d.ts +4 -9
  105. package/dist/frontend/lowering/lower-builtins.js +291 -51
  106. package/dist/frontend/lowering/lower-builtins.js.map +1 -1
  107. package/dist/frontend/lowering/lower-calls.js +283 -73
  108. package/dist/frontend/lowering/lower-calls.js.map +1 -1
  109. package/dist/frontend/lowering/lower-classes.d.ts +5 -0
  110. package/dist/frontend/lowering/lower-classes.js +439 -25
  111. package/dist/frontend/lowering/lower-classes.js.map +1 -1
  112. package/dist/frontend/lowering/lower-containers.d.ts +1 -1
  113. package/dist/frontend/lowering/lower-containers.js +39 -17
  114. package/dist/frontend/lowering/lower-containers.js.map +1 -1
  115. package/dist/frontend/lowering/lower-exprs.d.ts +10 -6
  116. package/dist/frontend/lowering/lower-exprs.js +294 -129
  117. package/dist/frontend/lowering/lower-exprs.js.map +1 -1
  118. package/dist/frontend/lowering/lower-generators.js +5 -1
  119. package/dist/frontend/lowering/lower-generators.js.map +1 -1
  120. package/dist/frontend/lowering/lower-inspect.js +15 -1
  121. package/dist/frontend/lowering/lower-inspect.js.map +1 -1
  122. package/dist/frontend/lowering/lower-island.js +4 -0
  123. package/dist/frontend/lowering/lower-island.js.map +1 -1
  124. package/dist/frontend/lowering/lower-island.test.d.ts +1 -0
  125. package/dist/frontend/lowering/lower-island.test.js +51 -0
  126. package/dist/frontend/lowering/lower-island.test.js.map +1 -0
  127. package/dist/frontend/lowering/lower-modules.d.ts +1 -3
  128. package/dist/frontend/lowering/lower-modules.js +186 -82
  129. package/dist/frontend/lowering/lower-modules.js.map +1 -1
  130. package/dist/frontend/lowering/lower-modules.test.js +69 -1
  131. package/dist/frontend/lowering/lower-modules.test.js.map +1 -1
  132. package/dist/frontend/lowering/lower-stmts.js +100 -35
  133. package/dist/frontend/lowering/lower-stmts.js.map +1 -1
  134. package/dist/frontend/lowering/lower-stmts.test.d.ts +1 -0
  135. package/dist/frontend/lowering/lower-stmts.test.js +77 -0
  136. package/dist/frontend/lowering/lower-stmts.test.js.map +1 -0
  137. package/dist/frontend/lowering/lower-stream.js +2 -0
  138. package/dist/frontend/lowering/lower-stream.js.map +1 -1
  139. package/dist/frontend/lowering/lower-url.d.ts +2 -1
  140. package/dist/frontend/lowering/lower-url.js +32 -9
  141. package/dist/frontend/lowering/lower-url.js.map +1 -1
  142. package/dist/frontend/lowering/lowerer.d.ts +26 -9
  143. package/dist/frontend/lowering/lowerer.js +218 -27
  144. package/dist/frontend/lowering/lowerer.js.map +1 -1
  145. package/dist/frontend/lowering/lowerer.test.js +38 -0
  146. package/dist/frontend/lowering/lowerer.test.js.map +1 -1
  147. package/dist/frontend/lowering/module-namespace-elements.d.ts +7 -0
  148. package/dist/frontend/lowering/module-namespace-elements.js +54 -0
  149. package/dist/frontend/lowering/module-namespace-elements.js.map +1 -0
  150. package/dist/frontend/lowering/object-factory-new.d.ts +4 -3
  151. package/dist/frontend/lowering/object-factory-new.js +27 -14
  152. package/dist/frontend/lowering/object-factory-new.js.map +1 -1
  153. package/dist/frontend/lowering/surfaces.d.ts +1 -0
  154. package/dist/frontend/lowering/surfaces.js +24 -12
  155. package/dist/frontend/lowering/surfaces.js.map +1 -1
  156. package/dist/frontend/lowering/text-decoder-encoding.js +3 -0
  157. package/dist/frontend/lowering/text-decoder-encoding.js.map +1 -1
  158. package/dist/frontend/lowering/text-decoder-encoding.test.js +2 -1
  159. package/dist/frontend/lowering/text-decoder-encoding.test.js.map +1 -1
  160. package/dist/frontend/program.js +4 -2
  161. package/dist/frontend/program.js.map +1 -1
  162. package/dist/frontend/type-mapper.js +83 -14
  163. package/dist/frontend/type-mapper.js.map +1 -1
  164. package/dist/frontend/union-discriminants.js +22 -7
  165. package/dist/frontend/union-discriminants.js.map +1 -1
  166. package/dist/index.js +16 -10
  167. package/dist/index.js.map +1 -1
  168. package/dist/ir/ir.d.ts +27 -13
  169. package/dist/ir/ir.js +26 -2
  170. package/dist/ir/ir.js.map +1 -1
  171. package/dist/ir/serialize.js +21 -1
  172. package/dist/ir/serialize.js.map +1 -1
  173. package/dist/ir/serialize.test.js +21 -0
  174. package/dist/ir/serialize.test.js.map +1 -1
  175. package/dist/ir/traverse.d.ts +0 -3
  176. package/dist/ir/traverse.js +33 -20
  177. package/dist/ir/traverse.js.map +1 -1
  178. package/dist/ir/validate.js +56 -5
  179. package/dist/ir/validate.js.map +1 -1
  180. package/dist/ir/validate.test.js +17 -1
  181. package/dist/ir/validate.test.js.map +1 -1
  182. package/dist/library/compiler-self-identity.js +1 -1
  183. package/dist/library/compiler-self-identity.test.js +2 -2
  184. package/dist/library/compiler-self-identity.test.js.map +1 -1
  185. package/dist/library/int-infer.d.ts +2 -2
  186. package/dist/library/int-infer.js +10 -7
  187. package/dist/library/int-infer.js.map +1 -1
  188. package/dist/library/int-infer.test.js +44 -0
  189. package/dist/library/int-infer.test.js.map +1 -1
  190. package/dist/library/prepare.js +2 -1
  191. package/dist/library/prepare.js.map +1 -1
  192. package/package.json +20 -20
  193. package/surface-manifest.json +115 -13
@@ -19,19 +19,19 @@ import { isProvenanceSourceFile } from "../provenance-registry.js";
19
19
  import { ambientUndefVarRootOf, lowerImportEquals, nsUndefRead, nsWritableTarget, trapDeclRootOf } from "./lower-namespaces.js";
20
20
  import { expandoWritableTarget, lowerExpandoAssignStmt } from "./lower-expando.js";
21
21
  import { lowerForOfArrayIter, lowerForOfMap, lowerForOfSearchParams, lowerForOfSet, lowerSafeIndexRead, objectIterOverIndexShape, strCharsCall } from "./lower-containers.js";
22
- import { bindingContextualGenericFnNodeOf, bindingGenericFnAliasInfoOf, bindingGenericFnInfoOf, bindingGenericFnNodeOf, bindingNeverReassigned, deadUnmappableBinding, implicitLocalFnInfoOf, implicitLocalFnNodeOf, implicitMethodCallInfersReturn, nullishExprUnitOf, nullishGenericBindingUnitOf, recordKeysArrayCall, registerOverloadedCallableAlias } from "./lower-calls.js";
22
+ import { bindingContextualGenericFnNodeOf, bindingGenericFnAliasInfoOf, bindingGenericFnInfoOf, bindingGenericFnNodeOf, bindingNeverReassigned, deadUnmappableBinding, hasExplicitJsDocReturn, implicitLocalFnInfoOf, implicitLocalFnNodeOf, implicitMethodCallInfersReturn, nullishExprUnitOf, nullishGenericBindingUnitOf, recordKeysArrayCall, registerOverloadedCallableAlias } from "./lower-calls.js";
23
23
  import { isMixinFnBinding, mixinResultBindingClassOf } from "./lower-mixins.js";
24
24
  import { isCompiledPrototypeMember } from "./class-prototypes.js";
25
25
  import { classStaticDataFor } from "./class-static-data.js";
26
26
  import { objectFactorySignature } from "./object-factory-new.js";
27
27
  import { isClassCallback, lowerClassCallbackAssign } from "./class-callbacks.js";
28
- import { classPropertiesHelper } from "./class-dynamic-dispatch.js";
28
+ import { classForInHasKey, classPropertiesHelper } from "./class-dynamic-dispatch.js";
29
29
  import { genericIfaceBindingKeepsClass, staticFieldWriteTarget } from "./lower-classes.js";
30
30
  import { lowerStreamUnderscoreAssign, streamClassAliasDecl } from "./lower-stream.js";
31
31
  import { lowerHttpResPropertyAssignment, lowerHttpServerTimeoutAssignment, lowerServerCloseOverrideAssignment } from "./lower-server.js";
32
32
  import { isNativeFfiRequire, builtinMemberRequireDecl, builtinNamespaceDestructureModuleOf, createRequireBindingDecl, createRequireCalleeFileOf, createRequireNamespaceDecl, createRequireProgramModuleDecl, createRequireProgramModuleOf, lowerNodeModuleCall, registerBuiltinCallableAlias } from "./lower-builtins.js";
33
33
  import { lowerEnumDeclaration } from "./lower-enums.js";
34
- import { abstractPropertyDeclOf, aliasTypeofNarrows, isMatchSliceType, lowerAbsenceProbe, lowerCompoundValueToTarget, lowerElementCompound, lowerGroupsProjection, matchResultNamedGroupsOf, runtimeOptionalGuardIds, runtimeOptionalTrueIds, symbolFieldInfo, withRuntimeOptionalNarrowed } from "./lower-exprs.js";
34
+ import { abstractPropertyDeclOf, aliasTypeofNarrows, isMatchSliceType, lowerAbsenceProbe, lowerCompoundValueToTarget, lowerElementCompound, lowerIncDec, lowerGroupsProjection, matchResultNamedGroupsOf, runtimeOptionalGuardIds, runtimeOptionalTrueIds, symbolFieldInfo, withRuntimeOptionalNarrowed } from "./lower-exprs.js";
35
35
  import { isSafeToRepeat } from "./expressions/evaluation-safety.js";
36
36
  import { globalSymbolKey } from "./expressions/global-symbols.js";
37
37
  import { lowerShortCircuitAssignment } from "./expressions/nullish-assignment.js";
@@ -71,6 +71,8 @@ function npmStaticReturnedEmptyArrayType(lowerer, decl) {
71
71
  const ownerBody = owner !== undefined && ts.isFunctionLike(owner) ? owner.body : undefined;
72
72
  if (ownerBody === undefined || !ts.isBlock(ownerBody))
73
73
  return null;
74
+ if (owner && ts.isFunctionLike(owner) && !owner.type && !hasExplicitJsDocReturn(owner))
75
+ return null;
74
76
  let returned = false;
75
77
  ts.walkPreorder(ownerBody, (node) => {
76
78
  if (node !== ownerBody && ts.isFunctionLike(node))
@@ -593,7 +595,12 @@ export function predeclareForwardCapture(lowerer, symbol) {
593
595
  // TDZ read until the initializing assign completes — JS exactly.
594
596
  if (idx < entry.index || entry.ctx === lowerer.ctx || entry.ctx.tdzPredeclared.has(symbol))
595
597
  return false;
596
- const type = lowerer.irTypeOf(decl.name);
598
+ let type = lowerer.irTypeOf(decl.name);
599
+ if (isJsSourceFile(decl.getSourceFile()) && !decl.type && !hasJsTypeAnnotation(decl) &&
600
+ (ts.isObjectLiteralExpression(decl.initializer) ||
601
+ (ts.isCallExpression(decl.initializer) && ts.isPropertyAccessExpression(decl.initializer.expression) &&
602
+ decl.initializer.expression.name.text === "assign" && lowerer.isStdlibGlobal(decl.initializer.expression.expression, "Object"))) && lowerer.dynConvertible(type))
603
+ type = DYN;
597
604
  if (!TDZ_KINDS.has(type.kind) || isUnitType(type))
598
605
  return false;
599
606
  const name = decl.name.text;
@@ -1035,12 +1042,9 @@ export function lowerStmt(lowerer, stmt) {
1035
1042
  // (JS), which the undefined arm carries — tsc only allows the bare
1036
1043
  // form when the return type includes undefined/void. A CHECKED-
1037
1044
  // DYNAMIC return slot holds the dyn undefined directly (the
1038
- // appendImplicitUndefinedReturn rule). What remains is JS-only —
1039
- // a JSDoc return claim the body contradicts (ms's parse: `@return
1040
- // {Number}` with a bare early `return;`): no undefined fits the
1041
- // declared representation, so the statement fences honestly (the
1042
- // per-statement JS deferral — the claimed paths still run) instead
1043
- // of slipping an empty return past the validator.
1045
+ // appendImplicitUndefinedReturn rule). JavaScript signatures include
1046
+ // observed empty returns even when JSDoc omits undefined. Any remaining
1047
+ // incompatible boundary keeps the ordinary per-statement refusal.
1044
1048
  let value = null;
1045
1049
  if (stmt.expression) {
1046
1050
  return lowerer.lowerReturnStmt(stmt.expression, locOf(stmt));
@@ -1885,6 +1889,10 @@ export function lowerBindingPattern(lowerer, pattern, srcRef, srcType, isLet, ou
1885
1889
  // scoped TypeScript exception: its declared result/token types are
1886
1890
  // deliberately carried by the checked-dynamic tree, so their ordinary
1887
1891
  // object patterns use the same exact keyed-read desugar.
1892
+ if (srcType.kind === "union" && isJsSourceFile(pattern.getSourceFile()) && lowerer.dynConvertible(srcType)) {
1893
+ lowerer.lowerBindingPattern(pattern, () => lowerer.coerceToExpected(srcRef(), DYN), DYN, isLet, out, dynSpell, allowDynObject);
1894
+ return;
1895
+ }
1888
1896
  if (srcType.kind === "dyn") {
1889
1897
  for (const el of pattern.elements) {
1890
1898
  if (el.name === undefined)
@@ -3323,7 +3331,7 @@ function inferredEvolvingLetType(lowerer, decl) {
3323
3331
  invalid = true;
3324
3332
  return "stop";
3325
3333
  }
3326
- if (ts.isCallExpression(node.right) && implicitMethodCallInfersReturn(lowerer, node.right)) {
3334
+ if (ts.isCallExpression(node.right) && (implicitMethodCallInfersReturn(lowerer, node.right) || isJsSourceFile(node.right.getSourceFile()))) {
3327
3335
  invalid = true;
3328
3336
  return "stop";
3329
3337
  }
@@ -3545,7 +3553,8 @@ export function lowerVarDecl(lowerer, decl, isLet) {
3545
3553
  : (declSymbol ? lowerer.globalsBySymbol.get(declSymbol) : undefined);
3546
3554
  if (g) {
3547
3555
  let promotedGlobal = lowerer.runtimeOptionalBindingType(decl.name, g.type);
3548
- if (g.type.kind === "func" && decl.initializer !== undefined && ts.isIdentifier(decl.initializer)) {
3556
+ if (g.type.kind === "func" && !decl.type && !hasJsTypeAnnotation(decl) &&
3557
+ decl.initializer !== undefined && ts.isIdentifier(decl.initializer)) {
3549
3558
  const sig = lowerer.fnSigOf(decl.initializer);
3550
3559
  if (sig) {
3551
3560
  promotedGlobal = {
@@ -3579,6 +3588,10 @@ export function lowerVarDecl(lowerer, decl, isLet) {
3579
3588
  }
3580
3589
  const raw = lowerVariableInitializer(lowerer, decl.initializer, g.type.kind === "dyn" && (isNativeBuiltinValueInitializer(lowerer, decl.initializer) ||
3581
3590
  ts.isArrayLiteralExpression(decl.initializer) || ts.isObjectLiteralExpression(decl.initializer)) ? DYN : undefined);
3591
+ if (isJsSourceFile(decl.getSourceFile()) && !decl.type && !hasJsTypeAnnotation(decl) && raw.type.kind === "dyn" &&
3592
+ (g.type.kind === "record" || g.type.kind === "object"))
3593
+ g.type = DYN;
3594
+ g.type = inferredOptionalRecordType(lowerer, decl, g.type, raw.type);
3582
3595
  const arithmetic = raw.type.kind === "union"
3583
3596
  ? lowerer.unions.get(raw.type.unionId)?.arms
3584
3597
  : undefined;
@@ -3651,7 +3664,10 @@ export function lowerVarDecl(lowerer, decl, isLet) {
3651
3664
  ? lowerer.unions.get(inferredObjectType.unionId)?.arms ?? [] : inferredObjectType ? [inferredObjectType] : [];
3652
3665
  const expandsObject = !decl.type && !hasJsTypeAnnotation(decl) && inferredObjectType !== null &&
3653
3666
  jsOpenObjectType(decl, inferredObjectType, lowerer.shapes, lowerer.unions).kind === "dyn" ||
3654
- inferredObjectArms.some((arm) => arm.kind === "record" && jsObjectBindingExpands(lowerer, decl, arm));
3667
+ inferredObjectArms.some((arm) => arm.kind === "record" && jsObjectBindingExpands(lowerer, decl, arm)) ||
3668
+ isJsSourceFile(decl.getSourceFile()) && !decl.type && !hasJsTypeAnnotation(decl) &&
3669
+ ts.isObjectLiteralExpression(decl.initializer) && decl.initializer.properties.some((property) => ts.isMethodDeclaration(property) || ts.isAccessor(property) || ts.isPropertyAssignment(property) &&
3670
+ (ts.isFunctionExpression(property.initializer) || ts.isArrowFunction(property.initializer)));
3655
3671
  let init;
3656
3672
  try {
3657
3673
  init = expandsObject || (isJsSourceFile(decl.getSourceFile()) && !decl.type &&
@@ -3806,6 +3822,8 @@ export function lowerVarDecl(lowerer, decl, isLet) {
3806
3822
  type = init.type;
3807
3823
  runtimeOptional = true;
3808
3824
  }
3825
+ if (type !== null)
3826
+ type = inferredOptionalRecordType(lowerer, decl, type, init.type);
3809
3827
  // A JS binding whose checker type spells a FUNCTION but whose VALUE is
3810
3828
  // already checked-dynamic (`const cb = mustCall(fn)` — the helper's
3811
3829
  // return rides its own box): keep the box. Extracting into the spelled
@@ -3817,6 +3835,9 @@ export function lowerVarDecl(lowerer, decl, isLet) {
3817
3835
  !decl.type && !hasJsTypeAnnotation(decl) && type.rest === true && type.restAbi === undefined)) {
3818
3836
  type = DYN;
3819
3837
  }
3838
+ if (isJsSourceFile(decl.getSourceFile()) && !decl.type && !hasJsTypeAnnotation(decl) && init.type.kind === "dyn" &&
3839
+ (type?.kind === "record" || type?.kind === "object"))
3840
+ type = DYN;
3820
3841
  // A checker-`any` CONST whose initializer lowered to a STATIC type
3821
3842
  // (`const name = rawName ? rawName.replace(...) : null` — the
3822
3843
  // dyn-receiver machinery and the any-ternary join answer static IR):
@@ -3987,6 +4008,21 @@ export function lowerVarDecl(lowerer, decl, isLet) {
3987
4008
  }
3988
4009
  return { kind: "varDecl", localId: local.id, init, loc: locOf(decl) };
3989
4010
  }
4011
+ // lib.d.ts declares named captures as strings, but nonparticipating captures
4012
+ // are undefined. Inferred index records retain that runtime representation;
4013
+ // explicit annotations still require a checked conversion at the boundary.
4014
+ function inferredOptionalRecordType(lowerer, decl, declared, actual) {
4015
+ if (decl.type || hasJsTypeAnnotation(decl) || declared.kind !== "record" || actual.kind !== "record")
4016
+ return declared;
4017
+ const target = lowerer.shapes.get(declared.shapeId);
4018
+ const source = lowerer.shapes.get(actual.shapeId);
4019
+ if (!target || !source || target.fields.length || source.fields.length || target.tuple || source.tuple ||
4020
+ !target.indexValue || source.indexValue?.kind !== "union" ||
4021
+ lowerer.armTag(source.indexValue.unionId, UNDEFINED_T) < 0 ||
4022
+ !typeEquals(lowerer.stripUndefinedArm(source.indexValue), target.indexValue))
4023
+ return declared;
4024
+ return actual;
4025
+ }
3990
4026
  function lowerVariableInitializer(lowerer, node, expected) {
3991
4027
  let value = node;
3992
4028
  while (ts.isParenthesizedExpression(value) ||
@@ -4132,18 +4168,24 @@ export function jsBindingHasOpenWrites(lowerer, decl) {
4132
4168
  let owner = decl;
4133
4169
  while (owner.parent && !ts.isFunctionLike(owner) && !ts.isSourceFile(owner))
4134
4170
  owner = owner.parent;
4135
- let open = false;
4136
- ts.walkPreorder(owner, (node) => {
4137
- if (ts.isBinaryExpression(node) && node.operatorToken.kind >= ts.SyntaxKind.FirstAssignment &&
4138
- node.operatorToken.kind <= ts.SyntaxKind.LastAssignment && ts.isIdentifier(node.left) &&
4139
- lowerer.resolveValueSymbol(node.left) === symbol &&
4140
- (lowerer.typeOf(node.right).flags & (ts.TypeFlags.Any | ts.TypeFlags.Unknown)) !== 0) {
4141
- open = true;
4142
- return "stop";
4143
- }
4144
- return undefined;
4145
- });
4146
- return open;
4171
+ let writes = lowerer.jsBindingWritesByOwner.get(owner);
4172
+ if (!writes) {
4173
+ const indexed = new Map();
4174
+ ts.walkPreorder(owner, (node) => {
4175
+ if (!ts.isBinaryExpression(node) || node.operatorToken.kind < ts.SyntaxKind.FirstAssignment ||
4176
+ node.operatorToken.kind > ts.SyntaxKind.LastAssignment || !ts.isIdentifier(node.left))
4177
+ return;
4178
+ const entries = indexed.get(node.left.text);
4179
+ if (entries)
4180
+ entries.push(node);
4181
+ else
4182
+ indexed.set(node.left.text, [node]);
4183
+ });
4184
+ writes = indexed;
4185
+ lowerer.jsBindingWritesByOwner.set(owner, writes);
4186
+ }
4187
+ return (writes.get(decl.name.text) ?? []).some((node) => lowerer.resolveValueSymbol(node.left) === symbol &&
4188
+ (lowerer.typeOf(node.right).flags & (ts.TypeFlags.Any | ts.TypeFlags.Unknown)) !== 0);
4147
4189
  }
4148
4190
  function immediatelyGuardedAbsenceProbe(lowerer, decl) {
4149
4191
  if (decl.type || !ts.isIdentifier(decl.name) || !decl.initializer)
@@ -4257,11 +4299,10 @@ function lowerDynSwitch(lowerer, stmt, disc, labels) {
4257
4299
  if (test.kind === "unitLit") {
4258
4300
  return { kind: "dynTest", test: test.unit, value: stableDisc, type: BOOL, loc: locOf(expression) };
4259
4301
  }
4260
- if (test.type.kind !== "string" && test.type.kind !== "f64" &&
4261
- test.type.kind !== "bool" && test.type.kind !== "dyn") {
4302
+ if (!lowerer.dynConvertible(test.type)) {
4262
4303
  lowerer.unsupported("SC1100", expression, "switch case values that cannot compare strictly with 'unknown'");
4263
4304
  }
4264
- return { kind: "dynScalarEq", left: stableDisc, right: test, type: BOOL, loc: locOf(expression) };
4305
+ return { kind: "dynScalarEq", left: stableDisc, right: lowerer.coerceInto(expression, test, DYN), type: BOOL, loc: locOf(expression) };
4265
4306
  });
4266
4307
  }
4267
4308
  function lowerBranchSwitch(lowerer, stmt, disc, labels, compare) {
@@ -5213,6 +5254,13 @@ export function lowerExprStatement(lowerer, expr) {
5213
5254
  }
5214
5255
  if (!expr.left.questionDotToken) {
5215
5256
  const recv = tryLowerExpression(lowerer, expr.left.expression);
5257
+ if (recv && (recv.type.kind === "dyn" || isJsSourceFile(expr.getSourceFile()) &&
5258
+ recv.type.kind === "union" && lowerer.dynConvertible(recv.type))) {
5259
+ const loc = locOf(expr);
5260
+ return { kind: "exprStmt", expr: { kind: "libCall", fn: "dyn.keySet", args: [lowerer.coerceInto(expr.left.expression, recv, DYN),
5261
+ { kind: "strLit", value: expr.left.name.text, type: STRING, loc },
5262
+ lowerer.lowerExprExpecting(expr.right, DYN)], type: VOID, loc }, loc };
5263
+ }
5216
5264
  if (recv?.type.kind === "object" && recv.type.className === "%Error") {
5217
5265
  const loc = locOf(expr);
5218
5266
  return { kind: "exprStmt", expr: { kind: "libCall", fn: "dyn.keySet", args: [
@@ -5322,6 +5370,16 @@ export function lowerExprStatement(lowerer, expr) {
5322
5370
  if ((ts.isPrefixUnaryExpression(expr) || ts.isPostfixUnaryExpression(expr)) &&
5323
5371
  (expr.operator === ts.SyntaxKind.PlusPlusToken ||
5324
5372
  expr.operator === ts.SyntaxKind.MinusMinusToken)) {
5373
+ if (ts.isPropertyAccessExpression(expr.operand) || ts.isElementAccessExpression(expr.operand)) {
5374
+ // Statement and value positions share ToNumeric and reference order.
5375
+ // Namespace/expando globals retain their direct binding path below.
5376
+ const binding = ts.isPropertyAccessExpression(expr.operand)
5377
+ ? expandoWritableTarget(lowerer, expr.operand) ?? nsWritableTarget(lowerer, expr.operand)
5378
+ : null;
5379
+ if (binding)
5380
+ return lowerIncDecToTarget(lowerer, expr, binding);
5381
+ return { kind: "exprStmt", expr: lowerIncDec(lowerer, expr, ts.isPrefixUnaryExpression(expr)), loc: locOf(expr) };
5382
+ }
5325
5383
  // Statement position only: pre/post distinction is unobservable, so
5326
5384
  // both desugar to `x = x ± 1`.
5327
5385
  if (ts.isPropertyAccessExpression(expr.operand) ||
@@ -7822,9 +7880,8 @@ function lowerForOfString(lowerer, stmt, iterable, labels) {
7822
7880
  * properties, so the enumeration is honestly EMPTY (zero iterations;
7823
7881
  * the body typechecked but never evaluates — SEMANTICS.md documents
7824
7882
  * the divergence).
7825
- * - class instances fence: which keys exist on one depends on runtime
7826
- * property creation (unset declared fields, useDefineForClassFields)
7827
- * that the struct model does not track — named, not guessed.
7883
+ * - JavaScript program classes use their live property-creation table.
7884
+ * TypeScript and runtime-owned layouts keep the class-instance fence.
7828
7885
  * Bindings mirror for-of's: const/let declare the per-iteration string
7829
7886
  * local, `var` assigns the hoisted shared slot, a pre-declared
7830
7887
  * identifier target assigns per pass; destructuring heads are tsc
@@ -7835,7 +7892,17 @@ function lowerForIn(lowerer, stmt) {
7835
7892
  if (stdlibGlobalNameOf(lowerer, stmt.expression) === "globalThis") {
7836
7893
  return { kind: "block", body: [], loc };
7837
7894
  }
7838
- const receiver = lowerer.lowerExpr(stmt.expression);
7895
+ let receiver = lowerer.lowerExpr(stmt.expression);
7896
+ if (receiver.type.kind === "object") {
7897
+ const info = lowerer.classes.get(receiver.type.className);
7898
+ let root = info;
7899
+ while (root?.base)
7900
+ root = root.base;
7901
+ if (info?.decl && isJsSourceFile(info.decl.getSourceFile()) && !info.def.runtime &&
7902
+ !root?.def.runtime && !info.builtinError && !info.builtinEmitter && !info.builtinStream) {
7903
+ receiver = lowerer.coerceToExpected(receiver, DYN);
7904
+ }
7905
+ }
7839
7906
  const recvT = receiver.type;
7840
7907
  if (recvT.kind === "dyn") {
7841
7908
  const recv = lowerer.declareHiddenLocal("%indyn", DYN);
@@ -7844,9 +7911,7 @@ function lowerForIn(lowerer, stmt) {
7844
7911
  kind: "dynCheck", value: { kind: "libCall", fn: "dyn.forInKeys", args: [ref], type: DYN, loc },
7845
7912
  type: arrayOf(STRING), loc,
7846
7913
  };
7847
- const loop = lowerForInOverKeys(lowerer, stmt, keys, labels, (key) => ({
7848
- kind: "libCall", fn: "dyn.hasKey", args: [ref, key], type: BOOL, loc,
7849
- }));
7914
+ const loop = lowerForInOverKeys(lowerer, stmt, keys, labels, (key) => classForInHasKey(lowerer, ref, key, loc));
7850
7915
  return { kind: "block", body: [{ kind: "varDecl", localId: recv.id, init: receiver, loc }, loop], loc };
7851
7916
  }
7852
7917
  if (recvT.kind === "array")