Skip to content

Commit

Permalink
Improve syntax error for class fields in ambient context (#12108)
Browse files Browse the repository at this point in the history
* Improve error messages for ambient context class fields

* Modify switching state.isDeclareContext for class fields with declare
  • Loading branch information
sosukesuzuki committed Sep 26, 2020
1 parent 3d5da4c commit 39a1267
Show file tree
Hide file tree
Showing 14 changed files with 237 additions and 11 deletions.
37 changes: 27 additions & 10 deletions packages/babel-parser/src/plugins/typescript/index.js
Expand Up @@ -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'",
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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`.
Expand Down Expand Up @@ -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(
Expand Down Expand Up @@ -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);
}

Expand Down Expand Up @@ -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;
}
}
};
Expand Up @@ -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",
Expand Down
@@ -0,0 +1,3 @@
declare class C {
field = "field";
}
@@ -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": []
}
}
@@ -0,0 +1,5 @@
declare module m {
class C {
field = "field";
}
}
@@ -0,0 +1,3 @@
{
"plugins": ["typescript", "classProperties"]
}
@@ -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": []
}
}
@@ -0,0 +1,6 @@
declare namespace m {
class C {
field = "field";
}
}

@@ -0,0 +1,3 @@
{
"plugins": ["typescript", "classProperties"]
}
@@ -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": []
}
}

0 comments on commit 39a1267

Please sign in to comment.