@scriptc/compiler 0.2.2 → 0.2.3
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 +99 -27
- package/dist/backend/cycle-analysis.js +63 -50
- package/dist/backend/cycle-analysis.js.map +1 -1
- package/dist/backend/cycle-analysis.test.js +51 -0
- package/dist/backend/cycle-analysis.test.js.map +1 -1
- package/dist/backend/llvm/borrowed-receivers.d.ts +9 -0
- package/dist/backend/llvm/borrowed-receivers.js +58 -0
- package/dist/backend/llvm/borrowed-receivers.js.map +1 -0
- package/dist/backend/llvm/call-lifetimes.d.ts +20 -0
- package/dist/backend/llvm/call-lifetimes.js +179 -0
- package/dist/backend/llvm/call-lifetimes.js.map +1 -0
- package/dist/backend/llvm/call-lifetimes.test.d.ts +1 -0
- package/dist/backend/llvm/call-lifetimes.test.js +205 -0
- package/dist/backend/llvm/call-lifetimes.test.js.map +1 -0
- package/dist/backend/llvm/dyn.d.ts +2 -2
- package/dist/backend/llvm/dyn.js +79 -35
- package/dist/backend/llvm/dyn.js.map +1 -1
- package/dist/backend/llvm/emitter.d.ts +33 -0
- package/dist/backend/llvm/emitter.js +189 -16
- package/dist/backend/llvm/emitter.js.map +1 -1
- package/dist/backend/llvm/emitter.test.js +20 -1
- package/dist/backend/llvm/emitter.test.js.map +1 -1
- package/dist/backend/llvm/expr-async.js +1 -1
- package/dist/backend/llvm/expr-async.js.map +1 -1
- package/dist/backend/llvm/expr-calls.js +42 -5
- package/dist/backend/llvm/expr-calls.js.map +1 -1
- package/dist/backend/llvm/expr-containers.js +70 -13
- package/dist/backend/llvm/expr-containers.js.map +1 -1
- package/dist/backend/llvm/expr-dynamic.js +1 -1
- package/dist/backend/llvm/expr-dynamic.js.map +1 -1
- package/dist/backend/llvm/expr-primitives.js +6 -5
- package/dist/backend/llvm/expr-primitives.js.map +1 -1
- package/dist/backend/llvm/expr-records.js +1 -1
- package/dist/backend/llvm/expr-records.js.map +1 -1
- package/dist/backend/llvm/expr-stream-bridges.js +5 -10
- package/dist/backend/llvm/expr-stream-bridges.js.map +1 -1
- package/dist/backend/llvm/lib-shared.js +35 -1
- package/dist/backend/llvm/lib-shared.js.map +1 -1
- package/dist/backend/llvm/local-array-reads.d.ts +44 -0
- package/dist/backend/llvm/local-array-reads.js +313 -0
- package/dist/backend/llvm/local-array-reads.js.map +1 -0
- package/dist/backend/llvm/local-array-reads.test.d.ts +1 -0
- package/dist/backend/llvm/local-array-reads.test.js +446 -0
- package/dist/backend/llvm/local-array-reads.test.js.map +1 -0
- package/dist/backend/llvm/map-read-lifetimes.d.ts +36 -0
- package/dist/backend/llvm/map-read-lifetimes.js +128 -0
- package/dist/backend/llvm/map-read-lifetimes.js.map +1 -0
- package/dist/backend/llvm/map-read-lifetimes.test.d.ts +1 -0
- package/dist/backend/llvm/map-read-lifetimes.test.js +123 -0
- package/dist/backend/llvm/map-read-lifetimes.test.js.map +1 -0
- package/dist/backend/llvm/shapes.js +1 -0
- package/dist/backend/llvm/shapes.js.map +1 -1
- package/dist/backend/llvm/split.js +15 -5
- package/dist/backend/llvm/split.js.map +1 -1
- package/dist/backend/llvm/split.test.js +17 -0
- package/dist/backend/llvm/split.test.js.map +1 -1
- package/dist/backend/llvm/stack-unions.d.ts +20 -0
- package/dist/backend/llvm/stack-unions.js +61 -0
- package/dist/backend/llvm/stack-unions.js.map +1 -0
- package/dist/backend/llvm/stack-unions.test.d.ts +1 -0
- package/dist/backend/llvm/stack-unions.test.js +241 -0
- package/dist/backend/llvm/stack-unions.test.js.map +1 -0
- package/dist/backend/llvm/string-lifetimes.d.ts +12 -0
- package/dist/backend/llvm/string-lifetimes.js +70 -0
- package/dist/backend/llvm/string-lifetimes.js.map +1 -0
- package/dist/backend/llvm/string-lifetimes.test.d.ts +1 -0
- package/dist/backend/llvm/string-lifetimes.test.js +230 -0
- package/dist/backend/llvm/string-lifetimes.test.js.map +1 -0
- package/dist/backend/mangle.d.ts +2 -0
- package/dist/backend/mangle.js +4 -0
- package/dist/backend/mangle.js.map +1 -1
- package/dist/backend/may-throw.js +67 -29
- package/dist/backend/may-throw.js.map +1 -1
- package/dist/backend/may-throw.test.js +104 -1
- package/dist/backend/may-throw.test.js.map +1 -1
- package/dist/backend/native-toolchain.d.ts +2 -2
- package/dist/backend/native-toolchain.js +2 -0
- package/dist/backend/native-toolchain.js.map +1 -1
- package/dist/frontend/input-tracker.js +3 -3
- package/dist/frontend/input-tracker.js.map +1 -1
- package/dist/frontend/input-tracker.test.js +38 -2
- package/dist/frontend/input-tracker.test.js.map +1 -1
- package/dist/frontend/lowering/collection-ingestion.d.ts +31 -0
- package/dist/frontend/lowering/collection-ingestion.js +215 -0
- package/dist/frontend/lowering/collection-ingestion.js.map +1 -0
- package/dist/frontend/lowering/containers/bytes.js +2 -0
- package/dist/frontend/lowering/containers/bytes.js.map +1 -1
- package/dist/frontend/lowering/import-meta.d.ts +10 -0
- package/dist/frontend/lowering/import-meta.js +52 -0
- package/dist/frontend/lowering/import-meta.js.map +1 -0
- package/dist/frontend/lowering/lower-assert.js +105 -41
- package/dist/frontend/lowering/lower-assert.js.map +1 -1
- package/dist/frontend/lowering/lower-builtin-values.d.ts +2 -0
- package/dist/frontend/lowering/lower-builtin-values.js +22 -1
- package/dist/frontend/lowering/lower-builtin-values.js.map +1 -1
- package/dist/frontend/lowering/lower-builtins.d.ts +3 -13
- package/dist/frontend/lowering/lower-builtins.js +150 -46
- package/dist/frontend/lowering/lower-builtins.js.map +1 -1
- package/dist/frontend/lowering/lower-calls.js +6 -3
- package/dist/frontend/lowering/lower-calls.js.map +1 -1
- package/dist/frontend/lowering/lower-classes.js +4 -4
- package/dist/frontend/lowering/lower-classes.js.map +1 -1
- package/dist/frontend/lowering/lower-containers.d.ts +5 -1
- package/dist/frontend/lowering/lower-containers.js +40 -3
- package/dist/frontend/lowering/lower-containers.js.map +1 -1
- package/dist/frontend/lowering/lower-exprs.js +35 -41
- package/dist/frontend/lowering/lower-exprs.js.map +1 -1
- package/dist/frontend/lowering/lower-inspect.js +43 -0
- package/dist/frontend/lowering/lower-inspect.js.map +1 -1
- package/dist/frontend/lowering/lower-stmts.js +72 -68
- package/dist/frontend/lowering/lower-stmts.js.map +1 -1
- package/dist/frontend/lowering/lower-system-errors.d.ts +6 -0
- package/dist/frontend/lowering/lower-system-errors.js +29 -0
- package/dist/frontend/lowering/lower-system-errors.js.map +1 -0
- package/dist/frontend/lowering/lowerer.d.ts +4 -3
- package/dist/frontend/lowering/lowerer.js +50 -22
- package/dist/frontend/lowering/lowerer.js.map +1 -1
- package/dist/frontend/lowering/surfaces.d.ts +2 -2
- package/dist/frontend/lowering/surfaces.js +69 -21
- package/dist/frontend/lowering/surfaces.js.map +1 -1
- package/dist/frontend/module-syntax.d.ts +1 -1
- package/dist/frontend/module-syntax.js +8 -1
- package/dist/frontend/module-syntax.js.map +1 -1
- package/dist/frontend/module-syntax.test.js +10 -0
- package/dist/frontend/module-syntax.test.js.map +1 -1
- package/dist/frontend/npm.d.ts +4 -0
- package/dist/frontend/npm.js +86 -33
- package/dist/frontend/npm.js.map +1 -1
- package/dist/frontend/npm.test.js +103 -0
- package/dist/frontend/npm.test.js.map +1 -1
- package/dist/frontend/pipeline-native.js +2 -1
- package/dist/frontend/pipeline-native.js.map +1 -1
- package/dist/frontend/services-node.js +3 -2
- package/dist/frontend/services-node.js.map +1 -1
- package/dist/frontend/services.d.ts +5 -1
- package/dist/frontend/services.js +9 -1
- package/dist/frontend/services.js.map +1 -1
- package/dist/frontend/services.test.js +21 -0
- package/dist/frontend/services.test.js.map +1 -1
- package/dist/frontend/ts7/ast-node.d.ts +2 -0
- package/dist/frontend/ts7/ast-node.js +30 -4
- package/dist/frontend/ts7/ast-node.js.map +1 -1
- package/dist/frontend/ts7/ast-node.test.js +60 -1
- package/dist/frontend/ts7/ast-node.test.js.map +1 -1
- package/dist/frontend/type-mapper.js +6 -0
- package/dist/frontend/type-mapper.js.map +1 -1
- package/dist/index.js +3 -2
- package/dist/index.js.map +1 -1
- package/dist/ir/analysis.js +1 -0
- package/dist/ir/analysis.js.map +1 -1
- package/dist/ir/integer-loops.d.ts +7 -0
- package/dist/ir/integer-loops.js +23 -0
- package/dist/ir/integer-loops.js.map +1 -1
- package/dist/ir/integer-loops.test.d.ts +1 -0
- package/dist/ir/integer-loops.test.js +41 -0
- package/dist/ir/integer-loops.test.js.map +1 -0
- package/dist/ir/ir.d.ts +21 -17
- package/dist/ir/ir.js +43 -9
- package/dist/ir/ir.js.map +1 -1
- package/dist/ir/ir.test.js +18 -0
- package/dist/ir/ir.test.js.map +1 -1
- package/dist/ir/validate.js +161 -76
- package/dist/ir/validate.js.map +1 -1
- package/dist/ir/validate.test.js +227 -0
- package/dist/ir/validate.test.js.map +1 -1
- package/dist/library/fence-eval.js +9 -2
- package/dist/library/fence-eval.js.map +1 -1
- package/dist/library/fence-eval.test.d.ts +1 -0
- package/dist/library/fence-eval.test.js +21 -0
- package/dist/library/fence-eval.test.js.map +1 -0
- package/dist/native/runtime-typescript.d.ts +4 -0
- package/dist/native/runtime-typescript.js +61 -0
- package/dist/native/runtime-typescript.js.map +1 -0
- package/dist/native/runtime-typescript.test.d.ts +1 -0
- package/dist/native/runtime-typescript.test.js +41 -0
- package/dist/native/runtime-typescript.test.js.map +1 -0
- package/package.json +20 -20
- package/surface-manifest.json +271 -17
package/dist/ir/validate.js
CHANGED
|
@@ -358,8 +358,13 @@ export const LIB_FN_SIGS = {
|
|
|
358
358
|
"url.port": { argTypes: [URL_T], result: STRING },
|
|
359
359
|
"url.pathname": { argTypes: [URL_T], result: STRING },
|
|
360
360
|
"url.href": { argTypes: [URL_T], result: STRING },
|
|
361
|
+
"url.set": { argTypes: [URL_T, STRING, STRING], result: VOID },
|
|
362
|
+
"url.setChecked": { argTypes: [URL_T, STRING, DYN], result: VOID },
|
|
361
363
|
"url.fileURLToPathUrl": { argTypes: [URL_T], result: STRING },
|
|
362
364
|
"url.fileURLToPathChecked": { argTypes: [DYN], result: STRING },
|
|
365
|
+
"url.fileURLToPathOptions": { argTypes: [DYN, DYN], result: STRING },
|
|
366
|
+
"url.fileURLToPathBuffer": { argTypes: [DYN, DYN], result: BYTES_U8 },
|
|
367
|
+
"url.pathToFileURLChecked": { argTypes: [DYN, DYN], result: URL_T },
|
|
363
368
|
"url.fileURLToPathStr": { argTypes: [STRING], result: STRING },
|
|
364
369
|
"url.pathToFileURL": { argTypes: [STRING], result: URL_T },
|
|
365
370
|
"url.pathToFileURLPlatform": { argTypes: [STRING, BOOL], result: URL_T },
|
|
@@ -400,6 +405,15 @@ export const LIB_FN_SIGS = {
|
|
|
400
405
|
"qs.unescape": { argTypes: [STRING], result: STRING },
|
|
401
406
|
"util.parseArgs": { argTypes: [DYN], result: DYN },
|
|
402
407
|
"util.parseEnv": { argTypes: [DYN], result: DYN },
|
|
408
|
+
"util.getSystemErrorName": { argTypes: [DYN], result: STRING },
|
|
409
|
+
"util.getSystemErrorMessage": { argTypes: [DYN], result: STRING },
|
|
410
|
+
"util.systemErrorEntries": { argTypes: [], result: DYN },
|
|
411
|
+
"util.stripVTControlCharacters": { argTypes: [DYN], result: STRING },
|
|
412
|
+
"util.toUSVString": { argTypes: [DYN], result: STRING },
|
|
413
|
+
"util.isDeepStrictEqual": { argTypes: [DYN, DYN, DYN], result: BOOL },
|
|
414
|
+
"util.styleText": { argTypes: [DYN, DYN, DYN], result: STRING },
|
|
415
|
+
"util.typeIs": { argTypes: [DYN, STRING], result: BOOL },
|
|
416
|
+
"util.typeValue": { argTypes: [DYN, STRING], result: DYN },
|
|
403
417
|
"fs.statSync": { argTypes: [STRING], result: STATS_T },
|
|
404
418
|
"fs.lstatSync": { argTypes: [STRING], result: STATS_T },
|
|
405
419
|
"fs.fstatSync": { argTypes: [F64], result: STATS_T },
|
|
@@ -407,9 +421,17 @@ export const LIB_FN_SIGS = {
|
|
|
407
421
|
"fs.fsyncSync": { argTypes: [F64], result: VOID },
|
|
408
422
|
"fs.fdatasyncSync": { argTypes: [F64], result: VOID },
|
|
409
423
|
"fs.ftruncateSync": { argTypes: [F64, F64], result: VOID },
|
|
424
|
+
"fs.utimesSync": { argTypes: [DYN, DYN, DYN], result: VOID },
|
|
425
|
+
"fs.futimesSync": { argTypes: [DYN, DYN, DYN], result: VOID },
|
|
426
|
+
"fs.lutimesSync": { argTypes: [DYN, DYN, DYN], result: VOID },
|
|
410
427
|
"fs.readvSync": { argTypes: [F64, arrayOf(BYTES_U8), F64], result: F64 },
|
|
411
428
|
"fs.writevSync": { argTypes: [F64, arrayOf(BYTES_U8), F64], result: F64 },
|
|
412
|
-
"fs.linkSync": { argTypes: [
|
|
429
|
+
"fs.linkSync": { argTypes: [DYN, DYN], result: VOID },
|
|
430
|
+
"fs.symlinkSync": { argTypes: [DYN, DYN, DYN], result: VOID },
|
|
431
|
+
"fs.readlinkSync": { argTypes: [DYN, DYN], result: DYN },
|
|
432
|
+
"fs.statfsSync": { argTypes: [DYN, DYN], result: DYN },
|
|
433
|
+
"fs.readlinkSyncStr": { argTypes: [DYN, DYN], result: STRING },
|
|
434
|
+
"fs.readlinkSyncBuffer": { argTypes: [DYN, DYN], result: BYTES_U8 },
|
|
413
435
|
"fs.openSync": { argTypes: [STRING, STRING], result: F64 },
|
|
414
436
|
"fs.openNumericSync": { argTypes: [STRING, F64, F64], result: F64 },
|
|
415
437
|
"fs.readSync": { argTypes: [F64, BYTES_U8, F64, F64, F64], result: F64 },
|
|
@@ -1051,6 +1073,14 @@ export const LIB_FN_SIGS = {
|
|
|
1051
1073
|
"fsp.mkdirRecursiveMode": { argTypes: [STRING, F64], result: { kind: "promise", inner: VOID } },
|
|
1052
1074
|
"fsp.unlink": { argTypes: [STRING], result: { kind: "promise", inner: VOID } },
|
|
1053
1075
|
"fsp.chmod": { argTypes: [STRING, F64], result: { kind: "promise", inner: VOID } },
|
|
1076
|
+
"fsp.link": { argTypes: [DYN, DYN], result: { kind: "promise", inner: VOID } },
|
|
1077
|
+
"fsp.symlink": { argTypes: [DYN, DYN, DYN], result: { kind: "promise", inner: VOID } },
|
|
1078
|
+
"fsp.readlink": { argTypes: [DYN, DYN], result: { kind: "promise", inner: DYN } },
|
|
1079
|
+
"fsp.statfs": { argTypes: [DYN, DYN], result: { kind: "promise", inner: DYN } },
|
|
1080
|
+
"fsp.readlinkStr": { argTypes: [DYN, DYN], result: { kind: "promise", inner: STRING } },
|
|
1081
|
+
"fsp.readlinkBuffer": { argTypes: [DYN, DYN], result: { kind: "promise", inner: BYTES_U8 } },
|
|
1082
|
+
"fsp.utimes": { argTypes: [DYN, DYN, DYN], result: { kind: "promise", inner: VOID } },
|
|
1083
|
+
"fsp.lutimes": { argTypes: [DYN, DYN, DYN], result: { kind: "promise", inner: VOID } },
|
|
1054
1084
|
"fsp.rename": { argTypes: [STRING, STRING], result: { kind: "promise", inner: VOID } },
|
|
1055
1085
|
"fsp.readdir": { argTypes: [STRING], result: { kind: "promise", inner: arrayOf(STRING) } },
|
|
1056
1086
|
// Result is promise<call-site Dirent record array>; the libCall case
|
|
@@ -1067,6 +1097,7 @@ export const LIB_FN_SIGS = {
|
|
|
1067
1097
|
"fileHandle.datasync": { argTypes: [FILEHANDLE_T], result: { kind: "promise", inner: VOID } },
|
|
1068
1098
|
"fileHandle.truncate": { argTypes: [FILEHANDLE_T, F64], result: { kind: "promise", inner: VOID } },
|
|
1069
1099
|
"fileHandle.chmod": { argTypes: [FILEHANDLE_T, F64], result: { kind: "promise", inner: VOID } },
|
|
1100
|
+
"fileHandle.utimes": { argTypes: [FILEHANDLE_T, DYN, DYN], result: { kind: "promise", inner: VOID } },
|
|
1070
1101
|
"fileHandle.readv": { argTypes: [FILEHANDLE_T, arrayOf(BYTES_U8), F64], result: { kind: "promise", inner: VOID } },
|
|
1071
1102
|
"fileHandle.writev": { argTypes: [FILEHANDLE_T, arrayOf(BYTES_U8), F64], result: { kind: "promise", inner: VOID } },
|
|
1072
1103
|
// read/write carry call-site result record shapes; the validator checks
|
|
@@ -1390,6 +1421,9 @@ export const LIB_FN_SIGS = {
|
|
|
1390
1421
|
"assert.shapeEnd": { argTypes: [STRING, BOOL], result: VOID },
|
|
1391
1422
|
"assert.regexErrTest": { argTypes: [REGEX, { kind: "object", className: "%Error" }], result: BOOL },
|
|
1392
1423
|
"assert.unwantedRejection": { argTypes: [{ kind: "object", className: "%Error" }, STRING, BOOL], result: VOID },
|
|
1424
|
+
"assert.unwantedError": { argTypes: [STRING, BOOL, STRING, BOOL], result: VOID },
|
|
1425
|
+
"assert.noErrorPredicate": { argTypes: [DYN, DYN], result: BOOL },
|
|
1426
|
+
"assert.regexDynTest": { argTypes: [REGEX, DYN], result: BOOL },
|
|
1393
1427
|
"assert.expectsErrDyn": { argTypes: [DYN, DYN, STRING, BOOL], result: VOID },
|
|
1394
1428
|
// assert.ifError's typed entries (always throw; unit args never
|
|
1395
1429
|
// lower). The error slot is program-dependent — any %Error-hierarchy
|
|
@@ -1761,6 +1795,7 @@ export function validateModule(mod) {
|
|
|
1761
1795
|
});
|
|
1762
1796
|
}
|
|
1763
1797
|
const classesByName = new Map();
|
|
1798
|
+
const classFields = new Map();
|
|
1764
1799
|
for (const cls of mod.classes ?? []) {
|
|
1765
1800
|
if (classesByName.has(cls.name)) {
|
|
1766
1801
|
errors.push({ message: `duplicate class "${cls.name}"`, loc: cls.loc });
|
|
@@ -1813,16 +1848,24 @@ export function validateModule(mod) {
|
|
|
1813
1848
|
errors.push({ message: `class ${cls.name}: invalid symbol field metadata`, loc: cls.loc });
|
|
1814
1849
|
}
|
|
1815
1850
|
}
|
|
1816
|
-
|
|
1851
|
+
// Reuse duplicate detection as the field index for function validation.
|
|
1852
|
+
// Array.find selected the first field, even in an invalid duplicate layout.
|
|
1853
|
+
const seen = new Map();
|
|
1817
1854
|
for (const f of cls.fields) {
|
|
1818
1855
|
if (seen.has(f.name)) {
|
|
1819
1856
|
errors.push({ message: `class ${cls.name}: duplicate field "${f.name}"`, loc: cls.loc });
|
|
1820
1857
|
}
|
|
1821
|
-
|
|
1858
|
+
else
|
|
1859
|
+
seen.set(f.name, f.type);
|
|
1822
1860
|
if (isUnitType(f.type)) {
|
|
1823
1861
|
errors.push({ message: `class ${cls.name}: field "${f.name}" is ${f.type.kind}`, loc: cls.loc });
|
|
1824
1862
|
}
|
|
1825
1863
|
}
|
|
1864
|
+
// Duplicate class names, like classesByName, select the last declaration.
|
|
1865
|
+
if (seen.size > 0)
|
|
1866
|
+
classFields.set(cls.name, seen);
|
|
1867
|
+
else
|
|
1868
|
+
classFields.delete(cls.name);
|
|
1826
1869
|
// Constructor presence is checked at `new` sites (below): a class kept
|
|
1827
1870
|
// only for its layout/type (reachability never constructs it) carries
|
|
1828
1871
|
// no constructor function, and that is fine — nothing calls it.
|
|
@@ -1899,30 +1942,41 @@ export function validateModule(mod) {
|
|
|
1899
1942
|
}
|
|
1900
1943
|
const noLoc = { file: mod.sourceFile, start: 0, end: 0 };
|
|
1901
1944
|
const recordsById = new Map();
|
|
1945
|
+
const recordIds = new Set((mod.records ?? []).map((record) => record.id));
|
|
1946
|
+
const recordValidation = new Map();
|
|
1902
1947
|
for (const rec of mod.records ?? []) {
|
|
1903
1948
|
if (recordsById.has(rec.id)) {
|
|
1904
1949
|
errors.push({ message: `duplicate record shape "${rec.id}"`, loc: noLoc });
|
|
1905
1950
|
}
|
|
1906
1951
|
recordsById.set(rec.id, rec);
|
|
1907
|
-
const
|
|
1952
|
+
const fields = new Map();
|
|
1908
1953
|
for (const f of rec.fields) {
|
|
1909
|
-
if (
|
|
1954
|
+
if (fields.has(f.name)) {
|
|
1910
1955
|
errors.push({ message: `record ${rec.id}: duplicate field "${f.name}"`, loc: noLoc });
|
|
1911
1956
|
}
|
|
1912
|
-
|
|
1957
|
+
else
|
|
1958
|
+
fields.set(f.name, f.type);
|
|
1913
1959
|
// Unit kinds (undefinedT/nullT) exist only as union arms — a BARE
|
|
1914
1960
|
// unit field is as malformed as a void one. dyn and jsval slots
|
|
1915
1961
|
// are valid; both are refcounted values held by the record shape.
|
|
1916
1962
|
if (f.type.kind === "void" || isUnitType(f.type)) {
|
|
1917
1963
|
errors.push({ message: `record ${rec.id}: field "${f.name}" is ${f.type.kind}`, loc: noLoc });
|
|
1918
1964
|
}
|
|
1919
|
-
if (f.type.kind === "record" && !
|
|
1965
|
+
if (f.type.kind === "record" && !recordIds.has(f.type.shapeId)) {
|
|
1920
1966
|
errors.push({
|
|
1921
1967
|
message: `record ${rec.id}: field "${f.name}" references undeclared shape "${f.type.shapeId}"`,
|
|
1922
1968
|
loc: noLoc,
|
|
1923
1969
|
});
|
|
1924
1970
|
}
|
|
1925
1971
|
}
|
|
1972
|
+
// Reads historically use the first duplicate field, while literal and
|
|
1973
|
+
// clone checks use the last. Preserve both on malformed shapes; valid
|
|
1974
|
+
// shapes share one index. All indexes belong to this validation call.
|
|
1975
|
+
recordValidation.set(rec.id, {
|
|
1976
|
+
fields,
|
|
1977
|
+
initializationFields: fields.size === rec.fields.length ? fields : new Map(rec.fields.map((field) => [field.name, field.type])),
|
|
1978
|
+
hasAccessorSlots: shapeHasAccessorSlots(rec),
|
|
1979
|
+
});
|
|
1926
1980
|
// Canonical order is the shape's identity — enforce it.
|
|
1927
1981
|
const sorted = [...rec.fields].map((f) => f.name).sort();
|
|
1928
1982
|
if (rec.fields.some((f, i) => f.name !== sorted[i])) {
|
|
@@ -1975,7 +2029,7 @@ export function validateModule(mod) {
|
|
|
1975
2029
|
for (const candidate of cases) {
|
|
1976
2030
|
const arm = u.arms[candidate.tag];
|
|
1977
2031
|
const record = arm?.kind === "record" ? recordsById.get(arm.shapeId) : undefined;
|
|
1978
|
-
const member = record?.fields.
|
|
2032
|
+
const member = record ? recordValidation.get(record.id)?.fields.get(field) : undefined;
|
|
1979
2033
|
if (!Number.isInteger(candidate.tag) || candidate.tag < 0 || !member || tags.has(candidate.tag)) {
|
|
1980
2034
|
errors.push({ message: `union ${u.id}: invalid discriminant tag ${candidate.tag}`, loc: noLoc });
|
|
1981
2035
|
}
|
|
@@ -1988,8 +2042,8 @@ export function validateModule(mod) {
|
|
|
1988
2042
|
errors.push({ message: `union ${u.id}: undefined discriminant value`, loc: noLoc });
|
|
1989
2043
|
continue;
|
|
1990
2044
|
}
|
|
1991
|
-
const fieldTypes = member?.
|
|
1992
|
-
? unionsById.get(member.
|
|
2045
|
+
const fieldTypes = member?.kind === "union"
|
|
2046
|
+
? unionsById.get(member.unionId)?.arms ?? [] : member ? [member] : [];
|
|
1993
2047
|
const valid = fieldTypes.some((type) => typeof value === "string" ? type.kind === "string"
|
|
1994
2048
|
: typeof value === "boolean" ? type.kind === "bool"
|
|
1995
2049
|
: typeof value === "number" && Number.isFinite(value) && type.kind === "f64");
|
|
@@ -2152,12 +2206,34 @@ export function validateModule(mod) {
|
|
|
2152
2206
|
}
|
|
2153
2207
|
}
|
|
2154
2208
|
}
|
|
2209
|
+
// Class metadata is invariant across functions. Keep field lookup, hierarchy
|
|
2210
|
+
// membership, and virtual-call resolution local to this validation invocation.
|
|
2211
|
+
const classValidation = {
|
|
2212
|
+
fields: classFields,
|
|
2213
|
+
hierarchy: new Set(), implementations: new Map(), virtualCalls: new Map(),
|
|
2214
|
+
};
|
|
2215
|
+
for (const cls of classesByName.values()) {
|
|
2216
|
+
if (cls.base !== undefined) {
|
|
2217
|
+
classValidation.hierarchy.add(cls.name);
|
|
2218
|
+
classValidation.hierarchy.add(cls.base);
|
|
2219
|
+
}
|
|
2220
|
+
if (cls.name === RUNTIME_EMITTER_CLASS)
|
|
2221
|
+
classValidation.hierarchy.add(cls.name);
|
|
2222
|
+
for (const method of new Set(cls.methods ?? [])) {
|
|
2223
|
+
if (cls.abstractMethods?.includes(method))
|
|
2224
|
+
continue;
|
|
2225
|
+
let implementations = classValidation.implementations.get(method);
|
|
2226
|
+
if (!implementations)
|
|
2227
|
+
classValidation.implementations.set(method, (implementations = []));
|
|
2228
|
+
implementations.push(cls);
|
|
2229
|
+
}
|
|
2230
|
+
}
|
|
2155
2231
|
for (const fn of mod.functions) {
|
|
2156
|
-
validateFunction(fn, functionsByName, ffiByName, classesByName, recordsById, unionsById, globalsById, errors);
|
|
2232
|
+
validateFunction(fn, functionsByName, ffiByName, classesByName, recordsById, recordValidation, unionsById, globalsById, classValidation, errors);
|
|
2157
2233
|
}
|
|
2158
2234
|
return errors;
|
|
2159
2235
|
}
|
|
2160
|
-
function validateFunction(fn, functions, ffiByName, classes, records, unions, globals, errors) {
|
|
2236
|
+
function validateFunction(fn, functions, ffiByName, classes, records, recordValidation, unions, globals, classValidation, errors) {
|
|
2161
2237
|
const locals = new Map(fn.locals.map((l) => [l.id, l]));
|
|
2162
2238
|
const err = (message, loc) => errors.push({ message: `in ${fn.name}: ${message}`, loc });
|
|
2163
2239
|
const asyncCaches = [
|
|
@@ -2200,17 +2276,41 @@ function validateFunction(fn, functions, ffiByName, classes, records, unions, gl
|
|
|
2200
2276
|
}
|
|
2201
2277
|
return false;
|
|
2202
2278
|
};
|
|
2203
|
-
const hierarchy =
|
|
2204
|
-
|
|
2205
|
-
|
|
2206
|
-
|
|
2207
|
-
|
|
2208
|
-
|
|
2209
|
-
|
|
2210
|
-
|
|
2211
|
-
|
|
2212
|
-
|
|
2213
|
-
|
|
2279
|
+
const hierarchy = classValidation.hierarchy;
|
|
2280
|
+
const virtualCallInfo = (className, method) => {
|
|
2281
|
+
let methods = classValidation.virtualCalls.get(className);
|
|
2282
|
+
const cached = methods?.get(method);
|
|
2283
|
+
if (cached)
|
|
2284
|
+
return cached;
|
|
2285
|
+
if (!methods)
|
|
2286
|
+
classValidation.virtualCalls.set(className, (methods = new Map()));
|
|
2287
|
+
let declared = false;
|
|
2288
|
+
let implementation;
|
|
2289
|
+
for (let c = classes.get(className); c; c = c.base !== undefined ? classes.get(c.base) : undefined) {
|
|
2290
|
+
if (c.methods?.includes(method)) {
|
|
2291
|
+
declared = true;
|
|
2292
|
+
if (!c.abstractMethods?.includes(method)) {
|
|
2293
|
+
implementation = functions.get(`%${c.name}.${method}`);
|
|
2294
|
+
break;
|
|
2295
|
+
}
|
|
2296
|
+
}
|
|
2297
|
+
}
|
|
2298
|
+
let hasOverride = false;
|
|
2299
|
+
if (declared) {
|
|
2300
|
+
// Preserve class-table order when choosing an abstract slot's ABI.
|
|
2301
|
+
for (const c of classValidation.implementations.get(method) ?? []) {
|
|
2302
|
+
if (!isStrictSubclass(c.name, className))
|
|
2303
|
+
continue;
|
|
2304
|
+
hasOverride = true;
|
|
2305
|
+
implementation ??= functions.get(`%${c.name}.${method}`);
|
|
2306
|
+
if (implementation)
|
|
2307
|
+
break;
|
|
2308
|
+
}
|
|
2309
|
+
}
|
|
2310
|
+
const result = { declared, hasOverride, implementation };
|
|
2311
|
+
methods.set(method, result);
|
|
2312
|
+
return result;
|
|
2313
|
+
};
|
|
2214
2314
|
// Unit kinds live only inside unions: a bare-unit local, param, or
|
|
2215
2315
|
// return type is frontend breakage (mapType never produces them).
|
|
2216
2316
|
for (const l of fn.locals) {
|
|
@@ -2636,15 +2736,15 @@ function validateFunction(fn, functions, ffiByName, classes, records, unions, gl
|
|
|
2636
2736
|
// dyn field with fieldDyn set (validated numeric read-modify-write).
|
|
2637
2737
|
checkExpr(e.obj);
|
|
2638
2738
|
const cls = classes.get(e.className);
|
|
2639
|
-
const
|
|
2739
|
+
const fieldType = classValidation.fields.get(e.className)?.get(e.field);
|
|
2640
2740
|
if (!cls)
|
|
2641
2741
|
err(`fieldIncDec on undeclared class "${e.className}"`, e.loc);
|
|
2642
|
-
else if (!
|
|
2742
|
+
else if (!fieldType)
|
|
2643
2743
|
err(`class ${e.className} has no field "${e.field}"`, e.loc);
|
|
2644
2744
|
else {
|
|
2645
2745
|
expectType(e.obj, { kind: "object", className: e.className }, "fieldIncDec receiver");
|
|
2646
|
-
if (e.fieldDyn ?
|
|
2647
|
-
err(`fieldIncDec ${e.className}.${e.field} field/flag mismatch (${
|
|
2746
|
+
if (e.fieldDyn ? fieldType.kind !== "dyn" : fieldType.kind !== "f64") {
|
|
2747
|
+
err(`fieldIncDec ${e.className}.${e.field} field/flag mismatch (${fieldType.kind})`, e.loc);
|
|
2648
2748
|
}
|
|
2649
2749
|
}
|
|
2650
2750
|
if (e.type.kind !== "f64")
|
|
@@ -3668,14 +3768,14 @@ function validateFunction(fn, functions, ffiByName, classes, records, unions, gl
|
|
|
3668
3768
|
case "fieldGet": {
|
|
3669
3769
|
checkExpr(e.obj);
|
|
3670
3770
|
const cls = classes.get(e.className);
|
|
3671
|
-
const
|
|
3771
|
+
const fieldType = classValidation.fields.get(e.className)?.get(e.field);
|
|
3672
3772
|
if (!cls)
|
|
3673
3773
|
err(`fieldGet on undeclared class "${e.className}"`, e.loc);
|
|
3674
|
-
else if (!
|
|
3774
|
+
else if (!fieldType)
|
|
3675
3775
|
err(`class ${e.className} has no field "${e.field}"`, e.loc);
|
|
3676
3776
|
else {
|
|
3677
3777
|
expectType(e.obj, { kind: "object", className: e.className }, "fieldGet receiver");
|
|
3678
|
-
if (!typeEquals(e.type,
|
|
3778
|
+
if (!typeEquals(e.type, fieldType)) {
|
|
3679
3779
|
err(`fieldGet ${e.className}.${e.field} type mismatch`, e.loc);
|
|
3680
3780
|
}
|
|
3681
3781
|
}
|
|
@@ -3849,30 +3949,15 @@ function validateFunction(fn, functions, ffiByName, classes, records, unions, gl
|
|
|
3849
3949
|
// is then well-formed against any concrete override below — the
|
|
3850
3950
|
// frontend's override-exactness rule makes every implementation
|
|
3851
3951
|
// ABI-identical, so any one of them carries the slot's signature.
|
|
3852
|
-
|
|
3853
|
-
|
|
3854
|
-
for (let c = classes.get(e.className); c; c = c.base !== undefined ? classes.get(c.base) : undefined) {
|
|
3855
|
-
if (c.methods?.includes(e.method)) {
|
|
3856
|
-
declared = true;
|
|
3857
|
-
if (!c.abstractMethods?.includes(e.method)) {
|
|
3858
|
-
impl = functions.get(`%${c.name}.${e.method}`);
|
|
3859
|
-
break;
|
|
3860
|
-
}
|
|
3861
|
-
}
|
|
3862
|
-
}
|
|
3863
|
-
if (!declared) {
|
|
3952
|
+
const info = virtualCallInfo(e.className, e.method);
|
|
3953
|
+
if (!info.declared) {
|
|
3864
3954
|
err(`virtualCall ${e.className}.${e.method}: no declaration on the base chain`, e.loc);
|
|
3865
3955
|
break;
|
|
3866
3956
|
}
|
|
3867
|
-
|
|
3868
|
-
!c.abstractMethods?.includes(e.method) &&
|
|
3869
|
-
isStrictSubclass(c.name, e.className));
|
|
3870
|
-
if (concreteBelow.length === 0) {
|
|
3957
|
+
if (!info.hasOverride) {
|
|
3871
3958
|
err(`virtualCall ${e.className}.${e.method}: no concrete override below the static class`, e.loc);
|
|
3872
3959
|
}
|
|
3873
|
-
impl
|
|
3874
|
-
.map((c) => functions.get(`%${c.name}.${e.method}`))
|
|
3875
|
-
.find((f) => f !== undefined);
|
|
3960
|
+
const impl = info.implementation;
|
|
3876
3961
|
if (!impl) {
|
|
3877
3962
|
err(`virtualCall ${e.className}.${e.method}: no implementation function exists`, e.loc);
|
|
3878
3963
|
break;
|
|
@@ -3908,7 +3993,7 @@ function validateFunction(fn, functions, ffiByName, classes, records, unions, gl
|
|
|
3908
3993
|
err(`recordLit of undeclared shape "${e.type.shapeId}"`, e.loc);
|
|
3909
3994
|
break;
|
|
3910
3995
|
}
|
|
3911
|
-
const want =
|
|
3996
|
+
const want = recordValidation.get(shape.id).initializationFields;
|
|
3912
3997
|
const seen = new Set();
|
|
3913
3998
|
for (const f of e.fields) {
|
|
3914
3999
|
checkExpr(f.value);
|
|
@@ -3964,11 +4049,11 @@ function validateFunction(fn, functions, ffiByName, classes, records, unions, gl
|
|
|
3964
4049
|
err(`recordClone of undeclared shape "${e.type.shapeId}"`, e.loc);
|
|
3965
4050
|
break;
|
|
3966
4051
|
}
|
|
3967
|
-
if (shape.tuple || shape.indexValue ||
|
|
4052
|
+
if (shape.tuple || shape.indexValue || recordValidation.get(shape.id).hasAccessorSlots) {
|
|
3968
4053
|
err(`recordClone requires a plain declared-field shape, got ${shape.id}`, e.loc);
|
|
3969
4054
|
}
|
|
3970
4055
|
expectType(e.source, e.type, "recordClone source");
|
|
3971
|
-
const want =
|
|
4056
|
+
const want = recordValidation.get(shape.id).initializationFields;
|
|
3972
4057
|
const seen = new Set();
|
|
3973
4058
|
for (const f of e.overrides) {
|
|
3974
4059
|
checkExpr(f.value);
|
|
@@ -3986,14 +4071,14 @@ function validateFunction(fn, functions, ffiByName, classes, records, unions, gl
|
|
|
3986
4071
|
case "recordGet": {
|
|
3987
4072
|
checkExpr(e.obj);
|
|
3988
4073
|
const shape = records.get(e.shapeId);
|
|
3989
|
-
const field =
|
|
4074
|
+
const field = recordValidation.get(e.shapeId)?.fields.get(e.field);
|
|
3990
4075
|
if (!shape)
|
|
3991
4076
|
err(`recordGet on undeclared shape "${e.shapeId}"`, e.loc);
|
|
3992
4077
|
else if (!field)
|
|
3993
4078
|
err(`shape ${e.shapeId} has no field "${e.field}"`, e.loc);
|
|
3994
4079
|
else {
|
|
3995
4080
|
expectType(e.obj, { kind: "record", shapeId: e.shapeId }, "recordGet receiver");
|
|
3996
|
-
if (!typeEquals(e.type, field
|
|
4081
|
+
if (!typeEquals(e.type, field)) {
|
|
3997
4082
|
err(`recordGet ${e.shapeId}.${e.field} type mismatch`, e.loc);
|
|
3998
4083
|
}
|
|
3999
4084
|
}
|
|
@@ -4365,9 +4450,9 @@ function validateFunction(fn, functions, ffiByName, classes, records, unions, gl
|
|
|
4365
4450
|
}
|
|
4366
4451
|
def.arms.forEach((arm, i) => {
|
|
4367
4452
|
const fieldType = arm.kind === "record"
|
|
4368
|
-
?
|
|
4453
|
+
? recordValidation.get(arm.shapeId)?.fields.get(e.field)
|
|
4369
4454
|
: arm.kind === "object"
|
|
4370
|
-
?
|
|
4455
|
+
? classValidation.fields.get(arm.className)?.get(e.field)
|
|
4371
4456
|
: undefined;
|
|
4372
4457
|
if (!fieldType) {
|
|
4373
4458
|
err(`unionDisc: arm ${i} of ${e.unionId} has no field "${e.field}"`, e.loc);
|
|
@@ -4430,7 +4515,7 @@ function validateFunction(fn, functions, ffiByName, classes, records, unions, gl
|
|
|
4430
4515
|
return;
|
|
4431
4516
|
}
|
|
4432
4517
|
const literal = e.key.kind === "strLit" ? e.key.value : null;
|
|
4433
|
-
const declared = literal !== null ? shape.fields.
|
|
4518
|
+
const declared = literal !== null ? recordValidation.get(shape.id)?.fields.get(literal) : undefined;
|
|
4434
4519
|
if (declared) {
|
|
4435
4520
|
if (!surfaces(declared)) {
|
|
4436
4521
|
err(`unionKeyGet: arm ${i} field "${literal}" of type ${declared.kind} cannot surface as the result`, e.loc);
|
|
@@ -4651,11 +4736,11 @@ function validateFunction(fn, functions, ffiByName, classes, records, unions, gl
|
|
|
4651
4736
|
const countName = e.fn === "fileHandle.read" || e.fn === "fileHandle.readv" ? "bytesRead" : "bytesWritten";
|
|
4652
4737
|
const payloadName = e.fn === "fileHandle.readv" || e.fn === "fileHandle.writev" ? "buffers" : "buffer";
|
|
4653
4738
|
const payload = e.args[1]?.type;
|
|
4654
|
-
const count = shape?.fields.
|
|
4655
|
-
const buffer = shape?.fields.
|
|
4739
|
+
const count = shape ? recordValidation.get(shape.id)?.fields.get(countName) : undefined;
|
|
4740
|
+
const buffer = shape ? recordValidation.get(shape.id)?.fields.get(payloadName) : undefined;
|
|
4656
4741
|
const ok = shape !== undefined && !shape.tuple && shape.indexValue === undefined && shape.fields.length === 2 &&
|
|
4657
|
-
count?.
|
|
4658
|
-
typeEquals(buffer
|
|
4742
|
+
count?.kind === "f64" && payload !== undefined && buffer !== undefined &&
|
|
4743
|
+
typeEquals(buffer, payload);
|
|
4659
4744
|
if (!ok) {
|
|
4660
4745
|
err(`libCall ${e.fn} must return a promise of { ${countName}: number, ${payloadName} }`, e.loc);
|
|
4661
4746
|
}
|
|
@@ -5948,17 +6033,17 @@ function validateFunction(fn, functions, ffiByName, classes, records, unions, gl
|
|
|
5948
6033
|
break;
|
|
5949
6034
|
}
|
|
5950
6035
|
const rec = records.get(resultT.shapeId);
|
|
5951
|
-
const doneF = rec?.fields.
|
|
5952
|
-
const valueF = rec?.fields.
|
|
5953
|
-
if (!rec || rec.fields.length !== 2 || doneF?.
|
|
6036
|
+
const doneF = rec ? recordValidation.get(rec.id)?.fields.get("done") : undefined;
|
|
6037
|
+
const valueF = rec ? recordValidation.get(rec.id)?.fields.get("value") : undefined;
|
|
6038
|
+
if (!rec || rec.fields.length !== 2 || doneF?.kind !== "bool" || valueF === undefined) {
|
|
5954
6039
|
err(`genResume result record ${resultT.shapeId} is not { done: bool, value: V }`, e.loc);
|
|
5955
6040
|
break;
|
|
5956
6041
|
}
|
|
5957
|
-
if (valueF.
|
|
6042
|
+
if (valueF.kind === "dyn")
|
|
5958
6043
|
break;
|
|
5959
|
-
const vdef = valueF.
|
|
6044
|
+
const vdef = valueF.kind === "union" ? unions.get(valueF.unionId) : undefined;
|
|
5960
6045
|
if (!vdef || !vdef.arms.some((a) => a.kind === "undefinedT")) {
|
|
5961
|
-
err(`genResume value slot ${typeKey(valueF
|
|
6046
|
+
err(`genResume value slot ${typeKey(valueF)} is neither dyn nor an undefined-armed union`, e.loc);
|
|
5962
6047
|
}
|
|
5963
6048
|
break;
|
|
5964
6049
|
}
|
|
@@ -6042,10 +6127,10 @@ function validateFunction(fn, functions, ffiByName, classes, records, unions, gl
|
|
|
6042
6127
|
break;
|
|
6043
6128
|
}
|
|
6044
6129
|
const shape = records.get(e.type.shapeId);
|
|
6045
|
-
const fields =
|
|
6046
|
-
const prom = fields
|
|
6047
|
-
const resolve = fields
|
|
6048
|
-
const reject = fields
|
|
6130
|
+
const fields = recordValidation.get(e.type.shapeId)?.initializationFields;
|
|
6131
|
+
const prom = fields?.get("promise");
|
|
6132
|
+
const resolve = fields?.get("resolve");
|
|
6133
|
+
const reject = fields?.get("reject");
|
|
6049
6134
|
if (!shape || shape.fields.length !== 3 || !prom || !resolve || !reject) {
|
|
6050
6135
|
err("promiseWithResolvers record must be { promise, resolve, reject }", e.loc);
|
|
6051
6136
|
break;
|
|
@@ -6357,14 +6442,14 @@ function validateFunction(fn, functions, ffiByName, classes, records, unions, gl
|
|
|
6357
6442
|
checkExpr(s.obj);
|
|
6358
6443
|
checkExpr(s.value);
|
|
6359
6444
|
const cls = classes.get(s.className);
|
|
6360
|
-
const
|
|
6445
|
+
const fieldType = classValidation.fields.get(s.className)?.get(s.field);
|
|
6361
6446
|
if (!cls)
|
|
6362
6447
|
err(`fieldSet on undeclared class "${s.className}"`, s.loc);
|
|
6363
|
-
else if (!
|
|
6448
|
+
else if (!fieldType)
|
|
6364
6449
|
err(`class ${s.className} has no field "${s.field}"`, s.loc);
|
|
6365
6450
|
else {
|
|
6366
6451
|
expectType(s.obj, { kind: "object", className: s.className }, "fieldSet receiver");
|
|
6367
|
-
expectType(s.value,
|
|
6452
|
+
expectType(s.value, fieldType, `fieldSet ${s.className}.${s.field}`);
|
|
6368
6453
|
}
|
|
6369
6454
|
break;
|
|
6370
6455
|
}
|
|
@@ -6372,14 +6457,14 @@ function validateFunction(fn, functions, ffiByName, classes, records, unions, gl
|
|
|
6372
6457
|
checkExpr(s.obj);
|
|
6373
6458
|
checkExpr(s.value);
|
|
6374
6459
|
const shape = records.get(s.shapeId);
|
|
6375
|
-
const field =
|
|
6460
|
+
const field = recordValidation.get(s.shapeId)?.fields.get(s.field);
|
|
6376
6461
|
if (!shape)
|
|
6377
6462
|
err(`recordSet on undeclared shape "${s.shapeId}"`, s.loc);
|
|
6378
6463
|
else if (!field)
|
|
6379
6464
|
err(`shape ${s.shapeId} has no field "${s.field}"`, s.loc);
|
|
6380
6465
|
else {
|
|
6381
6466
|
expectType(s.obj, { kind: "record", shapeId: s.shapeId }, "recordSet receiver");
|
|
6382
|
-
expectType(s.value, field
|
|
6467
|
+
expectType(s.value, field, `recordSet ${s.shapeId}.${s.field}`);
|
|
6383
6468
|
}
|
|
6384
6469
|
break;
|
|
6385
6470
|
}
|