Improve syntax error for class fields in ambient context (#12108)

* Improve error messages for ambient context class fields

* Modify switching state.isDeclareContext for class fields with declare
This commit is contained in:
Sosuke Suzuki 2020-09-27 04:52:12 +09:00 committed by GitHub
parent 3d5da4c2b9
commit 39a12674b4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 237 additions and 11 deletions

View File

@ -68,7 +68,7 @@ const TSErrors = Object.freeze({
ConstructorHasTypeParameters:
"Type parameters cannot appear on a constructor declaration.",
DeclareClassFieldHasInitializer:
"'declare' class fields cannot have an initializer",
"Initializers are not allowed in ambient contexts.",
DeclareFunctionHasImplementation:
"An implementation cannot be declared in ambient contexts.",
DuplicateModifier: "Duplicate modifier: '%0'",
@ -1478,10 +1478,7 @@ export default (superClass: Class<Parser>): Class<Parser> =>
kind = "let";
}
const oldIsDeclareContext = this.state.isDeclareContext;
this.state.isDeclareContext = true;
try {
return this.tsInDeclareContext(() => {
switch (starttype) {
case tt._function:
nany.declare = true;
@ -1519,9 +1516,7 @@ export default (superClass: Class<Parser>): Class<Parser> =>
}
}
}
} finally {
this.state.isDeclareContext = oldIsDeclareContext;
}
});
}
// Note: this won't be called unless the keyword is allowed in `shouldParseExportDeclaration`.
@ -2081,7 +2076,19 @@ export default (superClass: Class<Parser>): Class<Parser> =>
if (accessibility) member.accessibility = accessibility;
this.tsParseModifiers(member, ["declare"]);
super.parseClassMember(classBody, member, state, constructorAllowsSuper);
const callParseClassMember = () => {
super.parseClassMember(
classBody,
member,
state,
constructorAllowsSuper,
);
};
if (member.declare) {
this.tsInDeclareContext(callParseClassMember);
} else {
callParseClassMember();
}
}
parseClassMemberWithIsStatic(
@ -2294,7 +2301,7 @@ export default (superClass: Class<Parser>): Class<Parser> =>
parseClassProperty(node: N.ClassProperty): N.ClassProperty {
this.parseClassPropertyAnnotation(node);
if (node.declare && this.match(tt.eq)) {
if (this.state.isDeclareContext && this.match(tt.eq)) {
this.raise(this.state.start, TSErrors.DeclareClassFieldHasInitializer);
}
@ -2781,4 +2788,14 @@ export default (superClass: Class<Parser>): Class<Parser> =>
return param;
}
tsInDeclareContext<T>(cb: () => T): T {
const oldIsDeclareContext = this.state.isDeclareContext;
this.state.isDeclareContext = true;
try {
return cb();
} finally {
this.state.isDeclareContext = oldIsDeclareContext;
}
}
};

View File

@ -2,7 +2,7 @@
"type": "File",
"start":0,"end":43,"loc":{"start":{"line":1,"column":0},"end":{"line":3,"column":1}},
"errors": [
"SyntaxError: 'declare' class fields cannot have an initializer (2:22)"
"SyntaxError: Initializers are not allowed in ambient contexts. (2:22)"
],
"program": {
"type": "Program",

View File

@ -0,0 +1,3 @@
declare class C {
field = "field";
}

View File

@ -0,0 +1,53 @@
{
"type": "File",
"start":0,"end":38,"loc":{"start":{"line":1,"column":0},"end":{"line":3,"column":1}},
"errors": [
"SyntaxError: Initializers are not allowed in ambient contexts. (2:8)"
],
"program": {
"type": "Program",
"start":0,"end":38,"loc":{"start":{"line":1,"column":0},"end":{"line":3,"column":1}},
"sourceType": "module",
"interpreter": null,
"body": [
{
"type": "ClassDeclaration",
"start":0,"end":38,"loc":{"start":{"line":1,"column":0},"end":{"line":3,"column":1}},
"declare": true,
"id": {
"type": "Identifier",
"start":14,"end":15,"loc":{"start":{"line":1,"column":14},"end":{"line":1,"column":15},"identifierName":"C"},
"name": "C"
},
"superClass": null,
"body": {
"type": "ClassBody",
"start":16,"end":38,"loc":{"start":{"line":1,"column":16},"end":{"line":3,"column":1}},
"body": [
{
"type": "ClassProperty",
"start":20,"end":36,"loc":{"start":{"line":2,"column":2},"end":{"line":2,"column":18}},
"static": false,
"key": {
"type": "Identifier",
"start":20,"end":25,"loc":{"start":{"line":2,"column":2},"end":{"line":2,"column":7},"identifierName":"field"},
"name": "field"
},
"computed": false,
"value": {
"type": "StringLiteral",
"start":28,"end":35,"loc":{"start":{"line":2,"column":10},"end":{"line":2,"column":17}},
"extra": {
"rawValue": "field",
"raw": "\"field\""
},
"value": "field"
}
}
]
}
}
],
"directives": []
}
}

View File

@ -0,0 +1,5 @@
declare module m {
class C {
field = "field";
}
}

View File

@ -0,0 +1,3 @@
{
"plugins": ["typescript", "classProperties"]
}

View File

@ -0,0 +1,68 @@
{
"type": "File",
"start":0,"end":57,"loc":{"start":{"line":1,"column":0},"end":{"line":5,"column":1}},
"errors": [
"SyntaxError: Initializers are not allowed in ambient contexts. (3:10)"
],
"program": {
"type": "Program",
"start":0,"end":57,"loc":{"start":{"line":1,"column":0},"end":{"line":5,"column":1}},
"sourceType": "module",
"interpreter": null,
"body": [
{
"type": "TSModuleDeclaration",
"start":0,"end":57,"loc":{"start":{"line":1,"column":0},"end":{"line":5,"column":1}},
"id": {
"type": "Identifier",
"start":15,"end":16,"loc":{"start":{"line":1,"column":15},"end":{"line":1,"column":16},"identifierName":"m"},
"name": "m"
},
"body": {
"type": "TSModuleBlock",
"start":17,"end":57,"loc":{"start":{"line":1,"column":17},"end":{"line":5,"column":1}},
"body": [
{
"type": "ClassDeclaration",
"start":21,"end":55,"loc":{"start":{"line":2,"column":2},"end":{"line":4,"column":3}},
"id": {
"type": "Identifier",
"start":27,"end":28,"loc":{"start":{"line":2,"column":8},"end":{"line":2,"column":9},"identifierName":"C"},
"name": "C"
},
"superClass": null,
"body": {
"type": "ClassBody",
"start":29,"end":55,"loc":{"start":{"line":2,"column":10},"end":{"line":4,"column":3}},
"body": [
{
"type": "ClassProperty",
"start":35,"end":51,"loc":{"start":{"line":3,"column":4},"end":{"line":3,"column":20}},
"static": false,
"key": {
"type": "Identifier",
"start":35,"end":40,"loc":{"start":{"line":3,"column":4},"end":{"line":3,"column":9},"identifierName":"field"},
"name": "field"
},
"computed": false,
"value": {
"type": "StringLiteral",
"start":43,"end":50,"loc":{"start":{"line":3,"column":12},"end":{"line":3,"column":19}},
"extra": {
"rawValue": "field",
"raw": "\"field\""
},
"value": "field"
}
}
]
}
}
]
},
"declare": true
}
],
"directives": []
}
}

View File

@ -0,0 +1,6 @@
declare namespace m {
class C {
field = "field";
}
}

View File

@ -0,0 +1,3 @@
{
"plugins": ["typescript", "classProperties"]
}

View File

@ -0,0 +1,68 @@
{
"type": "File",
"start":0,"end":60,"loc":{"start":{"line":1,"column":0},"end":{"line":5,"column":1}},
"errors": [
"SyntaxError: Initializers are not allowed in ambient contexts. (3:10)"
],
"program": {
"type": "Program",
"start":0,"end":60,"loc":{"start":{"line":1,"column":0},"end":{"line":5,"column":1}},
"sourceType": "module",
"interpreter": null,
"body": [
{
"type": "TSModuleDeclaration",
"start":0,"end":60,"loc":{"start":{"line":1,"column":0},"end":{"line":5,"column":1}},
"id": {
"type": "Identifier",
"start":18,"end":19,"loc":{"start":{"line":1,"column":18},"end":{"line":1,"column":19},"identifierName":"m"},
"name": "m"
},
"body": {
"type": "TSModuleBlock",
"start":20,"end":60,"loc":{"start":{"line":1,"column":20},"end":{"line":5,"column":1}},
"body": [
{
"type": "ClassDeclaration",
"start":24,"end":58,"loc":{"start":{"line":2,"column":2},"end":{"line":4,"column":3}},
"id": {
"type": "Identifier",
"start":30,"end":31,"loc":{"start":{"line":2,"column":8},"end":{"line":2,"column":9},"identifierName":"C"},
"name": "C"
},
"superClass": null,
"body": {
"type": "ClassBody",
"start":32,"end":58,"loc":{"start":{"line":2,"column":10},"end":{"line":4,"column":3}},
"body": [
{
"type": "ClassProperty",
"start":38,"end":54,"loc":{"start":{"line":3,"column":4},"end":{"line":3,"column":20}},
"static": false,
"key": {
"type": "Identifier",
"start":38,"end":43,"loc":{"start":{"line":3,"column":4},"end":{"line":3,"column":9},"identifierName":"field"},
"name": "field"
},
"computed": false,
"value": {
"type": "StringLiteral",
"start":46,"end":53,"loc":{"start":{"line":3,"column":12},"end":{"line":3,"column":19}},
"extra": {
"rawValue": "field",
"raw": "\"field\""
},
"value": "field"
}
}
]
}
}
]
},
"declare": true
}
],
"directives": []
}
}