@tilua/parser 2.3.0 → 2.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +119 -21
- package/dist/index.d.cts +3 -1
- package/dist/index.d.ts +3 -1
- package/dist/index.js +119 -21
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -2112,7 +2112,7 @@ var Parser = class {
|
|
|
2112
2112
|
parseExpressionStatement() {
|
|
2113
2113
|
const start = this.current();
|
|
2114
2114
|
if (this.checkPunctuator("{") || this.checkPunctuator("[")) {
|
|
2115
|
-
const target = this.checkPunctuator("{") ? this.parseObjectPattern() : this.parseArrayPattern();
|
|
2115
|
+
const target = this.checkPunctuator("{") ? this.parseObjectPattern(true) : this.parseArrayPattern(true);
|
|
2116
2116
|
return this.parseAssignmentRest(start, target);
|
|
2117
2117
|
}
|
|
2118
2118
|
const statementStart = this.cursor;
|
|
@@ -2667,8 +2667,8 @@ var Parser = class {
|
|
|
2667
2667
|
/** An assignment target after the first — Luau's `a, b = ...`, read only
|
|
2668
2668
|
* to be reported: a prefix expression or a destructuring pattern. */
|
|
2669
2669
|
parseAssignTarget() {
|
|
2670
|
-
if (this.checkPunctuator("{")) return this.parseObjectPattern();
|
|
2671
|
-
if (this.checkPunctuator("[")) return this.parseArrayPattern();
|
|
2670
|
+
if (this.checkPunctuator("{")) return this.parseObjectPattern(true);
|
|
2671
|
+
if (this.checkPunctuator("[")) return this.parseArrayPattern(true);
|
|
2672
2672
|
return this.parsePrefixExpression();
|
|
2673
2673
|
}
|
|
2674
2674
|
/** Does a call's argument list start here? Lua's three forms: `(`, a
|
|
@@ -2847,13 +2847,17 @@ var Parser = class {
|
|
|
2847
2847
|
/** Parses a binding target. When `topLevel`, also consumes a trailing
|
|
2848
2848
|
* `<attr>` list (identifier only) and a `: Type` annotation — these are
|
|
2849
2849
|
* only valid at the outermost level of a `local` / parameter binding,
|
|
2850
|
-
* never nested inside another pattern.
|
|
2851
|
-
|
|
2850
|
+
* never nested inside another pattern. When `assign`, the pattern is a
|
|
2851
|
+
* destructuring assignment's (`[t[i], t[j]] = ...`), and a leaf is any
|
|
2852
|
+
* place a value can be assigned to: a name, a member or an index. */
|
|
2853
|
+
parseBindingTarget(topLevel, assign = false) {
|
|
2852
2854
|
let target;
|
|
2853
2855
|
if (this.checkPunctuator("{")) {
|
|
2854
|
-
target = this.parseObjectPattern();
|
|
2856
|
+
target = this.parseObjectPattern(assign);
|
|
2855
2857
|
} else if (this.checkPunctuator("[")) {
|
|
2856
|
-
target = this.parseArrayPattern();
|
|
2858
|
+
target = this.parseArrayPattern(assign);
|
|
2859
|
+
} else if (assign) {
|
|
2860
|
+
return this.parseAssignPatternLeaf();
|
|
2857
2861
|
} else {
|
|
2858
2862
|
const nameTok = this.expectIdentifier();
|
|
2859
2863
|
let attributes;
|
|
@@ -2875,10 +2879,25 @@ var Parser = class {
|
|
|
2875
2879
|
}
|
|
2876
2880
|
return target;
|
|
2877
2881
|
}
|
|
2878
|
-
|
|
2879
|
-
|
|
2882
|
+
/** A leaf of a destructuring assignment: `a`, `a.b` or `a[i]`. */
|
|
2883
|
+
parseAssignPatternLeaf() {
|
|
2884
|
+
const expression = this.parsePrefixExpression();
|
|
2885
|
+
if (expression.type === "Identifier") {
|
|
2886
|
+
return { type: "IdentifierPattern", name: expression.name, line: expression.line, column: expression.column };
|
|
2887
|
+
}
|
|
2888
|
+
if (expression.type === "MemberExpression" || expression.type === "IndexExpression") {
|
|
2889
|
+
this.rejectOptionalTarget(expression);
|
|
2890
|
+
return expression;
|
|
2891
|
+
}
|
|
2892
|
+
const err = new ParseError("Only a name, a member or an index can be assigned to", expression.line.start, expression.column.start);
|
|
2893
|
+
if (!this.recover) throw err;
|
|
2894
|
+
this.record(err);
|
|
2895
|
+
return { type: "IdentifierPattern", name: "", line: expression.line, column: expression.column };
|
|
2880
2896
|
}
|
|
2881
|
-
|
|
2897
|
+
parseObjectPattern(assign = false) {
|
|
2898
|
+
return this.inBrackets(() => this.parseObjectPatternInner(assign));
|
|
2899
|
+
}
|
|
2900
|
+
parseObjectPatternInner(assign) {
|
|
2882
2901
|
const start = this.current();
|
|
2883
2902
|
this.expectPunctuator("{");
|
|
2884
2903
|
const properties = [];
|
|
@@ -2886,7 +2905,7 @@ var Parser = class {
|
|
|
2886
2905
|
while (!this.checkPunctuator("}")) {
|
|
2887
2906
|
if (this.checkOperator("...")) {
|
|
2888
2907
|
this.advance();
|
|
2889
|
-
rest = this.parseBindingTarget(false);
|
|
2908
|
+
rest = this.parseBindingTarget(false, assign);
|
|
2890
2909
|
break;
|
|
2891
2910
|
}
|
|
2892
2911
|
const propStart = this.current();
|
|
@@ -2899,17 +2918,17 @@ var Parser = class {
|
|
|
2899
2918
|
key = this.parseExpression();
|
|
2900
2919
|
this.expectPunctuator("]");
|
|
2901
2920
|
this.expectPunctuator(":");
|
|
2902
|
-
value = this.parseBindingTarget(false);
|
|
2921
|
+
value = this.parseBindingTarget(false, assign);
|
|
2903
2922
|
} else if (this.checkType("Literal") && this.current().kind === "string") {
|
|
2904
2923
|
const t = this.advance();
|
|
2905
2924
|
key = { type: "StringLiteral", value: t.value, raw: t.raw, ...spanFrom(t, t) };
|
|
2906
2925
|
this.expectPunctuator(":");
|
|
2907
|
-
value = this.parseBindingTarget(false);
|
|
2926
|
+
value = this.parseBindingTarget(false, assign);
|
|
2908
2927
|
} else {
|
|
2909
2928
|
const nameTok = this.expectIdentifier();
|
|
2910
2929
|
key = { type: "Identifier", name: nameTok.value, ...spanFrom(nameTok, nameTok) };
|
|
2911
2930
|
if (this.matchPunctuator(":")) {
|
|
2912
|
-
value = this.parseBindingTarget(false);
|
|
2931
|
+
value = this.parseBindingTarget(false, assign);
|
|
2913
2932
|
} else {
|
|
2914
2933
|
shorthand = true;
|
|
2915
2934
|
value = { type: "IdentifierPattern", name: nameTok.value, ...spanFrom(nameTok, nameTok) };
|
|
@@ -2932,10 +2951,10 @@ var Parser = class {
|
|
|
2932
2951
|
this.expectPunctuator("}");
|
|
2933
2952
|
return { type: "ObjectPattern", properties, rest, ...spanFrom(start, this.previous()) };
|
|
2934
2953
|
}
|
|
2935
|
-
parseArrayPattern() {
|
|
2936
|
-
return this.inBrackets(() => this.parseArrayPatternInner());
|
|
2954
|
+
parseArrayPattern(assign = false) {
|
|
2955
|
+
return this.inBrackets(() => this.parseArrayPatternInner(assign));
|
|
2937
2956
|
}
|
|
2938
|
-
parseArrayPatternInner() {
|
|
2957
|
+
parseArrayPatternInner(assign) {
|
|
2939
2958
|
const start = this.current();
|
|
2940
2959
|
this.expectPunctuator("[");
|
|
2941
2960
|
const elements = [];
|
|
@@ -2943,7 +2962,7 @@ var Parser = class {
|
|
|
2943
2962
|
while (!this.checkPunctuator("]")) {
|
|
2944
2963
|
if (this.checkOperator("...")) {
|
|
2945
2964
|
this.advance();
|
|
2946
|
-
rest = this.parseBindingTarget(false);
|
|
2965
|
+
rest = this.parseBindingTarget(false, assign);
|
|
2947
2966
|
break;
|
|
2948
2967
|
}
|
|
2949
2968
|
if (this.checkPunctuator(",")) {
|
|
@@ -2952,7 +2971,7 @@ var Parser = class {
|
|
|
2952
2971
|
continue;
|
|
2953
2972
|
}
|
|
2954
2973
|
const elStart = this.current();
|
|
2955
|
-
const value = this.parseBindingTarget(false);
|
|
2974
|
+
const value = this.parseBindingTarget(false, assign);
|
|
2956
2975
|
let def;
|
|
2957
2976
|
if (this.matchOperator("=")) def = this.parseExpression();
|
|
2958
2977
|
elements.push({ type: "ArrayPatternElement", value, default: def, ...spanFrom(elStart, this.previous()) });
|
|
@@ -4089,6 +4108,10 @@ var Analyzer = class {
|
|
|
4089
4108
|
this.checkConstAssign(id, t);
|
|
4090
4109
|
return;
|
|
4091
4110
|
}
|
|
4111
|
+
case "MemberExpression":
|
|
4112
|
+
case "IndexExpression":
|
|
4113
|
+
this.visitExpression(t, scope);
|
|
4114
|
+
return;
|
|
4092
4115
|
case "ObjectPattern":
|
|
4093
4116
|
for (const p of t.properties) {
|
|
4094
4117
|
if (p.computed) this.visitExpression(p.key, scope);
|
|
@@ -4124,7 +4147,9 @@ var Analyzer = class {
|
|
|
4124
4147
|
switch (stmt.type) {
|
|
4125
4148
|
case "VariableDeclaration": {
|
|
4126
4149
|
if (stmt.init) this.visitExpression(stmt.init, scope);
|
|
4127
|
-
|
|
4150
|
+
if (stmt.name.type !== "MemberExpression" && stmt.name.type !== "IndexExpression") {
|
|
4151
|
+
this.visitType(stmt.name.typeAnnotation, scope);
|
|
4152
|
+
}
|
|
4128
4153
|
this.declarePattern(scope, stmt.name, "local", scope, stmt.kind === "const");
|
|
4129
4154
|
return;
|
|
4130
4155
|
}
|
|
@@ -6541,6 +6566,14 @@ var TypeAnalyzer = class {
|
|
|
6541
6566
|
report(stmt.superclass, known ? `'${stmt.superclass.name}' is not a class; a class can only extend another class` : `Cannot find class '${stmt.superclass.name}'`);
|
|
6542
6567
|
}
|
|
6543
6568
|
}
|
|
6569
|
+
this.withClass(stmt, () => this.withTypeParams(this.classTypeParams(stmt), () => {
|
|
6570
|
+
this.withSelfType(this.selfTypeOf(stmt), () => {
|
|
6571
|
+
for (const member of stmt.members) {
|
|
6572
|
+
if (member.type !== "ClassMethod" || !member.signatures) continue;
|
|
6573
|
+
for (const signature of member.signatures) this.checkOverload(member.func, signature);
|
|
6574
|
+
}
|
|
6575
|
+
});
|
|
6576
|
+
}));
|
|
6544
6577
|
for (const member of stmt.members) {
|
|
6545
6578
|
if (member.type === "ClassConstructor") continue;
|
|
6546
6579
|
if (CLASS_RESERVED.has(member.name.name)) {
|
|
@@ -8047,7 +8080,7 @@ var TypeAnalyzer = class {
|
|
|
8047
8080
|
/** Synthesize a type from a destructuring pattern used without an
|
|
8048
8081
|
* annotation (`function f({ a, b = 1 })`). */
|
|
8049
8082
|
patternToType(target, env) {
|
|
8050
|
-
const leaf = (v, def) => v.type
|
|
8083
|
+
const leaf = (v, def) => v.type === "ObjectPattern" || v.type === "ArrayPattern" ? this.patternToType(v, env) : v.type !== "IdentifierPattern" ? anyType : v.typeAnnotation ? this.resolveType(v.typeAnnotation) : def ? widen(this.infer(def, env)) : anyType;
|
|
8051
8084
|
if (target.type === "ObjectPattern") {
|
|
8052
8085
|
const entries = [];
|
|
8053
8086
|
for (const p of target.properties) {
|
|
@@ -8453,6 +8486,7 @@ var TypeAnalyzer = class {
|
|
|
8453
8486
|
* can actually be. An annotation, a pattern or a default still wins. */
|
|
8454
8487
|
paramsFromSignatures(func, signatures) {
|
|
8455
8488
|
if (!signatures?.length) return;
|
|
8489
|
+
for (const signature of signatures) this.checkOverload(func, signature);
|
|
8456
8490
|
const resolved = signatures.map((sig) => this.signatureToFnType(sig));
|
|
8457
8491
|
func.params.forEach((param, i) => {
|
|
8458
8492
|
if (param.typeAnnotation || param.pattern || param.default) return;
|
|
@@ -8466,6 +8500,64 @@ var TypeAnalyzer = class {
|
|
|
8466
8500
|
if (candidates.length) this.contextualParams.set(param, union(candidates));
|
|
8467
8501
|
});
|
|
8468
8502
|
}
|
|
8503
|
+
/** The implementation is what runs for every signature of an overload
|
|
8504
|
+
* set, so each signature must be one it can serve: no parameter it does
|
|
8505
|
+
* not have, no fewer arguments than it requires, no argument type it does
|
|
8506
|
+
* not accept, and a return it can give. Stricter than TypeScript, which
|
|
8507
|
+
* lets a signature name parameters the implementation never reads. */
|
|
8508
|
+
checkOverload(func, signature) {
|
|
8509
|
+
if (!this.emitDiagnostics) return;
|
|
8510
|
+
const node = signature;
|
|
8511
|
+
const report = (message) => {
|
|
8512
|
+
this.diagnostics.push({ node, message });
|
|
8513
|
+
};
|
|
8514
|
+
const own = (params) => params.filter((p, i) => !p.rest && !(i === 0 && !p.typeAnnotation && (p.name === "self" || p.name === "this")));
|
|
8515
|
+
const implementation = own(func.params);
|
|
8516
|
+
const offered = own(signature.params);
|
|
8517
|
+
const implementationRest = func.params.some((p) => p.rest);
|
|
8518
|
+
const signatureRest = signature.params.some((p) => p.rest);
|
|
8519
|
+
const label = (p) => p.pattern ? "a destructured parameter" : `'${p.name}'`;
|
|
8520
|
+
if (!implementationRest) {
|
|
8521
|
+
const extra = offered[implementation.length];
|
|
8522
|
+
if (extra) {
|
|
8523
|
+
report(`This overload takes parameter ${label(extra)}, which the implementation does not have: it takes ${implementation.length} parameter${implementation.length === 1 ? "" : "s"}`);
|
|
8524
|
+
return;
|
|
8525
|
+
}
|
|
8526
|
+
if (signatureRest) {
|
|
8527
|
+
report("This overload takes a rest parameter, which the implementation does not have");
|
|
8528
|
+
return;
|
|
8529
|
+
}
|
|
8530
|
+
}
|
|
8531
|
+
if (!signatureRest) {
|
|
8532
|
+
let required = 0;
|
|
8533
|
+
implementation.forEach((p, i) => {
|
|
8534
|
+
if (!p.optional && p.default === void 0) required = i + 1;
|
|
8535
|
+
});
|
|
8536
|
+
if (offered.length < required) {
|
|
8537
|
+
report(`The implementation requires ${required} argument${required === 1 ? "" : "s"}, and this overload passes at most ${offered.length}`);
|
|
8538
|
+
return;
|
|
8539
|
+
}
|
|
8540
|
+
}
|
|
8541
|
+
if (signature.generics.length || func.generics.length) return;
|
|
8542
|
+
for (let i = 0; i < offered.length && i < implementation.length; i++) {
|
|
8543
|
+
const target = implementation[i];
|
|
8544
|
+
if (!target.typeAnnotation && target.default === void 0) continue;
|
|
8545
|
+
let accepted = this.paramType(target, /* @__PURE__ */ new Map());
|
|
8546
|
+
if (target.default !== void 0) accepted = optional(accepted);
|
|
8547
|
+
const given = this.paramType(offered[i], /* @__PURE__ */ new Map());
|
|
8548
|
+
if (!isAssignable(given, accepted)) {
|
|
8549
|
+
report(`Parameter ${label(offered[i])} of this overload is '${briefType(given)}', which the implementation's '${briefType(accepted)}' does not accept`);
|
|
8550
|
+
return;
|
|
8551
|
+
}
|
|
8552
|
+
}
|
|
8553
|
+
if (signature.returnType && func.returnType) {
|
|
8554
|
+
const promised = this.resolveType(signature.returnType);
|
|
8555
|
+
const returned = this.resolveType(func.returnType);
|
|
8556
|
+
if (!isAssignable(promised, returned) && !isAssignable(returned, promised)) {
|
|
8557
|
+
report(`This overload returns '${briefType(promised)}', which the implementation's '${briefType(returned)}' cannot be`);
|
|
8558
|
+
}
|
|
8559
|
+
}
|
|
8560
|
+
}
|
|
8469
8561
|
signatureToFnType(sig) {
|
|
8470
8562
|
const names = sig.generics.map((g) => g.name);
|
|
8471
8563
|
const record = (type) => {
|
|
@@ -8890,6 +8982,12 @@ var TypeAnalyzer = class {
|
|
|
8890
8982
|
}
|
|
8891
8983
|
return;
|
|
8892
8984
|
}
|
|
8985
|
+
case "MemberExpression":
|
|
8986
|
+
case "IndexExpression":
|
|
8987
|
+
this.infer(target, env);
|
|
8988
|
+
this.checkReadonlyAssign(target, env);
|
|
8989
|
+
this.assignToRef(target, widen(valueType), env);
|
|
8990
|
+
return;
|
|
8893
8991
|
case "ObjectPattern": {
|
|
8894
8992
|
for (const p of target.properties) {
|
|
8895
8993
|
const key = !p.computed && p.key.type === "Identifier" ? p.key.name : !p.computed && p.key.type === "StringLiteral" ? p.key.value : void 0;
|
package/dist/index.d.cts
CHANGED
|
@@ -254,7 +254,9 @@ interface VariableDeclaration extends BaseNode {
|
|
|
254
254
|
/** Absent only on `let x`. */
|
|
255
255
|
init?: Expression;
|
|
256
256
|
}
|
|
257
|
-
|
|
257
|
+
/** A member or an index (`t.a`, `t[i]`) is a leaf only in a destructuring
|
|
258
|
+
* assignment (`[t[i], t[j]] = [t[j], t[i]]`): a declaration binds names. */
|
|
259
|
+
type BindingTarget = IdentifierPattern | ObjectPattern | ArrayPattern | MemberExpression | IndexExpression;
|
|
258
260
|
interface IdentifierPattern extends BaseNode {
|
|
259
261
|
type: "IdentifierPattern";
|
|
260
262
|
name: string;
|
package/dist/index.d.ts
CHANGED
|
@@ -254,7 +254,9 @@ interface VariableDeclaration extends BaseNode {
|
|
|
254
254
|
/** Absent only on `let x`. */
|
|
255
255
|
init?: Expression;
|
|
256
256
|
}
|
|
257
|
-
|
|
257
|
+
/** A member or an index (`t.a`, `t[i]`) is a leaf only in a destructuring
|
|
258
|
+
* assignment (`[t[i], t[j]] = [t[j], t[i]]`): a declaration binds names. */
|
|
259
|
+
type BindingTarget = IdentifierPattern | ObjectPattern | ArrayPattern | MemberExpression | IndexExpression;
|
|
258
260
|
interface IdentifierPattern extends BaseNode {
|
|
259
261
|
type: "IdentifierPattern";
|
|
260
262
|
name: string;
|
package/dist/index.js
CHANGED
|
@@ -2007,7 +2007,7 @@ var Parser = class {
|
|
|
2007
2007
|
parseExpressionStatement() {
|
|
2008
2008
|
const start = this.current();
|
|
2009
2009
|
if (this.checkPunctuator("{") || this.checkPunctuator("[")) {
|
|
2010
|
-
const target = this.checkPunctuator("{") ? this.parseObjectPattern() : this.parseArrayPattern();
|
|
2010
|
+
const target = this.checkPunctuator("{") ? this.parseObjectPattern(true) : this.parseArrayPattern(true);
|
|
2011
2011
|
return this.parseAssignmentRest(start, target);
|
|
2012
2012
|
}
|
|
2013
2013
|
const statementStart = this.cursor;
|
|
@@ -2562,8 +2562,8 @@ var Parser = class {
|
|
|
2562
2562
|
/** An assignment target after the first — Luau's `a, b = ...`, read only
|
|
2563
2563
|
* to be reported: a prefix expression or a destructuring pattern. */
|
|
2564
2564
|
parseAssignTarget() {
|
|
2565
|
-
if (this.checkPunctuator("{")) return this.parseObjectPattern();
|
|
2566
|
-
if (this.checkPunctuator("[")) return this.parseArrayPattern();
|
|
2565
|
+
if (this.checkPunctuator("{")) return this.parseObjectPattern(true);
|
|
2566
|
+
if (this.checkPunctuator("[")) return this.parseArrayPattern(true);
|
|
2567
2567
|
return this.parsePrefixExpression();
|
|
2568
2568
|
}
|
|
2569
2569
|
/** Does a call's argument list start here? Lua's three forms: `(`, a
|
|
@@ -2742,13 +2742,17 @@ var Parser = class {
|
|
|
2742
2742
|
/** Parses a binding target. When `topLevel`, also consumes a trailing
|
|
2743
2743
|
* `<attr>` list (identifier only) and a `: Type` annotation — these are
|
|
2744
2744
|
* only valid at the outermost level of a `local` / parameter binding,
|
|
2745
|
-
* never nested inside another pattern.
|
|
2746
|
-
|
|
2745
|
+
* never nested inside another pattern. When `assign`, the pattern is a
|
|
2746
|
+
* destructuring assignment's (`[t[i], t[j]] = ...`), and a leaf is any
|
|
2747
|
+
* place a value can be assigned to: a name, a member or an index. */
|
|
2748
|
+
parseBindingTarget(topLevel, assign = false) {
|
|
2747
2749
|
let target;
|
|
2748
2750
|
if (this.checkPunctuator("{")) {
|
|
2749
|
-
target = this.parseObjectPattern();
|
|
2751
|
+
target = this.parseObjectPattern(assign);
|
|
2750
2752
|
} else if (this.checkPunctuator("[")) {
|
|
2751
|
-
target = this.parseArrayPattern();
|
|
2753
|
+
target = this.parseArrayPattern(assign);
|
|
2754
|
+
} else if (assign) {
|
|
2755
|
+
return this.parseAssignPatternLeaf();
|
|
2752
2756
|
} else {
|
|
2753
2757
|
const nameTok = this.expectIdentifier();
|
|
2754
2758
|
let attributes;
|
|
@@ -2770,10 +2774,25 @@ var Parser = class {
|
|
|
2770
2774
|
}
|
|
2771
2775
|
return target;
|
|
2772
2776
|
}
|
|
2773
|
-
|
|
2774
|
-
|
|
2777
|
+
/** A leaf of a destructuring assignment: `a`, `a.b` or `a[i]`. */
|
|
2778
|
+
parseAssignPatternLeaf() {
|
|
2779
|
+
const expression = this.parsePrefixExpression();
|
|
2780
|
+
if (expression.type === "Identifier") {
|
|
2781
|
+
return { type: "IdentifierPattern", name: expression.name, line: expression.line, column: expression.column };
|
|
2782
|
+
}
|
|
2783
|
+
if (expression.type === "MemberExpression" || expression.type === "IndexExpression") {
|
|
2784
|
+
this.rejectOptionalTarget(expression);
|
|
2785
|
+
return expression;
|
|
2786
|
+
}
|
|
2787
|
+
const err = new ParseError("Only a name, a member or an index can be assigned to", expression.line.start, expression.column.start);
|
|
2788
|
+
if (!this.recover) throw err;
|
|
2789
|
+
this.record(err);
|
|
2790
|
+
return { type: "IdentifierPattern", name: "", line: expression.line, column: expression.column };
|
|
2775
2791
|
}
|
|
2776
|
-
|
|
2792
|
+
parseObjectPattern(assign = false) {
|
|
2793
|
+
return this.inBrackets(() => this.parseObjectPatternInner(assign));
|
|
2794
|
+
}
|
|
2795
|
+
parseObjectPatternInner(assign) {
|
|
2777
2796
|
const start = this.current();
|
|
2778
2797
|
this.expectPunctuator("{");
|
|
2779
2798
|
const properties = [];
|
|
@@ -2781,7 +2800,7 @@ var Parser = class {
|
|
|
2781
2800
|
while (!this.checkPunctuator("}")) {
|
|
2782
2801
|
if (this.checkOperator("...")) {
|
|
2783
2802
|
this.advance();
|
|
2784
|
-
rest = this.parseBindingTarget(false);
|
|
2803
|
+
rest = this.parseBindingTarget(false, assign);
|
|
2785
2804
|
break;
|
|
2786
2805
|
}
|
|
2787
2806
|
const propStart = this.current();
|
|
@@ -2794,17 +2813,17 @@ var Parser = class {
|
|
|
2794
2813
|
key = this.parseExpression();
|
|
2795
2814
|
this.expectPunctuator("]");
|
|
2796
2815
|
this.expectPunctuator(":");
|
|
2797
|
-
value = this.parseBindingTarget(false);
|
|
2816
|
+
value = this.parseBindingTarget(false, assign);
|
|
2798
2817
|
} else if (this.checkType("Literal") && this.current().kind === "string") {
|
|
2799
2818
|
const t = this.advance();
|
|
2800
2819
|
key = { type: "StringLiteral", value: t.value, raw: t.raw, ...spanFrom(t, t) };
|
|
2801
2820
|
this.expectPunctuator(":");
|
|
2802
|
-
value = this.parseBindingTarget(false);
|
|
2821
|
+
value = this.parseBindingTarget(false, assign);
|
|
2803
2822
|
} else {
|
|
2804
2823
|
const nameTok = this.expectIdentifier();
|
|
2805
2824
|
key = { type: "Identifier", name: nameTok.value, ...spanFrom(nameTok, nameTok) };
|
|
2806
2825
|
if (this.matchPunctuator(":")) {
|
|
2807
|
-
value = this.parseBindingTarget(false);
|
|
2826
|
+
value = this.parseBindingTarget(false, assign);
|
|
2808
2827
|
} else {
|
|
2809
2828
|
shorthand = true;
|
|
2810
2829
|
value = { type: "IdentifierPattern", name: nameTok.value, ...spanFrom(nameTok, nameTok) };
|
|
@@ -2827,10 +2846,10 @@ var Parser = class {
|
|
|
2827
2846
|
this.expectPunctuator("}");
|
|
2828
2847
|
return { type: "ObjectPattern", properties, rest, ...spanFrom(start, this.previous()) };
|
|
2829
2848
|
}
|
|
2830
|
-
parseArrayPattern() {
|
|
2831
|
-
return this.inBrackets(() => this.parseArrayPatternInner());
|
|
2849
|
+
parseArrayPattern(assign = false) {
|
|
2850
|
+
return this.inBrackets(() => this.parseArrayPatternInner(assign));
|
|
2832
2851
|
}
|
|
2833
|
-
parseArrayPatternInner() {
|
|
2852
|
+
parseArrayPatternInner(assign) {
|
|
2834
2853
|
const start = this.current();
|
|
2835
2854
|
this.expectPunctuator("[");
|
|
2836
2855
|
const elements = [];
|
|
@@ -2838,7 +2857,7 @@ var Parser = class {
|
|
|
2838
2857
|
while (!this.checkPunctuator("]")) {
|
|
2839
2858
|
if (this.checkOperator("...")) {
|
|
2840
2859
|
this.advance();
|
|
2841
|
-
rest = this.parseBindingTarget(false);
|
|
2860
|
+
rest = this.parseBindingTarget(false, assign);
|
|
2842
2861
|
break;
|
|
2843
2862
|
}
|
|
2844
2863
|
if (this.checkPunctuator(",")) {
|
|
@@ -2847,7 +2866,7 @@ var Parser = class {
|
|
|
2847
2866
|
continue;
|
|
2848
2867
|
}
|
|
2849
2868
|
const elStart = this.current();
|
|
2850
|
-
const value = this.parseBindingTarget(false);
|
|
2869
|
+
const value = this.parseBindingTarget(false, assign);
|
|
2851
2870
|
let def;
|
|
2852
2871
|
if (this.matchOperator("=")) def = this.parseExpression();
|
|
2853
2872
|
elements.push({ type: "ArrayPatternElement", value, default: def, ...spanFrom(elStart, this.previous()) });
|
|
@@ -3984,6 +4003,10 @@ var Analyzer = class {
|
|
|
3984
4003
|
this.checkConstAssign(id, t);
|
|
3985
4004
|
return;
|
|
3986
4005
|
}
|
|
4006
|
+
case "MemberExpression":
|
|
4007
|
+
case "IndexExpression":
|
|
4008
|
+
this.visitExpression(t, scope);
|
|
4009
|
+
return;
|
|
3987
4010
|
case "ObjectPattern":
|
|
3988
4011
|
for (const p of t.properties) {
|
|
3989
4012
|
if (p.computed) this.visitExpression(p.key, scope);
|
|
@@ -4019,7 +4042,9 @@ var Analyzer = class {
|
|
|
4019
4042
|
switch (stmt.type) {
|
|
4020
4043
|
case "VariableDeclaration": {
|
|
4021
4044
|
if (stmt.init) this.visitExpression(stmt.init, scope);
|
|
4022
|
-
|
|
4045
|
+
if (stmt.name.type !== "MemberExpression" && stmt.name.type !== "IndexExpression") {
|
|
4046
|
+
this.visitType(stmt.name.typeAnnotation, scope);
|
|
4047
|
+
}
|
|
4023
4048
|
this.declarePattern(scope, stmt.name, "local", scope, stmt.kind === "const");
|
|
4024
4049
|
return;
|
|
4025
4050
|
}
|
|
@@ -6436,6 +6461,14 @@ var TypeAnalyzer = class {
|
|
|
6436
6461
|
report(stmt.superclass, known ? `'${stmt.superclass.name}' is not a class; a class can only extend another class` : `Cannot find class '${stmt.superclass.name}'`);
|
|
6437
6462
|
}
|
|
6438
6463
|
}
|
|
6464
|
+
this.withClass(stmt, () => this.withTypeParams(this.classTypeParams(stmt), () => {
|
|
6465
|
+
this.withSelfType(this.selfTypeOf(stmt), () => {
|
|
6466
|
+
for (const member of stmt.members) {
|
|
6467
|
+
if (member.type !== "ClassMethod" || !member.signatures) continue;
|
|
6468
|
+
for (const signature of member.signatures) this.checkOverload(member.func, signature);
|
|
6469
|
+
}
|
|
6470
|
+
});
|
|
6471
|
+
}));
|
|
6439
6472
|
for (const member of stmt.members) {
|
|
6440
6473
|
if (member.type === "ClassConstructor") continue;
|
|
6441
6474
|
if (CLASS_RESERVED.has(member.name.name)) {
|
|
@@ -7942,7 +7975,7 @@ var TypeAnalyzer = class {
|
|
|
7942
7975
|
/** Synthesize a type from a destructuring pattern used without an
|
|
7943
7976
|
* annotation (`function f({ a, b = 1 })`). */
|
|
7944
7977
|
patternToType(target, env) {
|
|
7945
|
-
const leaf = (v, def) => v.type
|
|
7978
|
+
const leaf = (v, def) => v.type === "ObjectPattern" || v.type === "ArrayPattern" ? this.patternToType(v, env) : v.type !== "IdentifierPattern" ? anyType : v.typeAnnotation ? this.resolveType(v.typeAnnotation) : def ? widen(this.infer(def, env)) : anyType;
|
|
7946
7979
|
if (target.type === "ObjectPattern") {
|
|
7947
7980
|
const entries = [];
|
|
7948
7981
|
for (const p of target.properties) {
|
|
@@ -8348,6 +8381,7 @@ var TypeAnalyzer = class {
|
|
|
8348
8381
|
* can actually be. An annotation, a pattern or a default still wins. */
|
|
8349
8382
|
paramsFromSignatures(func, signatures) {
|
|
8350
8383
|
if (!signatures?.length) return;
|
|
8384
|
+
for (const signature of signatures) this.checkOverload(func, signature);
|
|
8351
8385
|
const resolved = signatures.map((sig) => this.signatureToFnType(sig));
|
|
8352
8386
|
func.params.forEach((param, i) => {
|
|
8353
8387
|
if (param.typeAnnotation || param.pattern || param.default) return;
|
|
@@ -8361,6 +8395,64 @@ var TypeAnalyzer = class {
|
|
|
8361
8395
|
if (candidates.length) this.contextualParams.set(param, union(candidates));
|
|
8362
8396
|
});
|
|
8363
8397
|
}
|
|
8398
|
+
/** The implementation is what runs for every signature of an overload
|
|
8399
|
+
* set, so each signature must be one it can serve: no parameter it does
|
|
8400
|
+
* not have, no fewer arguments than it requires, no argument type it does
|
|
8401
|
+
* not accept, and a return it can give. Stricter than TypeScript, which
|
|
8402
|
+
* lets a signature name parameters the implementation never reads. */
|
|
8403
|
+
checkOverload(func, signature) {
|
|
8404
|
+
if (!this.emitDiagnostics) return;
|
|
8405
|
+
const node = signature;
|
|
8406
|
+
const report = (message) => {
|
|
8407
|
+
this.diagnostics.push({ node, message });
|
|
8408
|
+
};
|
|
8409
|
+
const own = (params) => params.filter((p, i) => !p.rest && !(i === 0 && !p.typeAnnotation && (p.name === "self" || p.name === "this")));
|
|
8410
|
+
const implementation = own(func.params);
|
|
8411
|
+
const offered = own(signature.params);
|
|
8412
|
+
const implementationRest = func.params.some((p) => p.rest);
|
|
8413
|
+
const signatureRest = signature.params.some((p) => p.rest);
|
|
8414
|
+
const label = (p) => p.pattern ? "a destructured parameter" : `'${p.name}'`;
|
|
8415
|
+
if (!implementationRest) {
|
|
8416
|
+
const extra = offered[implementation.length];
|
|
8417
|
+
if (extra) {
|
|
8418
|
+
report(`This overload takes parameter ${label(extra)}, which the implementation does not have: it takes ${implementation.length} parameter${implementation.length === 1 ? "" : "s"}`);
|
|
8419
|
+
return;
|
|
8420
|
+
}
|
|
8421
|
+
if (signatureRest) {
|
|
8422
|
+
report("This overload takes a rest parameter, which the implementation does not have");
|
|
8423
|
+
return;
|
|
8424
|
+
}
|
|
8425
|
+
}
|
|
8426
|
+
if (!signatureRest) {
|
|
8427
|
+
let required = 0;
|
|
8428
|
+
implementation.forEach((p, i) => {
|
|
8429
|
+
if (!p.optional && p.default === void 0) required = i + 1;
|
|
8430
|
+
});
|
|
8431
|
+
if (offered.length < required) {
|
|
8432
|
+
report(`The implementation requires ${required} argument${required === 1 ? "" : "s"}, and this overload passes at most ${offered.length}`);
|
|
8433
|
+
return;
|
|
8434
|
+
}
|
|
8435
|
+
}
|
|
8436
|
+
if (signature.generics.length || func.generics.length) return;
|
|
8437
|
+
for (let i = 0; i < offered.length && i < implementation.length; i++) {
|
|
8438
|
+
const target = implementation[i];
|
|
8439
|
+
if (!target.typeAnnotation && target.default === void 0) continue;
|
|
8440
|
+
let accepted = this.paramType(target, /* @__PURE__ */ new Map());
|
|
8441
|
+
if (target.default !== void 0) accepted = optional(accepted);
|
|
8442
|
+
const given = this.paramType(offered[i], /* @__PURE__ */ new Map());
|
|
8443
|
+
if (!isAssignable(given, accepted)) {
|
|
8444
|
+
report(`Parameter ${label(offered[i])} of this overload is '${briefType(given)}', which the implementation's '${briefType(accepted)}' does not accept`);
|
|
8445
|
+
return;
|
|
8446
|
+
}
|
|
8447
|
+
}
|
|
8448
|
+
if (signature.returnType && func.returnType) {
|
|
8449
|
+
const promised = this.resolveType(signature.returnType);
|
|
8450
|
+
const returned = this.resolveType(func.returnType);
|
|
8451
|
+
if (!isAssignable(promised, returned) && !isAssignable(returned, promised)) {
|
|
8452
|
+
report(`This overload returns '${briefType(promised)}', which the implementation's '${briefType(returned)}' cannot be`);
|
|
8453
|
+
}
|
|
8454
|
+
}
|
|
8455
|
+
}
|
|
8364
8456
|
signatureToFnType(sig) {
|
|
8365
8457
|
const names = sig.generics.map((g) => g.name);
|
|
8366
8458
|
const record = (type) => {
|
|
@@ -8785,6 +8877,12 @@ var TypeAnalyzer = class {
|
|
|
8785
8877
|
}
|
|
8786
8878
|
return;
|
|
8787
8879
|
}
|
|
8880
|
+
case "MemberExpression":
|
|
8881
|
+
case "IndexExpression":
|
|
8882
|
+
this.infer(target, env);
|
|
8883
|
+
this.checkReadonlyAssign(target, env);
|
|
8884
|
+
this.assignToRef(target, widen(valueType), env);
|
|
8885
|
+
return;
|
|
8788
8886
|
case "ObjectPattern": {
|
|
8789
8887
|
for (const p of target.properties) {
|
|
8790
8888
|
const key = !p.computed && p.key.type === "Identifier" ? p.key.name : !p.computed && p.key.type === "StringLiteral" ? p.key.value : void 0;
|