@suss/resolution 0.34.0 → 0.35.0
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/dist/index.cjs +613 -28
- package/dist/index.d.cts +93 -2
- package/dist/index.d.ts +93 -2
- package/dist/index.js +604 -28
- package/package.json +2 -2
package/dist/index.cjs
CHANGED
|
@@ -24,6 +24,7 @@ __export(index_exports, {
|
|
|
24
24
|
ASKING_RELATIONS: () => ASKING_RELATIONS,
|
|
25
25
|
BASE_CLASS_RULE: () => BASE_CLASS_RULE,
|
|
26
26
|
DEFAULT_IMPORT_NAME: () => DEFAULT_IMPORT_NAME,
|
|
27
|
+
DISPATCH_QUESTION: () => DISPATCH_QUESTION,
|
|
27
28
|
DependencyLedger: () => DependencyLedger,
|
|
28
29
|
EntryReuse: () => EntryReuse,
|
|
29
30
|
FACT_CONTRACT_CASES: () => FACT_CONTRACT_CASES,
|
|
@@ -41,18 +42,23 @@ __export(index_exports, {
|
|
|
41
42
|
RESOLUTION_QUESTIONS: () => RESOLUTION_QUESTIONS,
|
|
42
43
|
RESOLUTION_RULES: () => RESOLUTION_RULES,
|
|
43
44
|
RESULT_STEP: () => RESULT_STEP,
|
|
45
|
+
SPREAD_ENTRY: () => SPREAD_ENTRY,
|
|
44
46
|
UNDER_ANSWER_RELATIONS: () => UNDER_ANSWER_RELATIONS,
|
|
45
47
|
UNDER_QUESTION_ROW_BUDGET: () => UNDER_QUESTION_ROW_BUDGET,
|
|
46
48
|
UNDER_RUN_ROW_BUDGET: () => UNDER_RUN_ROW_BUDGET,
|
|
47
49
|
UNPLACED_STORE_NAME: () => UNPLACED_STORE_NAME,
|
|
48
50
|
USES_QUESTION: () => USES_QUESTION,
|
|
51
|
+
VALUE_ENTRY: () => VALUE_ENTRY,
|
|
49
52
|
VALUE_STEP: () => VALUE_STEP,
|
|
50
53
|
WatchedMap: () => WatchedMap,
|
|
54
|
+
addEntryRows: () => addEntryRows,
|
|
51
55
|
addPackWords: () => addPackWords,
|
|
56
|
+
addTemplateRows: () => addTemplateRows,
|
|
52
57
|
agreedMountPrefix: () => agreedMountPrefix,
|
|
53
58
|
allocationSitesOf: () => allocationSitesOf,
|
|
54
59
|
alsoSteps: () => alsoSteps,
|
|
55
60
|
answersFor: () => answersFor,
|
|
61
|
+
answersFromTestsLeftOut: () => answersFromTestsLeftOut,
|
|
56
62
|
askResolution: () => askResolution,
|
|
57
63
|
askResolutionUnder: () => askResolutionUnder,
|
|
58
64
|
askSources: () => askSources,
|
|
@@ -64,6 +70,7 @@ __export(index_exports, {
|
|
|
64
70
|
comesToUnder: () => comesToUnder,
|
|
65
71
|
couldBeSettled: () => couldBeSettled,
|
|
66
72
|
declaredTypesOf: () => declaredTypesOf,
|
|
73
|
+
dispatchOutcomes: () => dispatchOutcomes,
|
|
67
74
|
exitCodeFunctions: () => exitCodeFunctions,
|
|
68
75
|
explainResolutionProof: () => explainResolutionProof,
|
|
69
76
|
explainResolvedKey: () => explainResolvedKey,
|
|
@@ -85,6 +92,7 @@ __export(index_exports, {
|
|
|
85
92
|
packHashes: () => packHashes,
|
|
86
93
|
proofRules: () => proofRules,
|
|
87
94
|
queryFacts: () => queryFacts,
|
|
95
|
+
readDispatchOutcomes: () => readDispatchOutcomes,
|
|
88
96
|
readUses: () => readUses,
|
|
89
97
|
recordsToReplay: () => recordsToReplay,
|
|
90
98
|
renderExplanation: () => renderExplanation,
|
|
@@ -93,6 +101,7 @@ __export(index_exports, {
|
|
|
93
101
|
resolvedFunctions: () => resolvedFunctions,
|
|
94
102
|
settledFunction: () => settledFunction,
|
|
95
103
|
sourceLeavesOf: () => sourceLeavesOf,
|
|
104
|
+
spanOfKey: () => spanOfKey,
|
|
96
105
|
startsAtName: () => startsAtName,
|
|
97
106
|
staysInItsFunction: () => staysInItsFunction,
|
|
98
107
|
stillValid: () => stillValid,
|
|
@@ -120,6 +129,7 @@ var ASKING_RELATIONS = [
|
|
|
120
129
|
"wantedEnvObject",
|
|
121
130
|
"wantedStreamObject",
|
|
122
131
|
"wantedExitSink",
|
|
132
|
+
"wantedDispatch",
|
|
123
133
|
"wantedOrigin",
|
|
124
134
|
"wantedCallOrigin",
|
|
125
135
|
"wantedExportsOf",
|
|
@@ -637,6 +647,29 @@ function classMemberOf(name) {
|
|
|
637
647
|
return name.startsWith(CLASS_MEMBER_PREFIX) ? name.slice(CLASS_MEMBER_PREFIX.length) : null;
|
|
638
648
|
}
|
|
639
649
|
|
|
650
|
+
// src/valuePositions.ts
|
|
651
|
+
var VALUE_ENTRY = "value";
|
|
652
|
+
var SPREAD_ENTRY = "spread";
|
|
653
|
+
function addEntryRows(add, container, entries) {
|
|
654
|
+
entries.forEach((entry, position) => {
|
|
655
|
+
add("writtenEntryAt", [container, String(position), entry.key, entry.form]);
|
|
656
|
+
});
|
|
657
|
+
}
|
|
658
|
+
function addTemplateRows(add, template, pieces) {
|
|
659
|
+
let position = 0;
|
|
660
|
+
for (const piece of pieces) {
|
|
661
|
+
if ("hole" in piece) {
|
|
662
|
+
add("holeAt", [template, String(position), piece.hole]);
|
|
663
|
+
position += 1;
|
|
664
|
+
continue;
|
|
665
|
+
}
|
|
666
|
+
if (piece.text !== "") {
|
|
667
|
+
add("partAt", [template, String(position), piece.text]);
|
|
668
|
+
position += 1;
|
|
669
|
+
}
|
|
670
|
+
}
|
|
671
|
+
}
|
|
672
|
+
|
|
640
673
|
// src/contract.ts
|
|
641
674
|
var distinct = (values) => new Set(values).size;
|
|
642
675
|
function leadsToOneOf(facts, key, targets) {
|
|
@@ -654,6 +687,30 @@ function leadsToOneOf(facts, key, targets) {
|
|
|
654
687
|
return false;
|
|
655
688
|
}
|
|
656
689
|
var RELATIONS_THAT_CAN_CROSS = ["imports", "binds", "reExports"];
|
|
690
|
+
function someValueLeadsTo(facts, key) {
|
|
691
|
+
const target = /* @__PURE__ */ new Set([key]);
|
|
692
|
+
return ["returnsValue", "holdsUnderKey"].some(
|
|
693
|
+
(relation) => facts(relation).some((row) => leadsToOneOf(facts, row[1] ?? "", target))
|
|
694
|
+
);
|
|
695
|
+
}
|
|
696
|
+
function holdsValueThenSpread(facts, name) {
|
|
697
|
+
const entries = facts("writtenEntryAt");
|
|
698
|
+
const held = facts("holdsProperty");
|
|
699
|
+
return [...new Set(entries.map((row) => row[0]))].some((container) => {
|
|
700
|
+
const own = entries.filter((row) => row[0] === container);
|
|
701
|
+
const value = own.find((row) => row[1] === "0");
|
|
702
|
+
const spread2 = own.find((row) => row[1] === "1");
|
|
703
|
+
return own.length === 2 && value?.[3] === VALUE_ENTRY && spread2?.[3] === SPREAD_ENTRY && held.some(
|
|
704
|
+
(row) => row[0] === container && row[1] === name && row[2] === value[2]
|
|
705
|
+
) && !held.some((row) => row[0] === container && row[2] === spread2[2]);
|
|
706
|
+
});
|
|
707
|
+
}
|
|
708
|
+
function valueThenSpread(facts, name) {
|
|
709
|
+
if (facts("writtenEntryAt").length === 0) {
|
|
710
|
+
return "no list or object states its entries, so nothing says the order they are written in";
|
|
711
|
+
}
|
|
712
|
+
return holdsValueThenSpread(facts, name) ? null : `no container's entries are the value under ${name} at 0, keyed as holdsProperty keys it, and then a spread at 1 keyed on the collection it unpacks`;
|
|
713
|
+
}
|
|
657
714
|
var FACT_CONTRACT_CASES = [
|
|
658
715
|
{
|
|
659
716
|
name: "two functions, one parameter name",
|
|
@@ -852,6 +909,122 @@ var FACT_CONTRACT_CASES = [
|
|
|
852
909
|
return stores.some((row) => leadsToOneOf(facts, row[0] ?? "", sites)) ? null : "the write is keyed so that nothing leads from it to the construction, so the rules cannot find the object it lands on";
|
|
853
910
|
}
|
|
854
911
|
},
|
|
912
|
+
{
|
|
913
|
+
name: "a table of functions called by a key worked out at run time",
|
|
914
|
+
requires: "a module-level table written out with a function under the name created and another under deleted, and a function that calls the table's entry under its parameter, `TABLE[kind](payload)` or the language's own spelling",
|
|
915
|
+
// The rules take the entries off the object the read's container
|
|
916
|
+
// leads to, so the container has to be keyed the way `binds` keys it,
|
|
917
|
+
// and each entry under the name the source writes, without quotes.
|
|
918
|
+
check: (facts) => {
|
|
919
|
+
const entries = facts("holdsProperty");
|
|
920
|
+
const tables = new Set(
|
|
921
|
+
entries.filter((row) => row[1] === "created").map((row) => row[0] ?? "").filter(
|
|
922
|
+
(table) => entries.some((row) => row[0] === table && row[1] === "deleted")
|
|
923
|
+
)
|
|
924
|
+
);
|
|
925
|
+
if (tables.size === 0) {
|
|
926
|
+
return "no object contains a function under created and another under deleted, written without quotes";
|
|
927
|
+
}
|
|
928
|
+
const reads = facts("choosesEntry");
|
|
929
|
+
if (reads.length === 0) {
|
|
930
|
+
return "the read at a key worked out at run time is not written down as choosesEntry, so no call through it finds the table's functions";
|
|
931
|
+
}
|
|
932
|
+
return reads.some((row) => leadsToOneOf(facts, row[1] ?? "", tables)) ? null : "the read's container is keyed so that nothing leads from it to the table";
|
|
933
|
+
}
|
|
934
|
+
},
|
|
935
|
+
{
|
|
936
|
+
name: "a function written into a table under a computed key",
|
|
937
|
+
requires: "a module-level empty table, and a function that writes its second parameter into it under its first, `REGISTRY[name] = handler` or the language's own spelling",
|
|
938
|
+
// A registry fills its table from a function its callers pass handlers
|
|
939
|
+
// to, so the write has to say the parameter went in, keyed so that
|
|
940
|
+
// `binds` leads from where it went to the table.
|
|
941
|
+
check: (facts) => {
|
|
942
|
+
const params = new Set(facts("paramOf").map((row) => row[2] ?? ""));
|
|
943
|
+
const writes = facts("holdsUnderKey").filter(
|
|
944
|
+
(row) => leadsToOneOf(facts, row[1] ?? "", params)
|
|
945
|
+
);
|
|
946
|
+
if (writes.length === 0) {
|
|
947
|
+
return "the write of a parameter into a table under a computed key is not written down as holdsUnderKey";
|
|
948
|
+
}
|
|
949
|
+
const objects = new Set(facts("objectValue").map((row) => row[0] ?? ""));
|
|
950
|
+
return writes.some((row) => leadsToOneOf(facts, row[0] ?? "", objects)) ? null : "the write is keyed so that nothing leads from it to the table";
|
|
951
|
+
}
|
|
952
|
+
},
|
|
953
|
+
{
|
|
954
|
+
name: "a list written with a spread",
|
|
955
|
+
requires: "a module-level name assigned a written-out list of a name and then a spread of another name, `[first, ...rest]` or the language's own spelling",
|
|
956
|
+
check: (facts) => valueThenSpread(facts, "0")
|
|
957
|
+
},
|
|
958
|
+
{
|
|
959
|
+
name: "an object written with a spread",
|
|
960
|
+
requires: "a module-level name assigned an object or a dictionary written out with a name under the key a, written as a string where the language writes keys that way, and then a spread of another name",
|
|
961
|
+
check: (facts) => valueThenSpread(facts, "a")
|
|
962
|
+
},
|
|
963
|
+
{
|
|
964
|
+
name: "a template string with a hole",
|
|
965
|
+
requires: "a module-level name assigned the result of a call, and a template string that puts that name between two pieces of text, `/users/${id}/posts` or the language's own spelling",
|
|
966
|
+
check: (facts) => {
|
|
967
|
+
const parts = facts("partAt");
|
|
968
|
+
const [hole, ...moreHoles] = facts("holeAt");
|
|
969
|
+
if (parts.length !== 2 || hole === void 0 || moreHoles.length > 0) {
|
|
970
|
+
return `expected two parts and one hole, found ${parts.length} and ${moreHoles.length + (hole === void 0 ? 0 : 1)}`;
|
|
971
|
+
}
|
|
972
|
+
const positions = [...parts, hole].filter((row) => row[0] === hole[0]).map((row) => row[1]).sort();
|
|
973
|
+
if (positions.join() !== "0,1,2" || hole[1] !== "1") {
|
|
974
|
+
return "the parts and the hole of one template are not numbered together in source order from 0";
|
|
975
|
+
}
|
|
976
|
+
const calls = new Set(facts("call").map((row) => row[0] ?? ""));
|
|
977
|
+
return leadsToOneOf(facts, hole[2] ?? "", calls) ? null : "the hole is keyed so that nothing leads from it to the value the name is given";
|
|
978
|
+
}
|
|
979
|
+
},
|
|
980
|
+
{
|
|
981
|
+
name: "a callback given each element of a list",
|
|
982
|
+
requires: "a function that maps its parameter through a callback returning the element it is given, `users.map((user) => user)`, a comprehension or the language's own spelling",
|
|
983
|
+
// The collection is a read of the function's parameter, and the
|
|
984
|
+
// callback's own read of its variable joins the key elementOf states.
|
|
985
|
+
check: (facts) => {
|
|
986
|
+
const [row, ...more] = facts("elementOf");
|
|
987
|
+
if (row === void 0 || more.length > 0) {
|
|
988
|
+
return `expected one elementOf row, found ${more.length + (row === void 0 ? 0 : 1)}`;
|
|
989
|
+
}
|
|
990
|
+
const params = new Set(facts("paramOf").map((one) => one[2] ?? ""));
|
|
991
|
+
if (!leadsToOneOf(facts, row[1] ?? "", params)) {
|
|
992
|
+
return "the collection is keyed so that nothing leads from it to the parameter it reads";
|
|
993
|
+
}
|
|
994
|
+
return someValueLeadsTo(facts, row[0] ?? "") ? null : "no read of the variable leads to the key elementOf gives it, so nothing knows what the read is given";
|
|
995
|
+
}
|
|
996
|
+
},
|
|
997
|
+
{
|
|
998
|
+
name: "a callback given the parts of each element of a list",
|
|
999
|
+
requires: "a function that maps its parameter through a callback taking each element apart into two names and returning the first, `pairs.map(([name, kind]) => name)`, `[name for name, kind in pairs]` or the language's own spelling",
|
|
1000
|
+
check: (facts) => {
|
|
1001
|
+
const parts = facts("elementPartOf");
|
|
1002
|
+
const first = parts.find((row) => row[2] === "0");
|
|
1003
|
+
const second = parts.find((row) => row[2] === "1");
|
|
1004
|
+
if (first === void 0 || second === void 0) {
|
|
1005
|
+
return "no two names are given parts 0 and 1 of each element, so nothing says what a name taken apart is given";
|
|
1006
|
+
}
|
|
1007
|
+
const params = new Set(facts("paramOf").map((one) => one[2] ?? ""));
|
|
1008
|
+
if (first[1] !== second[1] || !leadsToOneOf(facts, first[1] ?? "", params)) {
|
|
1009
|
+
return "the two parts name different collections, or one that nothing leads from to the parameter it reads";
|
|
1010
|
+
}
|
|
1011
|
+
return someValueLeadsTo(facts, first[0] ?? "") ? null : "no read of the first name leads to the key elementPartOf gives it";
|
|
1012
|
+
}
|
|
1013
|
+
},
|
|
1014
|
+
{
|
|
1015
|
+
name: "a callback given each position in a list",
|
|
1016
|
+
requires: "a function that maps its parameter through a callback taking the element and then its position and returning the position, `users.map((user, at) => at)`, `enumerate` in a comprehension, or the language's own spelling",
|
|
1017
|
+
check: (facts) => {
|
|
1018
|
+
const [row, ...more] = facts("positionOf");
|
|
1019
|
+
if (row === void 0 || more.length > 0) {
|
|
1020
|
+
return `expected one positionOf row, found ${more.length + (row === void 0 ? 0 : 1)}`;
|
|
1021
|
+
}
|
|
1022
|
+
if (!facts("elementOf").some((one) => one[0] === row[1])) {
|
|
1023
|
+
return "the position is tied to a variable that no elementOf row gives an element, so nothing says what it counts through";
|
|
1024
|
+
}
|
|
1025
|
+
return someValueLeadsTo(facts, row[0] ?? "") ? null : "no read of the position leads to the key positionOf gives it";
|
|
1026
|
+
}
|
|
1027
|
+
},
|
|
855
1028
|
{
|
|
856
1029
|
name: "a value another file declares",
|
|
857
1030
|
requires: "two files, one declaring a value and the other reading it by name",
|
|
@@ -1254,13 +1427,13 @@ var FactLog = class {
|
|
|
1254
1427
|
hashesByKey(relation, row) {
|
|
1255
1428
|
const hashes = /* @__PURE__ */ new Map();
|
|
1256
1429
|
const atoms = row.map((atom) => this.hashesOf(String(atom)));
|
|
1257
|
-
const term = (hash,
|
|
1430
|
+
const term = (hash, column2) => spread(hash + Math.imul(column2 + 1, 2654435761) >>> 0);
|
|
1258
1431
|
let loose = hashString(relation);
|
|
1259
|
-
atoms.forEach((atom,
|
|
1260
|
-
loose = loose + term(atom.loose,
|
|
1432
|
+
atoms.forEach((atom, column2) => {
|
|
1433
|
+
loose = loose + term(atom.loose, column2) >>> 0;
|
|
1261
1434
|
});
|
|
1262
|
-
atoms.forEach((atom,
|
|
1263
|
-
const key = String(row[
|
|
1435
|
+
atoms.forEach((atom, column2) => {
|
|
1436
|
+
const key = String(row[column2]);
|
|
1264
1437
|
if (!atom.key || hashes.has(key)) {
|
|
1265
1438
|
return;
|
|
1266
1439
|
}
|
|
@@ -1357,6 +1530,107 @@ var FactLog = class {
|
|
|
1357
1530
|
}
|
|
1358
1531
|
};
|
|
1359
1532
|
|
|
1533
|
+
// src/dispatch.ts
|
|
1534
|
+
function dispatchOutcomes(db, calls, program = resolutionProgram()) {
|
|
1535
|
+
const outcomes = /* @__PURE__ */ new Map();
|
|
1536
|
+
if (calls.length === 0) {
|
|
1537
|
+
return outcomes;
|
|
1538
|
+
}
|
|
1539
|
+
askResolution(db, calls, DISPATCH_QUESTION, program);
|
|
1540
|
+
return readDispatchOutcomes(db, calls);
|
|
1541
|
+
}
|
|
1542
|
+
var DISPATCH_QUESTION = "wantedDispatch";
|
|
1543
|
+
function readDispatchOutcomes(db, calls) {
|
|
1544
|
+
const outcomes = /* @__PURE__ */ new Map();
|
|
1545
|
+
for (const call of new Set(calls)) {
|
|
1546
|
+
const sites = column(db, "wantedDispatchSite", call, 1);
|
|
1547
|
+
if (sites.length === 0) {
|
|
1548
|
+
continue;
|
|
1549
|
+
}
|
|
1550
|
+
outcomes.set(call, outcomeOf(db, call, sites));
|
|
1551
|
+
}
|
|
1552
|
+
return outcomes;
|
|
1553
|
+
}
|
|
1554
|
+
function outcomeOf(db, call, sites) {
|
|
1555
|
+
const byEntry = /* @__PURE__ */ new Map();
|
|
1556
|
+
for (const entry of column(db, "wantedDispatchEntry", call, 1)) {
|
|
1557
|
+
byEntry.set(entry, /* @__PURE__ */ new Set());
|
|
1558
|
+
}
|
|
1559
|
+
for (const row of db.lookup("wantedDispatchLikeEntry", 0, call)) {
|
|
1560
|
+
const held = String(row[3]);
|
|
1561
|
+
if (!byEntry.has(held) && matchesWrittenPart(db, String(row[1]), String(row[2]))) {
|
|
1562
|
+
byEntry.set(held, /* @__PURE__ */ new Set());
|
|
1563
|
+
}
|
|
1564
|
+
}
|
|
1565
|
+
for (const relation of ENTRY_FUNCTIONS) {
|
|
1566
|
+
for (const row of db.lookup(relation, 0, call)) {
|
|
1567
|
+
byEntry.get(String(row[1]))?.add(String(row[2]));
|
|
1568
|
+
}
|
|
1569
|
+
}
|
|
1570
|
+
const functions = [
|
|
1571
|
+
...new Set([...byEntry.values()].flatMap((found) => [...found]))
|
|
1572
|
+
];
|
|
1573
|
+
const unresolved = [...byEntry.values()].filter(
|
|
1574
|
+
(found) => found.size === 0
|
|
1575
|
+
).length;
|
|
1576
|
+
const through = /* @__PURE__ */ new Map();
|
|
1577
|
+
for (const row of db.lookup("wantedDispatchThrough", 0, call)) {
|
|
1578
|
+
const inner = through.get(String(row[1])) ?? [];
|
|
1579
|
+
inner.push(String(row[2]));
|
|
1580
|
+
through.set(String(row[1]), inner);
|
|
1581
|
+
}
|
|
1582
|
+
return {
|
|
1583
|
+
functions,
|
|
1584
|
+
certain: functions.length === 1 && unresolved === 0 && narrowedToOneName(db, sites) && column(db, "wantedDispatchComputed", call, 1).length === 0 && column(db, "wantedDispatchInBranch", call, 1).length === 0,
|
|
1585
|
+
unresolved,
|
|
1586
|
+
through,
|
|
1587
|
+
containers: [
|
|
1588
|
+
...new Set(
|
|
1589
|
+
sites.flatMap(
|
|
1590
|
+
(site) => ENTRY_READS.flatMap((relation) => column(db, relation, site, 1))
|
|
1591
|
+
)
|
|
1592
|
+
)
|
|
1593
|
+
]
|
|
1594
|
+
};
|
|
1595
|
+
}
|
|
1596
|
+
var ENTRY_READS = [
|
|
1597
|
+
"choosesEntry",
|
|
1598
|
+
"choosesNamedEntry",
|
|
1599
|
+
"choosesEntryLike",
|
|
1600
|
+
"readsEntry"
|
|
1601
|
+
];
|
|
1602
|
+
var ENTRY_FUNCTIONS = [
|
|
1603
|
+
"wantedDispatchFunction",
|
|
1604
|
+
"wantedDispatchLikeFunction"
|
|
1605
|
+
];
|
|
1606
|
+
function matchesWrittenPart(db, site, name) {
|
|
1607
|
+
return db.lookup("choosesEntryLike", 0, site).some((row) => {
|
|
1608
|
+
const prefix = String(row[2]);
|
|
1609
|
+
const suffix = String(row[3]);
|
|
1610
|
+
return name.length >= prefix.length + suffix.length && name.startsWith(prefix) && name.endsWith(suffix);
|
|
1611
|
+
});
|
|
1612
|
+
}
|
|
1613
|
+
function narrowedToOneName(db, sites) {
|
|
1614
|
+
const names = /* @__PURE__ */ new Set();
|
|
1615
|
+
for (const site of sites) {
|
|
1616
|
+
if (db.lookup("choosesEntry", 0, site).length > 0) {
|
|
1617
|
+
return false;
|
|
1618
|
+
}
|
|
1619
|
+
for (const relation of NAMED_READS) {
|
|
1620
|
+
for (const row of db.lookup(relation, 0, site)) {
|
|
1621
|
+
names.add(String(row[2]));
|
|
1622
|
+
}
|
|
1623
|
+
}
|
|
1624
|
+
}
|
|
1625
|
+
return names.size === 1;
|
|
1626
|
+
}
|
|
1627
|
+
var NAMED_READS = ["choosesNamedEntry", "readsEntry"];
|
|
1628
|
+
function column(db, relation, key, at) {
|
|
1629
|
+
return [
|
|
1630
|
+
...new Set(db.lookup(relation, 0, key).map((row) => String(row[at])))
|
|
1631
|
+
];
|
|
1632
|
+
}
|
|
1633
|
+
|
|
1360
1634
|
// src/entryReuse.ts
|
|
1361
1635
|
function fileOfKey(key) {
|
|
1362
1636
|
return key.slice(0, key.lastIndexOf(":"));
|
|
@@ -1494,11 +1768,11 @@ function exportTrail(proof, describe) {
|
|
|
1494
1768
|
}
|
|
1495
1769
|
function argumentReason(proof, describe) {
|
|
1496
1770
|
const [, p, a] = proof.tuple;
|
|
1497
|
-
|
|
1498
|
-
|
|
1499
|
-
|
|
1500
|
-
const
|
|
1501
|
-
return `${describe(p)} is a parameter
|
|
1771
|
+
const f = proof.kind === "derived" ? proof.premises.find(
|
|
1772
|
+
(premise) => premise.relation === "paramOf" || premise.relation === "paramNamed"
|
|
1773
|
+
)?.tuple[0] : void 0;
|
|
1774
|
+
const ofFunction = f === void 0 ? "" : ` of ${describe(f)}`;
|
|
1775
|
+
return `${describe(p)} is a parameter${ofFunction}, and a call passes it ${describe(a)}`;
|
|
1502
1776
|
}
|
|
1503
1777
|
function memberSaid(name) {
|
|
1504
1778
|
const member = classMemberOf(name);
|
|
@@ -1883,14 +2157,24 @@ function startsAtName(node, name, rules) {
|
|
|
1883
2157
|
|
|
1884
2158
|
// src/nodeKey.ts
|
|
1885
2159
|
var SPAN_KEY = /^(.*):(\d+)-(\d+)$/;
|
|
1886
|
-
function
|
|
2160
|
+
function spanFileOf(key) {
|
|
2161
|
+
return key.match(SPAN_KEY)?.[1] ?? null;
|
|
2162
|
+
}
|
|
2163
|
+
function spanOfKey(key) {
|
|
1887
2164
|
const span = key.match(SPAN_KEY);
|
|
2165
|
+
return span === null ? null : {
|
|
2166
|
+
file: span[1],
|
|
2167
|
+
start: Number(span[2]),
|
|
2168
|
+
end: Number(span[3])
|
|
2169
|
+
};
|
|
2170
|
+
}
|
|
2171
|
+
function nodeOfKey(rootsByFile, key) {
|
|
2172
|
+
const span = spanOfKey(key);
|
|
1888
2173
|
if (span === null) {
|
|
1889
2174
|
return null;
|
|
1890
2175
|
}
|
|
1891
|
-
const root = rootsByFile.get(span
|
|
1892
|
-
const start =
|
|
1893
|
-
const end = Number(span[3]);
|
|
2176
|
+
const root = rootsByFile.get(span.file);
|
|
2177
|
+
const { start, end } = span;
|
|
1894
2178
|
if (root === void 0 || end <= start) {
|
|
1895
2179
|
return null;
|
|
1896
2180
|
}
|
|
@@ -2263,12 +2547,27 @@ function hasRow(db, relation, key, member) {
|
|
|
2263
2547
|
|
|
2264
2548
|
// src/writtenValue.ts
|
|
2265
2549
|
var WRITTEN_AS = "wantedIsWrittenAs";
|
|
2266
|
-
function writtenValueOf(db, key, ask, relation = WRITTEN_AS) {
|
|
2267
|
-
const
|
|
2550
|
+
function writtenValueOf(db, key, ask, relation = WRITTEN_AS, keep = () => true) {
|
|
2551
|
+
const settled = settledByKey(db, [key], ask, relation).get(key) ?? [];
|
|
2552
|
+
const answers = settled.filter(keep);
|
|
2268
2553
|
if (answers.length === 1) {
|
|
2269
2554
|
return answers[0];
|
|
2270
2555
|
}
|
|
2271
|
-
|
|
2556
|
+
if (answers.length === 0 && settled.length > 0) {
|
|
2557
|
+
return null;
|
|
2558
|
+
}
|
|
2559
|
+
const fallback = relation === WRITTEN_AS ? fallbackWrittenAs(db, key, ask) : null;
|
|
2560
|
+
return fallback !== null && keep(fallback) ? fallback : null;
|
|
2561
|
+
}
|
|
2562
|
+
function answersFromTestsLeftOut(key, isTestFile) {
|
|
2563
|
+
const asked = spanFileOf(key);
|
|
2564
|
+
if (asked === null || isTestFile(asked)) {
|
|
2565
|
+
return () => true;
|
|
2566
|
+
}
|
|
2567
|
+
return (answer) => {
|
|
2568
|
+
const file = spanFileOf(answer);
|
|
2569
|
+
return file === null || !isTestFile(file);
|
|
2570
|
+
};
|
|
2272
2571
|
}
|
|
2273
2572
|
var FALLBACK_BEHIND = "wantedFallbackBehind";
|
|
2274
2573
|
function fallbackWrittenAs(db, key, ask) {
|
|
@@ -2446,6 +2745,165 @@ var STEP_LATTICE = [
|
|
|
2446
2745
|
{ soFar: RESULT_STEP, next: INSTANCE_STEP, took: RESULT_STEP },
|
|
2447
2746
|
{ soFar: RESULT_STEP, next: RESULT_STEP, took: RESULT_STEP }
|
|
2448
2747
|
];
|
|
2748
|
+
var DISPATCH_RULES = [
|
|
2749
|
+
(0, import_datalog5.rule)(
|
|
2750
|
+
"entryRead",
|
|
2751
|
+
[(0, import_datalog5.variable)("site"), (0, import_datalog5.variable)("o")],
|
|
2752
|
+
[(0, import_datalog5.lit)("choosesEntry", (0, import_datalog5.variable)("site"), (0, import_datalog5.variable)("o"))]
|
|
2753
|
+
),
|
|
2754
|
+
(0, import_datalog5.rule)(
|
|
2755
|
+
"entryRead",
|
|
2756
|
+
[(0, import_datalog5.variable)("site"), (0, import_datalog5.variable)("o")],
|
|
2757
|
+
[(0, import_datalog5.lit)("namedEntryRead", (0, import_datalog5.variable)("site"), (0, import_datalog5.variable)("o"), (0, import_datalog5.variable)("n"))]
|
|
2758
|
+
),
|
|
2759
|
+
(0, import_datalog5.rule)(
|
|
2760
|
+
"entryRead",
|
|
2761
|
+
[(0, import_datalog5.variable)("site"), (0, import_datalog5.variable)("o")],
|
|
2762
|
+
[(0, import_datalog5.lit)("choosesEntryLike", (0, import_datalog5.variable)("site"), (0, import_datalog5.variable)("o"), (0, import_datalog5.variable)("p"), (0, import_datalog5.variable)("s"))]
|
|
2763
|
+
),
|
|
2764
|
+
// Every entry of a read whose key is partly written out, by name. A rule
|
|
2765
|
+
// cannot compare strings, so dispatch.ts keeps the names that match, and
|
|
2766
|
+
// these stay out of `dispatchesTo`.
|
|
2767
|
+
(0, import_datalog5.rule)(
|
|
2768
|
+
"likeEntryAt",
|
|
2769
|
+
[(0, import_datalog5.variable)("site"), (0, import_datalog5.variable)("n"), (0, import_datalog5.variable)("held")],
|
|
2770
|
+
[
|
|
2771
|
+
(0, import_datalog5.lit)("choosesEntryLike", (0, import_datalog5.variable)("site"), (0, import_datalog5.variable)("o"), (0, import_datalog5.variable)("p"), (0, import_datalog5.variable)("s")),
|
|
2772
|
+
(0, import_datalog5.lit)("containerOf", (0, import_datalog5.variable)("o"), (0, import_datalog5.variable)("obj")),
|
|
2773
|
+
(0, import_datalog5.lit)("contains", (0, import_datalog5.variable)("obj"), (0, import_datalog5.variable)("n"), (0, import_datalog5.variable)("held"))
|
|
2774
|
+
]
|
|
2775
|
+
),
|
|
2776
|
+
(0, import_datalog5.rule)(
|
|
2777
|
+
"namedEntryRead",
|
|
2778
|
+
[(0, import_datalog5.variable)("site"), (0, import_datalog5.variable)("o"), (0, import_datalog5.variable)("n")],
|
|
2779
|
+
[(0, import_datalog5.lit)("choosesNamedEntry", (0, import_datalog5.variable)("site"), (0, import_datalog5.variable)("o"), (0, import_datalog5.variable)("n"))]
|
|
2780
|
+
),
|
|
2781
|
+
(0, import_datalog5.rule)(
|
|
2782
|
+
"namedEntryRead",
|
|
2783
|
+
[(0, import_datalog5.variable)("site"), (0, import_datalog5.variable)("o"), (0, import_datalog5.variable)("n")],
|
|
2784
|
+
[(0, import_datalog5.lit)("readsEntry", (0, import_datalog5.variable)("site"), (0, import_datalog5.variable)("o"), (0, import_datalog5.variable)("n"))]
|
|
2785
|
+
),
|
|
2786
|
+
// The container a read takes its entry from: an object written out, or
|
|
2787
|
+
// a collection the program fills through its methods.
|
|
2788
|
+
(0, import_datalog5.rule)("containerOf", [(0, import_datalog5.variable)("o"), (0, import_datalog5.variable)("obj")], [(0, import_datalog5.lit)("objectOf", (0, import_datalog5.variable)("o"), (0, import_datalog5.variable)("obj"))]),
|
|
2789
|
+
(0, import_datalog5.rule)(
|
|
2790
|
+
"containerOf",
|
|
2791
|
+
[(0, import_datalog5.variable)("o"), (0, import_datalog5.variable)("c")],
|
|
2792
|
+
[
|
|
2793
|
+
(0, import_datalog5.lit)("reaches", (0, import_datalog5.variable)("o"), (0, import_datalog5.variable)("c"), VALUE_STEP),
|
|
2794
|
+
(0, import_datalog5.lit)("collectionValue", (0, import_datalog5.variable)("c"))
|
|
2795
|
+
]
|
|
2796
|
+
),
|
|
2797
|
+
(0, import_datalog5.rule)("containerOf", [(0, import_datalog5.variable)("c"), (0, import_datalog5.variable)("c")], [(0, import_datalog5.lit)("collectionValue", (0, import_datalog5.variable)("c"))]),
|
|
2798
|
+
(0, import_datalog5.rule)(
|
|
2799
|
+
"entryAt",
|
|
2800
|
+
[(0, import_datalog5.variable)("site"), (0, import_datalog5.variable)("held")],
|
|
2801
|
+
[
|
|
2802
|
+
(0, import_datalog5.lit)("choosesEntry", (0, import_datalog5.variable)("site"), (0, import_datalog5.variable)("o")),
|
|
2803
|
+
(0, import_datalog5.lit)("containerOf", (0, import_datalog5.variable)("o"), (0, import_datalog5.variable)("obj")),
|
|
2804
|
+
(0, import_datalog5.lit)("contains", (0, import_datalog5.variable)("obj"), (0, import_datalog5.variable)("n"), (0, import_datalog5.variable)("held"))
|
|
2805
|
+
],
|
|
2806
|
+
"any entry"
|
|
2807
|
+
),
|
|
2808
|
+
(0, import_datalog5.rule)(
|
|
2809
|
+
"entryAt",
|
|
2810
|
+
[(0, import_datalog5.variable)("site"), (0, import_datalog5.variable)("held")],
|
|
2811
|
+
[
|
|
2812
|
+
(0, import_datalog5.lit)("namedEntryRead", (0, import_datalog5.variable)("site"), (0, import_datalog5.variable)("o"), (0, import_datalog5.variable)("n")),
|
|
2813
|
+
(0, import_datalog5.lit)("containerOf", (0, import_datalog5.variable)("o"), (0, import_datalog5.variable)("obj")),
|
|
2814
|
+
(0, import_datalog5.lit)("contains", (0, import_datalog5.variable)("obj"), (0, import_datalog5.variable)("n"), (0, import_datalog5.variable)("held"))
|
|
2815
|
+
],
|
|
2816
|
+
"named entry"
|
|
2817
|
+
),
|
|
2818
|
+
(0, import_datalog5.rule)(
|
|
2819
|
+
"entryAt",
|
|
2820
|
+
[(0, import_datalog5.variable)("site"), (0, import_datalog5.variable)("held")],
|
|
2821
|
+
[(0, import_datalog5.lit)("computedEntryAt", (0, import_datalog5.variable)("site"), (0, import_datalog5.variable)("held"))]
|
|
2822
|
+
),
|
|
2823
|
+
// A write under a key the source computes, `T[name] = fn` or a map's
|
|
2824
|
+
// `set`, could be under any name, so every read of the container may
|
|
2825
|
+
// come back with it, a read narrowed to one name included.
|
|
2826
|
+
(0, import_datalog5.rule)(
|
|
2827
|
+
"computedEntryAt",
|
|
2828
|
+
[(0, import_datalog5.variable)("site"), (0, import_datalog5.variable)("held")],
|
|
2829
|
+
[
|
|
2830
|
+
(0, import_datalog5.lit)("entryRead", (0, import_datalog5.variable)("site"), (0, import_datalog5.variable)("o")),
|
|
2831
|
+
(0, import_datalog5.lit)("containerOf", (0, import_datalog5.variable)("o"), (0, import_datalog5.variable)("c")),
|
|
2832
|
+
(0, import_datalog5.lit)("refersToObject", (0, import_datalog5.variable)("x"), (0, import_datalog5.variable)("c")),
|
|
2833
|
+
(0, import_datalog5.lit)("holdsUnderKey", (0, import_datalog5.variable)("x"), (0, import_datalog5.variable)("held"))
|
|
2834
|
+
],
|
|
2835
|
+
"entry under a computed key"
|
|
2836
|
+
),
|
|
2837
|
+
// The read a call takes its function from: the callee itself, a name
|
|
2838
|
+
// for it, or the call when the call is the read, as Ruby's `send` is.
|
|
2839
|
+
(0, import_datalog5.rule)(
|
|
2840
|
+
"callsEntryAt",
|
|
2841
|
+
[(0, import_datalog5.variable)("r"), (0, import_datalog5.variable)("site")],
|
|
2842
|
+
[(0, import_datalog5.lit)("call", (0, import_datalog5.variable)("r"), (0, import_datalog5.variable)("site")), (0, import_datalog5.lit)("entryRead", (0, import_datalog5.variable)("site"), (0, import_datalog5.variable)("o"))]
|
|
2843
|
+
),
|
|
2844
|
+
(0, import_datalog5.rule)(
|
|
2845
|
+
"callsEntryAt",
|
|
2846
|
+
[(0, import_datalog5.variable)("r"), (0, import_datalog5.variable)("site")],
|
|
2847
|
+
[
|
|
2848
|
+
(0, import_datalog5.lit)("call", (0, import_datalog5.variable)("r"), (0, import_datalog5.variable)("c")),
|
|
2849
|
+
(0, import_datalog5.lit)("reaches", (0, import_datalog5.variable)("c"), (0, import_datalog5.variable)("site"), VALUE_STEP),
|
|
2850
|
+
(0, import_datalog5.lit)("entryRead", (0, import_datalog5.variable)("site"), (0, import_datalog5.variable)("o"))
|
|
2851
|
+
]
|
|
2852
|
+
),
|
|
2853
|
+
(0, import_datalog5.rule)("callsEntryAt", [(0, import_datalog5.variable)("r"), (0, import_datalog5.variable)("r")], [(0, import_datalog5.lit)("callsChosenEntry", (0, import_datalog5.variable)("r"))]),
|
|
2854
|
+
(0, import_datalog5.rule)(
|
|
2855
|
+
"callsEntryAt",
|
|
2856
|
+
[(0, import_datalog5.variable)("r"), (0, import_datalog5.variable)("site")],
|
|
2857
|
+
[(0, import_datalog5.lit)("callsEntryInBranch", (0, import_datalog5.variable)("r"), (0, import_datalog5.variable)("site"))]
|
|
2858
|
+
),
|
|
2859
|
+
// `c ? T[k] : undefined` is one of its branches, so a call through it
|
|
2860
|
+
// may run what the read gives. The other branch may be some other
|
|
2861
|
+
// function, so dispatch.ts never counts such a call as certain.
|
|
2862
|
+
(0, import_datalog5.rule)(
|
|
2863
|
+
"callsEntryInBranch",
|
|
2864
|
+
[(0, import_datalog5.variable)("r"), (0, import_datalog5.variable)("site")],
|
|
2865
|
+
[(0, import_datalog5.lit)("call", (0, import_datalog5.variable)("r"), (0, import_datalog5.variable)("c")), (0, import_datalog5.lit)("branchReadsEntry", (0, import_datalog5.variable)("c"), (0, import_datalog5.variable)("site"))]
|
|
2866
|
+
),
|
|
2867
|
+
(0, import_datalog5.rule)(
|
|
2868
|
+
"callsEntryInBranch",
|
|
2869
|
+
[(0, import_datalog5.variable)("r"), (0, import_datalog5.variable)("site")],
|
|
2870
|
+
[
|
|
2871
|
+
(0, import_datalog5.lit)("call", (0, import_datalog5.variable)("r"), (0, import_datalog5.variable)("c")),
|
|
2872
|
+
(0, import_datalog5.lit)("reaches", (0, import_datalog5.variable)("c"), (0, import_datalog5.variable)("x"), VALUE_STEP),
|
|
2873
|
+
(0, import_datalog5.lit)("branchReadsEntry", (0, import_datalog5.variable)("x"), (0, import_datalog5.variable)("site"))
|
|
2874
|
+
]
|
|
2875
|
+
),
|
|
2876
|
+
(0, import_datalog5.rule)(
|
|
2877
|
+
"branchReadsEntry",
|
|
2878
|
+
[(0, import_datalog5.variable)("x"), (0, import_datalog5.variable)("site")],
|
|
2879
|
+
[
|
|
2880
|
+
(0, import_datalog5.lit)("conditionalBranch", (0, import_datalog5.variable)("x"), (0, import_datalog5.variable)("site")),
|
|
2881
|
+
(0, import_datalog5.lit)("entryRead", (0, import_datalog5.variable)("site"), (0, import_datalog5.variable)("o"))
|
|
2882
|
+
]
|
|
2883
|
+
),
|
|
2884
|
+
(0, import_datalog5.rule)(
|
|
2885
|
+
"branchReadsEntry",
|
|
2886
|
+
[(0, import_datalog5.variable)("x"), (0, import_datalog5.variable)("site")],
|
|
2887
|
+
[
|
|
2888
|
+
(0, import_datalog5.lit)("conditionalBranch", (0, import_datalog5.variable)("x"), (0, import_datalog5.variable)("b")),
|
|
2889
|
+
(0, import_datalog5.lit)("reaches", (0, import_datalog5.variable)("b"), (0, import_datalog5.variable)("site"), VALUE_STEP),
|
|
2890
|
+
(0, import_datalog5.lit)("entryRead", (0, import_datalog5.variable)("site"), (0, import_datalog5.variable)("o"))
|
|
2891
|
+
]
|
|
2892
|
+
),
|
|
2893
|
+
(0, import_datalog5.rule)(
|
|
2894
|
+
"dispatchesTo",
|
|
2895
|
+
[(0, import_datalog5.variable)("r"), (0, import_datalog5.variable)("f")],
|
|
2896
|
+
[
|
|
2897
|
+
(0, import_datalog5.lit)("callsEntryAt", (0, import_datalog5.variable)("r"), (0, import_datalog5.variable)("site")),
|
|
2898
|
+
(0, import_datalog5.lit)("entryAt", (0, import_datalog5.variable)("site"), (0, import_datalog5.variable)("held")),
|
|
2899
|
+
(0, import_datalog5.lit)("comesTo", (0, import_datalog5.variable)("held"), (0, import_datalog5.variable)("f")),
|
|
2900
|
+
(0, import_datalog5.lit)("func", (0, import_datalog5.variable)("f"))
|
|
2901
|
+
]
|
|
2902
|
+
),
|
|
2903
|
+
// A collection a program fills is an object the way a written one is,
|
|
2904
|
+
// so a write through a name for it lands on it.
|
|
2905
|
+
(0, import_datalog5.rule)("refersToObject", [(0, import_datalog5.variable)("c"), (0, import_datalog5.variable)("c")], [(0, import_datalog5.lit)("collectionValue", (0, import_datalog5.variable)("c"))])
|
|
2906
|
+
];
|
|
2449
2907
|
var STATED_RULES = [
|
|
2450
2908
|
// Aliasing: const x = y, or an identifier referencing a declaration.
|
|
2451
2909
|
// Every chain that follows a name takes the name hops, so a hop added
|
|
@@ -2948,19 +3406,29 @@ var STATED_RULES = [
|
|
|
2948
3406
|
],
|
|
2949
3407
|
"construction enters its constructor"
|
|
2950
3408
|
),
|
|
3409
|
+
// When methodCallUnder and objectOfUnder bind as many columns, as they do
|
|
3410
|
+
// once contains has run, the rewrite joins the one written first. This
|
|
3411
|
+
// order reads the receiver under the call's own sites, not every site.
|
|
2951
3412
|
(0, import_datalog5.rule)(
|
|
2952
3413
|
"entersUnder",
|
|
2953
3414
|
[(0, import_datalog5.variable)("r"), (0, import_datalog5.variable)("f"), (0, import_datalog5.variable)("site"), (0, import_datalog5.variable)("caller")],
|
|
2954
3415
|
[
|
|
2955
|
-
(0, import_datalog5.lit)("
|
|
2956
|
-
(0, import_datalog5.lit)("readsProperty", (0, import_datalog5.variable)("cal"), (0, import_datalog5.variable)("o"), (0, import_datalog5.variable)("m")),
|
|
3416
|
+
(0, import_datalog5.lit)("methodCallUnder", (0, import_datalog5.variable)("r"), (0, import_datalog5.variable)("o"), (0, import_datalog5.variable)("m"), (0, import_datalog5.variable)("caller")),
|
|
2957
3417
|
(0, import_datalog5.lit)("objectOfUnder", (0, import_datalog5.variable)("o"), (0, import_datalog5.variable)("caller"), (0, import_datalog5.variable)("site")),
|
|
2958
3418
|
(0, import_datalog5.lit)("allocates", (0, import_datalog5.variable)("site"), (0, import_datalog5.variable)("cls")),
|
|
2959
|
-
(0, import_datalog5.lit)("contains", (0, import_datalog5.variable)("site"), (0, import_datalog5.variable)("m"), (0, import_datalog5.variable)("f"))
|
|
2960
|
-
(0, import_datalog5.lit)("callUnder", (0, import_datalog5.variable)("r"), (0, import_datalog5.variable)("caller"))
|
|
3419
|
+
(0, import_datalog5.lit)("contains", (0, import_datalog5.variable)("site"), (0, import_datalog5.variable)("m"), (0, import_datalog5.variable)("f"))
|
|
2961
3420
|
],
|
|
2962
3421
|
"method call enters under its receiver"
|
|
2963
3422
|
),
|
|
3423
|
+
(0, import_datalog5.rule)(
|
|
3424
|
+
"methodCallUnder",
|
|
3425
|
+
[(0, import_datalog5.variable)("r"), (0, import_datalog5.variable)("o"), (0, import_datalog5.variable)("m"), (0, import_datalog5.variable)("caller")],
|
|
3426
|
+
[
|
|
3427
|
+
(0, import_datalog5.lit)("call", (0, import_datalog5.variable)("r"), (0, import_datalog5.variable)("cal")),
|
|
3428
|
+
(0, import_datalog5.lit)("readsProperty", (0, import_datalog5.variable)("cal"), (0, import_datalog5.variable)("o"), (0, import_datalog5.variable)("m")),
|
|
3429
|
+
(0, import_datalog5.lit)("callUnder", (0, import_datalog5.variable)("r"), (0, import_datalog5.variable)("caller"))
|
|
3430
|
+
]
|
|
3431
|
+
),
|
|
2964
3432
|
// A call written as a name runs with whatever receiver the body
|
|
2965
3433
|
// around it has, so a plain function called from a method keeps the
|
|
2966
3434
|
// site rather than taking every caller of it.
|
|
@@ -3248,13 +3716,15 @@ var STATED_RULES = [
|
|
|
3248
3716
|
),
|
|
3249
3717
|
// An argument arriving at the parameter it is passed to, by position
|
|
3250
3718
|
// or by the name the caller wrote, keeping the call it went through
|
|
3251
|
-
// so a caller can tell two call sites apart.
|
|
3719
|
+
// so a caller can tell two call sites apart. The callee comes before the
|
|
3720
|
+
// parameter, so a walk that starts from the argument asks which function
|
|
3721
|
+
// its call runs instead of trying every function with a parameter there.
|
|
3252
3722
|
(0, import_datalog5.rule)(
|
|
3253
3723
|
"passesArgument",
|
|
3254
3724
|
[(0, import_datalog5.variable)("r"), (0, import_datalog5.variable)("p"), (0, import_datalog5.variable)("a")],
|
|
3255
3725
|
[
|
|
3256
|
-
(0, import_datalog5.lit)("paramOf", (0, import_datalog5.variable)("f"), (0, import_datalog5.variable)("k"), (0, import_datalog5.variable)("p")),
|
|
3257
3726
|
(0, import_datalog5.lit)("callsFunction", (0, import_datalog5.variable)("r"), (0, import_datalog5.variable)("f")),
|
|
3727
|
+
(0, import_datalog5.lit)("paramOf", (0, import_datalog5.variable)("f"), (0, import_datalog5.variable)("k"), (0, import_datalog5.variable)("p")),
|
|
3258
3728
|
(0, import_datalog5.lit)("callArg", (0, import_datalog5.variable)("r"), (0, import_datalog5.variable)("k"), (0, import_datalog5.variable)("a"))
|
|
3259
3729
|
]
|
|
3260
3730
|
),
|
|
@@ -3262,8 +3732,8 @@ var STATED_RULES = [
|
|
|
3262
3732
|
"passesArgument",
|
|
3263
3733
|
[(0, import_datalog5.variable)("r"), (0, import_datalog5.variable)("p"), (0, import_datalog5.variable)("a")],
|
|
3264
3734
|
[
|
|
3265
|
-
(0, import_datalog5.lit)("paramNamed", (0, import_datalog5.variable)("f"), (0, import_datalog5.variable)("n"), (0, import_datalog5.variable)("p")),
|
|
3266
3735
|
(0, import_datalog5.lit)("callsFunction", (0, import_datalog5.variable)("r"), (0, import_datalog5.variable)("f")),
|
|
3736
|
+
(0, import_datalog5.lit)("paramNamed", (0, import_datalog5.variable)("f"), (0, import_datalog5.variable)("n"), (0, import_datalog5.variable)("p")),
|
|
3267
3737
|
(0, import_datalog5.lit)("callKeywordArg", (0, import_datalog5.variable)("r"), (0, import_datalog5.variable)("n"), (0, import_datalog5.variable)("a"))
|
|
3268
3738
|
]
|
|
3269
3739
|
),
|
|
@@ -3536,6 +4006,17 @@ var STATED_RULES = [
|
|
|
3536
4006
|
(0, import_datalog5.lit)("callsNamed", (0, import_datalog5.variable)("r"), (0, import_datalog5.variable)("r0"))
|
|
3537
4007
|
]
|
|
3538
4008
|
),
|
|
4009
|
+
// The same, called straight off the factory's call, as
|
|
4010
|
+
// `register("created")(handler)` or a Python decorator written that way.
|
|
4011
|
+
(0, import_datalog5.rule)(
|
|
4012
|
+
"callsFunction",
|
|
4013
|
+
[(0, import_datalog5.variable)("r"), (0, import_datalog5.variable)("f")],
|
|
4014
|
+
[
|
|
4015
|
+
(0, import_datalog5.lit)("returnsValue", (0, import_datalog5.variable)("g"), (0, import_datalog5.variable)("f")),
|
|
4016
|
+
(0, import_datalog5.lit)("callsFunction", (0, import_datalog5.variable)("r0"), (0, import_datalog5.variable)("g")),
|
|
4017
|
+
(0, import_datalog5.lit)("call", (0, import_datalog5.variable)("r"), (0, import_datalog5.variable)("r0"))
|
|
4018
|
+
]
|
|
4019
|
+
),
|
|
3539
4020
|
// The expressions that refer to an object under another name, through
|
|
3540
4021
|
// a name hop or an import. Asked from the object, so it visits only
|
|
3541
4022
|
// them.
|
|
@@ -3981,6 +4462,7 @@ var STATED_RULES = [
|
|
|
3981
4462
|
[(0, import_datalog5.variable)("x"), (0, import_datalog5.variable)("z")],
|
|
3982
4463
|
[(0, import_datalog5.lit)("comesTo", (0, import_datalog5.variable)("x"), (0, import_datalog5.variable)("z")), (0, import_datalog5.lit)("func", (0, import_datalog5.variable)("z"))]
|
|
3983
4464
|
),
|
|
4465
|
+
...DISPATCH_RULES,
|
|
3984
4466
|
...PASSED_ON_RULES
|
|
3985
4467
|
];
|
|
3986
4468
|
function alsoSteps(rules) {
|
|
@@ -4184,18 +4666,112 @@ var RESOLUTION_QUESTIONS = [
|
|
|
4184
4666
|
),
|
|
4185
4667
|
// The functions whose return becomes the exit code: a call the value
|
|
4186
4668
|
// that ends up as the code is, or one it reaches. DESIGN.md has the seeds.
|
|
4669
|
+
(0, import_datalog5.rule)("exitStart", [(0, import_datalog5.variable)("x"), (0, import_datalog5.variable)("x")], [(0, import_datalog5.lit)("wantedExitSink", (0, import_datalog5.variable)("x"))]),
|
|
4670
|
+
// `reaches` takes no step through a call that picks its function from a
|
|
4671
|
+
// table, so the walk starts again from what each function there returns.
|
|
4672
|
+
(0, import_datalog5.rule)(
|
|
4673
|
+
"exitStart",
|
|
4674
|
+
[(0, import_datalog5.variable)("x"), (0, import_datalog5.variable)("ret")],
|
|
4675
|
+
[
|
|
4676
|
+
(0, import_datalog5.lit)("exitReached", (0, import_datalog5.variable)("x"), (0, import_datalog5.variable)("y")),
|
|
4677
|
+
(0, import_datalog5.lit)("dispatchesTo", (0, import_datalog5.variable)("y"), (0, import_datalog5.variable)("f")),
|
|
4678
|
+
(0, import_datalog5.lit)("returnsValue", (0, import_datalog5.variable)("f"), (0, import_datalog5.variable)("ret"))
|
|
4679
|
+
]
|
|
4680
|
+
),
|
|
4681
|
+
(0, import_datalog5.rule)("exitReached", [(0, import_datalog5.variable)("x"), (0, import_datalog5.variable)("s")], [(0, import_datalog5.lit)("exitStart", (0, import_datalog5.variable)("x"), (0, import_datalog5.variable)("s"))]),
|
|
4682
|
+
(0, import_datalog5.rule)(
|
|
4683
|
+
"exitReached",
|
|
4684
|
+
[(0, import_datalog5.variable)("x"), (0, import_datalog5.variable)("y")],
|
|
4685
|
+
[
|
|
4686
|
+
(0, import_datalog5.lit)("exitStart", (0, import_datalog5.variable)("x"), (0, import_datalog5.variable)("s")),
|
|
4687
|
+
(0, import_datalog5.lit)("reaches", (0, import_datalog5.variable)("s"), (0, import_datalog5.variable)("y"), (0, import_datalog5.variable)("kind"))
|
|
4688
|
+
]
|
|
4689
|
+
),
|
|
4187
4690
|
(0, import_datalog5.rule)(
|
|
4188
4691
|
"wantedExitCodeFrom",
|
|
4189
4692
|
[(0, import_datalog5.variable)("x"), (0, import_datalog5.variable)("f")],
|
|
4190
|
-
[(0, import_datalog5.lit)("
|
|
4693
|
+
[(0, import_datalog5.lit)("exitReached", (0, import_datalog5.variable)("x"), (0, import_datalog5.variable)("y")), (0, import_datalog5.lit)("invokes", (0, import_datalog5.variable)("y"), (0, import_datalog5.variable)("f"))]
|
|
4191
4694
|
),
|
|
4192
4695
|
(0, import_datalog5.rule)(
|
|
4193
4696
|
"wantedExitCodeFrom",
|
|
4194
4697
|
[(0, import_datalog5.variable)("x"), (0, import_datalog5.variable)("f")],
|
|
4698
|
+
[(0, import_datalog5.lit)("exitReached", (0, import_datalog5.variable)("x"), (0, import_datalog5.variable)("y")), (0, import_datalog5.lit)("dispatchesTo", (0, import_datalog5.variable)("y"), (0, import_datalog5.variable)("f"))]
|
|
4699
|
+
),
|
|
4700
|
+
// The functions a call may run when it takes one from a table, with the
|
|
4701
|
+
// entry each came from, and the entries that come to no function. The
|
|
4702
|
+
// reader in dispatch.ts decides whether the call runs exactly one.
|
|
4703
|
+
(0, import_datalog5.rule)(
|
|
4704
|
+
"wantedDispatchSite",
|
|
4705
|
+
[(0, import_datalog5.variable)("r"), (0, import_datalog5.variable)("site")],
|
|
4706
|
+
[(0, import_datalog5.lit)("wantedDispatch", (0, import_datalog5.variable)("r")), (0, import_datalog5.lit)("callsEntryAt", (0, import_datalog5.variable)("r"), (0, import_datalog5.variable)("site"))]
|
|
4707
|
+
),
|
|
4708
|
+
(0, import_datalog5.rule)(
|
|
4709
|
+
"wantedDispatchEntry",
|
|
4710
|
+
[(0, import_datalog5.variable)("r"), (0, import_datalog5.variable)("held")],
|
|
4711
|
+
[
|
|
4712
|
+
(0, import_datalog5.lit)("wantedDispatch", (0, import_datalog5.variable)("r")),
|
|
4713
|
+
(0, import_datalog5.lit)("callsEntryAt", (0, import_datalog5.variable)("r"), (0, import_datalog5.variable)("site")),
|
|
4714
|
+
(0, import_datalog5.lit)("entryAt", (0, import_datalog5.variable)("site"), (0, import_datalog5.variable)("held"))
|
|
4715
|
+
]
|
|
4716
|
+
),
|
|
4717
|
+
(0, import_datalog5.rule)(
|
|
4718
|
+
"wantedDispatchInBranch",
|
|
4719
|
+
[(0, import_datalog5.variable)("r"), (0, import_datalog5.variable)("site")],
|
|
4720
|
+
[
|
|
4721
|
+
(0, import_datalog5.lit)("wantedDispatch", (0, import_datalog5.variable)("r")),
|
|
4722
|
+
(0, import_datalog5.lit)("callsEntryInBranch", (0, import_datalog5.variable)("r"), (0, import_datalog5.variable)("site"))
|
|
4723
|
+
]
|
|
4724
|
+
),
|
|
4725
|
+
(0, import_datalog5.rule)(
|
|
4726
|
+
"wantedDispatchComputed",
|
|
4727
|
+
[(0, import_datalog5.variable)("r"), (0, import_datalog5.variable)("held")],
|
|
4728
|
+
[
|
|
4729
|
+
(0, import_datalog5.lit)("wantedDispatch", (0, import_datalog5.variable)("r")),
|
|
4730
|
+
(0, import_datalog5.lit)("callsEntryAt", (0, import_datalog5.variable)("r"), (0, import_datalog5.variable)("site")),
|
|
4731
|
+
(0, import_datalog5.lit)("computedEntryAt", (0, import_datalog5.variable)("site"), (0, import_datalog5.variable)("held"))
|
|
4732
|
+
]
|
|
4733
|
+
),
|
|
4734
|
+
(0, import_datalog5.rule)(
|
|
4735
|
+
"wantedDispatchFunction",
|
|
4736
|
+
[(0, import_datalog5.variable)("r"), (0, import_datalog5.variable)("held"), (0, import_datalog5.variable)("f")],
|
|
4737
|
+
[
|
|
4738
|
+
(0, import_datalog5.lit)("wantedDispatch", (0, import_datalog5.variable)("r")),
|
|
4739
|
+
(0, import_datalog5.lit)("callsEntryAt", (0, import_datalog5.variable)("r"), (0, import_datalog5.variable)("site")),
|
|
4740
|
+
(0, import_datalog5.lit)("entryAt", (0, import_datalog5.variable)("site"), (0, import_datalog5.variable)("held")),
|
|
4741
|
+
(0, import_datalog5.lit)("comesTo", (0, import_datalog5.variable)("held"), (0, import_datalog5.variable)("f")),
|
|
4742
|
+
(0, import_datalog5.lit)("func", (0, import_datalog5.variable)("f"))
|
|
4743
|
+
]
|
|
4744
|
+
),
|
|
4745
|
+
(0, import_datalog5.rule)(
|
|
4746
|
+
"wantedDispatchLikeEntry",
|
|
4747
|
+
[(0, import_datalog5.variable)("r"), (0, import_datalog5.variable)("site"), (0, import_datalog5.variable)("n"), (0, import_datalog5.variable)("held")],
|
|
4748
|
+
[
|
|
4749
|
+
(0, import_datalog5.lit)("wantedDispatch", (0, import_datalog5.variable)("r")),
|
|
4750
|
+
(0, import_datalog5.lit)("callsEntryAt", (0, import_datalog5.variable)("r"), (0, import_datalog5.variable)("site")),
|
|
4751
|
+
(0, import_datalog5.lit)("likeEntryAt", (0, import_datalog5.variable)("site"), (0, import_datalog5.variable)("n"), (0, import_datalog5.variable)("held"))
|
|
4752
|
+
]
|
|
4753
|
+
),
|
|
4754
|
+
(0, import_datalog5.rule)(
|
|
4755
|
+
"wantedDispatchLikeFunction",
|
|
4756
|
+
[(0, import_datalog5.variable)("r"), (0, import_datalog5.variable)("held"), (0, import_datalog5.variable)("f")],
|
|
4757
|
+
[
|
|
4758
|
+
(0, import_datalog5.lit)("wantedDispatch", (0, import_datalog5.variable)("r")),
|
|
4759
|
+
(0, import_datalog5.lit)("callsEntryAt", (0, import_datalog5.variable)("r"), (0, import_datalog5.variable)("site")),
|
|
4760
|
+
(0, import_datalog5.lit)("likeEntryAt", (0, import_datalog5.variable)("site"), (0, import_datalog5.variable)("n"), (0, import_datalog5.variable)("held")),
|
|
4761
|
+
(0, import_datalog5.lit)("comesTo", (0, import_datalog5.variable)("held"), (0, import_datalog5.variable)("f")),
|
|
4762
|
+
(0, import_datalog5.lit)("func", (0, import_datalog5.variable)("f"))
|
|
4763
|
+
]
|
|
4764
|
+
),
|
|
4765
|
+
// What a function there calls in its own body, for an entry written as
|
|
4766
|
+
// a lambda, which no summary describes.
|
|
4767
|
+
(0, import_datalog5.rule)(
|
|
4768
|
+
"wantedDispatchThrough",
|
|
4769
|
+
[(0, import_datalog5.variable)("r"), (0, import_datalog5.variable)("f"), (0, import_datalog5.variable)("g")],
|
|
4195
4770
|
[
|
|
4196
|
-
(0, import_datalog5.lit)("
|
|
4197
|
-
(0, import_datalog5.lit)("
|
|
4198
|
-
(0, import_datalog5.lit)("
|
|
4771
|
+
(0, import_datalog5.lit)("wantedDispatch", (0, import_datalog5.variable)("r")),
|
|
4772
|
+
(0, import_datalog5.lit)("dispatchesTo", (0, import_datalog5.variable)("r"), (0, import_datalog5.variable)("f")),
|
|
4773
|
+
(0, import_datalog5.lit)("makesCall", (0, import_datalog5.variable)("f"), (0, import_datalog5.variable)("r2")),
|
|
4774
|
+
(0, import_datalog5.lit)("invokes", (0, import_datalog5.variable)("r2"), (0, import_datalog5.variable)("g"))
|
|
4199
4775
|
]
|
|
4200
4776
|
),
|
|
4201
4777
|
// The calls that hand a stream on, so the asker can read the callee's file.
|
|
@@ -4630,6 +5206,7 @@ var UNDER_ANSWER_RELATIONS = [
|
|
|
4630
5206
|
ASKING_RELATIONS,
|
|
4631
5207
|
BASE_CLASS_RULE,
|
|
4632
5208
|
DEFAULT_IMPORT_NAME,
|
|
5209
|
+
DISPATCH_QUESTION,
|
|
4633
5210
|
DependencyLedger,
|
|
4634
5211
|
EntryReuse,
|
|
4635
5212
|
FACT_CONTRACT_CASES,
|
|
@@ -4647,18 +5224,23 @@ var UNDER_ANSWER_RELATIONS = [
|
|
|
4647
5224
|
RESOLUTION_QUESTIONS,
|
|
4648
5225
|
RESOLUTION_RULES,
|
|
4649
5226
|
RESULT_STEP,
|
|
5227
|
+
SPREAD_ENTRY,
|
|
4650
5228
|
UNDER_ANSWER_RELATIONS,
|
|
4651
5229
|
UNDER_QUESTION_ROW_BUDGET,
|
|
4652
5230
|
UNDER_RUN_ROW_BUDGET,
|
|
4653
5231
|
UNPLACED_STORE_NAME,
|
|
4654
5232
|
USES_QUESTION,
|
|
5233
|
+
VALUE_ENTRY,
|
|
4655
5234
|
VALUE_STEP,
|
|
4656
5235
|
WatchedMap,
|
|
5236
|
+
addEntryRows,
|
|
4657
5237
|
addPackWords,
|
|
5238
|
+
addTemplateRows,
|
|
4658
5239
|
agreedMountPrefix,
|
|
4659
5240
|
allocationSitesOf,
|
|
4660
5241
|
alsoSteps,
|
|
4661
5242
|
answersFor,
|
|
5243
|
+
answersFromTestsLeftOut,
|
|
4662
5244
|
askResolution,
|
|
4663
5245
|
askResolutionUnder,
|
|
4664
5246
|
askSources,
|
|
@@ -4670,6 +5252,7 @@ var UNDER_ANSWER_RELATIONS = [
|
|
|
4670
5252
|
comesToUnder,
|
|
4671
5253
|
couldBeSettled,
|
|
4672
5254
|
declaredTypesOf,
|
|
5255
|
+
dispatchOutcomes,
|
|
4673
5256
|
exitCodeFunctions,
|
|
4674
5257
|
explainResolutionProof,
|
|
4675
5258
|
explainResolvedKey,
|
|
@@ -4691,6 +5274,7 @@ var UNDER_ANSWER_RELATIONS = [
|
|
|
4691
5274
|
packHashes,
|
|
4692
5275
|
proofRules,
|
|
4693
5276
|
queryFacts,
|
|
5277
|
+
readDispatchOutcomes,
|
|
4694
5278
|
readUses,
|
|
4695
5279
|
recordsToReplay,
|
|
4696
5280
|
renderExplanation,
|
|
@@ -4699,6 +5283,7 @@ var UNDER_ANSWER_RELATIONS = [
|
|
|
4699
5283
|
resolvedFunctions,
|
|
4700
5284
|
settledFunction,
|
|
4701
5285
|
sourceLeavesOf,
|
|
5286
|
+
spanOfKey,
|
|
4702
5287
|
startsAtName,
|
|
4703
5288
|
staysInItsFunction,
|
|
4704
5289
|
stillValid,
|