@scriptc/compiler 0.2.8 → 0.2.9
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 +1 -0
- package/dist/backend/cycle-analysis.js +50 -17
- package/dist/backend/cycle-analysis.js.map +1 -1
- package/dist/backend/cycle-analysis.test.js +138 -14
- package/dist/backend/cycle-analysis.test.js.map +1 -1
- package/dist/backend/cycle-mutability.d.ts +31 -6
- package/dist/backend/cycle-mutability.js +120 -18
- package/dist/backend/cycle-mutability.js.map +1 -1
- package/dist/backend/llvm/alloc.d.ts +13 -3
- package/dist/backend/llvm/alloc.js +24 -10
- package/dist/backend/llvm/alloc.js.map +1 -1
- package/dist/backend/llvm/alloc.test.js +5 -5
- package/dist/backend/llvm/alloc.test.js.map +1 -1
- package/dist/backend/llvm/byte-numbers.js +2 -3
- package/dist/backend/llvm/byte-numbers.js.map +1 -1
- package/dist/backend/llvm/classes.js +7 -6
- package/dist/backend/llvm/classes.js.map +1 -1
- package/dist/backend/llvm/common.d.ts +17 -0
- package/dist/backend/llvm/common.js +28 -0
- package/dist/backend/llvm/common.js.map +1 -1
- package/dist/backend/llvm/dense-array-access.js +1 -1
- package/dist/backend/llvm/dense-array-access.test.js +1 -1
- package/dist/backend/llvm/dyn.d.ts +4 -4
- package/dist/backend/llvm/dyn.js +27 -11
- package/dist/backend/llvm/dyn.js.map +1 -1
- package/dist/backend/llvm/emitter.d.ts +45 -3
- package/dist/backend/llvm/emitter.js +333 -74
- package/dist/backend/llvm/emitter.js.map +1 -1
- package/dist/backend/llvm/emitter.test.js +36 -3
- package/dist/backend/llvm/emitter.test.js.map +1 -1
- package/dist/backend/llvm/expr-bytes.js +35 -28
- package/dist/backend/llvm/expr-bytes.js.map +1 -1
- package/dist/backend/llvm/expr-containers.js +1 -1
- package/dist/backend/llvm/expr-context.d.ts +2 -0
- package/dist/backend/llvm/expr-control.js +46 -5
- package/dist/backend/llvm/expr-control.js.map +1 -1
- package/dist/backend/llvm/expr-dynamic.js +3 -0
- package/dist/backend/llvm/expr-dynamic.js.map +1 -1
- package/dist/backend/llvm/expr-stream-bridges.d.ts +3 -0
- package/dist/backend/llvm/expr-stream-bridges.js +73 -11
- package/dist/backend/llvm/expr-stream-bridges.js.map +1 -1
- package/dist/backend/llvm/lib-filesystem.js +18 -2
- package/dist/backend/llvm/lib-filesystem.js.map +1 -1
- package/dist/backend/llvm/lib-shared.js +1 -0
- package/dist/backend/llvm/lib-shared.js.map +1 -1
- package/dist/backend/llvm/local-array-reads.d.ts +17 -6
- package/dist/backend/llvm/local-array-reads.js +155 -43
- package/dist/backend/llvm/local-array-reads.js.map +1 -1
- package/dist/backend/llvm/reference-effects.js +34 -1
- package/dist/backend/llvm/reference-effects.js.map +1 -1
- package/dist/backend/llvm/shapes.d.ts +14 -3
- package/dist/backend/llvm/shapes.js +43 -12
- package/dist/backend/llvm/shapes.js.map +1 -1
- package/dist/backend/llvm/shapes.test.js +5 -5
- package/dist/backend/llvm/shapes.test.js.map +1 -1
- package/dist/backend/llvm/string-reads.js +29 -26
- package/dist/backend/llvm/string-reads.js.map +1 -1
- package/dist/backend/llvm/string-slices.js +1 -1
- package/dist/backend/llvm/trunc.d.ts +8 -0
- package/dist/backend/llvm/trunc.js +28 -0
- package/dist/backend/llvm/trunc.js.map +1 -0
- package/dist/backend/loop-polls.d.ts +14 -0
- package/dist/backend/loop-polls.js +100 -0
- package/dist/backend/loop-polls.js.map +1 -0
- package/dist/backend/loop-polls.test.d.ts +1 -0
- package/dist/backend/loop-polls.test.js +86 -0
- package/dist/backend/loop-polls.test.js.map +1 -0
- package/dist/backend/may-throw.js +20 -1
- package/dist/backend/may-throw.js.map +1 -1
- package/dist/backend/may-throw.test.js +23 -0
- package/dist/backend/may-throw.test.js.map +1 -1
- package/dist/backend/native-codegen.d.ts +1 -3
- package/dist/backend/native-codegen.js +4 -32
- package/dist/backend/native-codegen.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-abi.js.map +1 -1
- package/dist/backend/runtime-pack-targets.test.js +1 -1
- package/dist/backend/runtime-pack-targets.test.js.map +1 -1
- package/dist/backend/runtime-pack.test.js +1 -1
- package/dist/backend/runtime-pack.test.js.map +1 -1
- package/dist/cli/command.js +8 -1
- package/dist/cli/command.js.map +1 -1
- package/dist/cli/output-options.d.ts +1 -0
- package/dist/cli/output-options.js +3 -0
- package/dist/cli/output-options.js.map +1 -1
- package/dist/cli/usage.d.ts +5 -1
- package/dist/cli/usage.js +6 -0
- package/dist/cli/usage.js.map +1 -1
- package/dist/compile-types.d.ts +5 -0
- package/dist/executable/executable-cache.d.ts +2 -0
- package/dist/executable/executable-cache.js +3 -0
- package/dist/executable/executable-cache.js.map +1 -1
- package/dist/executable/executable-cache.test.js +1 -0
- package/dist/executable/executable-cache.test.js.map +1 -1
- package/dist/frontend/lowering/array-values.js +37 -1
- package/dist/frontend/lowering/array-values.js.map +1 -1
- package/dist/frontend/lowering/builtins/strings.js +4 -1
- package/dist/frontend/lowering/builtins/strings.js.map +1 -1
- package/dist/frontend/lowering/call-arguments.js +96 -4
- package/dist/frontend/lowering/call-arguments.js.map +1 -1
- package/dist/frontend/lowering/class-method-mutations.js +88 -0
- package/dist/frontend/lowering/class-method-mutations.js.map +1 -1
- package/dist/frontend/lowering/containers/bytes.js +15 -4
- package/dist/frontend/lowering/containers/bytes.js.map +1 -1
- package/dist/frontend/lowering/expressions/union-fields.d.ts +19 -0
- package/dist/frontend/lowering/expressions/union-fields.js +236 -0
- package/dist/frontend/lowering/expressions/union-fields.js.map +1 -0
- package/dist/frontend/lowering/lower-calls.js +12 -2
- package/dist/frontend/lowering/lower-calls.js.map +1 -1
- package/dist/frontend/lowering/lower-exprs.d.ts +6 -0
- package/dist/frontend/lowering/lower-exprs.js +162 -3
- package/dist/frontend/lowering/lower-exprs.js.map +1 -1
- package/dist/frontend/lowering/lower-island.js +5 -19
- package/dist/frontend/lowering/lower-island.js.map +1 -1
- package/dist/frontend/lowering/lower-stmts.js +11 -1
- package/dist/frontend/lowering/lower-stmts.js.map +1 -1
- package/dist/frontend/lowering/lowerer.d.ts +5 -0
- package/dist/frontend/lowering/lowerer.js +174 -8
- package/dist/frontend/lowering/lowerer.js.map +1 -1
- package/dist/frontend/lowering/nan-coded-reads.d.ts +161 -0
- package/dist/frontend/lowering/nan-coded-reads.js +1342 -0
- package/dist/frontend/lowering/nan-coded-reads.js.map +1 -0
- package/dist/frontend/lowering/runtime-optional-bounds.d.ts +14 -2
- package/dist/frontend/lowering/runtime-optional-bounds.js +17 -11
- package/dist/frontend/lowering/runtime-optional-bounds.js.map +1 -1
- package/dist/frontend/lowering/runtime-optional-bounds.test.js +28 -0
- package/dist/frontend/lowering/runtime-optional-bounds.test.js.map +1 -1
- package/dist/frontend/lowering/surfaces.js +8 -0
- package/dist/frontend/lowering/surfaces.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +20 -8
- package/dist/index.js.map +1 -1
- package/dist/ir/builtin-signatures.d.ts +1 -1
- package/dist/ir/builtin-signatures.js +2 -0
- package/dist/ir/builtin-signatures.js.map +1 -1
- package/dist/ir/constant-globals.d.ts +14 -0
- package/dist/ir/constant-globals.js +81 -0
- package/dist/ir/constant-globals.js.map +1 -0
- package/dist/ir/constant-globals.test.d.ts +1 -0
- package/dist/ir/constant-globals.test.js +97 -0
- package/dist/ir/constant-globals.test.js.map +1 -0
- package/dist/ir/final-fields.d.ts +35 -0
- package/dist/ir/final-fields.js +187 -0
- package/dist/ir/final-fields.js.map +1 -0
- package/dist/ir/final-fields.test.d.ts +1 -0
- package/dist/ir/final-fields.test.js +106 -0
- package/dist/ir/final-fields.test.js.map +1 -0
- package/dist/ir/int32-slots.d.ts +9 -0
- package/dist/ir/int32-slots.js +70 -57
- package/dist/ir/int32-slots.js.map +1 -1
- package/dist/ir/int32-slots.test.js +27 -0
- package/dist/ir/int32-slots.test.js.map +1 -1
- package/dist/ir/integer-loops.d.ts +5 -0
- package/dist/ir/integer-loops.js +20 -4
- package/dist/ir/integer-loops.js.map +1 -1
- package/dist/ir/integer-loops.test.js +17 -0
- package/dist/ir/integer-loops.test.js.map +1 -1
- package/dist/ir/ir.d.ts +6 -1
- package/dist/ir/ir.js +4 -0
- package/dist/ir/ir.js.map +1 -1
- package/dist/ir/serialize.d.ts +12 -2
- package/dist/ir/serialize.js +190 -39
- package/dist/ir/serialize.js.map +1 -1
- package/dist/ir/serialize.test.js +65 -1
- package/dist/ir/serialize.test.js.map +1 -1
- package/dist/native/cache.d.ts +8 -1
- package/dist/native/cache.js +38 -1
- package/dist/native/cache.js.map +1 -1
- package/dist/native/cache.test.js +11 -0
- package/dist/native/cache.test.js.map +1 -1
- package/dist/native/compiler.js +4 -3
- package/dist/native/compiler.js.map +1 -1
- package/dist/native/prepare.d.ts +3 -1
- package/dist/native/prepare.js +63 -28
- package/dist/native/prepare.js.map +1 -1
- package/dist/native/prepare.test.js +23 -1
- package/dist/native/prepare.test.js.map +1 -1
- package/dist/native/text-file.d.ts +10 -0
- package/dist/native/text-file.js +41 -0
- package/dist/native/text-file.js.map +1 -0
- package/dist/text-parts.d.ts +5 -0
- package/dist/text-parts.js +36 -0
- package/dist/text-parts.js.map +1 -0
- package/package.json +20 -20
- package/surface-manifest.json +7 -1
- package/dist/frontend/lowering/expressions/union-field-write.d.ts +0 -8
- package/dist/frontend/lowering/expressions/union-field-write.js +0 -108
- package/dist/frontend/lowering/expressions/union-field-write.js.map +0 -1
|
@@ -164,6 +164,12 @@ export declare function lowerArrayLiteral(lowerer: Lowerer, expr: ts.ArrayLitera
|
|
|
164
164
|
* reads preserve their tagged value; JavaScript's ToNumber(undefined) is NaN,
|
|
165
165
|
* so compounds and binary arithmetic use this checked one-time extraction. */
|
|
166
166
|
export declare function lowerOptionalNumber(lowerer: Lowerer, operand: IrExpr, loc: SrcLoc, narrowedNode?: ts.Expression): IrExpr;
|
|
167
|
+
/** A number argument of a builtin that converts it with ToNumber (Math
|
|
168
|
+
* functions, String.fromCharCode, the global isNaN/isFinite, DataView
|
|
169
|
+
* offsets and values). ToNumber(undefined) is NaN, so a missing value — an
|
|
170
|
+
* out-of-range read, a local or field holding one, or a hole — converts to
|
|
171
|
+
* NaN instead of trusting the checker's number type. */
|
|
172
|
+
export declare function lowerToNumberArgument(lowerer: Lowerer, node: ts.Expression): IrExpr;
|
|
167
173
|
/** `a[i]` reads. Only f64 indices into array receivers are modeled; JS
|
|
168
174
|
* string-key element access (`a["length"]`) and string indexing (`s[0]`
|
|
169
175
|
* typechecks against the lib's index signature; use .charAt) stay out. */
|
|
@@ -20,7 +20,7 @@ import { dirname } from "node:path";
|
|
|
20
20
|
import * as posix from "node:path/posix";
|
|
21
21
|
import { checkedClassAssertion, checkedClassUnionAssertion } from "./class-assertions.js";
|
|
22
22
|
import { narrowClassUnion, narrowStoredClassValue } from "./class-unions.js";
|
|
23
|
-
import { lowerUnionFieldWrite } from "./expressions/union-
|
|
23
|
+
import { lowerUnionFieldRead, lowerUnionFieldWrite } from "./expressions/union-fields.js";
|
|
24
24
|
import { captureContextArguments } from "./function-context.js";
|
|
25
25
|
import { OBJECT_CALLABLE_VALUES } from "./surfaces.js";
|
|
26
26
|
import { wasiGuestPath } from "../../wasi-paths.js";
|
|
@@ -167,7 +167,14 @@ export function lowerExpr(lowerer, expr) {
|
|
|
167
167
|
}
|
|
168
168
|
lowerExprDepth++;
|
|
169
169
|
try {
|
|
170
|
-
|
|
170
|
+
let lowered = lowerExprInner(lowerer, expr);
|
|
171
|
+
const nanCoded = lowerer.nanCodedReads;
|
|
172
|
+
if (nanCoded) {
|
|
173
|
+
if (lowered.type.kind === "f64" && nanCoded.reboxes(expr))
|
|
174
|
+
lowered = reboxNanCoded(lowerer, lowered, locOf(expr));
|
|
175
|
+
else if (lowered.type.kind === "union" && nanCoded.convertsSource(expr))
|
|
176
|
+
lowered = lowerOptionalNumber(lowerer, lowered, locOf(expr));
|
|
177
|
+
}
|
|
171
178
|
if (lowered.type.kind === "void" && (lowerer.typeOf(expr).flags & ts.TypeFlags.Never) !== 0)
|
|
172
179
|
lowerer.neverValued.add(lowered);
|
|
173
180
|
return lowered;
|
|
@@ -176,6 +183,27 @@ export function lowerExpr(lowerer, expr) {
|
|
|
176
183
|
lowerExprDepth--;
|
|
177
184
|
}
|
|
178
185
|
}
|
|
186
|
+
/** `number | undefined` from a NaN-coded double whose slot never holds a
|
|
187
|
+
* genuine NaN (nan-coded-reads.ts): NaN is exactly undefined. */
|
|
188
|
+
function reboxNanCoded(lowerer, value, loc) {
|
|
189
|
+
const optional = lowerer.withUndefinedArm(F64);
|
|
190
|
+
const stmts = [];
|
|
191
|
+
let stable = value;
|
|
192
|
+
if (value.kind !== "varRef") {
|
|
193
|
+
const tmp = lowerer.declareHiddenLocal("%nanCoded", F64);
|
|
194
|
+
stmts.push({ kind: "varDecl", localId: tmp.id, init: value, loc });
|
|
195
|
+
stable = varRef(tmp.id, F64, loc);
|
|
196
|
+
}
|
|
197
|
+
const result = {
|
|
198
|
+
kind: "ternary",
|
|
199
|
+
cond: { kind: "libCall", fn: "num.isNaN", args: [stable], type: BOOL, loc },
|
|
200
|
+
then: lowerer.wrappedUndefined(optional, loc),
|
|
201
|
+
else_: lowerer.coerceToExpected(stable, optional),
|
|
202
|
+
type: optional,
|
|
203
|
+
loc,
|
|
204
|
+
};
|
|
205
|
+
return stmts.length === 0 ? result : { kind: "seqExpr", stmts, result, type: optional, loc };
|
|
206
|
+
}
|
|
179
207
|
function lowerExprInner(lowerer, expr) {
|
|
180
208
|
const loc = locOf(expr);
|
|
181
209
|
// An optional chain's guarded receiver: already evaluated by the
|
|
@@ -2209,6 +2237,11 @@ function lowerExprInner(lowerer, expr) {
|
|
|
2209
2237
|
handled.kind === "recordGet" &&
|
|
2210
2238
|
lowerer.isRuntimeOptionalField(handled.shapeId, handled.field))
|
|
2211
2239
|
return handled;
|
|
2240
|
+
// A class field assigned a missing read: the checker narrows this
|
|
2241
|
+
// read to the assigned value's bare type, but the stored undefined
|
|
2242
|
+
// arm is real (`obj.n = bytes[i]; obj.n` is undefined in Node).
|
|
2243
|
+
if (runtimeOptionalClassField(lowerer, handled, expr))
|
|
2244
|
+
return handled;
|
|
2212
2245
|
return lowerer.maybeNarrow(handled, expr);
|
|
2213
2246
|
}
|
|
2214
2247
|
// `globalThis.<name>` that no lowering above claimed
|
|
@@ -5582,6 +5615,34 @@ export function lowerOptionalNumber(lowerer, operand, loc, narrowedNode) {
|
|
|
5582
5615
|
? value
|
|
5583
5616
|
: { kind: "seqExpr", stmts: prefix, result: value, type: F64, loc };
|
|
5584
5617
|
}
|
|
5618
|
+
/** A number argument of a builtin that converts it with ToNumber (Math
|
|
5619
|
+
* functions, String.fromCharCode, the global isNaN/isFinite, DataView
|
|
5620
|
+
* offsets and values). ToNumber(undefined) is NaN, so a missing value — an
|
|
5621
|
+
* out-of-range read, a local or field holding one, or a hole — converts to
|
|
5622
|
+
* NaN instead of trusting the checker's number type. */
|
|
5623
|
+
export function lowerToNumberArgument(lowerer, node) {
|
|
5624
|
+
let inner = node;
|
|
5625
|
+
while (ts.isParenthesizedExpression(inner))
|
|
5626
|
+
inner = inner.expression;
|
|
5627
|
+
const loc = locOf(inner);
|
|
5628
|
+
const isOptionalNumber = (value) => value.type.kind === "union" &&
|
|
5629
|
+
lowerer.armTag(value.type.unionId, UNDEFINED_T) >= 0 &&
|
|
5630
|
+
lowerer.stripUndefinedArm(value.type).kind === "f64";
|
|
5631
|
+
const optional = ts.isIdentifier(inner)
|
|
5632
|
+
? runtimeOptionalStorageOperand(lowerer, inner)
|
|
5633
|
+
: ts.isElementAccessExpression(inner)
|
|
5634
|
+
? lowerAbsenceProbe(lowerer, inner)
|
|
5635
|
+
: null;
|
|
5636
|
+
if (optional && isOptionalNumber(optional))
|
|
5637
|
+
return lowerOptionalNumber(lowerer, optional, loc, inner);
|
|
5638
|
+
// A conditional builds each branch for the destination.
|
|
5639
|
+
if (ts.isConditionalExpression(inner))
|
|
5640
|
+
return lowerer.lowerExprExpecting(node, F64);
|
|
5641
|
+
const value = lowerer.lowerExpr(node);
|
|
5642
|
+
if (isOptionalNumber(value))
|
|
5643
|
+
return lowerOptionalNumber(lowerer, value, loc, inner);
|
|
5644
|
+
return lowerer.coerceInto(node, value, F64);
|
|
5645
|
+
}
|
|
5585
5646
|
/** `a[i]` reads. Only f64 indices into array receivers are modeled; JS
|
|
5586
5647
|
* string-key element access (`a["length"]`) and string indexing (`s[0]`
|
|
5587
5648
|
* typechecks against the lib's index signature; use .charAt) stay out. */
|
|
@@ -5866,7 +5927,10 @@ export function lowerElementAccess(lowerer, expr) {
|
|
|
5866
5927
|
// `t[i]!` asserts presence: the numeric element read (NaN when
|
|
5867
5928
|
// invalid). Every other read answers undefined for an invalid index,
|
|
5868
5929
|
// like Node.
|
|
5869
|
-
|
|
5930
|
+
// A read whose every consumer treats undefined like NaN (see
|
|
5931
|
+
// nan-coded-reads.ts) is the same plain numeric read.
|
|
5932
|
+
if ((ts.isNonNullExpression(expr.parent) && expr.parent.expression === expr) ||
|
|
5933
|
+
lowerer.nanCodedReads?.isNumericRead(expr) === true) {
|
|
5870
5934
|
return {
|
|
5871
5935
|
kind: "bytesIntrinsic",
|
|
5872
5936
|
method: "get",
|
|
@@ -6529,6 +6593,23 @@ export function runtimeOptionalStorageOperand(lowerer, node) {
|
|
|
6529
6593
|
return null;
|
|
6530
6594
|
return optional.value;
|
|
6531
6595
|
}
|
|
6596
|
+
/** A `T | undefined` class field read that the checker narrowed to `T`
|
|
6597
|
+
* where the field was assigned a value that may be missing (an unchecked
|
|
6598
|
+
* indexed read). TypeScript's assignment narrowing is not a runtime fact
|
|
6599
|
+
* there, so the read keeps the stored union instead of extracting `T`. */
|
|
6600
|
+
function runtimeOptionalClassField(lowerer, value, node) {
|
|
6601
|
+
if (value.kind !== "fieldGet" || value.type.kind !== "union")
|
|
6602
|
+
return false;
|
|
6603
|
+
if (lowerer.armTag(value.type.unionId, UNDEFINED_T) < 0)
|
|
6604
|
+
return false;
|
|
6605
|
+
if ((lowerer.unions.get(value.type.unionId)?.arms.length ?? 0) !== 2)
|
|
6606
|
+
return false;
|
|
6607
|
+
const symbol = lowerer.checker.getSymbolAtLocation(node.name);
|
|
6608
|
+
if (!symbol || !lowerer.runtimeOptionalAssignedSymbols.has(symbol))
|
|
6609
|
+
return false;
|
|
6610
|
+
const narrowed = lowerer.mapTypeOf(lowerer.typeOf(node));
|
|
6611
|
+
return narrowed !== null && typeEquals(narrowed, lowerer.stripUndefinedArm(value.type));
|
|
6612
|
+
}
|
|
6532
6613
|
/** A presence-test operand: an absence-aware element or field read, an
|
|
6533
6614
|
* identifier's runtime-optional storage, or the ordinary lowering. */
|
|
6534
6615
|
export function lowerPresenceOperand(lowerer, node) {
|
|
@@ -8298,12 +8379,75 @@ export function lowerCompoundValueToTarget(lowerer, expr, compound, target) {
|
|
|
8298
8379
|
}
|
|
8299
8380
|
lowerer.unsupported("SC1043", expr);
|
|
8300
8381
|
}
|
|
8382
|
+
/** Equality of two NaN-coded values (nan-coded-reads.ts), each of which may
|
|
8383
|
+
* stand for undefined and never holds a genuine NaN: Node's undefined equals
|
|
8384
|
+
* undefined, so two NaNs compare equal here. Operands evaluate once, in
|
|
8385
|
+
* order. */
|
|
8386
|
+
function lowerNanCodedEquality(lowerer, expr) {
|
|
8387
|
+
const loc = locOf(expr);
|
|
8388
|
+
const left = lowerer.lowerExpr(expr.left);
|
|
8389
|
+
const right = lowerer.lowerExpr(expr.right);
|
|
8390
|
+
if (left.type.kind !== "f64" || right.type.kind !== "f64") {
|
|
8391
|
+
throw new InternalCompilerError("NaN-coded equality operand is not a plain number");
|
|
8392
|
+
}
|
|
8393
|
+
const stmts = [];
|
|
8394
|
+
const stable = (value, name) => {
|
|
8395
|
+
if (value.kind === "varRef" || value.kind === "numLit")
|
|
8396
|
+
return value;
|
|
8397
|
+
const tmp = lowerer.declareHiddenLocal(name, F64);
|
|
8398
|
+
stmts.push({ kind: "varDecl", localId: tmp.id, init: value, loc });
|
|
8399
|
+
return varRef(tmp.id, F64, loc);
|
|
8400
|
+
};
|
|
8401
|
+
const a = stable(left, "%eqLeft");
|
|
8402
|
+
const b = stable(right, "%eqRight");
|
|
8403
|
+
const isNaN = (value) => ({
|
|
8404
|
+
kind: "libCall",
|
|
8405
|
+
fn: "num.isNaN",
|
|
8406
|
+
args: [value],
|
|
8407
|
+
type: BOOL,
|
|
8408
|
+
loc,
|
|
8409
|
+
});
|
|
8410
|
+
const bothUndefined = {
|
|
8411
|
+
kind: "logical",
|
|
8412
|
+
op: "&&",
|
|
8413
|
+
left: isNaN(a),
|
|
8414
|
+
right: isNaN(b),
|
|
8415
|
+
type: BOOL,
|
|
8416
|
+
loc,
|
|
8417
|
+
};
|
|
8418
|
+
const op = expr.operatorToken.kind;
|
|
8419
|
+
const negated = op === ts.SyntaxKind.ExclamationEqualsEqualsToken ||
|
|
8420
|
+
op === ts.SyntaxKind.ExclamationEqualsToken;
|
|
8421
|
+
const result = negated
|
|
8422
|
+
? {
|
|
8423
|
+
kind: "logical",
|
|
8424
|
+
op: "&&",
|
|
8425
|
+
left: { kind: "bin", op: "!==", left: a, right: b, type: BOOL, loc },
|
|
8426
|
+
right: { kind: "unary", op: "!", operand: bothUndefined, type: BOOL, loc },
|
|
8427
|
+
type: BOOL,
|
|
8428
|
+
loc,
|
|
8429
|
+
}
|
|
8430
|
+
: {
|
|
8431
|
+
kind: "logical",
|
|
8432
|
+
op: "||",
|
|
8433
|
+
left: { kind: "bin", op: "===", left: a, right: b, type: BOOL, loc },
|
|
8434
|
+
right: bothUndefined,
|
|
8435
|
+
type: BOOL,
|
|
8436
|
+
loc,
|
|
8437
|
+
};
|
|
8438
|
+
return stmts.length === 0 ? result : { kind: "seqExpr", stmts, result, type: BOOL, loc };
|
|
8439
|
+
}
|
|
8301
8440
|
export function lowerBinary(lowerer, expr) {
|
|
8302
8441
|
const loc = locOf(expr);
|
|
8303
8442
|
const op = expr.operatorToken.kind;
|
|
8304
8443
|
const cacheHas = lowerRequireCacheHas(lowerer, expr);
|
|
8305
8444
|
if (cacheHas)
|
|
8306
8445
|
return cacheHas;
|
|
8446
|
+
if (lowerer.nanCodedReads?.needsUndefinedEquality(expr)) {
|
|
8447
|
+
const undefinedEquality = lowerNanCodedEquality(lowerer, expr);
|
|
8448
|
+
if (undefinedEquality)
|
|
8449
|
+
return undefinedEquality;
|
|
8450
|
+
}
|
|
8307
8451
|
if (op === ts.SyntaxKind.EqualsToken ||
|
|
8308
8452
|
(op >= ts.SyntaxKind.FirstCompoundAssignment && op <= ts.SyntaxKind.LastCompoundAssignment)) {
|
|
8309
8453
|
const urlWrite = lowerUrlAssignment(lowerer, expr);
|
|
@@ -12246,6 +12390,11 @@ export function lowerUnionProperty(lowerer, expr) {
|
|
|
12246
12390
|
const helper = lowerer.narrowedRetagHelper(expr.expression, value.type.unionId, receiverIr.unionId, locOf(expr));
|
|
12247
12391
|
if (helper)
|
|
12248
12392
|
value = { kind: "call", callee: helper, args: [value], type: receiverIr, loc: locOf(expr) };
|
|
12393
|
+
// Optional storage of a base class (a runtime-optional binding holding
|
|
12394
|
+
// `Base | undefined`) that `instanceof` narrowed to several subclasses:
|
|
12395
|
+
// extract the instance and test its class, as typed slots do.
|
|
12396
|
+
else
|
|
12397
|
+
value = narrowStoredClassValue(lowerer, value, receiverIr) ?? value;
|
|
12249
12398
|
}
|
|
12250
12399
|
// A checker-union receiver whose VALUE lowered to a plain RECORD (the
|
|
12251
12400
|
// merged-signature fiction — `runner(cmd, args)` where runner joined
|
|
@@ -12368,6 +12517,11 @@ export function lowerUnionProperty(lowerer, expr) {
|
|
|
12368
12517
|
const keyed = lowerUnionKeyedRead(lowerer, expr, value.type.unionId, value, key, field);
|
|
12369
12518
|
if (keyed)
|
|
12370
12519
|
return keyed;
|
|
12520
|
+
// Class arms declaring the field with compatible but different types
|
|
12521
|
+
// (`T | undefined` beside `T`): per-arm slot reads widened to one type.
|
|
12522
|
+
const widened = lowerUnionFieldRead(lowerer, expr, value);
|
|
12523
|
+
if (widened)
|
|
12524
|
+
return widened;
|
|
12371
12525
|
// JavaScript overloads commonly inspect a class brand on a scalar-or-
|
|
12372
12526
|
// instance argument (e.g. Matrix4.makeTranslation). Preserve primitive
|
|
12373
12527
|
// missing-property semantics and dispatch class data through its native
|
|
@@ -12532,6 +12686,11 @@ function classFieldTarget(lowerer, receiverNode, receiverType, fieldName, saved)
|
|
|
12532
12686
|
const lowerObjectReceiver = () => {
|
|
12533
12687
|
let obj = represented;
|
|
12534
12688
|
if (obj.type.kind === "union") {
|
|
12689
|
+
// A receiver that may hold a missing value (a field assigned an
|
|
12690
|
+
// unchecked read): Node's member-read TypeError for the unit arm.
|
|
12691
|
+
const present = lowerer.runtimeOptionalPropertyReceiver(receiverNode, obj, receiverType, fieldName);
|
|
12692
|
+
if (present)
|
|
12693
|
+
return present;
|
|
12535
12694
|
const helper = lowerer.narrowedArmHelper(obj.type.unionId, receiverType, locOf(receiverNode));
|
|
12536
12695
|
obj = helper
|
|
12537
12696
|
? lowerer.checkedNarrowCall(helper, obj, receiverType, locOf(receiverNode))
|