@scriptc/compiler 0.2.0 → 0.2.1
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 +25 -15
- 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 +5 -0
- package/dist/backend/llvm/dyn.js +166 -99
- package/dist/backend/llvm/dyn.js.map +1 -1
- package/dist/backend/llvm/emitter.d.ts +2 -2
- package/dist/backend/llvm/emitter.js +79 -20
- package/dist/backend/llvm/emitter.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-control.js +1 -1
- package/dist/backend/llvm/expr-control.js.map +1 -1
- package/dist/backend/llvm/expr-dynamic.js +18 -9
- 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 +125 -17
- package/dist/backend/llvm/expr-stream-bridges.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 +45 -2
- 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/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/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/diagnostics/diagnostic.js +2 -7
- package/dist/diagnostics/diagnostic.js.map +1 -1
- package/dist/frontend/lowering/class-callbacks.d.ts +3 -3
- package/dist/frontend/lowering/class-callbacks.js +26 -15
- package/dist/frontend/lowering/class-callbacks.js.map +1 -1
- package/dist/frontend/lowering/class-construction.d.ts +12 -0
- package/dist/frontend/lowering/class-construction.js +156 -0
- package/dist/frontend/lowering/class-construction.js.map +1 -0
- package/dist/frontend/lowering/class-descriptors.d.ts +1 -0
- package/dist/frontend/lowering/class-descriptors.js +46 -5
- package/dist/frontend/lowering/class-descriptors.js.map +1 -1
- package/dist/frontend/lowering/class-dynamic-dispatch.d.ts +11 -1
- package/dist/frontend/lowering/class-dynamic-dispatch.js +403 -48
- package/dist/frontend/lowering/class-dynamic-dispatch.js.map +1 -1
- package/dist/frontend/lowering/class-dynamic-dispatch.test.js +2 -1
- package/dist/frontend/lowering/class-dynamic-dispatch.test.js.map +1 -1
- package/dist/frontend/lowering/class-instance-constructor.js +4 -1
- package/dist/frontend/lowering/class-instance-constructor.js.map +1 -1
- package/dist/frontend/lowering/class-method-values.d.ts +4 -1
- package/dist/frontend/lowering/class-method-values.js +72 -7
- package/dist/frontend/lowering/class-method-values.js.map +1 -1
- package/dist/frontend/lowering/class-prototypes.d.ts +5 -2
- package/dist/frontend/lowering/class-prototypes.js +121 -13
- 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 +66 -0
- package/dist/frontend/lowering/class-runtime-statics.js.map +1 -0
- package/dist/frontend/lowering/class-static-data.js +2 -2
- package/dist/frontend/lowering/class-static-data.js.map +1 -1
- package/dist/frontend/lowering/containers/bytes.js +49 -13
- package/dist/frontend/lowering/containers/bytes.js.map +1 -1
- package/dist/frontend/lowering/containers/string-and-regexp.js +19 -47
- package/dist/frontend/lowering/containers/string-and-regexp.js.map +1 -1
- 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 +38 -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 +69 -17
- 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 +6 -5
- package/dist/frontend/lowering/lower-builtins.js +156 -41
- 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 +448 -83
- package/dist/frontend/lowering/lower-calls.js.map +1 -1
- package/dist/frontend/lowering/lower-classes.d.ts +13 -13
- package/dist/frontend/lowering/lower-classes.js +650 -176
- 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 +135 -36
- 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 +2 -2
- package/dist/frontend/lowering/lower-exprs.js +531 -126
- package/dist/frontend/lowering/lower-exprs.js.map +1 -1
- package/dist/frontend/lowering/lower-generators.js +12 -1
- package/dist/frontend/lowering/lower-generators.js.map +1 -1
- package/dist/frontend/lowering/lower-island.d.ts +2 -0
- package/dist/frontend/lowering/lower-island.js +32 -10
- package/dist/frontend/lowering/lower-island.js.map +1 -1
- package/dist/frontend/lowering/lower-modules.js +220 -17
- 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 +39 -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 +135 -26
- package/dist/frontend/lowering/lower-stmts.js.map +1 -1
- package/dist/frontend/lowering/lower-stream.js +1 -1
- package/dist/frontend/lowering/lower-stream.js.map +1 -1
- package/dist/frontend/lowering/lowerer.d.ts +27 -1
- package/dist/frontend/lowering/lowerer.js +172 -50
- package/dist/frontend/lowering/lowerer.js.map +1 -1
- package/dist/frontend/lowering/lowerer.test.js +149 -3
- package/dist/frontend/lowering/lowerer.test.js.map +1 -1
- package/dist/frontend/lowering/surfaces.d.ts +2 -0
- package/dist/frontend/lowering/surfaces.js +25 -8
- 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 +5 -0
- package/dist/frontend/lowering/text-decoder-encoding.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 +53 -24
- 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 +90 -13
- 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 +2 -2
- package/dist/frontend/union-discriminants.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 +52 -33
- package/dist/ir/ir.js +142 -42
- 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 +15 -3
- package/dist/ir/serialize.js.map +1 -1
- package/dist/ir/serialize.test.js +5 -1
- package/dist/ir/serialize.test.js.map +1 -1
- package/dist/ir/validate.js +80 -11
- package/dist/ir/validate.js.map +1 -1
- package/dist/ir/validate.test.js +61 -1
- package/dist/ir/validate.test.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 +56 -81
|
@@ -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): 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
|
|
@@ -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")) {
|
|
@@ -2866,31 +2896,82 @@ export function lowerArrayOfCall(lowerer, call, access) {
|
|
|
2866
2896
|
}
|
|
2867
2897
|
/** Mapper-less checked Array.from: acquire once, then step through emitted
|
|
2868
2898
|
* property and call dispatch so native class iterators retain their methods. */
|
|
2869
|
-
function lowerCheckedArrayFrom(lowerer, source, loc) {
|
|
2899
|
+
export function lowerCheckedArrayFrom(lowerer, source, loc, mapper, receiver, numeric = false) {
|
|
2870
2900
|
const iterator = lowerer.declareHiddenLocal("%fromIterator", DYN);
|
|
2871
2901
|
const next = lowerer.declareHiddenLocal("%fromNext", DYN);
|
|
2872
2902
|
const step = lowerer.declareHiddenLocal("%fromStep", DYN);
|
|
2873
2903
|
const out = lowerer.declareHiddenLocal("%fromArray", DYN);
|
|
2874
2904
|
const done = lowerer.declareHiddenLocal("%fromDone", BOOL);
|
|
2875
2905
|
done.mutable = true;
|
|
2906
|
+
const index = mapper ? lowerer.declareHiddenLocal("%fromIndex", F64) : null;
|
|
2907
|
+
if (index)
|
|
2908
|
+
index.mutable = true;
|
|
2876
2909
|
const get = (value, key) => ({ kind: "dynKeyGet", value, key: strLit(key, loc), type: DYN, loc });
|
|
2910
|
+
const item = get(varRef(step.id, DYN, loc), "value");
|
|
2911
|
+
const mapped = mapper && index ? { kind: "ternary", cond: { kind: "dynTest", test: "undefined", value: mapper, type: BOOL, loc },
|
|
2912
|
+
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;
|
|
2913
|
+
const element = numeric ? lowerer.coerceToExpected({ kind: "libCall", fn: "dyn.toNumberCoerce", args: [mapped], type: F64, loc }, DYN) : mapped;
|
|
2914
|
+
let append = { kind: "exprStmt", expr: { kind: "dynInvoke", recv: varRef(out.id, DYN, loc), method: "push", calleeName: "Array.from", args: [element], type: DYN, loc }, loc };
|
|
2915
|
+
if (mapper) {
|
|
2916
|
+
const error = lowerer.declareHiddenLocal("%fromError", CAUGHT);
|
|
2917
|
+
const close = lowerer.declareHiddenLocal("%fromReturn", DYN);
|
|
2918
|
+
append = { kind: "tryCatch", tryBody: [append], catchLocalId: error.id, finallyBody: null, loc, catchBody: [
|
|
2919
|
+
{ kind: "tryCatch", catchLocalId: null, catchBody: [], finallyBody: null, loc, tryBody: [
|
|
2920
|
+
{ kind: "varDecl", localId: close.id, init: get(varRef(iterator.id, DYN, loc), "return"), loc },
|
|
2921
|
+
{ kind: "if", cond: { kind: "dynTest", test: "function", value: varRef(close.id, DYN, loc), type: BOOL, loc }, then: [
|
|
2922
|
+
{ 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 },
|
|
2923
|
+
], else_: null, loc },
|
|
2924
|
+
] },
|
|
2925
|
+
{ kind: "rethrow", localId: error.id, loc },
|
|
2926
|
+
] };
|
|
2927
|
+
}
|
|
2877
2928
|
const stmts = [
|
|
2929
|
+
...(mapper ? [{ kind: "if", cond: { kind: "dynTest", test: "undefined", value: mapper, type: BOOL, loc }, then: [], else_: [
|
|
2930
|
+
{ kind: "if", cond: { kind: "dynTest", test: "function", value: mapper, type: BOOL, loc }, then: [], else_: [
|
|
2931
|
+
{ kind: "exprStmt", expr: nodeThrowExpr(1, "", "Array.from mapper is not a function", DYN, loc), loc },
|
|
2932
|
+
], loc },
|
|
2933
|
+
], loc }] : []),
|
|
2878
2934
|
{ kind: "varDecl", localId: iterator.id, init: { kind: "libCall", fn: "dyn.iteratorResult", args: [{ kind: "libCall", fn: "dyn.arrayFromIterator", args: [source], type: DYN, loc }], type: DYN, loc }, loc },
|
|
2879
2935
|
{ kind: "varDecl", localId: next.id, init: get(varRef(iterator.id, DYN, loc), "next"), loc },
|
|
2880
2936
|
{ kind: "varDecl", localId: out.id, init: { kind: "dynArrLit", elems: [], type: DYN, loc }, loc },
|
|
2881
2937
|
{ kind: "varDecl", localId: done.id, init: boolLit(false, loc), loc },
|
|
2938
|
+
...(index ? [{ kind: "varDecl", localId: index.id, init: numLit(0, loc), loc }] : []),
|
|
2882
2939
|
{ kind: "while", cond: { kind: "unary", op: "!", operand: varRef(done.id, BOOL, loc), type: BOOL, loc }, body: [
|
|
2883
2940
|
{ kind: "varDecl", localId: step.id, init: { kind: "libCall", fn: "dyn.iteratorResult", args: [{
|
|
2884
2941
|
kind: "dynCall", callee: varRef(next.id, DYN, loc), receiver: varRef(iterator.id, DYN, loc), calleeName: "iterator.next", args: [], type: DYN, loc,
|
|
2885
2942
|
}], type: DYN, loc }, loc },
|
|
2886
2943
|
{ kind: "assign", localId: done.id, value: { kind: "dynTest", test: "truthy", value: get(varRef(step.id, DYN, loc), "done"), type: BOOL, loc }, loc },
|
|
2887
2944
|
{ kind: "if", cond: { kind: "unary", op: "!", operand: varRef(done.id, BOOL, loc), type: BOOL, loc }, then: [
|
|
2888
|
-
|
|
2945
|
+
append,
|
|
2946
|
+
...(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
2947
|
], else_: null, loc },
|
|
2890
2948
|
], loc },
|
|
2891
2949
|
];
|
|
2892
2950
|
return { kind: "seqExpr", stmts, result: varRef(out.id, DYN, loc), type: DYN, loc };
|
|
2893
2951
|
}
|
|
2952
|
+
export function lowerArrayFromValue(lowerer, loc) {
|
|
2953
|
+
const name = "%builtin.Array.from";
|
|
2954
|
+
if (!lowerer.liftedFns.some((fn) => fn.name === name)) {
|
|
2955
|
+
const context = newFnCtx(false, null, null, DYN);
|
|
2956
|
+
lowerer.fnStack.push(context);
|
|
2957
|
+
try {
|
|
2958
|
+
const params = ["source", "options"].map((name) => {
|
|
2959
|
+
const local = lowerer.declareHiddenLocal(name, DYN);
|
|
2960
|
+
return { localId: local.id, name, type: DYN };
|
|
2961
|
+
});
|
|
2962
|
+
const [source, options] = params.map((p) => varRef(p.localId, DYN, loc));
|
|
2963
|
+
const argument = (index) => ({ kind: "dynKeyGet", value: options, key: strLit(index, loc), type: DYN, loc });
|
|
2964
|
+
const value = lowerCheckedArrayFrom(lowerer, source, loc, argument("0"), argument("1"));
|
|
2965
|
+
const constructorCheck = { kind: "if", cond: { kind: "dynTest", test: "function", value: { kind: "libCall", fn: "dyn.this", args: [], type: DYN, loc }, type: BOOL, loc },
|
|
2966
|
+
then: [{ kind: "runtimeFence", code: "SC2020", message: "Array.from with a custom constructor receiver is not supported", loc }], else_: null, loc };
|
|
2967
|
+
lowerer.liftedFns.push({ name, params, returnType: DYN, locals: context.locals, body: [constructorCheck, ...value.stmts, { kind: "return", value: value.result, loc }], loc });
|
|
2968
|
+
}
|
|
2969
|
+
finally {
|
|
2970
|
+
lowerer.fnStack.pop();
|
|
2971
|
+
}
|
|
2972
|
+
}
|
|
2973
|
+
return { kind: "dynFrom", value: { kind: "closure", fnName: name, captures: [], type: { kind: "func", params: [DYN], ret: DYN, rest: true }, loc }, fnName: "from", type: DYN, loc };
|
|
2974
|
+
}
|
|
2894
2975
|
/** `Array.from({ length: n }, mapfn)` — the counted-generation idiom — on
|
|
2895
2976
|
* THE stdlib Array global. The source must be an OBJECT LITERAL whose
|
|
2896
2977
|
* single property is `length` (the shape the idiom always spells; the
|
|
@@ -2914,6 +2995,28 @@ export function lowerArrayFromCall(lowerer, call, access) {
|
|
|
2914
2995
|
return null;
|
|
2915
2996
|
const loc = locOf(call);
|
|
2916
2997
|
const args = call.arguments;
|
|
2998
|
+
if (isJsSourceFile(call.getSourceFile()) && args.length >= 1 && args.length <= 3 && !args.some(ts.isSpreadElement)) {
|
|
2999
|
+
const name = "%builtin.Array.fromDirect";
|
|
3000
|
+
if (!lowerer.liftedFns.some((fn) => fn.name === name)) {
|
|
3001
|
+
const context = newFnCtx(false, null, null, DYN);
|
|
3002
|
+
lowerer.fnStack.push(context);
|
|
3003
|
+
try {
|
|
3004
|
+
const params = ["source", "mapper", "receiver"].map((name) => {
|
|
3005
|
+
const local = lowerer.declareHiddenLocal(name, DYN);
|
|
3006
|
+
return { localId: local.id, name, type: DYN };
|
|
3007
|
+
});
|
|
3008
|
+
const refs = params.map((param) => varRef(param.localId, DYN, loc));
|
|
3009
|
+
const value = lowerCheckedArrayFrom(lowerer, refs[0], loc, refs[1], refs[2]);
|
|
3010
|
+
lowerer.liftedFns.push({ name, params, returnType: DYN, locals: context.locals,
|
|
3011
|
+
body: [...value.stmts, { kind: "return", value: value.result, loc }], loc });
|
|
3012
|
+
}
|
|
3013
|
+
finally {
|
|
3014
|
+
lowerer.fnStack.pop();
|
|
3015
|
+
}
|
|
3016
|
+
}
|
|
3017
|
+
return { kind: "call", callee: name, args: [0, 1, 2].map((i) => args[i]
|
|
3018
|
+
? lowerer.lowerExprExpecting(args[i], DYN) : dynUndefinedExpr(loc)), type: DYN, loc };
|
|
3019
|
+
}
|
|
2917
3020
|
// MAPPER-LESS `Array.from({ length: n })` (usually with an explicit
|
|
2918
3021
|
// type argument — the pMap results-array idiom): a length-n array of
|
|
2919
3022
|
// ABSENT slots, filled by index before any read. Union elements with
|
|
@@ -3225,14 +3328,11 @@ export function lowerMapMethodCall(lowerer, call, access) {
|
|
|
3225
3328
|
if (receiverIr?.kind !== "map")
|
|
3226
3329
|
return null;
|
|
3227
3330
|
// Collection views can refine has() while retaining its native ABI.
|
|
3228
|
-
if (!lowerer.isStdlibMember(access) && name !== "has")
|
|
3331
|
+
if (!probedUntyped && !lowerer.isStdlibMember(access) && name !== "has")
|
|
3229
3332
|
return null;
|
|
3230
3333
|
const loc = locOf(call);
|
|
3231
3334
|
const value = lowerer.lowerExpr(access.expression);
|
|
3232
3335
|
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
3336
|
if (receiver.type.kind !== "map") {
|
|
3237
3337
|
lowerer.noLowering("chained Map method calls", access.expression, "the lowered set() produces no value — call each set(k, v) as its own statement");
|
|
3238
3338
|
}
|
|
@@ -3256,7 +3356,12 @@ export function lowerMapMethodCall(lowerer, call, access) {
|
|
|
3256
3356
|
const v = receiverIr.value.kind === "dyn"
|
|
3257
3357
|
? lowerer.lowerCollectionKey(call.arguments[1], receiverIr.value)
|
|
3258
3358
|
: lowerer.lowerExprExpecting(call.arguments[1], receiverIr.value);
|
|
3259
|
-
|
|
3359
|
+
const slot = lowerer.declareHiddenLocal("%mapSetReceiver", receiver.type);
|
|
3360
|
+
const ref = varRef(slot.id, receiver.type, loc);
|
|
3361
|
+
return { kind: "seqExpr", stmts: [
|
|
3362
|
+
{ kind: "varDecl", localId: slot.id, init: receiver, loc },
|
|
3363
|
+
{ kind: "exprStmt", expr: { kind: "mapIntrinsic", method: "set", receiver: ref, args: [k, v], type: VOID, loc }, loc },
|
|
3364
|
+
], result: ref, type: receiver.type, loc };
|
|
3260
3365
|
}
|
|
3261
3366
|
if (name === "has" || name === "delete") {
|
|
3262
3367
|
const k = lowerer.lowerCollectionKey(call.arguments[0], receiverIr.key);
|
|
@@ -3612,21 +3717,24 @@ export function lowerSetMethodCall(lowerer, call, access) {
|
|
|
3612
3717
|
if (!SET_METHODS.has(name) && !SET_COMBINE_METHODS.has(name))
|
|
3613
3718
|
return null;
|
|
3614
3719
|
let receiverIr = lowerer.mapTypeOf(lowerer.typeOf(access.expression));
|
|
3720
|
+
let probedUntyped = false;
|
|
3615
3721
|
// The identity-Set idiom (JS): the CHECKER type is an unmappable
|
|
3616
3722
|
// Set<union-of-signatures>, but the VALUE lowered as a real Set of
|
|
3617
3723
|
// identity tokens (the new-Set probe) — the lowered receiver's type
|
|
3618
3724
|
// is the honest dispatch key.
|
|
3619
3725
|
if (receiverIr?.kind !== "set" && isJsSourceFile(access.getSourceFile())) {
|
|
3620
3726
|
const probed = tryLowerExpression(lowerer, access.expression);
|
|
3621
|
-
if (probed?.type.kind === "set")
|
|
3727
|
+
if (probed?.type.kind === "set") {
|
|
3622
3728
|
receiverIr = probed.type;
|
|
3729
|
+
probedUntyped = true;
|
|
3730
|
+
}
|
|
3623
3731
|
}
|
|
3624
3732
|
if (receiverIr?.kind !== "set")
|
|
3625
3733
|
return null;
|
|
3626
3734
|
// A collection interface may refine has() into a type predicate.
|
|
3627
3735
|
// Type mapping checked that view's native ABI; the value check below
|
|
3628
3736
|
// still rejects structural mocks and assertions over other objects.
|
|
3629
|
-
if (!lowerer.isStdlibMember(access) && name !== "has")
|
|
3737
|
+
if (!probedUntyped && !lowerer.isStdlibMember(access) && name !== "has")
|
|
3630
3738
|
return null;
|
|
3631
3739
|
const loc = locOf(call);
|
|
3632
3740
|
const value = lowerer.lowerExpr(access.expression);
|
|
@@ -5067,22 +5175,12 @@ function lowerForOfMapOrSet(lowerer, stmt, iterable, contT, proj) {
|
|
|
5067
5175
|
}
|
|
5068
5176
|
}
|
|
5069
5177
|
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
|
-
}
|
|
5178
|
+
// Derive the yielded layout from the represented container. JS
|
|
5179
|
+
// inference can leave the pattern at any even when the Map's
|
|
5180
|
+
// native key/value types are known after specialization.
|
|
5181
|
+
const elemT = yieldsPair
|
|
5182
|
+
? { kind: "record", shapeId: lowerer.shapes.intern([{ name: "0", type: keyT }, { name: "1", type: secondT }], true) }
|
|
5183
|
+
: singleT;
|
|
5086
5184
|
const elemInit = yieldsPair
|
|
5087
5185
|
? {
|
|
5088
5186
|
kind: "recordLit",
|
|
@@ -5447,7 +5545,8 @@ function mapFromSeedValue(lowerer, seed, mapT) {
|
|
|
5447
5545
|
}
|
|
5448
5546
|
return { kind: "call", callee: name, args: [seed], type: mapT, loc };
|
|
5449
5547
|
}
|
|
5450
|
-
if (seed.type.kind === "dyn" || seed.type.kind === "array" &&
|
|
5548
|
+
if (seed.type.kind === "dyn" || seed.type.kind === "array" &&
|
|
5549
|
+
(seed.type.elem.kind === "dyn" || seed.type.elem.kind === "array")) {
|
|
5451
5550
|
const key = `checked-seed:${typeKey(mapT)}`;
|
|
5452
5551
|
let name = lowerer.mapHofHelpers.get(key);
|
|
5453
5552
|
if (!name) {
|