@suss/resolution 0.30.0 → 0.31.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +997 -70
- package/dist/index.d.cts +216 -21
- package/dist/index.d.ts +216 -21
- package/dist/index.js +985 -70
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -1,7 +1,18 @@
|
|
|
1
1
|
// src/program.ts
|
|
2
|
-
import {
|
|
2
|
+
import {
|
|
3
|
+
BudgetExhausted,
|
|
4
|
+
chargeAbandoned,
|
|
5
|
+
chargeQuestion,
|
|
6
|
+
clearRelations,
|
|
7
|
+
deriveOnDemand,
|
|
8
|
+
evaluate,
|
|
9
|
+
rowBudget,
|
|
10
|
+
tupleKey
|
|
11
|
+
} from "@suss/datalog";
|
|
3
12
|
var ASKING_RELATIONS = [
|
|
4
13
|
"wanted",
|
|
14
|
+
"wantedUnder",
|
|
15
|
+
"wantedSites",
|
|
5
16
|
"wantedOrigin",
|
|
6
17
|
"wantedCallOrigin",
|
|
7
18
|
"wantedExportsOf",
|
|
@@ -11,8 +22,12 @@ var ASKING_RELATIONS = [
|
|
|
11
22
|
];
|
|
12
23
|
var NO_LANGUAGE_RULES = [];
|
|
13
24
|
var programs = /* @__PURE__ */ new WeakMap();
|
|
14
|
-
|
|
15
|
-
|
|
25
|
+
var underPrograms = /* @__PURE__ */ new WeakMap();
|
|
26
|
+
var contextFreeAnswers = () => ANSWER_RELATIONS.filter(
|
|
27
|
+
(relation) => !UNDER_ANSWER_RELATIONS.includes(relation)
|
|
28
|
+
);
|
|
29
|
+
function builtProgram(languageRules, cache, complete) {
|
|
30
|
+
const built = cache.get(languageRules);
|
|
16
31
|
if (built !== void 0) {
|
|
17
32
|
return built;
|
|
18
33
|
}
|
|
@@ -21,10 +36,16 @@ function resolutionProgram(languageRules = NO_LANGUAGE_RULES) {
|
|
|
21
36
|
...languageRules,
|
|
22
37
|
...RESOLUTION_QUESTIONS
|
|
23
38
|
];
|
|
24
|
-
const program = process.env.SUSS_RESOLUTION_ON_DEMAND === "0" ? { rules, demandDriven: [], demands: [] } : deriveOnDemand(rules,
|
|
25
|
-
|
|
39
|
+
const program = process.env.SUSS_RESOLUTION_ON_DEMAND === "0" ? { rules, demandDriven: [], demands: [] } : deriveOnDemand(rules, complete);
|
|
40
|
+
cache.set(languageRules, program);
|
|
26
41
|
return program;
|
|
27
42
|
}
|
|
43
|
+
function resolutionProgram(languageRules = NO_LANGUAGE_RULES) {
|
|
44
|
+
return builtProgram(languageRules, programs, contextFreeAnswers());
|
|
45
|
+
}
|
|
46
|
+
function resolutionUnderProgram(languageRules = NO_LANGUAGE_RULES) {
|
|
47
|
+
return builtProgram(languageRules, underPrograms, ANSWER_RELATIONS);
|
|
48
|
+
}
|
|
28
49
|
function queryFacts(program) {
|
|
29
50
|
if (program.demandDriven.length === 0) {
|
|
30
51
|
return [];
|
|
@@ -61,6 +82,75 @@ function askResolution(db, keys, asking = "wanted", program = resolutionProgram(
|
|
|
61
82
|
clearRelations(db, program.rules, forget);
|
|
62
83
|
}
|
|
63
84
|
}
|
|
85
|
+
var askedUnderByDb = /* @__PURE__ */ new WeakMap();
|
|
86
|
+
var UNDER_QUESTION_ROW_BUDGET = 2e7;
|
|
87
|
+
var UNDER_RUN_ROW_BUDGET = 4e7;
|
|
88
|
+
var spentUnderByDb = /* @__PURE__ */ new WeakMap();
|
|
89
|
+
function spendOf(db) {
|
|
90
|
+
let spend = spentUnderByDb.get(db);
|
|
91
|
+
if (spend === void 0) {
|
|
92
|
+
spend = { rows: 0, asked: 0, abandoned: 0, skipped: 0 };
|
|
93
|
+
spentUnderByDb.set(db, spend);
|
|
94
|
+
}
|
|
95
|
+
return spend;
|
|
96
|
+
}
|
|
97
|
+
function underQuestionSpend(db) {
|
|
98
|
+
return { ...spendOf(db) };
|
|
99
|
+
}
|
|
100
|
+
function askResolutionUnder(db, pairs, program = resolutionUnderProgram(), questionBudget = UNDER_QUESTION_ROW_BUDGET, runBudget = UNDER_RUN_ROW_BUDGET) {
|
|
101
|
+
let asked = askedUnderByDb.get(db);
|
|
102
|
+
if (asked === void 0) {
|
|
103
|
+
asked = /* @__PURE__ */ new Set();
|
|
104
|
+
askedUnderByDb.set(db, asked);
|
|
105
|
+
}
|
|
106
|
+
const fresh = [...pairs].filter(
|
|
107
|
+
([key, site]) => !asked.has(tupleKey([key, site]))
|
|
108
|
+
);
|
|
109
|
+
if (fresh.length === 0) {
|
|
110
|
+
return "answered";
|
|
111
|
+
}
|
|
112
|
+
const spend = spendOf(db);
|
|
113
|
+
for (const [key, site] of fresh) {
|
|
114
|
+
asked.add(tupleKey([key, site]));
|
|
115
|
+
}
|
|
116
|
+
spend.asked += 1;
|
|
117
|
+
if (spend.rows >= runBudget) {
|
|
118
|
+
spend.skipped += 1;
|
|
119
|
+
chargeQuestion("skipped");
|
|
120
|
+
return "abandoned";
|
|
121
|
+
}
|
|
122
|
+
for (const [key, site] of fresh) {
|
|
123
|
+
db.add("wantedUnder", [key, site]);
|
|
124
|
+
}
|
|
125
|
+
const forget = queryFacts(program);
|
|
126
|
+
const clearDerived = () => {
|
|
127
|
+
if (forget.length > 0) {
|
|
128
|
+
clearRelations(db, program.rules, forget);
|
|
129
|
+
}
|
|
130
|
+
};
|
|
131
|
+
const budget = rowBudget(questionBudget);
|
|
132
|
+
try {
|
|
133
|
+
evaluate(db, program.rules, void 0, budget);
|
|
134
|
+
} catch (error) {
|
|
135
|
+
if (!(error instanceof BudgetExhausted)) {
|
|
136
|
+
throw error;
|
|
137
|
+
}
|
|
138
|
+
spend.rows += error.examined;
|
|
139
|
+
spend.abandoned += 1;
|
|
140
|
+
chargeQuestion("abandoned");
|
|
141
|
+
db.retract("wantedUnder", fresh);
|
|
142
|
+
clearDerived();
|
|
143
|
+
chargeAbandoned(
|
|
144
|
+
fresh.map(([key, site]) => `${key} under ${site}`).join(", "),
|
|
145
|
+
error.examined
|
|
146
|
+
);
|
|
147
|
+
return "abandoned";
|
|
148
|
+
}
|
|
149
|
+
spend.rows += budget.examined;
|
|
150
|
+
chargeQuestion();
|
|
151
|
+
clearDerived();
|
|
152
|
+
return "answered";
|
|
153
|
+
}
|
|
64
154
|
|
|
65
155
|
// src/callee.ts
|
|
66
156
|
var UNDECLARED = { kind: "undeclared" };
|
|
@@ -489,6 +579,12 @@ var DEFAULT_PHRASES = {
|
|
|
489
579
|
"last write": ({ tuple, describe }) => ({
|
|
490
580
|
reason: `${describe(tuple[0])} is written more than once, and the last write leaves it as ${describe(tuple[1])}`
|
|
491
581
|
}),
|
|
582
|
+
"one of several writes": ({ tuple, describe }) => ({
|
|
583
|
+
reason: `${describe(tuple[0])} is written more than once, and one of those writes makes it ${describe(tuple[1])}`,
|
|
584
|
+
assumptions: [
|
|
585
|
+
`nothing says which write to ${describe(tuple[0])} ran last, so every write it has is a possible value`
|
|
586
|
+
]
|
|
587
|
+
}),
|
|
492
588
|
fallback: ({ tuple, describe }) => ({
|
|
493
589
|
reason: `${describe(tuple[0])} is a fallback expression, and ${describe(tuple[1])} is the branch that resolves`
|
|
494
590
|
}),
|
|
@@ -505,7 +601,7 @@ var DEFAULT_PHRASES = {
|
|
|
505
601
|
"property read": ({ tuple, premises, describe }) => {
|
|
506
602
|
const [, object, name] = premises[0].tuple;
|
|
507
603
|
const contains = premises[2];
|
|
508
|
-
const inherited = contains.kind === "derived" && contains.
|
|
604
|
+
const inherited = contains.kind === "derived" && ruleLabel(contains.rule) === BASE_CLASS_RULE;
|
|
509
605
|
return {
|
|
510
606
|
reason: `${describe(tuple[0])} reads ${String(name)} off ${describe(object)}, which contains ${describe(tuple[1])}`,
|
|
511
607
|
notes: inherited ? [`${String(name)} comes from a base class`] : []
|
|
@@ -584,7 +680,8 @@ var CHAIN_RELATIONS = /* @__PURE__ */ new Set([
|
|
|
584
680
|
"isWrittenAs",
|
|
585
681
|
"comesFrom",
|
|
586
682
|
"reaches",
|
|
587
|
-
"stepsTo"
|
|
683
|
+
"stepsTo",
|
|
684
|
+
"hop"
|
|
588
685
|
]);
|
|
589
686
|
function inlineChain(proof, state) {
|
|
590
687
|
const explained = explainResolutionProof(proof, {
|
|
@@ -640,6 +737,17 @@ function importStep(proof, state) {
|
|
|
640
737
|
assumptions: []
|
|
641
738
|
};
|
|
642
739
|
}
|
|
740
|
+
function namespaceMemberStep(proof, state) {
|
|
741
|
+
const [x, module, name] = proof.tuple;
|
|
742
|
+
return {
|
|
743
|
+
from: x,
|
|
744
|
+
to: module,
|
|
745
|
+
rule: NAMESPACE_MEMBER_RULE,
|
|
746
|
+
reason: `${state.describe(x)} reads ${String(name)} off ${state.describe(module)}, which is imported whole`,
|
|
747
|
+
notes: [],
|
|
748
|
+
assumptions: []
|
|
749
|
+
};
|
|
750
|
+
}
|
|
643
751
|
var flattenInto = (proof, state) => {
|
|
644
752
|
if (proof.kind === "truncated") {
|
|
645
753
|
state.truncated = true;
|
|
@@ -649,7 +757,7 @@ var flattenInto = (proof, state) => {
|
|
|
649
757
|
return;
|
|
650
758
|
}
|
|
651
759
|
const relation = proof.relation;
|
|
652
|
-
if (relation === "stepsTo") {
|
|
760
|
+
if (relation === "stepsTo" || relation === "hop") {
|
|
653
761
|
state.steps.push(stepFrom(proof, state));
|
|
654
762
|
return;
|
|
655
763
|
}
|
|
@@ -660,6 +768,10 @@ var flattenInto = (proof, state) => {
|
|
|
660
768
|
return;
|
|
661
769
|
}
|
|
662
770
|
if (relation === "comesFrom") {
|
|
771
|
+
if (ruleLabel(proof.rule) === NAMESPACE_MEMBER_RULE) {
|
|
772
|
+
state.steps.push(namespaceMemberStep(proof, state));
|
|
773
|
+
return;
|
|
774
|
+
}
|
|
663
775
|
if (proof.premises.length === 2) {
|
|
664
776
|
flattenInto(proof.premises[0], state);
|
|
665
777
|
state.steps.push(importStep(proof.premises[1], state));
|
|
@@ -836,6 +948,37 @@ function nodeOfKey(rootsByFile, key) {
|
|
|
836
948
|
return null;
|
|
837
949
|
}
|
|
838
950
|
|
|
951
|
+
// src/packWords.ts
|
|
952
|
+
function addPackWords(db, words) {
|
|
953
|
+
for (const word of words.givesBackOne ?? []) {
|
|
954
|
+
db.add("givesBackOne", [word.base, word.method]);
|
|
955
|
+
}
|
|
956
|
+
for (const word of words.givesBackOneOfArgument ?? []) {
|
|
957
|
+
db.add("givesBackOneOfArgument", [
|
|
958
|
+
word.base,
|
|
959
|
+
word.method,
|
|
960
|
+
String(word.argument)
|
|
961
|
+
]);
|
|
962
|
+
}
|
|
963
|
+
for (const word of words.givesBackOneOfImport ?? []) {
|
|
964
|
+
db.add("givesBackOneOfImport", [
|
|
965
|
+
word.module,
|
|
966
|
+
word.name,
|
|
967
|
+
String(word.argument)
|
|
968
|
+
]);
|
|
969
|
+
}
|
|
970
|
+
for (const word of words.entersAsSelf ?? []) {
|
|
971
|
+
db.add("entersAsSelf", [word.module, word.name]);
|
|
972
|
+
}
|
|
973
|
+
for (const word of words.unwrapsByName ?? []) {
|
|
974
|
+
db.add("unwrapsByName", [word.callee, String(word.argument)]);
|
|
975
|
+
db.add("wrapperModule", [word.callee, word.module]);
|
|
976
|
+
}
|
|
977
|
+
for (const word of words.associationConstructor ?? []) {
|
|
978
|
+
db.add("associationConstructor", [word.module, word.name]);
|
|
979
|
+
}
|
|
980
|
+
}
|
|
981
|
+
|
|
839
982
|
// src/session.ts
|
|
840
983
|
import { Database, evaluate as evaluate2, proofOf, witnesses } from "@suss/datalog";
|
|
841
984
|
function explainResolvedKey(options) {
|
|
@@ -891,7 +1034,7 @@ function explainResolvedKey(options) {
|
|
|
891
1034
|
|
|
892
1035
|
// src/singleAnswer.ts
|
|
893
1036
|
var NO_PLACEHOLDERS = /* @__PURE__ */ new Set();
|
|
894
|
-
function
|
|
1037
|
+
function answersByKey(rows, placeholders = NO_PLACEHOLDERS) {
|
|
895
1038
|
const candidates = /* @__PURE__ */ new Map();
|
|
896
1039
|
for (const row of rows) {
|
|
897
1040
|
const key = String(row[0]);
|
|
@@ -903,9 +1046,15 @@ function singleAnswers(rows, placeholders = NO_PLACEHOLDERS) {
|
|
|
903
1046
|
set.add(answer);
|
|
904
1047
|
candidates.set(key, set);
|
|
905
1048
|
}
|
|
906
|
-
const
|
|
1049
|
+
const answers = /* @__PURE__ */ new Map();
|
|
907
1050
|
for (const [key, set] of candidates) {
|
|
908
|
-
|
|
1051
|
+
answers.set(key, withoutPlaceholders(set, placeholders));
|
|
1052
|
+
}
|
|
1053
|
+
return answers;
|
|
1054
|
+
}
|
|
1055
|
+
function singleAnswers(rows, placeholders = NO_PLACEHOLDERS) {
|
|
1056
|
+
const settled = /* @__PURE__ */ new Map();
|
|
1057
|
+
for (const [key, answers] of answersByKey(rows, placeholders)) {
|
|
909
1058
|
if (answers.length === 1) {
|
|
910
1059
|
settled.set(key, answers[0]);
|
|
911
1060
|
}
|
|
@@ -923,6 +1072,28 @@ function withoutPlaceholders(answers, placeholders) {
|
|
|
923
1072
|
return kept;
|
|
924
1073
|
}
|
|
925
1074
|
|
|
1075
|
+
// src/underContext.ts
|
|
1076
|
+
function answersUnder(db, relation, key, site) {
|
|
1077
|
+
return db.lookup(relation, 0, key).filter((row) => String(row[1]) === site).map((row) => String(row[2]));
|
|
1078
|
+
}
|
|
1079
|
+
function isWrittenAsUnder(db, key, site) {
|
|
1080
|
+
return answersUnder(db, "wantedIsWrittenAsUnder", key, site);
|
|
1081
|
+
}
|
|
1082
|
+
function comesToUnder(db, key, site) {
|
|
1083
|
+
return answersUnder(db, "wantedComesToUnder", key, site);
|
|
1084
|
+
}
|
|
1085
|
+
function objectOfUnder(db, key, site) {
|
|
1086
|
+
return answersUnder(db, "wantedObjectOfUnder", key, site);
|
|
1087
|
+
}
|
|
1088
|
+
function writtenValueUnder(db, key, site) {
|
|
1089
|
+
const rows = isWrittenAsUnder(db, key, site).map((answer) => [key, answer]);
|
|
1090
|
+
const answers = answersByKey(rows, placeholderValues(db)).get(key) ?? [];
|
|
1091
|
+
return answers.length === 1 ? answers[0] : null;
|
|
1092
|
+
}
|
|
1093
|
+
function allocationSitesOf(db, cls) {
|
|
1094
|
+
return db.lookup("wantedAllocatedAt", 0, cls).map((row) => String(row[1]));
|
|
1095
|
+
}
|
|
1096
|
+
|
|
926
1097
|
// src/writes.ts
|
|
927
1098
|
function valueLeftByWrites(writes, ordered) {
|
|
928
1099
|
const deciding = writes.filter((write) => !write.narrowsName);
|
|
@@ -953,23 +1124,58 @@ function sharedConstruction(writes) {
|
|
|
953
1124
|
}
|
|
954
1125
|
|
|
955
1126
|
// src/writtenValue.ts
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
const
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
1127
|
+
var WRITTEN_AS = "wantedIsWrittenAs";
|
|
1128
|
+
function writtenValueOf(db, key, ask, relation = WRITTEN_AS) {
|
|
1129
|
+
const answers = settledByKey(db, [key], ask, relation).get(key) ?? [];
|
|
1130
|
+
return answers.length === 1 ? answers[0] : null;
|
|
1131
|
+
}
|
|
1132
|
+
function writtenValuesOf(db, key, ask, relation = WRITTEN_AS) {
|
|
1133
|
+
const settled = settledByKey(db, [key], ask, relation).get(key) ?? [];
|
|
1134
|
+
return settled.length > 0 ? settled : writesLeft(db, key);
|
|
1135
|
+
}
|
|
1136
|
+
function writtenValuesByKey(db, keys, ask, relation = WRITTEN_AS) {
|
|
1137
|
+
const one = /* @__PURE__ */ new Map();
|
|
1138
|
+
for (const [key, answers] of settledByKey(db, keys, ask, relation)) {
|
|
1139
|
+
if (answers.length === 1) {
|
|
1140
|
+
one.set(key, answers[0]);
|
|
1141
|
+
}
|
|
963
1142
|
}
|
|
964
|
-
|
|
965
|
-
|
|
1143
|
+
return one;
|
|
1144
|
+
}
|
|
1145
|
+
function settledByKey(db, keys, ask, relation) {
|
|
1146
|
+
const placeholders = placeholderValues(db);
|
|
1147
|
+
const byKey = answersByKey(db.facts(relation), placeholders);
|
|
1148
|
+
const direct = new Map(keys.map((key) => [key, byKey.get(key) ?? []]));
|
|
1149
|
+
const calls = new Set(db.facts("call").map((row) => String(row[0])));
|
|
1150
|
+
const throughCalls = [...direct.values()].flat().filter((answer) => calls.has(answer));
|
|
1151
|
+
if (throughCalls.length === 0) {
|
|
966
1152
|
return direct;
|
|
967
1153
|
}
|
|
968
|
-
ask(
|
|
969
|
-
const deeper = singleAnswers(db.facts(
|
|
970
|
-
|
|
1154
|
+
ask(throughCalls);
|
|
1155
|
+
const deeper = singleAnswers(db.facts(relation), placeholders);
|
|
1156
|
+
return new Map(
|
|
1157
|
+
[...direct].map(([key, answers]) => [
|
|
1158
|
+
key,
|
|
1159
|
+
collapseCalls(answers, calls, deeper)
|
|
1160
|
+
])
|
|
971
1161
|
);
|
|
972
|
-
|
|
1162
|
+
}
|
|
1163
|
+
function collapseCalls(direct, calls, deeper) {
|
|
1164
|
+
return [
|
|
1165
|
+
...new Set(
|
|
1166
|
+
direct.map(
|
|
1167
|
+
(answer) => calls.has(answer) ? deeper.get(answer) ?? answer : answer
|
|
1168
|
+
)
|
|
1169
|
+
)
|
|
1170
|
+
];
|
|
1171
|
+
}
|
|
1172
|
+
function writesLeft(db, key) {
|
|
1173
|
+
const unstated = db.facts("writesUnstated").some((row) => String(row[0]) === key);
|
|
1174
|
+
if (unstated) {
|
|
1175
|
+
return [];
|
|
1176
|
+
}
|
|
1177
|
+
const candidates = answersByKey(db.facts("mayHold"), placeholderValues(db)).get(key) ?? [];
|
|
1178
|
+
return candidates.length > 1 ? candidates : [];
|
|
973
1179
|
}
|
|
974
1180
|
|
|
975
1181
|
// src/index.ts
|
|
@@ -977,38 +1183,61 @@ import { constant, lit, rule, variable as v } from "@suss/datalog";
|
|
|
977
1183
|
var VALUE_STEP = constant("value");
|
|
978
1184
|
var NAMESPACE_IMPORT_NAME = "*";
|
|
979
1185
|
var NAMESPACE_IMPORT = constant(NAMESPACE_IMPORT_NAME);
|
|
1186
|
+
var NAMESPACE_MEMBER_RULE = "namespace member";
|
|
1187
|
+
var BASE_CLASS_RULE = "base class";
|
|
1188
|
+
var INSTANCE_STEP = constant("instance");
|
|
980
1189
|
var RESULT_STEP = constant("result");
|
|
981
|
-
var
|
|
1190
|
+
var NO_CONTEXT_NAME = "none";
|
|
1191
|
+
var NO_CONTEXT = constant(NO_CONTEXT_NAME);
|
|
1192
|
+
var STEP_LATTICE = [
|
|
1193
|
+
{ soFar: VALUE_STEP, next: v("kind"), took: v("kind") },
|
|
1194
|
+
{ soFar: INSTANCE_STEP, next: VALUE_STEP, took: INSTANCE_STEP },
|
|
1195
|
+
{ soFar: INSTANCE_STEP, next: INSTANCE_STEP, took: INSTANCE_STEP },
|
|
1196
|
+
{ soFar: INSTANCE_STEP, next: RESULT_STEP, took: RESULT_STEP },
|
|
1197
|
+
{ soFar: RESULT_STEP, next: VALUE_STEP, took: RESULT_STEP },
|
|
1198
|
+
{ soFar: RESULT_STEP, next: INSTANCE_STEP, took: RESULT_STEP },
|
|
1199
|
+
{ soFar: RESULT_STEP, next: RESULT_STEP, took: RESULT_STEP }
|
|
1200
|
+
];
|
|
1201
|
+
var STATED_RULES = [
|
|
982
1202
|
// Aliasing: const x = y, or an identifier referencing a declaration.
|
|
983
1203
|
// A language with a hop of its own, like JavaScript's `.bind`, states
|
|
984
1204
|
// it as a step too, or every question but `comesTo` misses it.
|
|
985
1205
|
rule(
|
|
986
|
-
"
|
|
1206
|
+
"hop",
|
|
987
1207
|
[v("x"), v("y"), VALUE_STEP],
|
|
988
1208
|
[lit("binds", v("x"), v("y"))],
|
|
989
1209
|
"alias"
|
|
990
1210
|
),
|
|
991
1211
|
// A name written more than once has the value the last write left
|
|
992
|
-
// there. The adapter works out which write that is and stays quiet
|
|
993
|
-
// when control flow decides
|
|
1212
|
+
// there. The adapter works out which write that is, and stays quiet
|
|
1213
|
+
// when control flow decides; the rule below takes that name instead.
|
|
994
1214
|
rule(
|
|
995
|
-
"
|
|
1215
|
+
"hop",
|
|
996
1216
|
[v("x"), v("y"), VALUE_STEP],
|
|
997
1217
|
[lit("endsHolding", v("x"), v("y"))],
|
|
998
1218
|
"last write"
|
|
999
1219
|
),
|
|
1220
|
+
// A name whose writes nothing orders leads to each of them, so a
|
|
1221
|
+
// caller that can use several values gets them all and one that needs
|
|
1222
|
+
// a single value gets none. A write stating no value stops every step.
|
|
1223
|
+
rule(
|
|
1224
|
+
"hop",
|
|
1225
|
+
[v("x"), v("y"), VALUE_STEP],
|
|
1226
|
+
[lit("mayHold", v("x"), v("y")), lit("writesAllStated", v("x"))],
|
|
1227
|
+
"one of several writes"
|
|
1228
|
+
),
|
|
1000
1229
|
// A fallback says the value is one of its branches, so each branch is
|
|
1001
1230
|
// a step. A branch that resolves to nothing makes no claim, and two
|
|
1002
1231
|
// branches resolving to different things fail the single-answer policy.
|
|
1003
1232
|
rule(
|
|
1004
|
-
"
|
|
1233
|
+
"hop",
|
|
1005
1234
|
[v("x"), v("b"), VALUE_STEP],
|
|
1006
1235
|
[lit("fallbackBranch", v("x"), v("b"))],
|
|
1007
1236
|
"fallback"
|
|
1008
1237
|
),
|
|
1009
1238
|
// An import steps to what the module exports under that name.
|
|
1010
1239
|
rule(
|
|
1011
|
-
"
|
|
1240
|
+
"hop",
|
|
1012
1241
|
[v("x"), v("value"), VALUE_STEP],
|
|
1013
1242
|
[
|
|
1014
1243
|
lit("imports", v("x"), v("m"), v("n")),
|
|
@@ -1042,8 +1271,8 @@ var RESOLUTION_RULES = [
|
|
|
1042
1271
|
// a method read off the result is the one the class declares. The
|
|
1043
1272
|
// caveat below is about a factory function, and a class is not one.
|
|
1044
1273
|
rule(
|
|
1045
|
-
"
|
|
1046
|
-
[v("r"), v("cls"),
|
|
1274
|
+
"hop",
|
|
1275
|
+
[v("r"), v("cls"), INSTANCE_STEP],
|
|
1047
1276
|
[
|
|
1048
1277
|
lit("call", v("r"), v("c")),
|
|
1049
1278
|
lit("comesTo", v("c"), v("cls")),
|
|
@@ -1051,12 +1280,21 @@ var RESOLUTION_RULES = [
|
|
|
1051
1280
|
],
|
|
1052
1281
|
"class instance"
|
|
1053
1282
|
),
|
|
1283
|
+
// The receiver a method is called on. Being one of a class is the
|
|
1284
|
+
// same hop a construction takes, so a method read off `self` finds
|
|
1285
|
+
// what the class declares.
|
|
1286
|
+
rule(
|
|
1287
|
+
"hop",
|
|
1288
|
+
[v("x"), v("cls"), INSTANCE_STEP],
|
|
1289
|
+
[lit("instanceOf", v("x"), v("cls"))],
|
|
1290
|
+
"receiver instance"
|
|
1291
|
+
),
|
|
1054
1292
|
// A finder the library declares, keyed on the base a pack named so a
|
|
1055
1293
|
// project class with a method of the same name on another hierarchy is
|
|
1056
1294
|
// left alone. The DESIGN says what a chain of them composes into.
|
|
1057
1295
|
rule(
|
|
1058
|
-
"
|
|
1059
|
-
[v("r"), v("cls"),
|
|
1296
|
+
"hop",
|
|
1297
|
+
[v("r"), v("cls"), INSTANCE_STEP],
|
|
1060
1298
|
[
|
|
1061
1299
|
lit("call", v("r"), v("c")),
|
|
1062
1300
|
lit("readsProperty", v("c"), v("o"), v("m")),
|
|
@@ -1073,8 +1311,8 @@ var RESOLUTION_RULES = [
|
|
|
1073
1311
|
// instead of as the receiver. The argument having to reach the base a
|
|
1074
1312
|
// pack named is what keeps an unrelated `get` out.
|
|
1075
1313
|
rule(
|
|
1076
|
-
"
|
|
1077
|
-
[v("r"), v("cls"),
|
|
1314
|
+
"hop",
|
|
1315
|
+
[v("r"), v("cls"), INSTANCE_STEP],
|
|
1078
1316
|
[
|
|
1079
1317
|
lit("call", v("r"), v("c")),
|
|
1080
1318
|
lit("readsProperty", v("c"), v("o"), v("m")),
|
|
@@ -1091,8 +1329,8 @@ var RESOLUTION_RULES = [
|
|
|
1091
1329
|
// anything, keyed on the module it was imported from so a project
|
|
1092
1330
|
// function spelled the same way is not mistaken for it.
|
|
1093
1331
|
rule(
|
|
1094
|
-
"
|
|
1095
|
-
[v("r"), v("cls"),
|
|
1332
|
+
"hop",
|
|
1333
|
+
[v("r"), v("cls"), INSTANCE_STEP],
|
|
1096
1334
|
[
|
|
1097
1335
|
lit("call", v("r"), v("c")),
|
|
1098
1336
|
lit("comesFrom", v("c"), v("mod"), v("n")),
|
|
@@ -1102,10 +1340,24 @@ var RESOLUTION_RULES = [
|
|
|
1102
1340
|
],
|
|
1103
1341
|
"declared import finder"
|
|
1104
1342
|
),
|
|
1343
|
+
// A block opened over a library's own constructor. The pack says
|
|
1344
|
+
// entering one gives back the object it built, so the name the block
|
|
1345
|
+
// opens is that call.
|
|
1346
|
+
rule(
|
|
1347
|
+
"hop",
|
|
1348
|
+
[v("y"), v("r"), VALUE_STEP],
|
|
1349
|
+
[
|
|
1350
|
+
lit("entersAs", v("y"), v("r")),
|
|
1351
|
+
lit("call", v("r"), v("c")),
|
|
1352
|
+
lit("comesFrom", v("c"), v("mod"), v("n")),
|
|
1353
|
+
lit("entersAsSelf", v("mod"), v("n"))
|
|
1354
|
+
],
|
|
1355
|
+
"context manager returns self"
|
|
1356
|
+
),
|
|
1105
1357
|
// Wrapper transparency, derived: calling a factory that returns a
|
|
1106
1358
|
// function which calls its parameter k steps to argument k.
|
|
1107
1359
|
rule(
|
|
1108
|
-
"
|
|
1360
|
+
"hop",
|
|
1109
1361
|
[v("r"), v("a"), VALUE_STEP],
|
|
1110
1362
|
[
|
|
1111
1363
|
lit("call", v("r"), v("c")),
|
|
@@ -1119,7 +1371,7 @@ var RESOLUTION_RULES = [
|
|
|
1119
1371
|
// argument k. The callee has to come from the library the pack said,
|
|
1120
1372
|
// so a local object spelled the same way is not mistaken for it.
|
|
1121
1373
|
rule(
|
|
1122
|
-
"
|
|
1374
|
+
"hop",
|
|
1123
1375
|
[v("r"), v("a"), VALUE_STEP],
|
|
1124
1376
|
[
|
|
1125
1377
|
lit("calleeName", v("r"), v("n")),
|
|
@@ -1133,44 +1385,441 @@ var RESOLUTION_RULES = [
|
|
|
1133
1385
|
// The one step that runs a function forwards: a call steps to what
|
|
1134
1386
|
// the function it invokes returns.
|
|
1135
1387
|
rule(
|
|
1136
|
-
"
|
|
1388
|
+
"hop",
|
|
1137
1389
|
[v("r"), v("ret"), RESULT_STEP],
|
|
1138
1390
|
[lit("invokes", v("r"), v("f")), lit("returnsValue", v("f"), v("ret"))],
|
|
1139
1391
|
"call result"
|
|
1140
1392
|
),
|
|
1141
|
-
//
|
|
1142
|
-
//
|
|
1143
|
-
//
|
|
1393
|
+
// What a function says it gives back when its body never states a
|
|
1394
|
+
// value. The adapter stays quiet about the annotation whenever the
|
|
1395
|
+
// body does state one, so the two never answer the same question.
|
|
1396
|
+
rule(
|
|
1397
|
+
"hop",
|
|
1398
|
+
[v("r"), v("cls"), RESULT_STEP],
|
|
1399
|
+
[
|
|
1400
|
+
lit("invokes", v("r"), v("f")),
|
|
1401
|
+
lit("returnsClass", v("f"), v("x")),
|
|
1402
|
+
lit("comesTo", v("x"), v("cls")),
|
|
1403
|
+
lit("objectValue", v("cls"))
|
|
1404
|
+
],
|
|
1405
|
+
"declared return type"
|
|
1406
|
+
),
|
|
1407
|
+
// Where a walk gets to, under the strongest step it took: value, then
|
|
1408
|
+
// instance, then result. The walk so far comes first, so demand stays
|
|
1409
|
+
// on the value asked about; the README says what the other order cost.
|
|
1144
1410
|
rule(
|
|
1145
1411
|
"reaches",
|
|
1146
1412
|
[v("x"), v("z"), v("kind")],
|
|
1147
1413
|
[lit("stepsTo", v("x"), v("z"), v("kind"))]
|
|
1148
1414
|
),
|
|
1415
|
+
// A rule per pair rather than one leaving the next step's kind free. A
|
|
1416
|
+
// free kind is a second question about the same relation, and a
|
|
1417
|
+
// demand-driven run then derives both to answer either.
|
|
1418
|
+
...STEP_LATTICE.map(
|
|
1419
|
+
({ soFar, next, took }) => rule(
|
|
1420
|
+
"reaches",
|
|
1421
|
+
[v("x"), v("z"), took],
|
|
1422
|
+
[
|
|
1423
|
+
lit("reaches", v("x"), v("y"), soFar),
|
|
1424
|
+
lit("stepsTo", v("y"), v("z"), next)
|
|
1425
|
+
]
|
|
1426
|
+
)
|
|
1427
|
+
),
|
|
1428
|
+
// A context is an allocation site, or nothing at all for a value read
|
|
1429
|
+
// outside every site. Both are stated, so a rule that starts a walk
|
|
1430
|
+
// binds its context from a premise rather than from a negation.
|
|
1431
|
+
rule("context", [NO_CONTEXT], [], "no context"),
|
|
1432
|
+
rule(
|
|
1433
|
+
"context",
|
|
1434
|
+
[v("site")],
|
|
1435
|
+
[lit("allocates", v("site"), v("cls"))],
|
|
1436
|
+
"site context"
|
|
1437
|
+
),
|
|
1438
|
+
// The same closure, with the context the walk started under and the
|
|
1439
|
+
// context it arrived under. It takes `hop`, because an argument and a
|
|
1440
|
+
// property read have their own rules below.
|
|
1441
|
+
rule(
|
|
1442
|
+
"reachesUnder",
|
|
1443
|
+
[v("x"), v("c"), v("z"), v("c"), v("kind")],
|
|
1444
|
+
[lit("context", v("c")), lit("hop", v("x"), v("z"), v("kind"))],
|
|
1445
|
+
"under one hop"
|
|
1446
|
+
),
|
|
1447
|
+
...STEP_LATTICE.map(
|
|
1448
|
+
({ soFar, next, took }) => rule(
|
|
1449
|
+
"reachesUnder",
|
|
1450
|
+
[v("x"), v("c"), v("z"), v("c2"), took],
|
|
1451
|
+
[
|
|
1452
|
+
lit("reachesUnder", v("x"), v("c"), v("y"), v("c2"), soFar),
|
|
1453
|
+
lit("hop", v("y"), v("z"), next)
|
|
1454
|
+
]
|
|
1455
|
+
)
|
|
1456
|
+
),
|
|
1457
|
+
// The receiver read under a site is that site. The ordinary hop from a
|
|
1458
|
+
// receiver to its class stays in `hop`, so `self` under any context
|
|
1459
|
+
// still comes to the class a single-answer reader wants.
|
|
1149
1460
|
rule(
|
|
1150
|
-
"
|
|
1151
|
-
[v("x"), v("
|
|
1461
|
+
"reachesUnder",
|
|
1462
|
+
[v("x"), v("c"), v("c"), v("c"), VALUE_STEP],
|
|
1463
|
+
[lit("instanceOf", v("x"), v("cls")), lit("allocates", v("c"), v("cls"))],
|
|
1464
|
+
"receiver is the site"
|
|
1465
|
+
),
|
|
1466
|
+
rule(
|
|
1467
|
+
"reachesUnder",
|
|
1468
|
+
[v("x"), v("c"), v("c2"), v("c2"), v("kind")],
|
|
1152
1469
|
[
|
|
1153
|
-
lit("
|
|
1154
|
-
lit("
|
|
1470
|
+
lit("reachesUnder", v("x"), v("c"), v("y"), v("c2"), v("kind")),
|
|
1471
|
+
lit("instanceOf", v("y"), v("cls")),
|
|
1472
|
+
lit("allocates", v("c2"), v("cls"))
|
|
1473
|
+
],
|
|
1474
|
+
"reached receiver is the site"
|
|
1475
|
+
),
|
|
1476
|
+
// The object an expression refers to under a context. A site is an
|
|
1477
|
+
// answer here, unlike `objectOf`, and the class an instance is one of
|
|
1478
|
+
// is an answer only under no context.
|
|
1479
|
+
rule(
|
|
1480
|
+
"objectOfUnder",
|
|
1481
|
+
[v("site"), v("c"), v("site")],
|
|
1482
|
+
[lit("context", v("c")), lit("allocates", v("site"), v("cls"))],
|
|
1483
|
+
"site is its own object"
|
|
1484
|
+
),
|
|
1485
|
+
rule(
|
|
1486
|
+
"objectOfUnder",
|
|
1487
|
+
[v("o"), v("c"), v("site")],
|
|
1488
|
+
[
|
|
1489
|
+
lit("reachesUnder", v("o"), v("c"), v("site"), v("c2"), VALUE_STEP),
|
|
1490
|
+
lit("allocates", v("site"), v("cls"))
|
|
1491
|
+
],
|
|
1492
|
+
"name of a site"
|
|
1493
|
+
),
|
|
1494
|
+
rule(
|
|
1495
|
+
"objectOfUnder",
|
|
1496
|
+
[v("o"), v("c"), v("obj")],
|
|
1497
|
+
[
|
|
1498
|
+
lit("reachesUnder", v("o"), v("c"), v("obj"), v("c2"), VALUE_STEP),
|
|
1499
|
+
lit("objectValue", v("obj"))
|
|
1500
|
+
],
|
|
1501
|
+
"written object under a context"
|
|
1502
|
+
),
|
|
1503
|
+
rule(
|
|
1504
|
+
"objectOfUnder",
|
|
1505
|
+
[v("o"), v("c"), v("obj")],
|
|
1506
|
+
[
|
|
1507
|
+
lit("reachesUnder", v("o"), v("c"), v("obj"), v("c2"), RESULT_STEP),
|
|
1508
|
+
lit("objectValue", v("obj"))
|
|
1509
|
+
],
|
|
1510
|
+
"returned object under a context"
|
|
1511
|
+
),
|
|
1512
|
+
rule(
|
|
1513
|
+
"objectOfUnder",
|
|
1514
|
+
[v("o"), NO_CONTEXT, v("cls")],
|
|
1515
|
+
[
|
|
1516
|
+
lit(
|
|
1517
|
+
"reachesUnder",
|
|
1518
|
+
v("o"),
|
|
1519
|
+
NO_CONTEXT,
|
|
1520
|
+
v("cls"),
|
|
1521
|
+
NO_CONTEXT,
|
|
1522
|
+
INSTANCE_STEP
|
|
1523
|
+
),
|
|
1524
|
+
lit("objectValue", v("cls"))
|
|
1525
|
+
],
|
|
1526
|
+
"class reached with no context"
|
|
1527
|
+
),
|
|
1528
|
+
rule(
|
|
1529
|
+
"objectOfUnder",
|
|
1530
|
+
[v("o"), NO_CONTEXT, v("cls")],
|
|
1531
|
+
[lit("instanceOf", v("o"), v("cls"))],
|
|
1532
|
+
"receiver class with no context"
|
|
1533
|
+
),
|
|
1534
|
+
rule(
|
|
1535
|
+
"objectOfUnder",
|
|
1536
|
+
[v("o"), v("c"), v("o")],
|
|
1537
|
+
[lit("context", v("c")), lit("objectValue", v("o"))],
|
|
1538
|
+
"object under a context is itself"
|
|
1539
|
+
),
|
|
1540
|
+
// A property read goes on under the site the object was made at, so a
|
|
1541
|
+
// field read off two constructions gives each one its own value. A
|
|
1542
|
+
// class or a literal object keeps the context the walk was already in.
|
|
1543
|
+
rule(
|
|
1544
|
+
"reachesUnder",
|
|
1545
|
+
[v("x"), v("c"), v("held"), v("site"), VALUE_STEP],
|
|
1546
|
+
[
|
|
1547
|
+
lit("context", v("c")),
|
|
1548
|
+
lit("readsProperty", v("x"), v("o"), v("n")),
|
|
1549
|
+
lit("objectOfUnder", v("o"), v("c"), v("site")),
|
|
1550
|
+
lit("allocates", v("site"), v("cls")),
|
|
1551
|
+
lit("contains", v("site"), v("n"), v("held"))
|
|
1552
|
+
],
|
|
1553
|
+
"property read at a site"
|
|
1554
|
+
),
|
|
1555
|
+
rule(
|
|
1556
|
+
"reachesUnder",
|
|
1557
|
+
[v("x"), v("c"), v("held"), v("c"), VALUE_STEP],
|
|
1558
|
+
[
|
|
1559
|
+
lit("context", v("c")),
|
|
1560
|
+
lit("readsProperty", v("x"), v("o"), v("n")),
|
|
1561
|
+
lit("objectOfUnder", v("o"), v("c"), v("obj")),
|
|
1562
|
+
lit("objectValue", v("obj")),
|
|
1563
|
+
lit("contains", v("obj"), v("n"), v("held"))
|
|
1564
|
+
],
|
|
1565
|
+
"property read off an object"
|
|
1566
|
+
),
|
|
1567
|
+
rule(
|
|
1568
|
+
"reachesUnder",
|
|
1569
|
+
[v("x"), v("c"), v("held"), v("site"), v("kind")],
|
|
1570
|
+
[
|
|
1571
|
+
lit("reachesUnder", v("x"), v("c"), v("y"), v("c2"), v("kind")),
|
|
1572
|
+
lit("readsProperty", v("y"), v("o"), v("n")),
|
|
1573
|
+
lit("objectOfUnder", v("o"), v("c2"), v("site")),
|
|
1574
|
+
lit("allocates", v("site"), v("cls")),
|
|
1575
|
+
lit("contains", v("site"), v("n"), v("held"))
|
|
1576
|
+
],
|
|
1577
|
+
"reached property read at a site"
|
|
1578
|
+
),
|
|
1579
|
+
rule(
|
|
1580
|
+
"reachesUnder",
|
|
1581
|
+
[v("x"), v("c"), v("held"), v("c2"), v("kind")],
|
|
1582
|
+
[
|
|
1583
|
+
lit("reachesUnder", v("x"), v("c"), v("y"), v("c2"), v("kind")),
|
|
1584
|
+
lit("readsProperty", v("y"), v("o"), v("n")),
|
|
1585
|
+
lit("objectOfUnder", v("o"), v("c2"), v("obj")),
|
|
1586
|
+
lit("objectValue", v("obj")),
|
|
1587
|
+
lit("contains", v("obj"), v("n"), v("held"))
|
|
1588
|
+
],
|
|
1589
|
+
"reached property read off an object"
|
|
1590
|
+
),
|
|
1591
|
+
// A parameter goes on at the argument, under the context its caller
|
|
1592
|
+
// was read in, and only from the calls that run the function under the
|
|
1593
|
+
// context the walk is in. This is the one hop that changes context.
|
|
1594
|
+
rule(
|
|
1595
|
+
"reachesUnder",
|
|
1596
|
+
[v("p"), v("c"), v("a"), v("c3"), VALUE_STEP],
|
|
1597
|
+
[
|
|
1598
|
+
lit("context", v("c")),
|
|
1599
|
+
lit("paramOf", v("f"), v("i"), v("p")),
|
|
1600
|
+
lit("entersUnder", v("r"), v("f"), v("c"), v("c3")),
|
|
1601
|
+
lit("callArg", v("r"), v("i"), v("a"))
|
|
1602
|
+
],
|
|
1603
|
+
"argument under a context"
|
|
1604
|
+
),
|
|
1605
|
+
rule(
|
|
1606
|
+
"reachesUnder",
|
|
1607
|
+
[v("p"), v("c"), v("a"), v("c3"), VALUE_STEP],
|
|
1608
|
+
[
|
|
1609
|
+
lit("context", v("c")),
|
|
1610
|
+
lit("paramNamed", v("f"), v("n"), v("p")),
|
|
1611
|
+
lit("entersUnder", v("r"), v("f"), v("c"), v("c3")),
|
|
1612
|
+
lit("callKeywordArg", v("r"), v("n"), v("a"))
|
|
1613
|
+
],
|
|
1614
|
+
"keyword argument under a context"
|
|
1615
|
+
),
|
|
1616
|
+
rule(
|
|
1617
|
+
"reachesUnder",
|
|
1618
|
+
[v("x"), v("c"), v("a"), v("c3"), v("kind")],
|
|
1619
|
+
[
|
|
1620
|
+
lit("reachesUnder", v("x"), v("c"), v("p"), v("c2"), v("kind")),
|
|
1621
|
+
lit("paramOf", v("f"), v("i"), v("p")),
|
|
1622
|
+
lit("entersUnder", v("r"), v("f"), v("c2"), v("c3")),
|
|
1623
|
+
lit("callArg", v("r"), v("i"), v("a"))
|
|
1624
|
+
],
|
|
1625
|
+
"reached argument under a context"
|
|
1626
|
+
),
|
|
1627
|
+
rule(
|
|
1628
|
+
"reachesUnder",
|
|
1629
|
+
[v("x"), v("c"), v("a"), v("c3"), v("kind")],
|
|
1630
|
+
[
|
|
1631
|
+
lit("reachesUnder", v("x"), v("c"), v("p"), v("c2"), v("kind")),
|
|
1632
|
+
lit("paramNamed", v("f"), v("n"), v("p")),
|
|
1633
|
+
lit("entersUnder", v("r"), v("f"), v("c2"), v("c3")),
|
|
1634
|
+
lit("callKeywordArg", v("r"), v("n"), v("a"))
|
|
1635
|
+
],
|
|
1636
|
+
"reached keyword argument under a context"
|
|
1637
|
+
),
|
|
1638
|
+
// Which call runs which function under which context. A construction
|
|
1639
|
+
// runs its constructor under the site it makes, a method call runs
|
|
1640
|
+
// under the site its receiver is, and anything else under no context.
|
|
1641
|
+
rule(
|
|
1642
|
+
"entersUnder",
|
|
1643
|
+
[v("site"), v("ctor"), v("site"), v("caller")],
|
|
1644
|
+
[
|
|
1645
|
+
lit("allocates", v("site"), v("cls")),
|
|
1646
|
+
lit("runsConstructor", v("cls"), v("ctor")),
|
|
1647
|
+
lit("callUnder", v("site"), v("caller"))
|
|
1648
|
+
],
|
|
1649
|
+
"construction enters its constructor"
|
|
1650
|
+
),
|
|
1651
|
+
rule(
|
|
1652
|
+
"entersUnder",
|
|
1653
|
+
[v("r"), v("f"), v("site"), v("caller")],
|
|
1654
|
+
[
|
|
1655
|
+
lit("call", v("r"), v("cal")),
|
|
1656
|
+
lit("readsProperty", v("cal"), v("o"), v("m")),
|
|
1657
|
+
lit("objectOfUnder", v("o"), v("caller"), v("site")),
|
|
1658
|
+
lit("allocates", v("site"), v("cls")),
|
|
1659
|
+
lit("contains", v("site"), v("m"), v("f")),
|
|
1660
|
+
lit("callUnder", v("r"), v("caller"))
|
|
1661
|
+
],
|
|
1662
|
+
"method call enters under its receiver"
|
|
1663
|
+
),
|
|
1664
|
+
// A call written as a name runs with whatever receiver the body
|
|
1665
|
+
// around it has, so a plain function called from a method keeps the
|
|
1666
|
+
// site rather than taking every caller of it.
|
|
1667
|
+
rule(
|
|
1668
|
+
"entersUnder",
|
|
1669
|
+
[v("r"), v("f"), v("c"), v("c")],
|
|
1670
|
+
[
|
|
1671
|
+
lit("context", v("c")),
|
|
1672
|
+
lit("callsNamed", v("r"), v("f")),
|
|
1673
|
+
lit("callUnder", v("r"), v("c"))
|
|
1674
|
+
],
|
|
1675
|
+
"named call enters under the site it is made in"
|
|
1676
|
+
),
|
|
1677
|
+
rule(
|
|
1678
|
+
"entersUnder",
|
|
1679
|
+
[v("r"), v("f"), NO_CONTEXT, v("caller")],
|
|
1680
|
+
[
|
|
1681
|
+
lit("callsFunction", v("r"), v("f")),
|
|
1682
|
+
lit("callUnder", v("r"), v("caller"))
|
|
1683
|
+
],
|
|
1684
|
+
"call enters with no context"
|
|
1685
|
+
),
|
|
1686
|
+
// The constructor a construction runs, the ancestry included, so a
|
|
1687
|
+
// subclass that declares none still fills in what it inherits.
|
|
1688
|
+
rule(
|
|
1689
|
+
"runsConstructor",
|
|
1690
|
+
[v("cls"), v("f")],
|
|
1691
|
+
[lit("initializes", v("cls"), v("f"))]
|
|
1692
|
+
),
|
|
1693
|
+
rule(
|
|
1694
|
+
"runsConstructor",
|
|
1695
|
+
[v("cls"), v("f")],
|
|
1696
|
+
[
|
|
1697
|
+
lit("extends", v("cls"), v("b")),
|
|
1698
|
+
lit("comesTo", v("b"), v("base")),
|
|
1699
|
+
lit("runsConstructor", v("base"), v("f"))
|
|
1155
1700
|
]
|
|
1156
1701
|
),
|
|
1157
|
-
//
|
|
1158
|
-
//
|
|
1159
|
-
// demand-driven run then derives both to answer either.
|
|
1702
|
+
// Which body a call is written in. One adapter states the call it
|
|
1703
|
+
// found and another states the callee, so both spellings are read.
|
|
1160
1704
|
rule(
|
|
1161
|
-
"
|
|
1162
|
-
[v("
|
|
1705
|
+
"callInBody",
|
|
1706
|
+
[v("f"), v("r")],
|
|
1707
|
+
[lit("bodyCallsDeep", v("f"), v("r")), lit("call", v("r"), v("c"))]
|
|
1708
|
+
),
|
|
1709
|
+
rule(
|
|
1710
|
+
"callInBody",
|
|
1711
|
+
[v("f"), v("r")],
|
|
1712
|
+
[lit("bodyCallsDeep", v("f"), v("c")), lit("call", v("r"), v("c"))]
|
|
1713
|
+
),
|
|
1714
|
+
// The context a call is made under: every site of the class whose
|
|
1715
|
+
// method or constructor it is written in, and no context for a call
|
|
1716
|
+
// outside every method body.
|
|
1717
|
+
rule(
|
|
1718
|
+
"callUnder",
|
|
1719
|
+
[v("r"), v("site")],
|
|
1720
|
+
[
|
|
1721
|
+
lit("callInBody", v("f"), v("r")),
|
|
1722
|
+
lit("holdsProperty", v("cls"), v("m"), v("f")),
|
|
1723
|
+
lit("allocates", v("site"), v("cls"))
|
|
1724
|
+
],
|
|
1725
|
+
"call in a method"
|
|
1726
|
+
),
|
|
1727
|
+
rule(
|
|
1728
|
+
"callUnder",
|
|
1729
|
+
[v("r"), v("site")],
|
|
1163
1730
|
[
|
|
1164
|
-
lit("
|
|
1165
|
-
lit("
|
|
1731
|
+
lit("callInBody", v("f"), v("r")),
|
|
1732
|
+
lit("initializes", v("cls"), v("f")),
|
|
1733
|
+
lit("allocates", v("site"), v("cls"))
|
|
1734
|
+
],
|
|
1735
|
+
"call in a constructor"
|
|
1736
|
+
),
|
|
1737
|
+
// A plain function entered under a site makes its own calls under
|
|
1738
|
+
// that site, so a chain of plain functions off one method keeps it.
|
|
1739
|
+
rule(
|
|
1740
|
+
"callUnder",
|
|
1741
|
+
[v("r"), v("c")],
|
|
1742
|
+
[
|
|
1743
|
+
lit("callOutsideMethod", v("r")),
|
|
1744
|
+
lit("callInBody", v("f"), v("r")),
|
|
1745
|
+
lit("entersUnder", v("into"), v("f"), v("c"), v("c4"))
|
|
1746
|
+
],
|
|
1747
|
+
"call in a function entered under a site"
|
|
1748
|
+
),
|
|
1749
|
+
rule(
|
|
1750
|
+
"callUnder",
|
|
1751
|
+
[v("r"), NO_CONTEXT],
|
|
1752
|
+
[lit("callOutsideMethod", v("r"))],
|
|
1753
|
+
"call outside every method"
|
|
1754
|
+
),
|
|
1755
|
+
// The two questions a caller puts under a context, stopping where
|
|
1756
|
+
// `isWrittenAs` and `comesTo` stop, whatever context the walk ended in.
|
|
1757
|
+
rule(
|
|
1758
|
+
"isWrittenAsUnder",
|
|
1759
|
+
[v("x"), v("c"), v("x")],
|
|
1760
|
+
[lit("context", v("c")), lit("writtenValue", v("x"))]
|
|
1761
|
+
),
|
|
1762
|
+
rule(
|
|
1763
|
+
"isWrittenAsUnder",
|
|
1764
|
+
[v("x"), v("c"), v("x")],
|
|
1765
|
+
[lit("context", v("c")), lit("objectValue", v("x"))]
|
|
1766
|
+
),
|
|
1767
|
+
rule(
|
|
1768
|
+
"isWrittenAsUnder",
|
|
1769
|
+
[v("x"), v("c"), v("z")],
|
|
1770
|
+
[
|
|
1771
|
+
lit("reachesUnder", v("x"), v("c"), v("z"), v("c2"), VALUE_STEP),
|
|
1772
|
+
lit("writtenValue", v("z"))
|
|
1166
1773
|
]
|
|
1167
1774
|
),
|
|
1168
1775
|
rule(
|
|
1169
|
-
"
|
|
1170
|
-
[v("x"), v("
|
|
1776
|
+
"isWrittenAsUnder",
|
|
1777
|
+
[v("x"), v("c"), v("z")],
|
|
1778
|
+
[
|
|
1779
|
+
lit("reachesUnder", v("x"), v("c"), v("z"), v("c2"), VALUE_STEP),
|
|
1780
|
+
lit("objectValue", v("z"))
|
|
1781
|
+
]
|
|
1782
|
+
),
|
|
1783
|
+
rule(
|
|
1784
|
+
"comesToUnder",
|
|
1785
|
+
[v("x"), v("c"), v("x")],
|
|
1786
|
+
[lit("context", v("c")), lit("func", v("x"))]
|
|
1787
|
+
),
|
|
1788
|
+
rule(
|
|
1789
|
+
"comesToUnder",
|
|
1790
|
+
[v("x"), v("c"), v("x")],
|
|
1791
|
+
[lit("context", v("c")), lit("objectValue", v("x"))]
|
|
1792
|
+
),
|
|
1793
|
+
rule(
|
|
1794
|
+
"comesToUnder",
|
|
1795
|
+
[v("x"), v("c"), v("z")],
|
|
1796
|
+
[
|
|
1797
|
+
lit("reachesUnder", v("x"), v("c"), v("z"), v("c2"), VALUE_STEP),
|
|
1798
|
+
lit("func", v("z"))
|
|
1799
|
+
]
|
|
1800
|
+
),
|
|
1801
|
+
rule(
|
|
1802
|
+
"comesToUnder",
|
|
1803
|
+
[v("x"), v("c"), v("z")],
|
|
1804
|
+
[
|
|
1805
|
+
lit("reachesUnder", v("x"), v("c"), v("z"), v("c2"), VALUE_STEP),
|
|
1806
|
+
lit("objectValue", v("z"))
|
|
1807
|
+
]
|
|
1808
|
+
),
|
|
1809
|
+
rule(
|
|
1810
|
+
"comesToUnder",
|
|
1811
|
+
[v("x"), v("c"), v("z")],
|
|
1812
|
+
[
|
|
1813
|
+
lit("reachesUnder", v("x"), v("c"), v("z"), v("c2"), INSTANCE_STEP),
|
|
1814
|
+
lit("func", v("z"))
|
|
1815
|
+
]
|
|
1816
|
+
),
|
|
1817
|
+
rule(
|
|
1818
|
+
"comesToUnder",
|
|
1819
|
+
[v("x"), v("c"), v("z")],
|
|
1171
1820
|
[
|
|
1172
|
-
lit("
|
|
1173
|
-
lit("
|
|
1821
|
+
lit("reachesUnder", v("x"), v("c"), v("z"), v("c2"), INSTANCE_STEP),
|
|
1822
|
+
lit("objectValue", v("z"))
|
|
1174
1823
|
]
|
|
1175
1824
|
),
|
|
1176
1825
|
// What a value comes down to: the walk that never ran a call, stopped
|
|
@@ -1188,6 +1837,18 @@ var RESOLUTION_RULES = [
|
|
|
1188
1837
|
[v("x"), v("z")],
|
|
1189
1838
|
[lit("reaches", v("x"), v("z"), VALUE_STEP), lit("objectValue", v("z"))]
|
|
1190
1839
|
),
|
|
1840
|
+
// An instance walk stops the same way, so a method read off
|
|
1841
|
+
// `new App()` still finds what the class declares.
|
|
1842
|
+
rule(
|
|
1843
|
+
"comesTo",
|
|
1844
|
+
[v("x"), v("z")],
|
|
1845
|
+
[lit("reaches", v("x"), v("z"), INSTANCE_STEP), lit("func", v("z"))]
|
|
1846
|
+
),
|
|
1847
|
+
rule(
|
|
1848
|
+
"comesTo",
|
|
1849
|
+
[v("x"), v("z")],
|
|
1850
|
+
[lit("reaches", v("x"), v("z"), INSTANCE_STEP), lit("objectValue", v("z"))]
|
|
1851
|
+
),
|
|
1191
1852
|
// The same stopping condition, for the walk that ran a call. A call
|
|
1192
1853
|
// gets no `comesTo` answer on purpose: coming back with what a
|
|
1193
1854
|
// factory returned would fight the unwrapping answer.
|
|
@@ -1228,6 +1889,13 @@ var RESOLUTION_RULES = [
|
|
|
1228
1889
|
lit("isWrittenAs", v("ret"), v("z"))
|
|
1229
1890
|
]
|
|
1230
1891
|
),
|
|
1892
|
+
// Which expression running f hands back, whether f returns it, writes
|
|
1893
|
+
// it into a name first, or ends on it as a shorthand body.
|
|
1894
|
+
rule(
|
|
1895
|
+
"returnsCall",
|
|
1896
|
+
[v("f"), v("c")],
|
|
1897
|
+
[lit("returnsValue", v("f"), v("v")), lit("isWrittenAs", v("v"), v("c"))]
|
|
1898
|
+
),
|
|
1231
1899
|
// What one call site put in a parameter, told apart from what the
|
|
1232
1900
|
// other callers passed.
|
|
1233
1901
|
rule(
|
|
@@ -1325,18 +1993,34 @@ var RESOLUTION_RULES = [
|
|
|
1325
1993
|
[v("x"), v("obj")],
|
|
1326
1994
|
[lit("givesBack", v("x"), v("obj")), lit("objectValue", v("obj"))]
|
|
1327
1995
|
),
|
|
1996
|
+
// A construction is the object it made, and so is any name for it.
|
|
1997
|
+
// The class stays an answer too, so an instance whose site is not in
|
|
1998
|
+
// the run still reads what the class stores.
|
|
1999
|
+
rule(
|
|
2000
|
+
"objectOf",
|
|
2001
|
+
[v("site"), v("site")],
|
|
2002
|
+
[lit("allocates", v("site"), v("c"))]
|
|
2003
|
+
),
|
|
2004
|
+
rule(
|
|
2005
|
+
"objectOf",
|
|
2006
|
+
[v("o"), v("site")],
|
|
2007
|
+
[
|
|
2008
|
+
lit("reaches", v("o"), v("site"), VALUE_STEP),
|
|
2009
|
+
lit("allocates", v("site"), v("c"))
|
|
2010
|
+
]
|
|
2011
|
+
),
|
|
1328
2012
|
// Which calls a function, found by the name the call is written as
|
|
1329
2013
|
// rather than by resolving every callee in the project. A caller knows
|
|
1330
2014
|
// the function and wants its call sites, so both of these start from
|
|
1331
2015
|
// the function. Starting from `call` instead asks what every call in
|
|
1332
2016
|
// the project imports, which was 72% of everything derived.
|
|
1333
2017
|
rule(
|
|
1334
|
-
"
|
|
2018
|
+
"callsNamed",
|
|
1335
2019
|
[v("r"), v("f")],
|
|
1336
2020
|
[lit("binds", v("c"), v("f")), lit("call", v("r"), v("c"))]
|
|
1337
2021
|
),
|
|
1338
2022
|
rule(
|
|
1339
|
-
"
|
|
2023
|
+
"callsNamed",
|
|
1340
2024
|
[v("r"), v("f")],
|
|
1341
2025
|
[
|
|
1342
2026
|
lit("moduleExport", v("m"), v("n"), v("f")),
|
|
@@ -1347,7 +2031,7 @@ var RESOLUTION_RULES = [
|
|
|
1347
2031
|
// The same, for a language whose adapter writes the import down as a
|
|
1348
2032
|
// declaration and the call's callee as the name referring to it.
|
|
1349
2033
|
rule(
|
|
1350
|
-
"
|
|
2034
|
+
"callsNamed",
|
|
1351
2035
|
[v("r"), v("f")],
|
|
1352
2036
|
[
|
|
1353
2037
|
lit("moduleExport", v("m"), v("n"), v("f")),
|
|
@@ -1356,6 +2040,62 @@ var RESOLUTION_RULES = [
|
|
|
1356
2040
|
lit("call", v("r"), v("c"))
|
|
1357
2041
|
]
|
|
1358
2042
|
),
|
|
2043
|
+
// `const f = (x) => ...` declares the name and puts the parameters on
|
|
2044
|
+
// the arrow, so everything above arrives at the declaration and
|
|
2045
|
+
// `paramOf` is about the arrow. One binds hop joins the two.
|
|
2046
|
+
rule(
|
|
2047
|
+
"callsNamed",
|
|
2048
|
+
[v("r"), v("f")],
|
|
2049
|
+
[lit("binds", v("g"), v("f")), lit("callsNamed", v("r"), v("g"))]
|
|
2050
|
+
),
|
|
2051
|
+
// Every one of those, and the binds hop again over the whole
|
|
2052
|
+
// relation, so a property holding a name for a function is reached
|
|
2053
|
+
// the way it was before the two were told apart.
|
|
2054
|
+
rule("callsFunction", [v("r"), v("f")], [lit("callsNamed", v("r"), v("f"))]),
|
|
2055
|
+
rule(
|
|
2056
|
+
"callsFunction",
|
|
2057
|
+
[v("r"), v("f")],
|
|
2058
|
+
[lit("binds", v("g"), v("f")), lit("callsFunction", v("r"), v("g"))]
|
|
2059
|
+
),
|
|
2060
|
+
// A function written on an object, called off it: `client.get(o)`.
|
|
2061
|
+
// The receiver comes from the object through `refersToObject`, not from
|
|
2062
|
+
// `objectOf`: a walk from every reader of the name was most of a run.
|
|
2063
|
+
rule(
|
|
2064
|
+
"callsFunction",
|
|
2065
|
+
[v("r"), v("f")],
|
|
2066
|
+
[
|
|
2067
|
+
lit("holdsProperty", v("obj"), v("n"), v("f")),
|
|
2068
|
+
lit("refersToObject", v("o"), v("obj")),
|
|
2069
|
+
lit("readsProperty", v("c"), v("o"), v("n")),
|
|
2070
|
+
lit("call", v("r"), v("c"))
|
|
2071
|
+
]
|
|
2072
|
+
),
|
|
2073
|
+
// The expressions that refer to an object literal by binding alone: the
|
|
2074
|
+
// declaration written as it, a reference or import of that, and a
|
|
2075
|
+
// fallback over any of those. Asked from the object, so it visits only them.
|
|
2076
|
+
rule("refersToObject", [v("obj"), v("obj")], [lit("objectValue", v("obj"))]),
|
|
2077
|
+
rule(
|
|
2078
|
+
"refersToObject",
|
|
2079
|
+
[v("x"), v("obj")],
|
|
2080
|
+
[lit("refersToObject", v("y"), v("obj")), lit("binds", v("x"), v("y"))]
|
|
2081
|
+
),
|
|
2082
|
+
rule(
|
|
2083
|
+
"refersToObject",
|
|
2084
|
+
[v("x"), v("obj")],
|
|
2085
|
+
[
|
|
2086
|
+
lit("refersToObject", v("y"), v("obj")),
|
|
2087
|
+
lit("moduleExport", v("m"), v("n"), v("y")),
|
|
2088
|
+
lit("imports", v("x"), v("m"), v("n"))
|
|
2089
|
+
]
|
|
2090
|
+
),
|
|
2091
|
+
rule(
|
|
2092
|
+
"refersToObject",
|
|
2093
|
+
[v("x"), v("obj")],
|
|
2094
|
+
[
|
|
2095
|
+
lit("refersToObject", v("b"), v("obj")),
|
|
2096
|
+
lit("fallbackBranch", v("x"), v("b"))
|
|
2097
|
+
]
|
|
2098
|
+
),
|
|
1359
2099
|
// What an object contains, its base class included, so a method the base
|
|
1360
2100
|
// declares is found on a subclass that never overrode it. A method both
|
|
1361
2101
|
// declare gives two, and the caller decides. This is its own relation
|
|
@@ -1373,7 +2113,8 @@ var RESOLUTION_RULES = [
|
|
|
1373
2113
|
lit("extends", v("cls"), v("base")),
|
|
1374
2114
|
lit("comesTo", v("base"), v("baseCls")),
|
|
1375
2115
|
lit("contains", v("baseCls"), v("n"), v("held"))
|
|
1376
|
-
]
|
|
2116
|
+
],
|
|
2117
|
+
BASE_CLASS_RULE
|
|
1377
2118
|
),
|
|
1378
2119
|
// An association is read off an instance as a property, and stating
|
|
1379
2120
|
// it as `contains` is what puts it on the ancestry rule, so a concern
|
|
@@ -1397,6 +2138,69 @@ var RESOLUTION_RULES = [
|
|
|
1397
2138
|
],
|
|
1398
2139
|
"constructed association"
|
|
1399
2140
|
),
|
|
2141
|
+
// What the constructor put on the receiver. The class is the object
|
|
2142
|
+
// for an instance whose own site is not in the run.
|
|
2143
|
+
rule(
|
|
2144
|
+
"contains",
|
|
2145
|
+
[v("cls"), v("n"), v("held")],
|
|
2146
|
+
[
|
|
2147
|
+
lit("initializes", v("cls"), v("f")),
|
|
2148
|
+
lit("storesProperty", v("f"), v("n"), v("held"))
|
|
2149
|
+
],
|
|
2150
|
+
"constructor store"
|
|
2151
|
+
),
|
|
2152
|
+
// What any other method of the class put there. Two methods writing
|
|
2153
|
+
// one name give two rows, since nothing here orders them.
|
|
2154
|
+
rule(
|
|
2155
|
+
"contains",
|
|
2156
|
+
[v("cls"), v("n"), v("held")],
|
|
2157
|
+
[
|
|
2158
|
+
lit("holdsProperty", v("cls"), v("m"), v("f")),
|
|
2159
|
+
lit("storesProperty", v("f"), v("n"), v("held"))
|
|
2160
|
+
],
|
|
2161
|
+
"method store"
|
|
2162
|
+
),
|
|
2163
|
+
// A write through a name rather than through the receiver,
|
|
2164
|
+
// `client.timeout = 5`, which lands on whatever that name refers to.
|
|
2165
|
+
rule(
|
|
2166
|
+
"contains",
|
|
2167
|
+
[v("obj"), v("n"), v("held")],
|
|
2168
|
+
[
|
|
2169
|
+
lit("storesProperty", v("r"), v("n"), v("held")),
|
|
2170
|
+
lit("objectOf", v("r"), v("obj"))
|
|
2171
|
+
],
|
|
2172
|
+
"named receiver store"
|
|
2173
|
+
),
|
|
2174
|
+
// A call written with a class's own name, which is how most languages
|
|
2175
|
+
// spell a construction. A language that spells one some other way
|
|
2176
|
+
// states its own rule for this, the way Ruby does for `Const.new`.
|
|
2177
|
+
rule(
|
|
2178
|
+
"constructsNamed",
|
|
2179
|
+
[v("r"), v("cls")],
|
|
2180
|
+
[lit("objectValue", v("cls")), lit("callsNamed", v("r"), v("cls"))]
|
|
2181
|
+
),
|
|
2182
|
+
// Each construction is an object of its own containing what its
|
|
2183
|
+
// class stores, so two sites are two objects.
|
|
2184
|
+
rule(
|
|
2185
|
+
"contains",
|
|
2186
|
+
[v("site"), v("n"), v("held")],
|
|
2187
|
+
[
|
|
2188
|
+
lit("allocates", v("site"), v("cls")),
|
|
2189
|
+
lit("contains", v("cls"), v("n"), v("held"))
|
|
2190
|
+
],
|
|
2191
|
+
"allocated instance"
|
|
2192
|
+
),
|
|
2193
|
+
// A call that makes one of a class. Every finder a pack declared is
|
|
2194
|
+
// one too, so `User.find(1)` is a site the same way `User.new` is.
|
|
2195
|
+
rule(
|
|
2196
|
+
"allocates",
|
|
2197
|
+
[v("site"), v("cls")],
|
|
2198
|
+
[
|
|
2199
|
+
lit("call", v("site"), v("c")),
|
|
2200
|
+
lit("stepsTo", v("site"), v("cls"), INSTANCE_STEP)
|
|
2201
|
+
],
|
|
2202
|
+
"allocation site"
|
|
2203
|
+
),
|
|
1400
2204
|
// The library base a class's ancestry arrives at, however many of a
|
|
1401
2205
|
// project's own classes sit in between. A base the run declares has a
|
|
1402
2206
|
// node to keep walking from; one it does not has only a name.
|
|
@@ -1486,8 +2290,8 @@ var RESOLUTION_RULES = [
|
|
|
1486
2290
|
]
|
|
1487
2291
|
),
|
|
1488
2292
|
// Where a name comes from, when what it refers to lives outside the
|
|
1489
|
-
// source being read. A walk ends at
|
|
1490
|
-
//
|
|
2293
|
+
// source being read. A walk ends at what the source writes out, so it
|
|
2294
|
+
// never reaches a library's own function; these rules do.
|
|
1491
2295
|
rule(
|
|
1492
2296
|
"comesFrom",
|
|
1493
2297
|
[v("x"), v("m"), v("n")],
|
|
@@ -1501,6 +2305,28 @@ var RESOLUTION_RULES = [
|
|
|
1501
2305
|
lit("imports", v("y"), v("m"), v("n"))
|
|
1502
2306
|
]
|
|
1503
2307
|
),
|
|
2308
|
+
// A member read off a whole-module import: the member's own name is
|
|
2309
|
+
// what the module exports, so `fastapi.APIRouter` comes from
|
|
2310
|
+
// fastapi's `APIRouter`. Directly, or through a name for the module.
|
|
2311
|
+
rule(
|
|
2312
|
+
"comesFrom",
|
|
2313
|
+
[v("x"), v("m"), v("n")],
|
|
2314
|
+
[
|
|
2315
|
+
lit("readsProperty", v("x"), v("ns"), v("n")),
|
|
2316
|
+
lit("imports", v("ns"), v("m"), NAMESPACE_IMPORT)
|
|
2317
|
+
],
|
|
2318
|
+
NAMESPACE_MEMBER_RULE
|
|
2319
|
+
),
|
|
2320
|
+
rule(
|
|
2321
|
+
"comesFrom",
|
|
2322
|
+
[v("x"), v("m"), v("n")],
|
|
2323
|
+
[
|
|
2324
|
+
lit("readsProperty", v("x"), v("o"), v("n")),
|
|
2325
|
+
lit("reaches", v("o"), v("ns"), VALUE_STEP),
|
|
2326
|
+
lit("imports", v("ns"), v("m"), NAMESPACE_IMPORT)
|
|
2327
|
+
],
|
|
2328
|
+
NAMESPACE_MEMBER_RULE
|
|
2329
|
+
),
|
|
1504
2330
|
// Calling f ends up calling the name n that module m exports, one
|
|
1505
2331
|
// hop through f's own body or deeper through a wrapper of a wrapper.
|
|
1506
2332
|
// Several results is normal: a composed decorator applies them all.
|
|
@@ -1530,6 +2356,13 @@ var RESOLUTION_RULES = [
|
|
|
1530
2356
|
[lit("comesTo", v("x"), v("z")), lit("func", v("z"))]
|
|
1531
2357
|
)
|
|
1532
2358
|
];
|
|
2359
|
+
function alsoSteps(rules) {
|
|
2360
|
+
return [
|
|
2361
|
+
...rules,
|
|
2362
|
+
...rules.filter((r) => r.head.relation === "hop").map((r) => ({ ...r, head: { ...r.head, relation: "stepsTo" } }))
|
|
2363
|
+
];
|
|
2364
|
+
}
|
|
2365
|
+
var RESOLUTION_RULES = alsoSteps(STATED_RULES);
|
|
1533
2366
|
var RESOLUTION_QUESTIONS = [
|
|
1534
2367
|
rule(
|
|
1535
2368
|
"wantedResolves",
|
|
@@ -1552,12 +2385,55 @@ var RESOLUTION_QUESTIONS = [
|
|
|
1552
2385
|
[lit("wanted", v("x")), lit("isWrittenAs", v("x"), v("z"))]
|
|
1553
2386
|
),
|
|
1554
2387
|
// A call is given no `comesTo`, so this is the only way to ask what
|
|
1555
|
-
// object one arrives at, and
|
|
1556
|
-
//
|
|
2388
|
+
// object one arrives at, and a demand-driven run derives `objectOf`
|
|
2389
|
+
// nowhere without it. An allocation site is not one of the answers.
|
|
1557
2390
|
rule(
|
|
1558
2391
|
"wantedObjectOf",
|
|
1559
2392
|
[v("x"), v("z")],
|
|
1560
|
-
[
|
|
2393
|
+
[
|
|
2394
|
+
lit("wanted", v("x")),
|
|
2395
|
+
lit("objectOf", v("x"), v("z")),
|
|
2396
|
+
lit("objectValue", v("z"))
|
|
2397
|
+
]
|
|
2398
|
+
),
|
|
2399
|
+
// The same three questions under one allocation site, keyed by the
|
|
2400
|
+
// value and the site both. An allocation site is an answer here,
|
|
2401
|
+
// unlike `wantedObjectOf`, since a site is what a context is.
|
|
2402
|
+
rule(
|
|
2403
|
+
"wantedIsWrittenAsUnder",
|
|
2404
|
+
[v("x"), v("c"), v("z")],
|
|
2405
|
+
[
|
|
2406
|
+
lit("wantedUnder", v("x"), v("c")),
|
|
2407
|
+
lit("isWrittenAsUnder", v("x"), v("c"), v("z"))
|
|
2408
|
+
]
|
|
2409
|
+
),
|
|
2410
|
+
// Where a class was made, for a caller about to ask a value question
|
|
2411
|
+
// under each. Going through `constructsNamed` keeps the demand on the
|
|
2412
|
+
// calls written with the class's name rather than on every call.
|
|
2413
|
+
rule(
|
|
2414
|
+
"wantedAllocatedAt",
|
|
2415
|
+
[v("cls"), v("site")],
|
|
2416
|
+
[
|
|
2417
|
+
lit("wantedSites", v("cls")),
|
|
2418
|
+
lit("constructsNamed", v("site"), v("cls")),
|
|
2419
|
+
lit("allocates", v("site"), v("cls"))
|
|
2420
|
+
]
|
|
2421
|
+
),
|
|
2422
|
+
rule(
|
|
2423
|
+
"wantedComesToUnder",
|
|
2424
|
+
[v("x"), v("c"), v("z")],
|
|
2425
|
+
[
|
|
2426
|
+
lit("wantedUnder", v("x"), v("c")),
|
|
2427
|
+
lit("comesToUnder", v("x"), v("c"), v("z"))
|
|
2428
|
+
]
|
|
2429
|
+
),
|
|
2430
|
+
rule(
|
|
2431
|
+
"wantedObjectOfUnder",
|
|
2432
|
+
[v("x"), v("c"), v("z")],
|
|
2433
|
+
[
|
|
2434
|
+
lit("wantedUnder", v("x"), v("c")),
|
|
2435
|
+
lit("objectOfUnder", v("x"), v("c"), v("z"))
|
|
2436
|
+
]
|
|
1561
2437
|
),
|
|
1562
2438
|
// The same for the function a call returns: `app.use(requireCaller(config))`
|
|
1563
2439
|
// registers what the factory gives back, and `resolves` on the call
|
|
@@ -1574,6 +2450,19 @@ var RESOLUTION_QUESTIONS = [
|
|
|
1574
2450
|
[v("p"), v("r"), v("z")],
|
|
1575
2451
|
[lit("wanted", v("p")), lit("paramAt", v("r"), v("p"), v("z"))]
|
|
1576
2452
|
),
|
|
2453
|
+
// The argument as the caller wrote it. A parameter given a GraphQL
|
|
2454
|
+
// document has no `paramAt` answer, since that settles through
|
|
2455
|
+
// `comesTo`, which stops at a function or an object.
|
|
2456
|
+
rule(
|
|
2457
|
+
"wantedPassesArgument",
|
|
2458
|
+
[v("p"), v("r"), v("a")],
|
|
2459
|
+
[lit("wanted", v("p")), lit("passesArgument", v("r"), v("p"), v("a"))]
|
|
2460
|
+
),
|
|
2461
|
+
rule(
|
|
2462
|
+
"wantedReturnsCall",
|
|
2463
|
+
[v("f"), v("c")],
|
|
2464
|
+
[lit("wanted", v("f")), lit("returnsCall", v("f"), v("c"))]
|
|
2465
|
+
),
|
|
1577
2466
|
rule(
|
|
1578
2467
|
"wantedComesFrom",
|
|
1579
2468
|
[v("x"), v("m"), v("n")],
|
|
@@ -1837,35 +2726,61 @@ var RESOLUTION_QUESTIONS = [
|
|
|
1837
2726
|
var ANSWER_RELATIONS = [
|
|
1838
2727
|
...new Set(RESOLUTION_QUESTIONS.map((r) => r.head.relation))
|
|
1839
2728
|
];
|
|
2729
|
+
var UNDER_ANSWER_RELATIONS = [
|
|
2730
|
+
"wantedIsWrittenAsUnder",
|
|
2731
|
+
"wantedComesToUnder",
|
|
2732
|
+
"wantedObjectOfUnder"
|
|
2733
|
+
];
|
|
1840
2734
|
export {
|
|
1841
2735
|
ANSWER_RELATIONS,
|
|
1842
2736
|
ASKING_RELATIONS,
|
|
2737
|
+
BASE_CLASS_RULE,
|
|
1843
2738
|
FACT_CONTRACT_CASES,
|
|
2739
|
+
INSTANCE_STEP,
|
|
1844
2740
|
NAMESPACE_IMPORT,
|
|
1845
2741
|
NAMESPACE_IMPORT_NAME,
|
|
2742
|
+
NAMESPACE_MEMBER_RULE,
|
|
2743
|
+
NO_CONTEXT,
|
|
2744
|
+
NO_CONTEXT_NAME,
|
|
1846
2745
|
RESOLUTION_QUESTIONS,
|
|
1847
2746
|
RESOLUTION_RULES,
|
|
1848
2747
|
RESULT_STEP,
|
|
2748
|
+
UNDER_ANSWER_RELATIONS,
|
|
2749
|
+
UNDER_QUESTION_ROW_BUDGET,
|
|
2750
|
+
UNDER_RUN_ROW_BUDGET,
|
|
1849
2751
|
VALUE_STEP,
|
|
2752
|
+
addPackWords,
|
|
1850
2753
|
agreedMountPrefix,
|
|
2754
|
+
allocationSitesOf,
|
|
2755
|
+
alsoSteps,
|
|
2756
|
+
answersByKey,
|
|
1851
2757
|
askResolution,
|
|
2758
|
+
askResolutionUnder,
|
|
1852
2759
|
calleeOutcomeOf,
|
|
1853
2760
|
calleeOutcomes,
|
|
1854
2761
|
checkFactContract,
|
|
2762
|
+
comesToUnder,
|
|
1855
2763
|
couldBeSettled,
|
|
1856
2764
|
explainResolutionProof,
|
|
1857
2765
|
explainResolvedKey,
|
|
2766
|
+
isWrittenAsUnder,
|
|
1858
2767
|
joinMountedPath,
|
|
1859
2768
|
mountPathsOf,
|
|
1860
2769
|
nodeOfKey,
|
|
2770
|
+
objectOfUnder,
|
|
1861
2771
|
placeholderValues,
|
|
1862
2772
|
queryFacts,
|
|
1863
2773
|
renderExplanation,
|
|
1864
2774
|
resolutionProgram,
|
|
2775
|
+
resolutionUnderProgram,
|
|
1865
2776
|
singleAnswers,
|
|
1866
2777
|
startsAtName,
|
|
2778
|
+
underQuestionSpend,
|
|
1867
2779
|
valueLeftByWrites,
|
|
1868
2780
|
writesRunInOrder,
|
|
1869
2781
|
writtenSourcesOf,
|
|
1870
|
-
writtenValueOf
|
|
2782
|
+
writtenValueOf,
|
|
2783
|
+
writtenValueUnder,
|
|
2784
|
+
writtenValuesByKey,
|
|
2785
|
+
writtenValuesOf
|
|
1871
2786
|
};
|