@scriptc/compiler 0.0.31 → 0.0.33
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 -1
- package/dist/backend/cc-cache.test.js +308 -1
- package/dist/backend/cc-cache.test.js.map +1 -1
- package/dist/backend/cc.d.ts +17 -5
- package/dist/backend/cc.js +745 -75
- package/dist/backend/cc.js.map +1 -1
- package/dist/backend/emission/emit-exprs.js +53 -2
- package/dist/backend/emission/emit-exprs.js.map +1 -1
- package/dist/backend/emission/emitter.d.ts +12 -5
- package/dist/backend/emission/emitter.js +160 -22
- package/dist/backend/emission/emitter.js.map +1 -1
- package/dist/backend/emission/may-throw.js +7 -4
- package/dist/backend/emission/may-throw.js.map +1 -1
- package/dist/backend/ffi-callbacks.d.ts +38 -1
- package/dist/backend/ffi-callbacks.js +76 -3
- package/dist/backend/ffi-callbacks.js.map +1 -1
- package/dist/backend/llvm/emitter.js +243 -12
- package/dist/backend/llvm/emitter.js.map +1 -1
- package/dist/diagnostics/diagnostic.js +2 -0
- package/dist/diagnostics/diagnostic.js.map +1 -1
- package/dist/ffi/profile.d.ts +17 -5
- package/dist/ffi/profile.js +169 -22
- package/dist/ffi/profile.js.map +1 -1
- package/dist/frontend/lowering/lower-calls.d.ts +1 -0
- package/dist/frontend/lowering/lower-calls.js +89 -23
- package/dist/frontend/lowering/lower-calls.js.map +1 -1
- package/dist/frontend/lowering/lower-containers.js +65 -19
- package/dist/frontend/lowering/lower-containers.js.map +1 -1
- package/dist/frontend/lowering/lowerer.d.ts +12 -0
- package/dist/frontend/lowering/lowerer.js +20 -1
- package/dist/frontend/lowering/lowerer.js.map +1 -1
- package/dist/frontend/ts7/checker.d.ts +2 -0
- package/dist/frontend/ts7/checker.js +20 -3
- package/dist/frontend/ts7/checker.js.map +1 -1
- package/dist/frontend/types.d.ts +8 -0
- package/dist/frontend/types.js +33 -5
- package/dist/frontend/types.js.map +1 -1
- package/dist/index.js +35 -0
- package/dist/index.js.map +1 -1
- package/dist/ir/nodes.d.ts +22 -9
- package/dist/ir/nodes.js +7 -1
- package/dist/ir/nodes.js.map +1 -1
- package/dist/ir/serialize.d.ts +1 -1
- package/dist/ir/serialize.js +1 -1
- package/dist/ir/validate.js +74 -1
- package/dist/ir/validate.js.map +1 -1
- package/dist/library/int-infer.js +7 -1
- package/dist/library/int-infer.js.map +1 -1
- package/dist/library/int-infer.test.js +73 -4
- package/dist/library/int-infer.test.js.map +1 -1
- package/dist/library/profile.d.ts +3 -0
- package/dist/library/profile.js +9 -1
- package/dist/library/profile.js.map +1 -1
- package/package.json +2 -2
- package/surface-manifest.json +1 -1
|
@@ -8,7 +8,7 @@ import { ARRAY_METHODS, MAP_METHODS, SET_COMBINE_METHODS, SET_METHODS, STR_METHO
|
|
|
8
8
|
import { droppableStatic, isRequireMainFilename, lowerDynObjectLiteral, probeLower, pureReemittable } from "./lower-exprs.js";
|
|
9
9
|
import { forOfVarTarget, lowerDestructuringAssign } from "./lower-stmts.js";
|
|
10
10
|
import { isJsSourceFile, locOf } from "../program.js";
|
|
11
|
-
import {
|
|
11
|
+
import { islandPrimitiveExit, lowerDynDispatchMethodCall } from "./lower-calls.js";
|
|
12
12
|
import { typeKey } from "../types.js";
|
|
13
13
|
import { dynUndefinedExpr, own } from "./lowerer.js";
|
|
14
14
|
/** Lower an expression whose checker type is statically `undefined`/`void`.
|
|
@@ -142,7 +142,11 @@ export function lowerArrayMethodCall(L, call, access) {
|
|
|
142
142
|
{
|
|
143
143
|
const receiver = L.lowerExpr(access.expression);
|
|
144
144
|
if (receiver.type.kind === "jsval") {
|
|
145
|
-
const
|
|
145
|
+
const loweredArgs = call.arguments.map((a) => L.lowerExpr(a));
|
|
146
|
+
if (name === "filter" && loweredArgs[0]?.type.kind === "func" && loweredArgs[0].type.ret.kind === "void") {
|
|
147
|
+
L.unsupported("SC1090", call.arguments[0], "'.filter()' with a void-returning predicate (the callback return value is erased before its truthiness can be tested)");
|
|
148
|
+
}
|
|
149
|
+
const args = loweredArgs.map((arg, i) => L.jsvalIn(arg, call.arguments[i]));
|
|
146
150
|
const result = { kind: "jsOp", op: "callMethod", name, args: [receiver, ...args], type: JSVAL, loc };
|
|
147
151
|
return islandPrimitiveExit(L, call, result);
|
|
148
152
|
}
|
|
@@ -155,21 +159,9 @@ export function lowerArrayMethodCall(L, call, access) {
|
|
|
155
159
|
// ICE). Consumers validate the dyn result where a static type is
|
|
156
160
|
// required (dynCheck — the member-read discipline).
|
|
157
161
|
if (receiver.type.kind === "dyn") {
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
}
|
|
162
|
-
const args = call.arguments.map((a) => L.lowerExprExpecting(a, DYN));
|
|
163
|
-
return {
|
|
164
|
-
kind: "dynInvoke",
|
|
165
|
-
recv: receiver,
|
|
166
|
-
method: name,
|
|
167
|
-
calleeName: access.getText(),
|
|
168
|
-
args,
|
|
169
|
-
type: DYN,
|
|
170
|
-
loc,
|
|
171
|
-
};
|
|
172
|
-
}
|
|
162
|
+
const dispatched = lowerDynDispatchMethodCall(L, call, access, receiver, true);
|
|
163
|
+
if (dispatched)
|
|
164
|
+
return dispatched;
|
|
173
165
|
L.noLowering(`.${name} on an array value held in a checked-dynamic binding`, call, "assign it to an array-typed binding first (the validated extraction), then call the method");
|
|
174
166
|
}
|
|
175
167
|
// An evolving-`any` array binding under --dynamic whose flow type
|
|
@@ -596,12 +588,64 @@ export function lowerArrayHofCall(L, call, access, method, elem) {
|
|
|
596
588
|
// declaration, so the honest answer is the fence).
|
|
597
589
|
L.unsupported("SC1090", call, "'.map()' with a callback returning 'unknown'-typed values (the result array has no static element type — annotate the callback's return)");
|
|
598
590
|
}
|
|
599
|
-
|
|
591
|
+
// JS applies ToBoolean to whatever the predicate answers, so a non-bool
|
|
592
|
+
// result is not an error — the filter loop wraps the call in the same
|
|
593
|
+
// toBool an `if` statement would apply. The island/dyn shapes, whose
|
|
594
|
+
// truthiness needs the engine, and void, whose real answer the ABI has
|
|
595
|
+
// already discarded, keep the fence. No separate
|
|
596
|
+
// requireTruthyUnion call belongs here: its check (no dyn/caught arm)
|
|
597
|
+
// IS filterPredicateOk's union branch, so it could never speak.
|
|
598
|
+
if (method === "filter" && !filterPredicateOk(L, fnRet)) {
|
|
599
|
+
if (fnRet.kind === "void") {
|
|
600
|
+
L.unsupported("SC1090", argNode, "'.filter()' with a void-returning predicate (the callback return value is erased before its truthiness can be tested)");
|
|
601
|
+
}
|
|
600
602
|
L.badType(argNode, L.typeOf(argNode));
|
|
603
|
+
}
|
|
601
604
|
const helper = arrayHofHelper(L, method, elem, fnRet, arity, loc);
|
|
602
605
|
const resultType = method === "map" ? arrayOf(fnRet) : method === "filter" ? arrayOf(elem) : VOID;
|
|
603
606
|
return { kind: "call", callee: helper, args: [receiver, fnArg], type: resultType, loc };
|
|
604
607
|
}
|
|
608
|
+
/** The predicate result kinds `.filter()` accepts. JS applies ToBoolean to
|
|
609
|
+
* whatever the callback answers, so a bool is not required: the scalars and
|
|
610
|
+
* the reference kinds have constant or by-value answers, and a union is fine
|
|
611
|
+
* when every arm does. void/dyn/jsval/caught stay out — see below. */
|
|
612
|
+
function filterPredicateOk(L, ret) {
|
|
613
|
+
if (ret.kind === "bool")
|
|
614
|
+
return true;
|
|
615
|
+
// VOID is a TYPE erasure, not a runtime value: TS lets a value-returning
|
|
616
|
+
// function sit in a void-returning slot (`const p: (n: number) => void =
|
|
617
|
+
// (n) => n`), so the predicate's real answer can be truthy while the
|
|
618
|
+
// compiled ABI has already discarded it. Treating void as constantly
|
|
619
|
+
// falsy would silently answer [] where Node answers [1]. Fenced until
|
|
620
|
+
// the returned value can be preserved through the void ABI.
|
|
621
|
+
// dyn/jsval/caught stay out too: no native ToBoolean to compile against.
|
|
622
|
+
if (ret.kind === "void")
|
|
623
|
+
return false;
|
|
624
|
+
if (ret.kind === "dyn" || ret.kind === "jsval" || ret.kind === "caught")
|
|
625
|
+
return false;
|
|
626
|
+
if (ret.kind === "union") {
|
|
627
|
+
const def = L.unions.get(ret.unionId);
|
|
628
|
+
return def !== undefined && def.arms.every((a) => a.kind !== "dyn" && a.kind !== "caught");
|
|
629
|
+
}
|
|
630
|
+
return true;
|
|
631
|
+
}
|
|
632
|
+
/** The filter loop's condition: the predicate's result put through JS
|
|
633
|
+
* ToBoolean. A bool answer is already the condition; everything else takes
|
|
634
|
+
* the same `toBool` wrapper an `if` statement would apply (a union answer
|
|
635
|
+
* routes through its interned per-arm truthy helper). */
|
|
636
|
+
function filterCond(call, fnRet, loc) {
|
|
637
|
+
if (fnRet.kind === "bool")
|
|
638
|
+
return call;
|
|
639
|
+
// No constant-false arm here: void is fenced at the call site, and a
|
|
640
|
+
// bare undefinedT/nullT return cannot arise (mapType sends `undefined`/
|
|
641
|
+
// `void` returns to void and a standalone `null` return to the unit-ONLY
|
|
642
|
+
// UNION, which routes through toBool below; ir/validate.ts rejects a
|
|
643
|
+
// bare unit return type outright). filterPredicateOk already rejected
|
|
644
|
+
// the arms with no native ToBoolean (dyn/caught) — which is exactly what
|
|
645
|
+
// requireTruthyUnion checks — and it did so at the call site, where a
|
|
646
|
+
// real node exists for the diagnostic.
|
|
647
|
+
return { kind: "toBool", operand: call, type: BOOL, loc };
|
|
648
|
+
}
|
|
605
649
|
/** Interned synthetic loop function for one (method, elem, fnRet, arity)
|
|
606
650
|
* combo. Named `%arr.<method>.<n>` ('%' keeps it out of the user
|
|
607
651
|
* namespace); rides `liftedFns` into the module like a lifted lambda (it
|
|
@@ -934,7 +978,9 @@ export function buildArrayHofFn(L, name, method, elem, fnRet, arity, loc) {
|
|
|
934
978
|
{ kind: "varDecl", localId: "v.0", init: getElem, loc },
|
|
935
979
|
{
|
|
936
980
|
kind: "if",
|
|
937
|
-
|
|
981
|
+
// ToBoolean over the predicate's answer — inert when it already
|
|
982
|
+
// returned bool, the per-union helper when it returned a union.
|
|
983
|
+
cond: filterCond(callF(ref("v.0", elem)), fnRet, loc),
|
|
938
984
|
then: [push(arrT, ref("v.0", elem))],
|
|
939
985
|
else_: null,
|
|
940
986
|
loc,
|