@scriptc/compiler 0.2.0 → 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.
- package/ambient/scriptc-node-fallback.d.ts +84 -19
- package/dist/backend/cycle-analysis.js +1 -0
- package/dist/backend/cycle-analysis.js.map +1 -1
- package/dist/backend/llvm/classes.js +21 -5
- package/dist/backend/llvm/classes.js.map +1 -1
- package/dist/backend/llvm/dyn.d.ts +8 -0
- package/dist/backend/llvm/dyn.js +247 -108
- package/dist/backend/llvm/dyn.js.map +1 -1
- package/dist/backend/llvm/emitter.d.ts +6 -3
- package/dist/backend/llvm/emitter.js +99 -25
- package/dist/backend/llvm/emitter.js.map +1 -1
- package/dist/backend/llvm/emitter.test.js +9 -1
- package/dist/backend/llvm/emitter.test.js.map +1 -1
- package/dist/backend/llvm/expr-bytes.d.ts +1 -1
- package/dist/backend/llvm/expr-bytes.js +28 -17
- package/dist/backend/llvm/expr-bytes.js.map +1 -1
- package/dist/backend/llvm/expr-containers.js +5 -0
- package/dist/backend/llvm/expr-containers.js.map +1 -1
- package/dist/backend/llvm/expr-control.js +1 -1
- package/dist/backend/llvm/expr-control.js.map +1 -1
- package/dist/backend/llvm/expr-dynamic.js +47 -13
- package/dist/backend/llvm/expr-dynamic.js.map +1 -1
- package/dist/backend/llvm/expr-primitives.js +11 -1
- package/dist/backend/llvm/expr-primitives.js.map +1 -1
- package/dist/backend/llvm/expr-records.js +11 -3
- package/dist/backend/llvm/expr-records.js.map +1 -1
- package/dist/backend/llvm/expr-stream-bridges.js +187 -18
- package/dist/backend/llvm/expr-stream-bridges.js.map +1 -1
- package/dist/backend/llvm/expr-stream-callbacks.d.ts +2 -2
- package/dist/backend/llvm/expr-stream-callbacks.js +7 -57
- package/dist/backend/llvm/expr-stream-callbacks.js.map +1 -1
- package/dist/backend/llvm/lib-dispatch.js +41 -3
- package/dist/backend/llvm/lib-dispatch.js.map +1 -1
- package/dist/backend/llvm/lib-filesystem.js +12 -9
- package/dist/backend/llvm/lib-filesystem.js.map +1 -1
- package/dist/backend/llvm/lib-process.js +23 -3
- package/dist/backend/llvm/lib-process.js.map +1 -1
- package/dist/backend/llvm/lib-shared.js +80 -3
- package/dist/backend/llvm/lib-shared.js.map +1 -1
- package/dist/backend/llvm/shapes.js +8 -2
- package/dist/backend/llvm/shapes.js.map +1 -1
- package/dist/backend/may-throw.js +4 -0
- package/dist/backend/may-throw.js.map +1 -1
- package/dist/backend/native-codegen.d.ts +1 -1
- package/dist/backend/native-codegen.js +4 -3
- package/dist/backend/native-codegen.js.map +1 -1
- package/dist/backend/native-codegen.test.js +11 -0
- package/dist/backend/native-codegen.test.js.map +1 -1
- package/dist/backend/native-toolchain.d.ts +3 -6
- package/dist/backend/native-toolchain.js +53 -23
- package/dist/backend/native-toolchain.js.map +1 -1
- package/dist/backend/native-toolchain.test.js +72 -0
- package/dist/backend/native-toolchain.test.js.map +1 -1
- package/dist/backend/runtime-abi.d.ts +2 -2
- package/dist/backend/runtime-abi.js +2 -2
- package/dist/backend/runtime-pack-native.js +4 -1
- package/dist/backend/runtime-pack-native.js.map +1 -1
- package/dist/backend/runtime-pack-targets.test.js +1 -1
- package/dist/backend/runtime-pack.test.js +1 -1
- package/dist/backend/target-diagnostics.d.ts +5 -0
- package/dist/backend/target-diagnostics.js +72 -1
- package/dist/backend/target-diagnostics.js.map +1 -1
- package/dist/backend/target-diagnostics.test.d.ts +1 -0
- package/dist/backend/target-diagnostics.test.js +68 -0
- package/dist/backend/target-diagnostics.test.js.map +1 -0
- package/dist/backend/targets.js +10 -6
- package/dist/backend/targets.js.map +1 -1
- package/dist/backend/targets.test.js +7 -0
- package/dist/backend/targets.test.js.map +1 -1
- package/dist/compat/fetch-profile.js +34 -4
- package/dist/compat/fetch-profile.js.map +1 -1
- package/dist/coverage/surface-manifest.js +5 -3
- package/dist/coverage/surface-manifest.js.map +1 -1
- package/dist/diagnostics/diagnostic.js +2 -7
- package/dist/diagnostics/diagnostic.js.map +1 -1
- package/dist/executable/executable-cache.d.ts +7 -3
- package/dist/executable/executable-cache.js +47 -11
- package/dist/executable/executable-cache.js.map +1 -1
- package/dist/executable/executable-cache.test.js +109 -2
- package/dist/executable/executable-cache.test.js.map +1 -1
- package/dist/executable/prepare.js +2 -1
- package/dist/executable/prepare.js.map +1 -1
- package/dist/frontend/builtin-modules.d.ts +1 -1
- package/dist/frontend/builtin-modules.js +1 -1
- package/dist/frontend/builtin-modules.js.map +1 -1
- package/dist/frontend/function-completion.d.ts +6 -0
- package/dist/frontend/function-completion.js +50 -0
- package/dist/frontend/function-completion.js.map +1 -0
- package/dist/frontend/lowering/abstract-equality.js +5 -1
- package/dist/frontend/lowering/abstract-equality.js.map +1 -1
- package/dist/frontend/lowering/checked-iterable-spread.d.ts +4 -0
- package/dist/frontend/lowering/checked-iterable-spread.js +30 -0
- package/dist/frontend/lowering/checked-iterable-spread.js.map +1 -0
- package/dist/frontend/lowering/checked-promise-all.d.ts +5 -0
- package/dist/frontend/lowering/checked-promise-all.js +31 -0
- package/dist/frontend/lowering/checked-promise-all.js.map +1 -0
- package/dist/frontend/lowering/class-callbacks.d.ts +4 -4
- package/dist/frontend/lowering/class-callbacks.js +29 -17
- package/dist/frontend/lowering/class-callbacks.js.map +1 -1
- package/dist/frontend/lowering/class-construction.d.ts +14 -0
- package/dist/frontend/lowering/class-construction.js +185 -0
- package/dist/frontend/lowering/class-construction.js.map +1 -0
- package/dist/frontend/lowering/class-descriptors.d.ts +2 -1
- package/dist/frontend/lowering/class-descriptors.js +58 -10
- package/dist/frontend/lowering/class-descriptors.js.map +1 -1
- package/dist/frontend/lowering/class-dynamic-dispatch.d.ts +36 -1
- package/dist/frontend/lowering/class-dynamic-dispatch.js +965 -91
- package/dist/frontend/lowering/class-dynamic-dispatch.js.map +1 -1
- package/dist/frontend/lowering/class-dynamic-dispatch.test.js +66 -3
- package/dist/frontend/lowering/class-dynamic-dispatch.test.js.map +1 -1
- package/dist/frontend/lowering/class-instance-constructor.d.ts +1 -1
- package/dist/frontend/lowering/class-instance-constructor.js +15 -42
- package/dist/frontend/lowering/class-instance-constructor.js.map +1 -1
- package/dist/frontend/lowering/class-method-values.d.ts +20 -1
- package/dist/frontend/lowering/class-method-values.js +120 -24
- package/dist/frontend/lowering/class-method-values.js.map +1 -1
- package/dist/frontend/lowering/class-prototypes.d.ts +10 -3
- package/dist/frontend/lowering/class-prototypes.js +188 -21
- package/dist/frontend/lowering/class-prototypes.js.map +1 -1
- package/dist/frontend/lowering/class-runtime-statics.d.ts +8 -0
- package/dist/frontend/lowering/class-runtime-statics.js +84 -0
- package/dist/frontend/lowering/class-runtime-statics.js.map +1 -0
- package/dist/frontend/lowering/class-static-data.d.ts +1 -0
- package/dist/frontend/lowering/class-static-data.js +6 -4
- package/dist/frontend/lowering/class-static-data.js.map +1 -1
- package/dist/frontend/lowering/containers/bytes.js +66 -17
- package/dist/frontend/lowering/containers/bytes.js.map +1 -1
- package/dist/frontend/lowering/containers/string-and-regexp.js +24 -47
- package/dist/frontend/lowering/containers/string-and-regexp.js.map +1 -1
- package/dist/frontend/lowering/deferred-module-initializers.d.ts +13 -0
- package/dist/frontend/lowering/deferred-module-initializers.js +410 -0
- package/dist/frontend/lowering/deferred-module-initializers.js.map +1 -0
- package/dist/frontend/lowering/deferred-module-initializers.test.d.ts +1 -0
- package/dist/frontend/lowering/deferred-module-initializers.test.js +92 -0
- package/dist/frontend/lowering/deferred-module-initializers.test.js.map +1 -0
- package/dist/frontend/lowering/error-methods.d.ts +4 -1
- package/dist/frontend/lowering/error-methods.js +100 -1
- package/dist/frontend/lowering/error-methods.js.map +1 -1
- package/dist/frontend/lowering/expressions/native-proxy.js +3 -1
- package/dist/frontend/lowering/expressions/native-proxy.js.map +1 -1
- package/dist/frontend/lowering/expressions/nullish-assignment.js +19 -11
- package/dist/frontend/lowering/expressions/nullish-assignment.js.map +1 -1
- package/dist/frontend/lowering/expressions/object-literals.js +68 -7
- package/dist/frontend/lowering/expressions/object-literals.js.map +1 -1
- package/dist/frontend/lowering/expressions/optional-chains.d.ts +3 -4
- package/dist/frontend/lowering/expressions/optional-chains.js +72 -20
- package/dist/frontend/lowering/expressions/optional-chains.js.map +1 -1
- package/dist/frontend/lowering/function-context.d.ts +11 -3
- package/dist/frontend/lowering/function-context.js +11 -5
- package/dist/frontend/lowering/function-context.js.map +1 -1
- package/dist/frontend/lowering/generator-dynamic-dispatch.d.ts +1 -0
- package/dist/frontend/lowering/generator-dynamic-dispatch.js +39 -1
- package/dist/frontend/lowering/generator-dynamic-dispatch.js.map +1 -1
- package/dist/frontend/lowering/lib-boundary.d.ts +2 -0
- package/dist/frontend/lowering/lib-boundary.js +54 -1
- package/dist/frontend/lowering/lib-boundary.js.map +1 -1
- package/dist/frontend/lowering/lower-builtin-values.d.ts +7 -1
- package/dist/frontend/lowering/lower-builtin-values.js +113 -3
- package/dist/frontend/lowering/lower-builtin-values.js.map +1 -1
- package/dist/frontend/lowering/lower-builtins.d.ts +10 -14
- package/dist/frontend/lowering/lower-builtins.js +443 -88
- package/dist/frontend/lowering/lower-builtins.js.map +1 -1
- package/dist/frontend/lowering/lower-calls.d.ts +8 -5
- package/dist/frontend/lowering/lower-calls.js +717 -142
- package/dist/frontend/lowering/lower-calls.js.map +1 -1
- package/dist/frontend/lowering/lower-classes.d.ts +18 -13
- package/dist/frontend/lowering/lower-classes.js +1076 -188
- package/dist/frontend/lowering/lower-classes.js.map +1 -1
- package/dist/frontend/lowering/lower-containers.d.ts +9 -0
- package/dist/frontend/lowering/lower-containers.js +172 -51
- package/dist/frontend/lowering/lower-containers.js.map +1 -1
- package/dist/frontend/lowering/lower-dgram.js +3 -2
- package/dist/frontend/lowering/lower-dgram.js.map +1 -1
- package/dist/frontend/lowering/lower-exprs.d.ts +12 -8
- package/dist/frontend/lowering/lower-exprs.js +802 -232
- package/dist/frontend/lowering/lower-exprs.js.map +1 -1
- package/dist/frontend/lowering/lower-generators.js +17 -2
- package/dist/frontend/lowering/lower-generators.js.map +1 -1
- package/dist/frontend/lowering/lower-inspect.js +15 -1
- package/dist/frontend/lowering/lower-inspect.js.map +1 -1
- package/dist/frontend/lowering/lower-island.d.ts +2 -0
- package/dist/frontend/lowering/lower-island.js +36 -10
- package/dist/frontend/lowering/lower-island.js.map +1 -1
- package/dist/frontend/lowering/lower-island.test.d.ts +1 -0
- package/dist/frontend/lowering/lower-island.test.js +51 -0
- package/dist/frontend/lowering/lower-island.test.js.map +1 -0
- package/dist/frontend/lowering/lower-modules.d.ts +1 -3
- package/dist/frontend/lowering/lower-modules.js +380 -73
- package/dist/frontend/lowering/lower-modules.js.map +1 -1
- package/dist/frontend/lowering/lower-modules.test.d.ts +1 -0
- package/dist/frontend/lowering/lower-modules.test.js +107 -0
- package/dist/frontend/lowering/lower-modules.test.js.map +1 -0
- package/dist/frontend/lowering/lower-stmts.d.ts +7 -3
- package/dist/frontend/lowering/lower-stmts.js +221 -47
- package/dist/frontend/lowering/lower-stmts.js.map +1 -1
- package/dist/frontend/lowering/lower-stmts.test.d.ts +1 -0
- package/dist/frontend/lowering/lower-stmts.test.js +77 -0
- package/dist/frontend/lowering/lower-stmts.test.js.map +1 -0
- package/dist/frontend/lowering/lower-stream.js +3 -1
- package/dist/frontend/lowering/lower-stream.js.map +1 -1
- package/dist/frontend/lowering/lower-url.d.ts +2 -1
- package/dist/frontend/lowering/lower-url.js +32 -9
- package/dist/frontend/lowering/lower-url.js.map +1 -1
- package/dist/frontend/lowering/lowerer.d.ts +53 -10
- package/dist/frontend/lowering/lowerer.js +390 -77
- package/dist/frontend/lowering/lowerer.js.map +1 -1
- package/dist/frontend/lowering/lowerer.test.js +187 -3
- package/dist/frontend/lowering/lowerer.test.js.map +1 -1
- package/dist/frontend/lowering/module-namespace-elements.d.ts +7 -0
- package/dist/frontend/lowering/module-namespace-elements.js +54 -0
- package/dist/frontend/lowering/module-namespace-elements.js.map +1 -0
- package/dist/frontend/lowering/object-factory-new.d.ts +4 -3
- package/dist/frontend/lowering/object-factory-new.js +27 -14
- package/dist/frontend/lowering/object-factory-new.js.map +1 -1
- package/dist/frontend/lowering/surfaces.d.ts +3 -0
- package/dist/frontend/lowering/surfaces.js +48 -19
- package/dist/frontend/lowering/surfaces.js.map +1 -1
- package/dist/frontend/lowering/text-decoder-encoding.d.ts +2 -0
- package/dist/frontend/lowering/text-decoder-encoding.js +8 -0
- package/dist/frontend/lowering/text-decoder-encoding.js.map +1 -1
- package/dist/frontend/lowering/text-decoder-encoding.test.js +2 -1
- package/dist/frontend/lowering/text-decoder-encoding.test.js.map +1 -1
- package/dist/frontend/lowering/unregistered-class-types.test.js +3 -3
- package/dist/frontend/lowering/unregistered-class-types.test.js.map +1 -1
- package/dist/frontend/npm-static-prune.js +116 -34
- package/dist/frontend/npm-static-prune.js.map +1 -1
- package/dist/frontend/npm-static-prune.test.js +8 -0
- package/dist/frontend/npm-static-prune.test.js.map +1 -1
- package/dist/frontend/program.d.ts +1 -1
- package/dist/frontend/program.js +57 -26
- package/dist/frontend/program.js.map +1 -1
- package/dist/frontend/program.test.js +18 -0
- package/dist/frontend/program.test.js.map +1 -1
- package/dist/frontend/ts7/ast.js +4 -3
- package/dist/frontend/ts7/ast.js.map +1 -1
- package/dist/frontend/ts7/semantic-json.js +5 -10
- package/dist/frontend/ts7/semantic-json.js.map +1 -1
- package/dist/frontend/type-mapper.d.ts +9 -1
- package/dist/frontend/type-mapper.js +169 -23
- package/dist/frontend/type-mapper.js.map +1 -1
- package/dist/frontend/type-mapper.test.js +23 -0
- package/dist/frontend/type-mapper.test.js.map +1 -1
- package/dist/frontend/union-discriminants.d.ts +1 -1
- package/dist/frontend/union-discriminants.js +24 -9
- package/dist/frontend/union-discriminants.js.map +1 -1
- package/dist/index.js +16 -10
- package/dist/index.js.map +1 -1
- package/dist/ir/analysis.js +2 -0
- package/dist/ir/analysis.js.map +1 -1
- package/dist/ir/ir.d.ts +74 -41
- package/dist/ir/ir.js +167 -43
- package/dist/ir/ir.js.map +1 -1
- package/dist/ir/ir.test.js +35 -0
- package/dist/ir/ir.test.js.map +1 -1
- package/dist/ir/serialize.js +35 -3
- package/dist/ir/serialize.js.map +1 -1
- package/dist/ir/serialize.test.js +26 -1
- package/dist/ir/serialize.test.js.map +1 -1
- package/dist/ir/traverse.d.ts +0 -3
- package/dist/ir/traverse.js +33 -20
- package/dist/ir/traverse.js.map +1 -1
- package/dist/ir/validate.js +136 -16
- package/dist/ir/validate.js.map +1 -1
- package/dist/ir/validate.test.js +77 -1
- package/dist/ir/validate.test.js.map +1 -1
- package/dist/library/compiler-self-identity.js +1 -1
- package/dist/library/compiler-self-identity.test.js +2 -2
- package/dist/library/compiler-self-identity.test.js.map +1 -1
- package/dist/library/int-infer.d.ts +2 -2
- package/dist/library/int-infer.js +10 -7
- package/dist/library/int-infer.js.map +1 -1
- package/dist/library/int-infer.test.js +44 -0
- package/dist/library/int-infer.test.js.map +1 -1
- package/dist/library/prepare.js +2 -1
- package/dist/library/prepare.js.map +1 -1
- package/dist/native/sanitizer.js +3 -1
- package/dist/native/sanitizer.js.map +1 -1
- package/dist/native/toolchain.d.ts +1 -1
- package/dist/native/toolchain.js +26 -6
- package/dist/native/toolchain.js.map +1 -1
- package/dist/native/toolchain.test.js +53 -1
- package/dist/native/toolchain.test.js.map +1 -1
- package/package.json +20 -20
- package/surface-manifest.json +170 -93
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
import * as ts from "../ts7/adapter.js";
|
|
2
2
|
import type { Lowerer } from "./lowerer.js";
|
|
3
3
|
import { type IrExpr, type IrFunction, type IrRecordShape, type IrStmt, type IrType, type SrcLoc } from "../../ir/ir.js";
|
|
4
|
+
/** Object() and new Object() preserve known object inputs. Primitive
|
|
5
|
+
* boxing and unproven checked-dynamic values retain their refusal. */
|
|
6
|
+
export declare function lowerObjectConstructor(lowerer: Lowerer, args: readonly ts.Expression[], loc: SrcLoc): IrExpr | null;
|
|
4
7
|
/** Ambient array method calls. `push`/`unshift`/`pop`/`reverse`/
|
|
5
8
|
* `indexOf`/`includes`/`join`
|
|
6
9
|
* lower to arrIntrinsic; the HOF family — `map`/`filter`/`forEach`/
|
|
@@ -29,6 +32,12 @@ export declare const lowerNpmStaticSafeIndexRead: typeof lowerSafeIndexRead;
|
|
|
29
32
|
export declare function lowerArrayConstructor(lowerer: Lowerer, expr: ts.CallExpression | ts.NewExpression, args: readonly ts.Expression[]): IrExpr;
|
|
30
33
|
/** `Array.of` creates an array of its arguments, including a lone number. */
|
|
31
34
|
export declare function lowerArrayOfCall(lowerer: Lowerer, call: ts.CallExpression, access: ts.PropertyAccessExpression): IrExpr | null;
|
|
35
|
+
/** Mapper-less checked Array.from: acquire once, then step through emitted
|
|
36
|
+
* property and call dispatch so native class iterators retain their methods. */
|
|
37
|
+
export declare function lowerCheckedArrayFrom(lowerer: Lowerer, source: IrExpr, loc: SrcLoc, mapper?: IrExpr, receiver?: IrExpr, numeric?: boolean, iterable?: IrExpr): Extract<IrExpr, {
|
|
38
|
+
kind: "seqExpr";
|
|
39
|
+
}>;
|
|
40
|
+
export declare function lowerArrayFromValue(lowerer: Lowerer, loc: SrcLoc): IrExpr;
|
|
32
41
|
/** `Array.from({ length: n }, mapfn)` — the counted-generation idiom — on
|
|
33
42
|
* THE stdlib Array global. The source must be an OBJECT LITERAL whose
|
|
34
43
|
* single property is `length` (the shape the idiom always spells; the
|
|
@@ -6,7 +6,7 @@ import { InternalCompilerError } from "../../errors.js";
|
|
|
6
6
|
* record operations. */
|
|
7
7
|
import * as ts from "../ts7/adapter.js";
|
|
8
8
|
import { BOOL, CAUGHT, DYN, F64, JSVAL, STRING, UNDEFINED_T, VOID, arrayOf, funcOf, isRefCounted, isSupportedArrayElem, isSupportedIndexValue, isUnitType, typeEquals } from "../../ir/ir.js";
|
|
9
|
-
import { ARRAY_METHODS, MAP_METHODS, SET_COMBINE_METHODS, SET_METHODS } from "./surfaces.js";
|
|
9
|
+
import { ARRAY_METHODS, COLLECTION_ITERATOR_METHODS, MAP_METHODS, SET_COMBINE_METHODS, SET_METHODS } from "./surfaces.js";
|
|
10
10
|
import { tryLowerExpression } from "./expressions/try-lower-expression.js";
|
|
11
11
|
import { forOfVarTarget, lowerDestructuringAssign } from "./lower-stmts.js";
|
|
12
12
|
import { isJsSourceFile, locOf } from "../program.js";
|
|
@@ -14,10 +14,25 @@ import { islandPrimitiveExit, lowerDynDispatchMethodCall } from "./lower-calls.j
|
|
|
14
14
|
import { buildArraySortFn } from "./lower-array-sort.js";
|
|
15
15
|
import { arrayIndexPresent, arrayValueRead, arrayValueStore, arrayValueType, currentArrayIndexPresent } from "./array-values.js";
|
|
16
16
|
import { typeKey } from "../type-mapper.js";
|
|
17
|
-
import { nodeThrowExpr } from "./lowerer.js";
|
|
17
|
+
import { dynUndefinedExpr, newFnCtx, nodeThrowExpr } from "./lowerer.js";
|
|
18
18
|
import { boolLit, countedFor, numLit, strLit, varRef } from "../../ir/build.js";
|
|
19
19
|
import { defaultAfterUndefined, lowerPositionArgument, lowerStaticallyUndefinedArgument, positionNumber } from "./optional-arguments.js";
|
|
20
20
|
import { lowerArrayCopyWithin, lowerArrayFill } from "./array-indexed-mutation.js";
|
|
21
|
+
/** Object() and new Object() preserve known object inputs. Primitive
|
|
22
|
+
* boxing and unproven checked-dynamic values retain their refusal. */
|
|
23
|
+
export function lowerObjectConstructor(lowerer, args, loc) {
|
|
24
|
+
if (args.length === 0) {
|
|
25
|
+
return { kind: "recordLit", fields: [], type: { kind: "record", shapeId: lowerer.shapes.intern([]) }, loc };
|
|
26
|
+
}
|
|
27
|
+
if (args.length !== 1 || ts.isSpreadElement(args[0]))
|
|
28
|
+
return null;
|
|
29
|
+
const value = lowerer.lowerExpr(args[0]);
|
|
30
|
+
if (value.kind === "dynObjLit" || value.kind === "dynArrLit")
|
|
31
|
+
return value;
|
|
32
|
+
if (["record", "array", "object", "regex", "date", "bytes", "map", "set", "func", "classval"].includes(value.type.kind))
|
|
33
|
+
return value;
|
|
34
|
+
return null;
|
|
35
|
+
}
|
|
21
36
|
function primitivePositionType(lowerer, type) {
|
|
22
37
|
if (type.kind === "union") {
|
|
23
38
|
return lowerer.unions.get(type.unionId)?.arms.every((arm) => primitivePositionType(lowerer, arm)) ?? false;
|
|
@@ -144,9 +159,6 @@ function lowerArrayJoinSeparator(lowerer, node, loc) {
|
|
|
144
159
|
* directly from its IR return type. Fence element kinds ScrArr cannot hold
|
|
145
160
|
* before constructing that array type. */
|
|
146
161
|
function fenceProducedArrayElem(lowerer, node, producer, elem) {
|
|
147
|
-
if (elem.kind === "dyn") {
|
|
148
|
-
lowerer.unsupported("SC1090", node, `${producer} with a callback returning 'unknown'-typed values (the result array has no static element type — annotate the callback's return)`);
|
|
149
|
-
}
|
|
150
162
|
if (!isSupportedArrayElem(elem)) {
|
|
151
163
|
lowerer.unsupported("SC1090", node, `${producer} with a callback returning '${lowerer.fmt(elem)}' values (arrays of this element kind have no representation — store the values individually)`);
|
|
152
164
|
}
|
|
@@ -545,7 +557,12 @@ export function lowerArrayMethodCall(lowerer, call, access) {
|
|
|
545
557
|
// IsArray says spread; no honest static answer exists.
|
|
546
558
|
lowerer.unsupported("SC1090", argNode, "concat of a bare inner array onto an array-of-arrays (JS would SPREAD it one level — wrap it: a.concat([inner]))");
|
|
547
559
|
}
|
|
548
|
-
|
|
560
|
+
// Declaration-backed JS methods can return checked values even
|
|
561
|
+
// when their public signature names a concrete array. Validate
|
|
562
|
+
// that boundary before spreading the represented elements.
|
|
563
|
+
let arg = lowerer.lowerExpr(argNode);
|
|
564
|
+
if (arg.type.kind === "dyn")
|
|
565
|
+
arg = lowerer.coerceInto(argNode, arg, argArrayType);
|
|
549
566
|
if (arg.type.kind !== "array")
|
|
550
567
|
lowerer.badType(argNode, lowerer.typeOf(argNode));
|
|
551
568
|
shape.push("a");
|
|
@@ -615,6 +632,12 @@ export function lowerArrayMethodCall(lowerer, call, access) {
|
|
|
615
632
|
return { kind: "arrIntrinsic", method: "shift", receiver, args: [], type: arrayValueType(lowerer, elem), loc };
|
|
616
633
|
}
|
|
617
634
|
if (name === "join") {
|
|
635
|
+
if (elem.kind === "dyn") {
|
|
636
|
+
const receiver = lowerer.coerceToExpected(lowerer.lowerExpr(access.expression), DYN);
|
|
637
|
+
const args = call.arguments.length ? [lowerer.lowerExprExpecting(call.arguments[0], DYN)] : [];
|
|
638
|
+
return lowerer.coerceToExpected({ kind: "dynInvoke", recv: receiver, method: "join",
|
|
639
|
+
calleeName: access.getText(), args, type: DYN, loc }, STRING);
|
|
640
|
+
}
|
|
618
641
|
// The ambient declares join on every Array<T> (a per-element-type
|
|
619
642
|
// interface split isn't expressible there), so string-convertible
|
|
620
643
|
// elements are enforced here: nested arrays would need JS's recursive
|
|
@@ -1686,6 +1709,9 @@ export function lowerTupleReadMethodCall(lowerer, call, access, tupleReceiver) {
|
|
|
1686
1709
|
const ret = fnArg.type.ret;
|
|
1687
1710
|
if (ret.kind === "void" || ret.kind === "func")
|
|
1688
1711
|
lowerer.badType(call, lowerer.typeOf(call));
|
|
1712
|
+
if (method === "flatMap" && (ret.kind === "dyn" || ret.kind === "jsval" || (ret.kind === "record" && lowerer.shapes.get(ret.shapeId)?.tuple))) {
|
|
1713
|
+
return { kind: "dynInvoke", recv: { kind: "dynFrom", value: receiver, type: DYN, loc }, method: "flatMap", calleeName: access.getText(), args: [{ kind: "dynFrom", value: fnArg, type: DYN, loc }], type: DYN, loc };
|
|
1714
|
+
}
|
|
1689
1715
|
if (method === "flatMap" && ret.kind === "union" && lowerer.unions.get(ret.unionId).arms.some(arm => arm.kind === "array")) {
|
|
1690
1716
|
lowerer.noLowering("tuple .flatMap callback mixing array and scalar results", callback, "return an array from every path");
|
|
1691
1717
|
}
|
|
@@ -1975,8 +2001,7 @@ function buildArrayHofFn(lowerer, name, method, elem, fnRet, arity, loc, outElem
|
|
|
1975
2001
|
* undefined unit arm (for REF elements that arm is the unit instance, the
|
|
1976
2002
|
* standard union machinery). The Last pair is the SAME loop walked
|
|
1977
2003
|
* backwards (`i = n - 1; i >= 0; i--`), exactly the es2023 spec's
|
|
1978
|
-
* descending index walk.
|
|
1979
|
-
* (JS's ToBoolean of arbitrary predicate results has no lowering). */
|
|
2004
|
+
* descending index walk. Predicate results use JavaScript ToBoolean. */
|
|
1980
2005
|
function lowerArrayFindLikeCall(lowerer, call, access, method, elem, bindUntyped = false) {
|
|
1981
2006
|
const loc = locOf(call);
|
|
1982
2007
|
const receiver = lowerer.lowerExpr(access.expression);
|
|
@@ -1991,7 +2016,7 @@ function lowerArrayFindLikeCall(lowerer, call, access, method, elem, bindUntyped
|
|
|
1991
2016
|
// `packages.some((p) => p.scripts[name])` idiom, whose callback
|
|
1992
2017
|
// returns the index read's `string | undefined`).
|
|
1993
2018
|
const fnRet = fnArg.type.ret;
|
|
1994
|
-
const truthyRet = fnRet.kind === "bool" || fnRet.kind === "f64" || fnRet.kind === "string" ||
|
|
2019
|
+
const truthyRet = fnRet.kind === "bool" || fnRet.kind === "f64" || fnRet.kind === "string" || fnRet.kind === "dyn" ||
|
|
1995
2020
|
(fnRet.kind === "union" &&
|
|
1996
2021
|
(lowerer.unions.get(fnRet.unionId)?.arms ?? []).every((a) => a.kind !== "dyn" && a.kind !== "caught" && a.kind !== "jsval"));
|
|
1997
2022
|
if (!truthyRet)
|
|
@@ -2044,11 +2069,13 @@ function lowerArrayFindLikeCall(lowerer, call, access, method, elem, bindUntyped
|
|
|
2044
2069
|
return { kind: "call", callee: helper, args: [receiver, fnArg], type: resultT, loc };
|
|
2045
2070
|
}
|
|
2046
2071
|
/** ToBoolean of a predicate result inside a synthesized HOF helper — the
|
|
2047
|
-
* ensureBool subset the find-like path admits (bool through;
|
|
2048
|
-
* truthy-answerable unions via toBool). */
|
|
2072
|
+
* ensureBool subset the find-like path admits (bool through; checked
|
|
2073
|
+
* values via dynTest; f64/string/truthy-answerable unions via toBool). */
|
|
2049
2074
|
function predToBool(e) {
|
|
2050
2075
|
if (e.type.kind === "bool")
|
|
2051
2076
|
return e;
|
|
2077
|
+
if (e.type.kind === "dyn")
|
|
2078
|
+
return { kind: "dynTest", test: "truthy", value: e, type: BOOL, loc: e.loc };
|
|
2052
2079
|
return { kind: "toBool", operand: e, type: BOOL, loc: e.loc };
|
|
2053
2080
|
}
|
|
2054
2081
|
/** The find loop, from existing IR nodes:
|
|
@@ -2250,6 +2277,9 @@ function lowerArrayFlatMapCall(lowerer, call, access, elem) {
|
|
|
2250
2277
|
lowerer.unsupported("SC1090", call, "this call form"); // tsc-guarded
|
|
2251
2278
|
const { fnArg, arity } = hofCallbackArg(lowerer, argNode, [arrayValueType(lowerer, elem)], arrT);
|
|
2252
2279
|
const fnRet = fnArg.type.ret;
|
|
2280
|
+
if (fnRet.kind === "dyn" || fnRet.kind === "jsval" || (fnRet.kind === "record" && lowerer.shapes.get(fnRet.shapeId)?.tuple)) {
|
|
2281
|
+
return { kind: "dynInvoke", recv: { kind: "dynFrom", value: receiver, liveRef: true, type: DYN, loc }, method: "flatMap", calleeName: access.getText(), args: [{ kind: "dynFrom", value: fnArg, type: DYN, loc }], type: DYN, loc };
|
|
2282
|
+
}
|
|
2253
2283
|
if (fnRet.kind === "union") {
|
|
2254
2284
|
const def = lowerer.unions.get(fnRet.unionId);
|
|
2255
2285
|
if (def?.arms.some((a) => a.kind === "array")) {
|
|
@@ -2778,6 +2808,14 @@ export function lowerArrayConstructor(lowerer, expr, args) {
|
|
|
2778
2808
|
lowerer.noLowering("Array constructor with spread arguments", expr);
|
|
2779
2809
|
}
|
|
2780
2810
|
let result = lowerer.mapTypeOf(lowerer.typeOf(expr));
|
|
2811
|
+
// Constructors without a concrete element layout keep their checked
|
|
2812
|
+
// reference. Known element forms retain native arrays, including their
|
|
2813
|
+
// existing sparse storage and indexed property contracts.
|
|
2814
|
+
if (!lowerer.dynamic && isJsSourceFile(expr.getSourceFile()) &&
|
|
2815
|
+
(result?.kind !== "array" || result.elem.kind === "dyn")) {
|
|
2816
|
+
return { kind: "dynCall", callee: { kind: "libCall", fn: "dyn.arrayConstructor", args: [], type: DYN, loc },
|
|
2817
|
+
calleeName: "Array", args: args.map((arg) => lowerer.lowerExprExpecting(arg, DYN)), type: DYN, loc };
|
|
2818
|
+
}
|
|
2781
2819
|
if (result?.kind !== "array") {
|
|
2782
2820
|
const contextual = lowerer.checker.getContextualType(expr);
|
|
2783
2821
|
if (contextual)
|
|
@@ -2866,31 +2904,82 @@ export function lowerArrayOfCall(lowerer, call, access) {
|
|
|
2866
2904
|
}
|
|
2867
2905
|
/** Mapper-less checked Array.from: acquire once, then step through emitted
|
|
2868
2906
|
* property and call dispatch so native class iterators retain their methods. */
|
|
2869
|
-
function lowerCheckedArrayFrom(lowerer, source, loc) {
|
|
2907
|
+
export function lowerCheckedArrayFrom(lowerer, source, loc, mapper, receiver, numeric = false, iterable) {
|
|
2870
2908
|
const iterator = lowerer.declareHiddenLocal("%fromIterator", DYN);
|
|
2871
2909
|
const next = lowerer.declareHiddenLocal("%fromNext", DYN);
|
|
2872
2910
|
const step = lowerer.declareHiddenLocal("%fromStep", DYN);
|
|
2873
2911
|
const out = lowerer.declareHiddenLocal("%fromArray", DYN);
|
|
2874
2912
|
const done = lowerer.declareHiddenLocal("%fromDone", BOOL);
|
|
2875
2913
|
done.mutable = true;
|
|
2914
|
+
const index = mapper ? lowerer.declareHiddenLocal("%fromIndex", F64) : null;
|
|
2915
|
+
if (index)
|
|
2916
|
+
index.mutable = true;
|
|
2876
2917
|
const get = (value, key) => ({ kind: "dynKeyGet", value, key: strLit(key, loc), type: DYN, loc });
|
|
2918
|
+
const item = get(varRef(step.id, DYN, loc), "value");
|
|
2919
|
+
const mapped = mapper && index ? { kind: "ternary", cond: { kind: "dynTest", test: "undefined", value: mapper, type: BOOL, loc },
|
|
2920
|
+
then: item, else_: { kind: "dynCall", callee: mapper, ...(receiver ? { receiver } : {}), calleeName: "Array.from mapper", args: [item, lowerer.coerceToExpected(varRef(index.id, F64, loc), DYN)], type: DYN, loc }, type: DYN, loc } : item;
|
|
2921
|
+
const element = numeric ? lowerer.coerceToExpected({ kind: "libCall", fn: "dyn.toNumberCoerce", args: [mapped], type: F64, loc }, DYN) : mapped;
|
|
2922
|
+
let append = { kind: "exprStmt", expr: { kind: "dynInvoke", recv: varRef(out.id, DYN, loc), method: "push", calleeName: "Array.from", args: [element], type: DYN, loc }, loc };
|
|
2923
|
+
if (mapper) {
|
|
2924
|
+
const error = lowerer.declareHiddenLocal("%fromError", CAUGHT);
|
|
2925
|
+
const close = lowerer.declareHiddenLocal("%fromReturn", DYN);
|
|
2926
|
+
append = { kind: "tryCatch", tryBody: [append], catchLocalId: error.id, finallyBody: null, loc, catchBody: [
|
|
2927
|
+
{ kind: "tryCatch", catchLocalId: null, catchBody: [], finallyBody: null, loc, tryBody: [
|
|
2928
|
+
{ kind: "varDecl", localId: close.id, init: get(varRef(iterator.id, DYN, loc), "return"), loc },
|
|
2929
|
+
{ kind: "if", cond: { kind: "dynTest", test: "function", value: varRef(close.id, DYN, loc), type: BOOL, loc }, then: [
|
|
2930
|
+
{ kind: "exprStmt", expr: { kind: "dynCall", callee: varRef(close.id, DYN, loc), receiver: varRef(iterator.id, DYN, loc), calleeName: "iterator.return", args: [], type: DYN, loc }, loc },
|
|
2931
|
+
], else_: null, loc },
|
|
2932
|
+
] },
|
|
2933
|
+
{ kind: "rethrow", localId: error.id, loc },
|
|
2934
|
+
] };
|
|
2935
|
+
}
|
|
2877
2936
|
const stmts = [
|
|
2878
|
-
|
|
2937
|
+
...(mapper ? [{ kind: "if", cond: { kind: "dynTest", test: "undefined", value: mapper, type: BOOL, loc }, then: [], else_: [
|
|
2938
|
+
{ kind: "if", cond: { kind: "dynTest", test: "function", value: mapper, type: BOOL, loc }, then: [], else_: [
|
|
2939
|
+
{ kind: "exprStmt", expr: nodeThrowExpr(1, "", "Array.from mapper is not a function", DYN, loc), loc },
|
|
2940
|
+
], loc },
|
|
2941
|
+
], loc }] : []),
|
|
2942
|
+
{ kind: "varDecl", localId: iterator.id, init: { kind: "libCall", fn: "dyn.iteratorResult", args: [{ kind: "libCall", fn: iterable ? "dyn.iterator" : "dyn.arrayFromIterator", args: iterable ? [source, iterable] : [source], type: DYN, loc }], type: DYN, loc }, loc },
|
|
2879
2943
|
{ kind: "varDecl", localId: next.id, init: get(varRef(iterator.id, DYN, loc), "next"), loc },
|
|
2880
2944
|
{ kind: "varDecl", localId: out.id, init: { kind: "dynArrLit", elems: [], type: DYN, loc }, loc },
|
|
2881
2945
|
{ kind: "varDecl", localId: done.id, init: boolLit(false, loc), loc },
|
|
2946
|
+
...(index ? [{ kind: "varDecl", localId: index.id, init: numLit(0, loc), loc }] : []),
|
|
2882
2947
|
{ kind: "while", cond: { kind: "unary", op: "!", operand: varRef(done.id, BOOL, loc), type: BOOL, loc }, body: [
|
|
2883
2948
|
{ kind: "varDecl", localId: step.id, init: { kind: "libCall", fn: "dyn.iteratorResult", args: [{
|
|
2884
2949
|
kind: "dynCall", callee: varRef(next.id, DYN, loc), receiver: varRef(iterator.id, DYN, loc), calleeName: "iterator.next", args: [], type: DYN, loc,
|
|
2885
2950
|
}], type: DYN, loc }, loc },
|
|
2886
2951
|
{ kind: "assign", localId: done.id, value: { kind: "dynTest", test: "truthy", value: get(varRef(step.id, DYN, loc), "done"), type: BOOL, loc }, loc },
|
|
2887
2952
|
{ kind: "if", cond: { kind: "unary", op: "!", operand: varRef(done.id, BOOL, loc), type: BOOL, loc }, then: [
|
|
2888
|
-
|
|
2953
|
+
append,
|
|
2954
|
+
...(index ? [{ kind: "assign", localId: index.id, value: { kind: "bin", op: "+", left: varRef(index.id, F64, loc), right: numLit(1, loc), type: F64, loc }, loc }] : []),
|
|
2889
2955
|
], else_: null, loc },
|
|
2890
2956
|
], loc },
|
|
2891
2957
|
];
|
|
2892
2958
|
return { kind: "seqExpr", stmts, result: varRef(out.id, DYN, loc), type: DYN, loc };
|
|
2893
2959
|
}
|
|
2960
|
+
export function lowerArrayFromValue(lowerer, loc) {
|
|
2961
|
+
const name = "%builtin.Array.from";
|
|
2962
|
+
if (!lowerer.liftedFns.some((fn) => fn.name === name)) {
|
|
2963
|
+
const context = newFnCtx(false, null, null, DYN);
|
|
2964
|
+
lowerer.fnStack.push(context);
|
|
2965
|
+
try {
|
|
2966
|
+
const params = ["source", "options"].map((name) => {
|
|
2967
|
+
const local = lowerer.declareHiddenLocal(name, DYN);
|
|
2968
|
+
return { localId: local.id, name, type: DYN };
|
|
2969
|
+
});
|
|
2970
|
+
const [source, options] = params.map((p) => varRef(p.localId, DYN, loc));
|
|
2971
|
+
const argument = (index) => ({ kind: "dynKeyGet", value: options, key: strLit(index, loc), type: DYN, loc });
|
|
2972
|
+
const value = lowerCheckedArrayFrom(lowerer, source, loc, argument("0"), argument("1"));
|
|
2973
|
+
const constructorCheck = { kind: "if", cond: { kind: "dynTest", test: "function", value: { kind: "libCall", fn: "dyn.this", args: [], type: DYN, loc }, type: BOOL, loc },
|
|
2974
|
+
then: [{ kind: "runtimeFence", code: "SC2020", message: "Array.from with a custom constructor receiver is not supported", loc }], else_: null, loc };
|
|
2975
|
+
lowerer.liftedFns.push({ name, params, returnType: DYN, locals: context.locals, body: [constructorCheck, ...value.stmts, { kind: "return", value: value.result, loc }], loc });
|
|
2976
|
+
}
|
|
2977
|
+
finally {
|
|
2978
|
+
lowerer.fnStack.pop();
|
|
2979
|
+
}
|
|
2980
|
+
}
|
|
2981
|
+
return { kind: "dynFrom", value: { kind: "closure", fnName: name, captures: [], type: { kind: "func", params: [DYN], ret: DYN, rest: true }, loc }, fnName: "from", type: DYN, loc };
|
|
2982
|
+
}
|
|
2894
2983
|
/** `Array.from({ length: n }, mapfn)` — the counted-generation idiom — on
|
|
2895
2984
|
* THE stdlib Array global. The source must be an OBJECT LITERAL whose
|
|
2896
2985
|
* single property is `length` (the shape the idiom always spells; the
|
|
@@ -2914,6 +3003,28 @@ export function lowerArrayFromCall(lowerer, call, access) {
|
|
|
2914
3003
|
return null;
|
|
2915
3004
|
const loc = locOf(call);
|
|
2916
3005
|
const args = call.arguments;
|
|
3006
|
+
if (isJsSourceFile(call.getSourceFile()) && args.length >= 1 && args.length <= 3 && !args.some(ts.isSpreadElement)) {
|
|
3007
|
+
const name = "%builtin.Array.fromDirect";
|
|
3008
|
+
if (!lowerer.liftedFns.some((fn) => fn.name === name)) {
|
|
3009
|
+
const context = newFnCtx(false, null, null, DYN);
|
|
3010
|
+
lowerer.fnStack.push(context);
|
|
3011
|
+
try {
|
|
3012
|
+
const params = ["source", "mapper", "receiver"].map((name) => {
|
|
3013
|
+
const local = lowerer.declareHiddenLocal(name, DYN);
|
|
3014
|
+
return { localId: local.id, name, type: DYN };
|
|
3015
|
+
});
|
|
3016
|
+
const refs = params.map((param) => varRef(param.localId, DYN, loc));
|
|
3017
|
+
const value = lowerCheckedArrayFrom(lowerer, refs[0], loc, refs[1], refs[2]);
|
|
3018
|
+
lowerer.liftedFns.push({ name, params, returnType: DYN, locals: context.locals,
|
|
3019
|
+
body: [...value.stmts, { kind: "return", value: value.result, loc }], loc });
|
|
3020
|
+
}
|
|
3021
|
+
finally {
|
|
3022
|
+
lowerer.fnStack.pop();
|
|
3023
|
+
}
|
|
3024
|
+
}
|
|
3025
|
+
return { kind: "call", callee: name, args: [0, 1, 2].map((i) => args[i]
|
|
3026
|
+
? lowerer.lowerExprExpecting(args[i], DYN) : dynUndefinedExpr(loc)), type: DYN, loc };
|
|
3027
|
+
}
|
|
2917
3028
|
// MAPPER-LESS `Array.from({ length: n })` (usually with an explicit
|
|
2918
3029
|
// type argument — the pMap results-array idiom): a length-n array of
|
|
2919
3030
|
// ABSENT slots, filled by index before any read. Union elements with
|
|
@@ -3211,7 +3322,7 @@ export function lowerMapMethodCall(lowerer, call, access) {
|
|
|
3211
3322
|
if (lowerer.chainBlocked(access, call))
|
|
3212
3323
|
return null;
|
|
3213
3324
|
const name = access.name.text;
|
|
3214
|
-
if (!MAP_METHODS.has(name)
|
|
3325
|
+
if (!MAP_METHODS.has(name))
|
|
3215
3326
|
return null;
|
|
3216
3327
|
let receiverIr = lowerer.mapTypeOf(lowerer.typeOf(access.expression));
|
|
3217
3328
|
let probedUntyped = false;
|
|
@@ -3225,14 +3336,11 @@ export function lowerMapMethodCall(lowerer, call, access) {
|
|
|
3225
3336
|
if (receiverIr?.kind !== "map")
|
|
3226
3337
|
return null;
|
|
3227
3338
|
// Collection views can refine has() while retaining its native ABI.
|
|
3228
|
-
if (!lowerer.isStdlibMember(access) && name !== "has")
|
|
3339
|
+
if (!probedUntyped && !lowerer.isStdlibMember(access) && name !== "has")
|
|
3229
3340
|
return null;
|
|
3230
3341
|
const loc = locOf(call);
|
|
3231
3342
|
const value = lowerer.lowerExpr(access.expression);
|
|
3232
3343
|
const receiver = lowerer.runtimeOptionalPropertyReceiver(access.expression, value, receiverIr, name) ?? value;
|
|
3233
|
-
// The lib's `set` returns the Map (chaining typechecks); the lowered
|
|
3234
|
-
// set is a void statement, so a chained receiver has no value — fence
|
|
3235
|
-
// it instead of emitting a void receiver.
|
|
3236
3344
|
if (receiver.type.kind !== "map") {
|
|
3237
3345
|
lowerer.noLowering("chained Map method calls", access.expression, "the lowered set() produces no value — call each set(k, v) as its own statement");
|
|
3238
3346
|
}
|
|
@@ -3256,7 +3364,12 @@ export function lowerMapMethodCall(lowerer, call, access) {
|
|
|
3256
3364
|
const v = receiverIr.value.kind === "dyn"
|
|
3257
3365
|
? lowerer.lowerCollectionKey(call.arguments[1], receiverIr.value)
|
|
3258
3366
|
: lowerer.lowerExprExpecting(call.arguments[1], receiverIr.value);
|
|
3259
|
-
|
|
3367
|
+
const slot = lowerer.declareHiddenLocal("%mapSetReceiver", receiver.type);
|
|
3368
|
+
const ref = varRef(slot.id, receiver.type, loc);
|
|
3369
|
+
return { kind: "seqExpr", stmts: [
|
|
3370
|
+
{ kind: "varDecl", localId: slot.id, init: receiver, loc },
|
|
3371
|
+
{ kind: "exprStmt", expr: { kind: "mapIntrinsic", method: "set", receiver: ref, args: [k, v], type: VOID, loc }, loc },
|
|
3372
|
+
], result: ref, type: receiver.type, loc };
|
|
3260
3373
|
}
|
|
3261
3374
|
if (name === "has" || name === "delete") {
|
|
3262
3375
|
const k = lowerer.lowerCollectionKey(call.arguments[0], receiverIr.key);
|
|
@@ -3265,31 +3378,39 @@ export function lowerMapMethodCall(lowerer, call, access) {
|
|
|
3265
3378
|
if (name === "clear") {
|
|
3266
3379
|
return { kind: "mapIntrinsic", method: "clear", receiver, args: [], type: VOID, loc };
|
|
3267
3380
|
}
|
|
3268
|
-
if (
|
|
3381
|
+
if (COLLECTION_ITERATOR_METHODS.has(name)) {
|
|
3269
3382
|
return lowerMapIterDrainCall(lowerer, call, receiver, receiverIr, name);
|
|
3270
3383
|
}
|
|
3271
3384
|
// forEach
|
|
3272
3385
|
return lowerMapForEachCall(lowerer, call, receiver, receiverIr, probedUntyped);
|
|
3273
3386
|
}
|
|
3274
|
-
/**
|
|
3275
|
-
|
|
3387
|
+
/** Stored collection iterators retain the native collection by reference. The
|
|
3388
|
+
* checked-value runtime supplies the live cursor without embedding an engine. */
|
|
3389
|
+
function lowerCollectionIteratorCall(lowerer, call, receiver, method) {
|
|
3390
|
+
const access = call.expression;
|
|
3391
|
+
if (!ts.isPropertyAccessExpression(access))
|
|
3392
|
+
throw new InternalCompilerError("collection iterator requires a member call");
|
|
3393
|
+
const boxed = lowerer.coerceInto(access.expression, receiver, DYN);
|
|
3394
|
+
const result = lowerDynDispatchMethodCall(lowerer, call, access, boxed, false);
|
|
3395
|
+
if (!result)
|
|
3396
|
+
throw new InternalCompilerError(`missing collection iterator dispatch: ${method}`);
|
|
3397
|
+
return result;
|
|
3398
|
+
}
|
|
3276
3399
|
/** `[...m.keys()]` / `[...m.values()]` / `[...m.entries()]` — the iterator
|
|
3277
|
-
* methods
|
|
3400
|
+
* methods use an optimized drain as the operand of a spread inside an array
|
|
3278
3401
|
* literal, where JS drains the iterator on the spot. The call desugars to
|
|
3279
3402
|
* a direct call of a synthetic drain function whose loop walks the same
|
|
3280
3403
|
* iteration primitives as the forEach desugar and pushes each live entry
|
|
3281
3404
|
* into a fresh array — key, value, or `[K, V]` tuple record per method.
|
|
3282
3405
|
* No user code runs mid-drain (and nothing here mutates the map), so no
|
|
3283
3406
|
* compaction can shift indices: the enter/exit bracket is unnecessary and
|
|
3284
|
-
* the snapshot IS what JS's immediate drain observes.
|
|
3285
|
-
*
|
|
3286
|
-
* iterator value — fenced with the spread spelling as the hint. */
|
|
3407
|
+
* the snapshot IS what JS's immediate drain observes. Other contexts keep
|
|
3408
|
+
* a live iterator through the native checked-value runtime. */
|
|
3287
3409
|
function lowerMapIterDrainCall(lowerer, call, receiver, mapT, method) {
|
|
3288
3410
|
const loc = locOf(call);
|
|
3289
3411
|
const inArraySpread = ts.isSpreadElement(call.parent) && ts.isArrayLiteralExpression(call.parent.parent);
|
|
3290
|
-
if (!inArraySpread)
|
|
3291
|
-
lowerer
|
|
3292
|
-
}
|
|
3412
|
+
if (!inArraySpread)
|
|
3413
|
+
return lowerCollectionIteratorCall(lowerer, call, receiver, method);
|
|
3293
3414
|
// The pushed element type. For entries the checker's own element type —
|
|
3294
3415
|
// the [K, V] tuple behind MapIterator<[K, V]> — carries the interned
|
|
3295
3416
|
// tuple shape the surrounding literal will intern too.
|
|
@@ -3612,21 +3733,24 @@ export function lowerSetMethodCall(lowerer, call, access) {
|
|
|
3612
3733
|
if (!SET_METHODS.has(name) && !SET_COMBINE_METHODS.has(name))
|
|
3613
3734
|
return null;
|
|
3614
3735
|
let receiverIr = lowerer.mapTypeOf(lowerer.typeOf(access.expression));
|
|
3736
|
+
let probedUntyped = false;
|
|
3615
3737
|
// The identity-Set idiom (JS): the CHECKER type is an unmappable
|
|
3616
3738
|
// Set<union-of-signatures>, but the VALUE lowered as a real Set of
|
|
3617
3739
|
// identity tokens (the new-Set probe) — the lowered receiver's type
|
|
3618
3740
|
// is the honest dispatch key.
|
|
3619
3741
|
if (receiverIr?.kind !== "set" && isJsSourceFile(access.getSourceFile())) {
|
|
3620
3742
|
const probed = tryLowerExpression(lowerer, access.expression);
|
|
3621
|
-
if (probed?.type.kind === "set")
|
|
3743
|
+
if (probed?.type.kind === "set") {
|
|
3622
3744
|
receiverIr = probed.type;
|
|
3745
|
+
probedUntyped = true;
|
|
3746
|
+
}
|
|
3623
3747
|
}
|
|
3624
3748
|
if (receiverIr?.kind !== "set")
|
|
3625
3749
|
return null;
|
|
3626
3750
|
// A collection interface may refine has() into a type predicate.
|
|
3627
3751
|
// Type mapping checked that view's native ABI; the value check below
|
|
3628
3752
|
// still rejects structural mocks and assertions over other objects.
|
|
3629
|
-
if (!lowerer.isStdlibMember(access) && name !== "has")
|
|
3753
|
+
if (!probedUntyped && !lowerer.isStdlibMember(access) && name !== "has")
|
|
3630
3754
|
return null;
|
|
3631
3755
|
const loc = locOf(call);
|
|
3632
3756
|
const value = lowerer.lowerExpr(access.expression);
|
|
@@ -3639,6 +3763,9 @@ export function lowerSetMethodCall(lowerer, call, access) {
|
|
|
3639
3763
|
if (name === "forEach" && call.arguments.length !== 1) {
|
|
3640
3764
|
lowerer.noLowering(`.forEach with ${call.arguments.length} arguments`, call, "the thisArg parameter has no lowering — use an arrow function");
|
|
3641
3765
|
}
|
|
3766
|
+
if (COLLECTION_ITERATOR_METHODS.has(name)) {
|
|
3767
|
+
return lowerCollectionIteratorCall(lowerer, call, receiver, name);
|
|
3768
|
+
}
|
|
3642
3769
|
if (SET_COMBINE_METHODS.has(name)) {
|
|
3643
3770
|
return lowerSetCombineCall(lowerer, call, name, receiver, receiverIr);
|
|
3644
3771
|
}
|
|
@@ -5067,22 +5194,12 @@ function lowerForOfMapOrSet(lowerer, stmt, iterable, contT, proj) {
|
|
|
5067
5194
|
}
|
|
5068
5195
|
}
|
|
5069
5196
|
else {
|
|
5070
|
-
//
|
|
5071
|
-
//
|
|
5072
|
-
//
|
|
5073
|
-
|
|
5074
|
-
|
|
5075
|
-
|
|
5076
|
-
const shape = elemT?.kind === "record" ? lowerer.shapes.get(elemT.shapeId) : null;
|
|
5077
|
-
if (elemT?.kind !== "record" || !shape?.tuple || shape.fields.length !== 2 ||
|
|
5078
|
-
!typeEquals(shape.fields.find((f) => f.name === "0").type, keyT) ||
|
|
5079
|
-
!typeEquals(shape.fields.find((f) => f.name === "1").type, secondT)) {
|
|
5080
|
-
lowerer.badType(decl.name, lowerer.checker.getTypeAtLocation(decl.name)); // defensive: the lib declares [K, V]
|
|
5081
|
-
}
|
|
5082
|
-
}
|
|
5083
|
-
else if (!elemT || !typeEquals(elemT, singleT)) {
|
|
5084
|
-
lowerer.badType(decl.name, lowerer.checker.getTypeAtLocation(decl.name)); // defensive: the lib declares T
|
|
5085
|
-
}
|
|
5197
|
+
// Derive the yielded layout from the represented container. JS
|
|
5198
|
+
// inference can leave the pattern at any even when the Map's
|
|
5199
|
+
// native key/value types are known after specialization.
|
|
5200
|
+
const elemT = yieldsPair
|
|
5201
|
+
? { kind: "record", shapeId: lowerer.shapes.intern([{ name: "0", type: keyT }, { name: "1", type: secondT }], true) }
|
|
5202
|
+
: singleT;
|
|
5086
5203
|
const elemInit = yieldsPair
|
|
5087
5204
|
? {
|
|
5088
5205
|
kind: "recordLit",
|
|
@@ -5253,8 +5370,8 @@ export function lowerSetSeedNew(lowerer, node, setT) {
|
|
|
5253
5370
|
(source.type.kind === "dyn" || source.type.kind === "jsval")) {
|
|
5254
5371
|
source = lowerer.coerceInto(node, source, STRING);
|
|
5255
5372
|
}
|
|
5256
|
-
if (
|
|
5257
|
-
return { kind: "dynCheck", value: { kind: "libCall", fn: "dyn.nativeSetNew", args: [source], type: DYN, loc }, type: setT, loc };
|
|
5373
|
+
if (setT.elem.kind === "dyn" && lowerer.dynConvertible(source.type)) {
|
|
5374
|
+
return { kind: "dynCheck", value: { kind: "libCall", fn: "dyn.nativeSetNew", args: [lowerer.coerceInto(node, source, DYN)], type: DYN, loc }, type: setT, loc };
|
|
5258
5375
|
}
|
|
5259
5376
|
if (declared?.kind === "array" && typeEquals(declared.elem, setT.elem)) {
|
|
5260
5377
|
// Preserve the existing checked scalar-iterable bridge. Reference
|
|
@@ -5447,7 +5564,8 @@ function mapFromSeedValue(lowerer, seed, mapT) {
|
|
|
5447
5564
|
}
|
|
5448
5565
|
return { kind: "call", callee: name, args: [seed], type: mapT, loc };
|
|
5449
5566
|
}
|
|
5450
|
-
if (seed.type.kind === "dyn" || seed.type.kind === "array" &&
|
|
5567
|
+
if (seed.type.kind === "dyn" || seed.type.kind === "array" &&
|
|
5568
|
+
!(seed.type.elem.kind === "record" && lowerer.shapes.get(seed.type.elem.shapeId)?.tuple)) {
|
|
5451
5569
|
const key = `checked-seed:${typeKey(mapT)}`;
|
|
5452
5570
|
let name = lowerer.mapHofHelpers.get(key);
|
|
5453
5571
|
if (!name) {
|
|
@@ -5802,6 +5920,9 @@ function lowerTypedObjectFromEntriesCall(lowerer, call, callee) {
|
|
|
5802
5920
|
const argIr = lowerer.mapTypeOf(lowerer.typeOf(argNode));
|
|
5803
5921
|
if (argIr?.kind !== "array")
|
|
5804
5922
|
return null;
|
|
5923
|
+
const represented = tryLowerExpression(lowerer, argNode);
|
|
5924
|
+
if (represented && !typeEquals(represented.type, argIr))
|
|
5925
|
+
return null;
|
|
5805
5926
|
// `Object.fromEntries(rows)` over a `string[][]` VALUE — the env-line
|
|
5806
5927
|
// idiom (`envArray.map((env) => env.split('='))`). The checker has no
|
|
5807
5928
|
// tuple to type here (string[] misses the lib's [PropertyKey, T]
|