@lcap/nasl-language-server-core 4.0.1-rc.0 → 4.0.1-rc.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/README.md +85 -0
- package/out/checker.d.ts.map +1 -1
- package/out/checker.js +28 -13
- package/out/checker.js.map +1 -1
- package/out/index.d.ts +2 -1
- package/out/index.d.ts.map +1 -1
- package/out/index.js +2 -1
- package/out/index.js.map +1 -1
- package/out/query/context-variable-query.d.ts +31 -0
- package/out/query/context-variable-query.d.ts.map +1 -0
- package/out/query/context-variable-query.js +105 -0
- package/out/query/context-variable-query.js.map +1 -0
- package/out/query/index.d.ts +2 -0
- package/out/query/index.d.ts.map +1 -0
- package/out/query/index.js +18 -0
- package/out/query/index.js.map +1 -0
- package/out/reference-manager/builtin-q-name.d.ts +1 -1
- package/out/reference-manager/builtin-q-name.d.ts.map +1 -1
- package/out/reference-manager/builtin-q-name.js +2 -2
- package/out/reference-manager/builtin-q-name.js.map +1 -1
- package/out/reference-manager/collect-q-name.d.ts +2 -1
- package/out/reference-manager/collect-q-name.d.ts.map +1 -1
- package/out/reference-manager/collect-q-name.js +8 -4
- package/out/reference-manager/collect-q-name.js.map +1 -1
- package/out/reference-manager/get-q-name.d.ts +1 -1
- package/out/reference-manager/get-q-name.d.ts.map +1 -1
- package/out/reference-manager/get-q-name.js +35 -31
- package/out/reference-manager/get-q-name.js.map +1 -1
- package/out/reference-manager/reference-manager.d.ts +6 -7
- package/out/reference-manager/reference-manager.d.ts.map +1 -1
- package/out/reference-manager/reference-manager.js +7 -6
- package/out/reference-manager/reference-manager.js.map +1 -1
- package/out/reference-manager/remove-q-name.d.ts +30 -28
- package/out/reference-manager/remove-q-name.d.ts.map +1 -1
- package/out/reference-manager/remove-q-name.js +54 -47
- package/out/reference-manager/remove-q-name.js.map +1 -1
- package/out/reference-manager/rename-q-name.d.ts +2 -1
- package/out/reference-manager/rename-q-name.d.ts.map +1 -1
- package/out/reference-manager/rename-q-name.js +31 -36
- package/out/reference-manager/rename-q-name.js.map +1 -1
- package/out/reference-manager/symbol-type.d.ts +2 -2
- package/out/reference-manager/symbol-type.d.ts.map +1 -1
- package/out/reference-manager/symbol-type.js +1 -1
- package/out/reference-manager/symbol-type.js.map +1 -1
- package/out/reference-manager/update-nasl-fragment.d.ts +2 -1
- package/out/reference-manager/update-nasl-fragment.d.ts.map +1 -1
- package/out/reference-manager/update-nasl-fragment.js +9 -1
- package/out/reference-manager/update-nasl-fragment.js.map +1 -1
- package/out/typer/collectGlobalDefs.d.ts.map +1 -1
- package/out/typer/collectGlobalDefs.js.map +1 -1
- package/out/typer/component-def-manager/component-def-manager.d.ts +32 -5
- package/out/typer/component-def-manager/component-def-manager.d.ts.map +1 -1
- package/out/typer/component-def-manager/component-def-manager.js +96 -19
- package/out/typer/component-def-manager/component-def-manager.js.map +1 -1
- package/out/typer/component-def-manager/utils.d.ts.map +1 -1
- package/out/typer/component-def-manager/utils.js +39 -12
- package/out/typer/component-def-manager/utils.js.map +1 -1
- package/out/typer/dispatch-all.d.ts +1 -1
- package/out/typer/dispatch-all.d.ts.map +1 -1
- package/out/typer/dispatch-all.js +3 -7
- package/out/typer/dispatch-all.js.map +1 -1
- package/out/typer/dispatch-def.d.ts +1 -1
- package/out/typer/dispatch-def.d.ts.map +1 -1
- package/out/typer/dispatch-def.js +7 -5
- package/out/typer/dispatch-def.js.map +1 -1
- package/out/typer/dispatch-expr.d.ts +1 -1
- package/out/typer/dispatch-expr.d.ts.map +1 -1
- package/out/typer/dispatch-expr.js +28 -14
- package/out/typer/dispatch-expr.js.map +1 -1
- package/out/typer/dispatch-stmt.d.ts.map +1 -1
- package/out/typer/dispatch-stmt.js +10 -1
- package/out/typer/dispatch-stmt.js.map +1 -1
- package/out/typer/dispatch-view.d.ts.map +1 -1
- package/out/typer/dispatch-view.js +115 -115
- package/out/typer/dispatch-view.js.map +1 -1
- package/out/typer/helper.js +3 -3
- package/out/typer/helper.js.map +1 -1
- package/out/typer/incremental-update.d.ts +15 -13
- package/out/typer/incremental-update.d.ts.map +1 -1
- package/out/typer/incremental-update.js +89 -42
- package/out/typer/incremental-update.js.map +1 -1
- package/out/typer/nasl-predicate.d.ts +1 -1
- package/out/typer/nasl-predicate.d.ts.map +1 -1
- package/out/typer/solver.d.ts +37 -24
- package/out/typer/solver.d.ts.map +1 -1
- package/out/typer/solver.js +205 -426
- package/out/typer/solver.js.map +1 -1
- package/out/typer/subster.d.ts +2 -4
- package/out/typer/subster.d.ts.map +1 -1
- package/out/typer/subster.js +42 -34
- package/out/typer/subster.js.map +1 -1
- package/out/typer/topo-sort.d.ts.map +1 -1
- package/out/typer/topo-sort.js +9 -2
- package/out/typer/topo-sort.js.map +1 -1
- package/out/typer/type-hint-manager/type-hint-manager.d.ts +3 -0
- package/out/typer/type-hint-manager/type-hint-manager.d.ts.map +1 -1
- package/out/typer/type-hint-manager/type-hint-manager.js +2 -0
- package/out/typer/type-hint-manager/type-hint-manager.js.map +1 -1
- package/out/typer/type-manager.d.ts +6 -2
- package/out/typer/type-manager.d.ts.map +1 -1
- package/out/typer/type-manager.js.map +1 -1
- package/out/typer/type-predicate.d.ts.map +1 -1
- package/out/typer/type-predicate.js +61 -6
- package/out/typer/type-predicate.js.map +1 -1
- package/out/typer/typer.d.ts +10 -5
- package/out/typer/typer.d.ts.map +1 -1
- package/out/typer/typer.js +34 -60
- package/out/typer/typer.js.map +1 -1
- package/out/typer/unifier.d.ts +0 -3
- package/out/typer/unifier.d.ts.map +1 -1
- package/out/typer/unifier.js +58 -35
- package/out/typer/unifier.js.map +1 -1
- package/out/utils/nasl-type-manipulation.d.ts +1 -0
- package/out/utils/nasl-type-manipulation.d.ts.map +1 -1
- package/out/utils/nasl-type-manipulation.js +3 -1
- package/out/utils/nasl-type-manipulation.js.map +1 -1
- package/out/utils/parseTsClassType.d.ts.map +1 -1
- package/out/utils/parseTsClassType.js +7 -3
- package/out/utils/parseTsClassType.js.map +1 -1
- package/out/utils/type-operator.d.ts.map +1 -1
- package/out/utils/type-operator.js.map +1 -1
- package/package.json +13 -6
package/out/typer/solver.js
CHANGED
|
@@ -2,28 +2,29 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.printBounds = exports.Solver = void 0;
|
|
4
4
|
const index_1 = require("./index");
|
|
5
|
-
const
|
|
5
|
+
const typer_1 = require("./typer");
|
|
6
|
+
const sem_diag_1 = require("./sem-diag");
|
|
6
7
|
const helper_1 = require("./helper");
|
|
7
8
|
const subster_1 = require("./subster");
|
|
8
9
|
const type_predicate_1 = require("./type-predicate");
|
|
9
10
|
const type_manager_1 = require("./type-manager");
|
|
10
11
|
const type_predicate_2 = require("./type-predicate");
|
|
11
|
-
const type_predicate_3 = require("./type-predicate");
|
|
12
12
|
function collectCandidateBounds(bounds) {
|
|
13
13
|
const allBounds = [...bounds.lb, ...bounds.ub];
|
|
14
14
|
return allBounds.filter(x => {
|
|
15
15
|
// @ts-expect-error FIXME
|
|
16
|
-
return !x.ignored;
|
|
17
|
-
});
|
|
16
|
+
return !x.bound.ignored;
|
|
17
|
+
}).map(x => x.bound);
|
|
18
18
|
}
|
|
19
19
|
class Solver {
|
|
20
20
|
constructor(env) {
|
|
21
21
|
// 没有子类型,除了数值外几乎都是 equal 就行,似乎不需要使用 SCC 这种找依赖链路的复杂求解了……
|
|
22
22
|
this.simpleSolveConstraints = (cs0 = this.cs) => {
|
|
23
23
|
const subst = new Map();
|
|
24
|
+
// topoSort 会做浅拷贝
|
|
24
25
|
const cs = this.topoSortTyVars(cs0);
|
|
25
26
|
let newInfo = false;
|
|
26
|
-
// Stage 1: 首先从下界和上界寻找非
|
|
27
|
+
// Stage 1: 首先从下界和上界寻找非 any 的具体类型,优先处理数值类型
|
|
27
28
|
const targetTV = "";
|
|
28
29
|
const stop = targetTV
|
|
29
30
|
? (x) => {
|
|
@@ -36,41 +37,39 @@ class Solver {
|
|
|
36
37
|
const str = (0, helper_1.showConstraints)(cs);
|
|
37
38
|
console.log(str);
|
|
38
39
|
}
|
|
39
|
-
for (
|
|
40
|
+
for (const [tyVar, rawBounds] of cs.entries()) {
|
|
40
41
|
const deref = (subst, bounds) => {
|
|
41
42
|
const pSubst = (0, subster_1.inPlaceSubstTyAnn)(this.env, subst);
|
|
42
43
|
for (let i = 0; i < bounds.lb.length; i++) {
|
|
43
|
-
bounds.lb[i] = pSubst(bounds.lb[i]);
|
|
44
|
+
bounds.lb[i] = { bound: pSubst(bounds.lb[i].bound), boundary: bounds.lb[i].boundary, fromPlayground: bounds.lb[i].fromPlayground };
|
|
44
45
|
}
|
|
45
46
|
for (let i = 0; i < bounds.ub.length; i++) {
|
|
46
|
-
bounds.ub[i] = pSubst(bounds.ub[i]);
|
|
47
|
+
bounds.ub[i] = { bound: pSubst(bounds.ub[i].bound), boundary: bounds.ub[i].boundary, fromPlayground: bounds.ub[i].fromPlayground };
|
|
47
48
|
}
|
|
48
49
|
return bounds;
|
|
49
50
|
};
|
|
50
51
|
if (stop(tyVar)) {
|
|
51
52
|
printBounds(rawBounds);
|
|
52
53
|
}
|
|
53
|
-
function
|
|
54
|
+
function keepValidCandidateInBounds(bounds) {
|
|
54
55
|
return new index_1.Bounds(bounds.lb.filter((x) => {
|
|
55
56
|
// @ts-expect-error
|
|
56
|
-
return !x.ignored;
|
|
57
|
+
return !x.bound.ignored;
|
|
57
58
|
}), bounds.ub.filter((x) => {
|
|
58
59
|
// @ts-expect-error
|
|
59
|
-
return !x.ignored;
|
|
60
|
+
return !x.bound.ignored;
|
|
60
61
|
}));
|
|
61
62
|
}
|
|
62
|
-
const validBounds =
|
|
63
|
+
const validBounds = keepValidCandidateInBounds(rawBounds);
|
|
63
64
|
const derefedBounds = deref(subst, validBounds);
|
|
64
65
|
if (stop(tyVar)) {
|
|
65
66
|
printBounds(derefedBounds);
|
|
66
67
|
debugger;
|
|
67
68
|
}
|
|
68
69
|
// FIXME wudengke 这里hack了一下,需要justify。
|
|
69
|
-
// 之所以对current变量直接使用下界和上界,是因为它上下界中那些预期被选中的候选因为包含有类型变元而被
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
: this.getConcreteTysFromBoundsPriority1(derefedBounds, subst) ?? [];
|
|
73
|
-
const concreteTys = rawConcreteTys;
|
|
70
|
+
// 之所以对current变量直接使用下界和上界,是因为它上下界中那些预期被选中的候选因为包含有类型变元而被getConcreteTysFromBoundsPriority排除
|
|
71
|
+
// HACK: 下界优先选 union,上界优先选非 union
|
|
72
|
+
const concreteTys = this.getConcreteTys(derefedBounds, subst, tyVar.startsWith('Tp_current_of')) ?? [];
|
|
74
73
|
concreteTys.forEach((concreteTy) => {
|
|
75
74
|
const res = this.addToSubstAndCheck(tyVar, concreteTy, subst);
|
|
76
75
|
if (stop(tyVar)) {
|
|
@@ -98,31 +97,6 @@ class Solver {
|
|
|
98
97
|
newInfo = false;
|
|
99
98
|
}
|
|
100
99
|
} while (newInfo);
|
|
101
|
-
// Stage 2: 从所有界寻找包括 union 和 any 的类型
|
|
102
|
-
do {
|
|
103
|
-
let oldSize = subst.size;
|
|
104
|
-
for (let [tyVar, bounds] of cs.entries()) {
|
|
105
|
-
const concreteTys = this.getConcreteTysFromBoundsPriority2(bounds, subst);
|
|
106
|
-
concreteTys?.forEach(concreteTy => {
|
|
107
|
-
const res = this.addToSubstAndCheck(tyVar, concreteTy, subst);
|
|
108
|
-
if (stop(tyVar)) {
|
|
109
|
-
const msg = res ? `stage 2, addToSubstAndCheck: 更新 ${(0, type_manager_1.showType)(concreteTy)}` : `stage 2, addToSubstAndCheck: 未更新 ${(0, type_manager_1.showType)(concreteTy)}`;
|
|
110
|
-
this.env.unifier.trace(targetTV, msg);
|
|
111
|
-
}
|
|
112
|
-
});
|
|
113
|
-
// @ts-expect-error
|
|
114
|
-
if (concreteTys?.length || concreteTys?.size) {
|
|
115
|
-
cs.delete(tyVar);
|
|
116
|
-
}
|
|
117
|
-
}
|
|
118
|
-
if (subst.size > oldSize) {
|
|
119
|
-
this.inPlaceSubstConstraints(subst, cs);
|
|
120
|
-
newInfo = true;
|
|
121
|
-
}
|
|
122
|
-
else {
|
|
123
|
-
newInfo = false;
|
|
124
|
-
}
|
|
125
|
-
} while (newInfo);
|
|
126
100
|
// TODO FIXME: zirun 紧急fix:对 subst 再代换一次,解决大部分问题,但是速度受影响,尽早修复
|
|
127
101
|
this.substSubst(subst);
|
|
128
102
|
this.subst = subst;
|
|
@@ -141,7 +115,7 @@ class Solver {
|
|
|
141
115
|
return true;
|
|
142
116
|
}
|
|
143
117
|
// old bound and new bound both cannot be type variables
|
|
144
|
-
if ((0,
|
|
118
|
+
if ((0, type_predicate_2.isNullTy)(newBound)) {
|
|
145
119
|
return false;
|
|
146
120
|
}
|
|
147
121
|
if ((0, index_1.isAnyTy)(newBound)) {
|
|
@@ -154,11 +128,6 @@ class Solver {
|
|
|
154
128
|
if ((0, type_predicate_1.isStructuralSubTy)(this.env, oldBound, newBound)) { // 用老的就行,不用报错。比如老的是 A 而新的是 A | B,其实也是兼容的
|
|
155
129
|
return true;
|
|
156
130
|
}
|
|
157
|
-
// @ts-expect-error FIXME wudengke 确认这里是否要ignore
|
|
158
|
-
if (!(0, type_predicate_2.isUnResolvedTy)(newBound) && !(0, type_predicate_2.isUnResolvedTy)(oldBound) && !newBound.ignored && !oldBound.ignored) {
|
|
159
|
-
// 先屏蔽掉好了
|
|
160
|
-
// this.env.addError(mkIncompatibleBounds(oldBound, newBound));
|
|
161
|
-
}
|
|
162
131
|
return false;
|
|
163
132
|
};
|
|
164
133
|
// in-place substitution
|
|
@@ -166,333 +135,176 @@ class Solver {
|
|
|
166
135
|
const pSubst = (0, subster_1.inPlaceSubstTyAnn)(this.env, subst);
|
|
167
136
|
for (let i = 0; i < constraints.length; i++) {
|
|
168
137
|
const [tyVar, bounds] = constraints[i];
|
|
169
|
-
const newLb = bounds.lb.map(pSubst);
|
|
170
|
-
const newUb = bounds.ub.map(pSubst);
|
|
138
|
+
const newLb = bounds.lb.map(b => ({ bound: pSubst(b.bound), boundary: b.boundary, fromPlayground: b.fromPlayground }));
|
|
139
|
+
const newUb = bounds.ub.map(b => ({ bound: pSubst(b.bound), boundary: b.boundary, fromPlayground: b.fromPlayground }));
|
|
171
140
|
const newBounds = new index_1.Bounds(newLb, newUb);
|
|
172
141
|
constraints[i] = [tyVar, newBounds];
|
|
173
142
|
}
|
|
174
143
|
};
|
|
175
|
-
this.inPlaceSubstConstraints = (subst,
|
|
144
|
+
this.inPlaceSubstConstraints = (subst, cs) => {
|
|
176
145
|
const pSubst = (0, subster_1.inPlaceSubstTyAnn)(this.env, subst);
|
|
177
|
-
for (
|
|
146
|
+
for (const [tyVar, bounds] of cs.entries()) {
|
|
178
147
|
for (let i = 0; i < bounds.lb.length; i++) {
|
|
179
|
-
bounds.lb[i] = pSubst(bounds.lb[i]);
|
|
148
|
+
bounds.lb[i] = { bound: pSubst(bounds.lb[i].bound), boundary: bounds.lb[i].boundary, fromPlayground: bounds.lb[i].fromPlayground };
|
|
180
149
|
}
|
|
181
150
|
for (let i = 0; i < bounds.ub.length; i++) {
|
|
182
|
-
bounds.ub[i] = pSubst(bounds.ub[i]);
|
|
151
|
+
bounds.ub[i] = { bound: pSubst(bounds.ub[i].bound), boundary: bounds.ub[i].boundary, fromPlayground: bounds.ub[i].fromPlayground };
|
|
183
152
|
}
|
|
184
153
|
}
|
|
185
154
|
};
|
|
186
|
-
//
|
|
187
|
-
this.
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
let lbHasNum = false;
|
|
192
|
-
bounds.lb.forEach(ty => {
|
|
193
|
-
if (hasNaslTyParamAnn(ty, subst)) {
|
|
194
|
-
return;
|
|
195
|
-
}
|
|
196
|
-
else if (lbUsefulTys.find(ty2 => (0, type_predicate_1.isSameRefTy)(ty, ty2))) {
|
|
197
|
-
return;
|
|
198
|
-
}
|
|
199
|
-
if ((0, type_predicate_1.isSameRefTy)(ty, index_1.naslLongTy)) {
|
|
200
|
-
lbHasLong = true;
|
|
201
|
-
}
|
|
202
|
-
if ((0, type_predicate_1.isSameRefTy)(ty, index_1.naslDecimalTy)) {
|
|
203
|
-
lbHasDecimal = true;
|
|
204
|
-
}
|
|
205
|
-
if ((0, type_predicate_1.isSameRefTy)(ty, index_1.naslNumTy)) {
|
|
206
|
-
lbHasNum = true;
|
|
207
|
-
}
|
|
208
|
-
lbUsefulTys.push(ty);
|
|
209
|
-
});
|
|
210
|
-
// danger
|
|
211
|
-
if (lbHasDecimal) {
|
|
212
|
-
return [index_1.naslDecimalTy];
|
|
213
|
-
}
|
|
214
|
-
else if (lbHasLong) {
|
|
215
|
-
return [index_1.naslLongTy];
|
|
216
|
-
}
|
|
217
|
-
else if (lbUsefulTys.length === 1 && lbUsefulTys[0].typeName !== 'Number') {
|
|
218
|
-
return Array.from(lbUsefulTys);
|
|
219
|
-
}
|
|
220
|
-
let ubUsefulTys = new Array();
|
|
221
|
-
let ubHasLong = false;
|
|
222
|
-
let ubHasDecimal = false;
|
|
223
|
-
let ubHasNum = false;
|
|
224
|
-
bounds.ub.forEach(ty => {
|
|
225
|
-
if (hasNaslTyParamAnn(ty, subst)) {
|
|
226
|
-
return;
|
|
227
|
-
}
|
|
228
|
-
else if (ubUsefulTys.find(ty2 => (0, type_predicate_1.isSameRefTy)(ty, ty2))) {
|
|
229
|
-
return;
|
|
230
|
-
}
|
|
231
|
-
else if ((0, type_predicate_1.isSameRefTy)(ty, index_1.naslLongTy)) {
|
|
232
|
-
ubHasLong = true;
|
|
233
|
-
}
|
|
234
|
-
else if ((0, type_predicate_1.isSameRefTy)(ty, index_1.naslDecimalTy)) {
|
|
235
|
-
ubHasDecimal = true;
|
|
155
|
+
// Normalize constraints in place after substitution
|
|
156
|
+
this.normalizeConstraintsInPlace = (cs) => {
|
|
157
|
+
for (const [tyVar, bounds] of cs.entries()) {
|
|
158
|
+
for (let i = 0; i < bounds.lb.length; i++) {
|
|
159
|
+
bounds.lb[i] = { bound: (0, typer_1.normalize)(this.env, bounds.lb[i].bound), boundary: bounds.lb[i].boundary, fromPlayground: bounds.lb[i].fromPlayground };
|
|
236
160
|
}
|
|
237
|
-
|
|
238
|
-
|
|
161
|
+
for (let i = 0; i < bounds.ub.length; i++) {
|
|
162
|
+
bounds.ub[i] = { bound: (0, typer_1.normalize)(this.env, bounds.ub[i].bound), boundary: bounds.ub[i].boundary, fromPlayground: bounds.ub[i].fromPlayground };
|
|
239
163
|
}
|
|
240
|
-
ubUsefulTys.push(ty);
|
|
241
|
-
});
|
|
242
|
-
// danger
|
|
243
|
-
if (ubHasLong) {
|
|
244
|
-
return [index_1.naslLongTy];
|
|
245
164
|
}
|
|
246
|
-
|
|
247
|
-
|
|
165
|
+
};
|
|
166
|
+
/**
|
|
167
|
+
* 通用的类型获取策略函数,为不同类型的变量调度合适的策略
|
|
168
|
+
* @param bounds - 类型边界
|
|
169
|
+
* @param subst - 类型替换映射
|
|
170
|
+
* @param incTyVars - pick 时是否包含类型变元
|
|
171
|
+
*/
|
|
172
|
+
this.getConcreteTys = (bounds, subst, incTyVars) => {
|
|
173
|
+
// 处理下界
|
|
174
|
+
const lowerBoundResult = this.processSingleBounds(bounds.lb, subst, incTyVars, true);
|
|
175
|
+
if (lowerBoundResult && lowerBoundResult.length > 0) {
|
|
176
|
+
return lowerBoundResult;
|
|
248
177
|
}
|
|
249
|
-
|
|
250
|
-
|
|
178
|
+
// 处理上界
|
|
179
|
+
const upperBoundResult = this.processSingleBounds(bounds.ub, subst, incTyVars, false);
|
|
180
|
+
if (upperBoundResult && upperBoundResult.length > 0) {
|
|
181
|
+
return upperBoundResult;
|
|
251
182
|
}
|
|
252
|
-
|
|
253
|
-
|
|
183
|
+
// 特殊处理:若上界只有一个 any 约束且下界为空
|
|
184
|
+
if (bounds.ub.length === 1 && bounds.lb.length === 0 && bounds.ub[0].bound === index_1.naslAnyTy) {
|
|
185
|
+
return [bounds.ub[0].bound];
|
|
254
186
|
}
|
|
255
|
-
// console.log('ub usefulTys', ubUsefulTys.length);
|
|
256
|
-
// ubUsefulTys.forEach(printType);
|
|
257
|
-
// throw new Error('getUsefulTyFromBounds: unsolvable constraints');
|
|
258
187
|
return undefined;
|
|
259
188
|
};
|
|
260
|
-
// 同时从下界和上界寻找非 union 和非 any 的具体类型,特别处理数值类型的情况
|
|
261
189
|
/**
|
|
262
|
-
*
|
|
263
|
-
* 1. 下界含有
|
|
264
|
-
* 2.
|
|
265
|
-
* 3. 下界只有 Number
|
|
266
|
-
* 4.
|
|
267
|
-
* 5. 下界含有 Long
|
|
268
|
-
* 6.
|
|
190
|
+
* 处理特定边界(下界或上界)的类型:@warning decimal 和 long 的处理被 AI 破坏,现在是只处理单个 lb 或 ub,之后修复 Zirun
|
|
191
|
+
* 1. 下界含有 union:选择 union
|
|
192
|
+
* 2. 下界含有 Decimal:选择 Decimal
|
|
193
|
+
* 3. 下界只有 Number,上界含有 Decimal:选择 Decimal
|
|
194
|
+
* 4. 下界只有 Number,上界没有 Decimal:选择 Long (2、3 合并:下界 Number 上界任意数值类型)
|
|
195
|
+
* 5. 下界含有 Long 且上界有 Decimal:选择 Long
|
|
196
|
+
* 6. 下界含有 Long 且上界没有 Decimal:选择 Long (1、2、4、5合并后:下界没有 Decimal,有 Long,而是上界任意数值类型)
|
|
269
197
|
* 7. 下界和上界都只有 Number:选择 Long
|
|
198
|
+
* 8. 下界和上界都只有 Number:选择 Long
|
|
270
199
|
*/
|
|
271
|
-
this.
|
|
272
|
-
//
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
else if (ty.typeName === 'Long') {
|
|
285
|
-
lbHasLong = true;
|
|
200
|
+
this.processSingleBounds = (boundEntries, subst, incTyVars, preferUnion) => {
|
|
201
|
+
// 首先考虑 union 类型优先级
|
|
202
|
+
if (preferUnion) {
|
|
203
|
+
// 下界策略:优先选择 union 类型
|
|
204
|
+
const unionTypes = [];
|
|
205
|
+
for (const boundEntry of boundEntries) {
|
|
206
|
+
const ty = boundEntry.bound;
|
|
207
|
+
const shouldInclude = !(0, index_1.isAnyTy)(ty) && (incTyVars || !hasNaslTyParamAnn(ty, subst));
|
|
208
|
+
if (shouldInclude && (0, index_1.isUnionTy)(ty)) {
|
|
209
|
+
if (!unionTypes.includes(ty)) {
|
|
210
|
+
unionTypes.push(ty);
|
|
211
|
+
}
|
|
212
|
+
}
|
|
286
213
|
}
|
|
287
|
-
|
|
288
|
-
|
|
214
|
+
// 如果找到 union 类型,优先返回
|
|
215
|
+
if (unionTypes.length > 0) {
|
|
216
|
+
return unionTypes;
|
|
289
217
|
}
|
|
290
218
|
}
|
|
291
|
-
|
|
219
|
+
// 如果没有优先 union 或没找到 union 类型,检查数值类型
|
|
220
|
+
let hasDecimal = false;
|
|
221
|
+
let hasLong = false;
|
|
222
|
+
let hasNumber = false;
|
|
223
|
+
for (const boundEntry of boundEntries) {
|
|
224
|
+
const ty = boundEntry.bound;
|
|
292
225
|
if (ty.typeName === 'Decimal') {
|
|
293
|
-
|
|
226
|
+
hasDecimal = true;
|
|
294
227
|
}
|
|
295
228
|
else if (ty.typeName === 'Long') {
|
|
296
|
-
|
|
229
|
+
hasLong = true;
|
|
297
230
|
}
|
|
298
231
|
else if (ty.typeName === 'Number') {
|
|
299
|
-
|
|
232
|
+
hasNumber = true;
|
|
300
233
|
}
|
|
301
234
|
}
|
|
302
|
-
//
|
|
303
|
-
|
|
304
|
-
if (lbHasDecimal) {
|
|
235
|
+
// 数值类型优先级:Decimal > Long/Number
|
|
236
|
+
if (hasDecimal) {
|
|
305
237
|
return [index_1.naslDecimalTy];
|
|
306
238
|
}
|
|
307
|
-
|
|
308
|
-
if (lbHasNumber && !lbHasLong && ubHasDecimal) {
|
|
309
|
-
return [index_1.naslDecimalTy];
|
|
310
|
-
}
|
|
311
|
-
// 3. 下界只有 Number,上界没有 Decimal:选择 Long
|
|
312
|
-
// 4. 下界含有 Long 且上界有 Decimal:选择 Long (类型冲突,Long更具体)
|
|
313
|
-
// 5. 下界含有 Long 且上界没有 Decimal:选择 Long
|
|
314
|
-
// 6. 下界和上界都只有 Number:选择 Long
|
|
315
|
-
// 7. 下界和上界都只有 Number:选择 Long
|
|
316
|
-
if (lbHasLong || lbHasNumber || ubHasNumber) {
|
|
239
|
+
if (hasLong || hasNumber) {
|
|
317
240
|
return [index_1.naslLongTy];
|
|
318
241
|
}
|
|
319
|
-
//
|
|
320
|
-
const
|
|
321
|
-
const
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
if (
|
|
325
|
-
|
|
326
|
-
}
|
|
327
|
-
}
|
|
328
|
-
// 如果下界有非数值的类型,优先使用
|
|
329
|
-
if (lbRes.length > 0) {
|
|
330
|
-
return lbRes;
|
|
331
|
-
}
|
|
332
|
-
// 收集上界的非数值类型
|
|
333
|
-
for (const ty of bounds.ub) {
|
|
334
|
-
if (!ubRes.includes(ty) && !(0, index_1.isUnionTy)(ty) && !(0, index_1.isAnyTy)(ty) && !hasNaslTyParamAnn(ty, subst)) {
|
|
335
|
-
ubRes.push(ty);
|
|
242
|
+
// 处理其他非数值类型
|
|
243
|
+
const result = [];
|
|
244
|
+
for (const boundEntry of boundEntries) {
|
|
245
|
+
const ty = boundEntry.bound;
|
|
246
|
+
const shouldInclude = !(0, index_1.isAnyTy)(ty) && (incTyVars || !hasNaslTyParamAnn(ty, subst));
|
|
247
|
+
if (shouldInclude && !result.includes(ty)) {
|
|
248
|
+
result.push(ty);
|
|
336
249
|
}
|
|
337
250
|
}
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
return ubRes;
|
|
251
|
+
if (result.length > 0) {
|
|
252
|
+
return result;
|
|
341
253
|
}
|
|
342
|
-
/**
|
|
343
|
-
* 若这个变元的整个上界就只有这个约束且为 any ,那么它必定选上。
|
|
344
|
-
* 可以通过往一个变元的上界添加 naslAnyTy,而令下界留空来迫使它走这个分支。
|
|
345
|
-
* 主要用在前端类型变元求解上,参考 {@link Unifier#initBoundsFor}
|
|
346
|
-
*/
|
|
347
|
-
if (bounds.ub.length === 1 && bounds.lb.length === 0 && bounds.ub[0] === index_1.naslAnyTy) {
|
|
348
|
-
return bounds.ub;
|
|
349
|
-
}
|
|
350
|
-
// 如果没有找到任何合适的类型
|
|
351
254
|
return undefined;
|
|
352
255
|
};
|
|
353
|
-
// 从所有界寻找包括 union 和 any 的类型(合并了Lower和Upper的逻辑)
|
|
354
|
-
this.getConcreteTysFromBoundsPriority2 = (bounds, subst) => {
|
|
355
|
-
const res = new Set();
|
|
356
|
-
// 首先检查下界(优先)
|
|
357
|
-
for (const ty of bounds.lb) {
|
|
358
|
-
if (!res.has(ty) && !hasNaslTyParamAnn(ty, subst)) {
|
|
359
|
-
res.add(ty);
|
|
360
|
-
}
|
|
361
|
-
}
|
|
362
|
-
// 然后检查上界
|
|
363
|
-
for (const ty of bounds.ub) {
|
|
364
|
-
if (!res.has(ty) && !hasNaslTyParamAnn(ty, subst)) {
|
|
365
|
-
res.add(ty);
|
|
366
|
-
}
|
|
367
|
-
}
|
|
368
|
-
if (res.size === 0) {
|
|
369
|
-
return undefined;
|
|
370
|
-
}
|
|
371
|
-
else {
|
|
372
|
-
return refineUnionAnyTy(res);
|
|
373
|
-
}
|
|
374
|
-
function refineUnionAnyTy(tys) {
|
|
375
|
-
let hasAny = false;
|
|
376
|
-
let hasUnion = false;
|
|
377
|
-
// weak test
|
|
378
|
-
tys.forEach(ty => {
|
|
379
|
-
if (ty.typeName === 'any') {
|
|
380
|
-
hasAny = true;
|
|
381
|
-
}
|
|
382
|
-
else if ((0, index_1.isUnionTy)(ty)) {
|
|
383
|
-
hasUnion = true;
|
|
384
|
-
}
|
|
385
|
-
});
|
|
386
|
-
const result = [];
|
|
387
|
-
if (hasUnion) {
|
|
388
|
-
if (tys.size > 1) {
|
|
389
|
-
for (const ty of tys) {
|
|
390
|
-
if ((0, index_1.isUnionTy)(ty)) {
|
|
391
|
-
result.push(ty);
|
|
392
|
-
}
|
|
393
|
-
}
|
|
394
|
-
return result;
|
|
395
|
-
}
|
|
396
|
-
else {
|
|
397
|
-
return tys;
|
|
398
|
-
}
|
|
399
|
-
}
|
|
400
|
-
else if (hasAny) {
|
|
401
|
-
return [index_1.naslAnyTy];
|
|
402
|
-
}
|
|
403
|
-
else {
|
|
404
|
-
return tys;
|
|
405
|
-
}
|
|
406
|
-
}
|
|
407
|
-
;
|
|
408
|
-
};
|
|
409
|
-
// strongly connected components
|
|
410
|
-
this.findSCCs = (cs0) => {
|
|
411
|
-
const depG = new Map();
|
|
412
|
-
let index = 0;
|
|
413
|
-
const indices = new Map();
|
|
414
|
-
const lowLinks = new Map();
|
|
415
|
-
const onStack = new Set();
|
|
416
|
-
const stack = [];
|
|
417
|
-
// Build the graph
|
|
418
|
-
for (const [tyVar, bounds] of cs0) {
|
|
419
|
-
depG.set(tyVar, new Set());
|
|
420
|
-
for (const lb of bounds.lb.map(index_1.extractTyParamAnns)) {
|
|
421
|
-
for (const dep of (lb.map(getTyName))) {
|
|
422
|
-
if (dep !== tyVar && dep) {
|
|
423
|
-
depG.get(tyVar).add(dep);
|
|
424
|
-
}
|
|
425
|
-
}
|
|
426
|
-
}
|
|
427
|
-
for (const ub of bounds.ub.map(index_1.extractTyParamAnns)) {
|
|
428
|
-
for (const dep of (ub.map(getTyName))) {
|
|
429
|
-
if (dep !== tyVar && dep) {
|
|
430
|
-
depG.get(tyVar).add(dep);
|
|
431
|
-
}
|
|
432
|
-
}
|
|
433
|
-
}
|
|
434
|
-
}
|
|
435
|
-
const res = [];
|
|
436
|
-
// Tarjan's algorithm
|
|
437
|
-
function strongConnect(v) {
|
|
438
|
-
indices.set(v, index);
|
|
439
|
-
lowLinks.set(v, index);
|
|
440
|
-
index++;
|
|
441
|
-
stack.push(v);
|
|
442
|
-
onStack.add(v);
|
|
443
|
-
if (depG.has(v)) {
|
|
444
|
-
for (const w of depG.get(v)) {
|
|
445
|
-
if (!indices.has(w)) {
|
|
446
|
-
strongConnect(w);
|
|
447
|
-
lowLinks.set(v, Math.min(lowLinks.get(v), lowLinks.get(w)));
|
|
448
|
-
}
|
|
449
|
-
else if (onStack.has(w)) {
|
|
450
|
-
lowLinks.set(v, Math.min(lowLinks.get(v), indices.get(w)));
|
|
451
|
-
}
|
|
452
|
-
}
|
|
453
|
-
}
|
|
454
|
-
if (lowLinks.get(v) === indices.get(v)) {
|
|
455
|
-
const comp = [];
|
|
456
|
-
let w;
|
|
457
|
-
do {
|
|
458
|
-
w = stack.pop();
|
|
459
|
-
onStack.delete(w);
|
|
460
|
-
comp.push(w);
|
|
461
|
-
} while (w !== v);
|
|
462
|
-
res.push(comp);
|
|
463
|
-
}
|
|
464
|
-
}
|
|
465
|
-
for (const v of cs0.keys()) {
|
|
466
|
-
if (!indices.has(v)) {
|
|
467
|
-
strongConnect(v);
|
|
468
|
-
}
|
|
469
|
-
}
|
|
470
|
-
return res;
|
|
471
|
-
};
|
|
472
256
|
this.topoSortTyVars = (cs) => {
|
|
473
257
|
const sortedCs = new Map();
|
|
474
258
|
const visited = new Set();
|
|
475
259
|
let index = 0;
|
|
476
260
|
let indexMap = new Map();
|
|
477
|
-
|
|
261
|
+
// Phase 1: Use only lower bounds for dependency resolution
|
|
262
|
+
const addToMapPhase1 = (tyVar, bounds) => {
|
|
478
263
|
if (visited.has(tyVar)) {
|
|
479
264
|
return;
|
|
480
265
|
}
|
|
481
266
|
visited.add(tyVar);
|
|
267
|
+
// Only consider lower bounds in phase 1
|
|
268
|
+
const lbCandidates = bounds.lb.filter((x) => {
|
|
269
|
+
// @ts-expect-error
|
|
270
|
+
return !x.bound.ignored;
|
|
271
|
+
}).map(x => x.bound);
|
|
272
|
+
for (const ty of lbCandidates) {
|
|
273
|
+
const tyParams = (0, index_1.extractTyParamAnns)(ty);
|
|
274
|
+
for (const param of tyParams) {
|
|
275
|
+
const name = getTyName(param);
|
|
276
|
+
if (name && cs.has(name)) {
|
|
277
|
+
addToMapPhase1(name, cs.get(name));
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
indexMap.set(index++, tyVar);
|
|
282
|
+
};
|
|
283
|
+
// Phase 2: Use upper bounds for remaining unvisited type variables
|
|
284
|
+
const addToMapPhase2 = (tyVar, bounds) => {
|
|
285
|
+
if (visited.has(tyVar)) {
|
|
286
|
+
return;
|
|
287
|
+
}
|
|
288
|
+
visited.add(tyVar);
|
|
289
|
+
// Consider both lower and upper bounds in phase 2
|
|
482
290
|
for (const ty of collectCandidateBounds(bounds)) {
|
|
483
291
|
const tyParams = (0, index_1.extractTyParamAnns)(ty);
|
|
484
292
|
for (const param of tyParams) {
|
|
485
293
|
const name = getTyName(param);
|
|
486
294
|
if (name && cs.has(name)) {
|
|
487
|
-
|
|
295
|
+
addToMapPhase2(name, cs.get(name));
|
|
488
296
|
}
|
|
489
297
|
}
|
|
490
298
|
}
|
|
491
299
|
indexMap.set(index++, tyVar);
|
|
492
300
|
};
|
|
493
|
-
//
|
|
301
|
+
// Phase 1: Process all constraints using only lower bounds
|
|
302
|
+
for (const [tyVar, bounds] of cs.entries()) {
|
|
303
|
+
addToMapPhase1(tyVar, bounds);
|
|
304
|
+
}
|
|
305
|
+
// Phase 2: Process any remaining unvisited constraints using all bounds
|
|
494
306
|
for (const [tyVar, bounds] of cs.entries()) {
|
|
495
|
-
|
|
307
|
+
addToMapPhase2(tyVar, bounds);
|
|
496
308
|
}
|
|
497
309
|
for (let i = 0; i < cs.size; i++) {
|
|
498
310
|
const name = indexMap.get(i);
|
|
@@ -500,124 +312,91 @@ class Solver {
|
|
|
500
312
|
}
|
|
501
313
|
return sortedCs;
|
|
502
314
|
};
|
|
503
|
-
//
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
// const [tvDepDegree, cachedTC] = this.buildTyVarDepDegree(cs);
|
|
508
|
-
const sccs = this.findSCCs(cs);
|
|
509
|
-
// console.log('original cs')
|
|
510
|
-
// printConstraints(cs);
|
|
511
|
-
// 因为有环,SCC 和依赖度只能分两次算
|
|
512
|
-
const depDegreeG = this.calcDepDegree(cs, sccs);
|
|
513
|
-
console.log('depDegreeG');
|
|
514
|
-
console.log(depDegreeG);
|
|
515
|
-
// 环上的点,dep degree 不一定都相同
|
|
516
|
-
//
|
|
517
|
-
// A <--> B <-- C dep degree 为 A:0 B:0 C:1,先解环
|
|
518
|
-
//
|
|
519
|
-
// A <--> B --> C dep degree 为 A:0 B:1 C:0,先解非环 C
|
|
520
|
-
//
|
|
521
|
-
// A1, A2 <---> B1, B2 --> C dep degree 为 A1:0, A2:0, B1:1, B2:1, C:0, 先解 C
|
|
522
|
-
this.reorderSCCs(depDegreeG, cs);
|
|
523
|
-
console.log('reordered depDegreeG');
|
|
524
|
-
console.log(depDegreeG);
|
|
525
|
-
const res = new Array();
|
|
526
|
-
for (const scc of depDegreeG) {
|
|
527
|
-
for (const { tv, depDeg, tyCounts } of scc) {
|
|
528
|
-
res.push([tv, cs.get(tv)]);
|
|
529
|
-
}
|
|
315
|
+
// 紧急fix:对 subst 再代换一次,解决大部分问题
|
|
316
|
+
this.substSubst = (subst) => {
|
|
317
|
+
for (const [from, to] of subst.entries()) {
|
|
318
|
+
subst.set(from, (0, subster_1.inPlaceSubstTyAnn)(this.env, subst)(to));
|
|
530
319
|
}
|
|
531
|
-
return res;
|
|
532
|
-
};
|
|
533
|
-
this.reorderSCCs = (sccs, cs) => {
|
|
534
|
-
sccs.forEach(scc => this.reorderSCC(scc, cs));
|
|
535
|
-
sccs.sort((scc1, scc2) => {
|
|
536
|
-
if (scc1.length === 1) {
|
|
537
|
-
return -1; // 无依赖,可优先解决
|
|
538
|
-
}
|
|
539
|
-
else if (scc2.length === 1) {
|
|
540
|
-
return 1;
|
|
541
|
-
}
|
|
542
|
-
else {
|
|
543
|
-
return 0; // return scc1[0][1] - scc2[0][1];
|
|
544
|
-
}
|
|
545
|
-
}); // according to the first element
|
|
546
|
-
return sccs;
|
|
547
320
|
};
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
//
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
321
|
+
/**
|
|
322
|
+
* Post-check if a solution (substitution) is valid by testing if it satisfies all bounds.
|
|
323
|
+
* For each type variable in the substitution:
|
|
324
|
+
* - The solution should be a supertype of all lower bounds (lb ⊆ solution)
|
|
325
|
+
* - The solution should be a subtype of all upper bounds (solution ⊆ ub)
|
|
326
|
+
*
|
|
327
|
+
* @param subst The substitution to validate (defaults to this.subst)
|
|
328
|
+
* @param cs The constraints to check against (defaults to this.cs)
|
|
329
|
+
* @returns Object with validation result and any violations found
|
|
330
|
+
*/
|
|
331
|
+
// Post-check solution using consistent normalization approach as traversal
|
|
332
|
+
this.postCheckSolution = (subst, cs0, normalizedSemTyMap) => {
|
|
333
|
+
// 对 cs 做浅拷贝,并使用与 traversal 一致的 normalizeWithSubst 方法
|
|
334
|
+
const cs = new Map(cs0);
|
|
335
|
+
// this.inPlaceSubstConstraintsWithNormalization(cs, pNormalizedSubst);
|
|
336
|
+
const violations = [];
|
|
337
|
+
const pSubst = (0, index_1.substTyAnn)(this.env, subst);
|
|
338
|
+
// Check each type variable that has a solution
|
|
339
|
+
for (const [tyVar, __actual] of subst.entries()) {
|
|
340
|
+
const actual = normalizedSemTyMap.get(__actual) ?? (0, subster_1.normalizeWithSubst)(this.env, pSubst, __actual);
|
|
341
|
+
const bounds = cs.get(tyVar);
|
|
342
|
+
if (!bounds) {
|
|
343
|
+
// No constraints for this type variable, skip
|
|
344
|
+
continue;
|
|
345
|
+
}
|
|
346
|
+
// Check lower bounds: solution should be a supertype of each lower bound
|
|
347
|
+
// i.e., for each lb: lb ⊆ solution (or isSubTy(lb, solution))
|
|
348
|
+
for (const lbEntry of bounds.lb) {
|
|
349
|
+
const __expect = lbEntry.bound;
|
|
350
|
+
const expect = normalizedSemTyMap.get(__expect) ?? (0, subster_1.normalizeWithSubst)(this.env, pSubst, __expect);
|
|
351
|
+
// Fixme: wudengke 这里之后需要看下为什么父亲 ViewElement 引入了 true 但是 bindAttr 引入了 false 导致报错
|
|
352
|
+
if (actual.typeKind === 'literal' && expect.typeKind === 'literal') {
|
|
353
|
+
continue;
|
|
354
|
+
}
|
|
355
|
+
if (!(0, index_1.isSubTy)(this.env, expect, actual)) {
|
|
356
|
+
violations.push({
|
|
357
|
+
expect,
|
|
358
|
+
actual,
|
|
359
|
+
errBoundary: lbEntry.boundary,
|
|
360
|
+
message: (0, sem_diag_1.mkIncompatibleTyErr)(this.env, expect, actual),
|
|
361
|
+
fromPlayground: lbEntry.fromPlayground ?? false
|
|
362
|
+
});
|
|
363
|
+
}
|
|
574
364
|
}
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
365
|
+
// Check upper bounds: solution should be a subtype of each upper bound
|
|
366
|
+
// i.e., for each ub: solution ⊆ ub (or isSubTy(solution, ub))
|
|
367
|
+
for (const ubEntry of bounds.ub) {
|
|
368
|
+
const __expect = ubEntry.bound;
|
|
369
|
+
// HACK wudengke 这里额外处理了generic 和dataSource,动机都是通过type desctrutor添加反向约束。这里应当统一一下处理方式。
|
|
370
|
+
if (this.env.typeHintManager.isDataSourceTy(__expect)) {
|
|
371
|
+
continue;
|
|
372
|
+
}
|
|
373
|
+
const expect = normalizedSemTyMap.get(__expect) ?? (0, subster_1.normalizeWithSubst)(this.env, pSubst, __expect);
|
|
374
|
+
// Fixme: wudengke 这里之后需要看下为什么父亲 ViewElement 引入了 true 但是 bindAttr 引入了 false 导致报错
|
|
375
|
+
if (actual.typeKind === 'literal' && expect.typeKind === 'literal') {
|
|
376
|
+
continue;
|
|
377
|
+
}
|
|
378
|
+
if (!(0, index_1.isSubTy)(this.env, actual, expect)) {
|
|
379
|
+
violations.push({
|
|
380
|
+
expect,
|
|
381
|
+
actual,
|
|
382
|
+
errBoundary: ubEntry.boundary,
|
|
383
|
+
message: (0, sem_diag_1.mkIncompatibleTyErr)(this.env, actual, expect),
|
|
384
|
+
fromPlayground: ubEntry.fromPlayground ?? false
|
|
385
|
+
});
|
|
386
|
+
}
|
|
591
387
|
}
|
|
592
|
-
depDegree.push(subRes);
|
|
593
388
|
}
|
|
594
|
-
return
|
|
389
|
+
return violations;
|
|
595
390
|
};
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
cs.forEach((bounds, tyVar) => {
|
|
602
|
-
const lbHasLongOrDecimal = bounds.lb.find(ty => (0, type_predicate_1.isSameRefTy)(ty, index_1.naslLongTy)) ||
|
|
603
|
-
bounds.lb.find(ty => (0, type_predicate_1.isSameRefTy)(ty, index_1.naslDecimalTy));
|
|
604
|
-
// console.log('lb has long or decimal', lbHasLongOrDecimal);
|
|
605
|
-
if (lbHasLongOrDecimal) {
|
|
606
|
-
bounds.lb = bounds.lb.filter(ty => !(0, type_predicate_1.isSameRefTy)(ty, index_1.naslNumTy));
|
|
391
|
+
// Apply normalization to constraints using the same approach as traversal
|
|
392
|
+
this.inPlaceSubstConstraintsWithNormalization = (cs, pNormalizedSubst) => {
|
|
393
|
+
for (const [tyVar, bounds] of cs.entries()) {
|
|
394
|
+
for (let i = 0; i < bounds.lb.length; i++) {
|
|
395
|
+
bounds.lb[i] = { bound: (0, typer_1.normalize)(this.env, pNormalizedSubst(bounds.lb[i].bound)), boundary: bounds.lb[i].boundary, fromPlayground: bounds.lb[i].fromPlayground };
|
|
607
396
|
}
|
|
608
|
-
|
|
609
|
-
bounds.ub
|
|
610
|
-
// console.log('ub has long or decimal', ubHasLongOrDecimal);
|
|
611
|
-
if (ubHasLongOrDecimal) {
|
|
612
|
-
bounds.ub = bounds.ub.filter(ty => !(0, type_predicate_1.isSameRefTy)(ty, index_1.naslNumTy));
|
|
397
|
+
for (let i = 0; i < bounds.ub.length; i++) {
|
|
398
|
+
bounds.ub[i] = { bound: (0, typer_1.normalize)(this.env, pNormalizedSubst(bounds.ub[i].bound)), boundary: bounds.ub[i].boundary, fromPlayground: bounds.ub[i].fromPlayground };
|
|
613
399
|
}
|
|
614
|
-
});
|
|
615
|
-
return cs;
|
|
616
|
-
};
|
|
617
|
-
// 紧急fix:对 subst 再代换一次,解决大部分问题
|
|
618
|
-
this.substSubst = (subst) => {
|
|
619
|
-
for (const [from, to] of subst.entries()) {
|
|
620
|
-
subst.set(from, (0, subster_1.inPlaceSubstTyAnn)(this.env, subst)(to));
|
|
621
400
|
}
|
|
622
401
|
};
|
|
623
402
|
// substTyEnv = (m: TyVarSolution, env: TypingEnv) => {
|
|
@@ -687,8 +466,8 @@ const hasNaslTyParamAnn = (ty, subst) => {
|
|
|
687
466
|
return false;
|
|
688
467
|
};
|
|
689
468
|
function printBounds(b) {
|
|
690
|
-
console.log("上界:\n", b.ub.map(type_manager_1.showType).join('\n '));
|
|
691
|
-
console.log("下界:\n", b.lb.map(type_manager_1.showType).join('\n '));
|
|
469
|
+
console.log("上界:\n", b.ub.map(bound => (0, type_manager_1.showType)(bound.bound)).join('\n '));
|
|
470
|
+
console.log("下界:\n", b.lb.map(bound => (0, type_manager_1.showType)(bound.bound)).join('\n '));
|
|
692
471
|
}
|
|
693
472
|
exports.printBounds = printBounds;
|
|
694
473
|
//# sourceMappingURL=solver.js.map
|