From 96cc8292b721459b9fc14d535206d5464dd704ce Mon Sep 17 00:00:00 2001 From: Brian Ng Date: Wed, 19 Aug 2020 14:15:01 -0500 Subject: [PATCH] Fix parsing type casted generic flow arrow exprs (#11955) --- packages/babel-parser/src/plugins/flow.js | 51 ++++++-- .../input.js | 1 + .../options.json | 6 + .../generic-arrow-func-invalid/input.js | 1 + .../generic-arrow-func-invalid/options.json | 5 + .../generic-arrow-func-parenthesized/input.js | 2 + .../options.json | 5 + .../output.json | 109 ++++++++++++++++++ .../typecasts/generic-arrow-func/input.js | 2 + .../typecasts/generic-arrow-func/output.json | 109 ++++++++++++++++++ 10 files changed, 282 insertions(+), 9 deletions(-) create mode 100644 packages/babel-parser/test/fixtures/flow/typecasts/generic-arrow-func-invalid-parenthesized/input.js create mode 100644 packages/babel-parser/test/fixtures/flow/typecasts/generic-arrow-func-invalid-parenthesized/options.json create mode 100644 packages/babel-parser/test/fixtures/flow/typecasts/generic-arrow-func-invalid/input.js create mode 100644 packages/babel-parser/test/fixtures/flow/typecasts/generic-arrow-func-invalid/options.json create mode 100644 packages/babel-parser/test/fixtures/flow/typecasts/generic-arrow-func-parenthesized/input.js create mode 100644 packages/babel-parser/test/fixtures/flow/typecasts/generic-arrow-func-parenthesized/options.json create mode 100644 packages/babel-parser/test/fixtures/flow/typecasts/generic-arrow-func-parenthesized/output.json create mode 100644 packages/babel-parser/test/fixtures/flow/typecasts/generic-arrow-func/input.js create mode 100644 packages/babel-parser/test/fixtures/flow/typecasts/generic-arrow-func/output.json diff --git a/packages/babel-parser/src/plugins/flow.js b/packages/babel-parser/src/plugins/flow.js index 20d09c4d22dc..619412a49abd 100644 --- a/packages/babel-parser/src/plugins/flow.js +++ b/packages/babel-parser/src/plugins/flow.js @@ -2674,28 +2674,57 @@ export default (superClass: Class): Class => let typeParameters; - const arrow = this.tryParse(() => { + const arrow = this.tryParse(abort => { typeParameters = this.flowParseTypeParameterDeclaration(); const arrowExpression = this.forwardNoArrowParamsConversionAt( typeParameters, - () => - super.parseMaybeAssign( + () => { + const result = super.parseMaybeAssign( refExpressionErrors, afterLeftParse, refNeedsArrowPos, - ), + ); + + this.resetStartLocationFromNode(result, typeParameters); + + return result; + }, ); - arrowExpression.typeParameters = typeParameters; - this.resetStartLocationFromNode(arrowExpression, typeParameters); + + // (() => {}: any); + if ( + arrowExpression.type !== "ArrowFunctionExpression" && + arrowExpression.extra?.parenthesized + ) { + abort(); + } + + // The above can return a TypeCastExpression when the arrow + // expression is not wrapped in parens. See also `this.parseParenItem`. + const expr = this.maybeUnwrapTypeCastExpression(arrowExpression); + expr.typeParameters = typeParameters; + this.resetStartLocationFromNode(expr, typeParameters); return arrowExpression; }, state); - const arrowExpression: ?N.ArrowFunctionExpression = - arrow.node?.type === "ArrowFunctionExpression" ? arrow.node : null; + let arrowExpression: ?( + | N.ArrowFunctionExpression + | N.TypeCastExpression + ) = null; - if (!arrow.error && arrowExpression) return arrowExpression; + if ( + arrow.node && + this.maybeUnwrapTypeCastExpression(arrow.node).type === + "ArrowFunctionExpression" + ) { + if (!arrow.error && !arrow.aborted) { + return arrow.node; + } + + arrowExpression = arrow.node; + } // If we are here, both JSX and Flow parsing attempts failed. // Give the precedence to the JSX error, except if JSX had an @@ -3482,4 +3511,8 @@ export default (superClass: Class): Class => } return false; } + + maybeUnwrapTypeCastExpression(node: N.Node) { + return node.type === "TypeCastExpression" ? node.expression : node; + } }; diff --git a/packages/babel-parser/test/fixtures/flow/typecasts/generic-arrow-func-invalid-parenthesized/input.js b/packages/babel-parser/test/fixtures/flow/typecasts/generic-arrow-func-invalid-parenthesized/input.js new file mode 100644 index 000000000000..40b148b6973c --- /dev/null +++ b/packages/babel-parser/test/fixtures/flow/typecasts/generic-arrow-func-invalid-parenthesized/input.js @@ -0,0 +1 @@ +(() => {}: any); diff --git a/packages/babel-parser/test/fixtures/flow/typecasts/generic-arrow-func-invalid-parenthesized/options.json b/packages/babel-parser/test/fixtures/flow/typecasts/generic-arrow-func-invalid-parenthesized/options.json new file mode 100644 index 000000000000..a1bb4174e9e8 --- /dev/null +++ b/packages/babel-parser/test/fixtures/flow/typecasts/generic-arrow-func-invalid-parenthesized/options.json @@ -0,0 +1,6 @@ +{ + "sourceType": "module", + "plugins": ["flow"], + "createParenthesizedExpressions": true, + "throws": "Expected an arrow function after this type parameter declaration (1:0)" +} diff --git a/packages/babel-parser/test/fixtures/flow/typecasts/generic-arrow-func-invalid/input.js b/packages/babel-parser/test/fixtures/flow/typecasts/generic-arrow-func-invalid/input.js new file mode 100644 index 000000000000..40b148b6973c --- /dev/null +++ b/packages/babel-parser/test/fixtures/flow/typecasts/generic-arrow-func-invalid/input.js @@ -0,0 +1 @@ +(() => {}: any); diff --git a/packages/babel-parser/test/fixtures/flow/typecasts/generic-arrow-func-invalid/options.json b/packages/babel-parser/test/fixtures/flow/typecasts/generic-arrow-func-invalid/options.json new file mode 100644 index 000000000000..ad808bcb8ba6 --- /dev/null +++ b/packages/babel-parser/test/fixtures/flow/typecasts/generic-arrow-func-invalid/options.json @@ -0,0 +1,5 @@ +{ + "sourceType": "module", + "plugins": ["flow"], + "throws": "Expected an arrow function after this type parameter declaration (1:0)" +} diff --git a/packages/babel-parser/test/fixtures/flow/typecasts/generic-arrow-func-parenthesized/input.js b/packages/babel-parser/test/fixtures/flow/typecasts/generic-arrow-func-parenthesized/input.js new file mode 100644 index 000000000000..28ae7c8caa5c --- /dev/null +++ b/packages/babel-parser/test/fixtures/flow/typecasts/generic-arrow-func-parenthesized/input.js @@ -0,0 +1,2 @@ +(() => {}: any); +((() => {}): any); diff --git a/packages/babel-parser/test/fixtures/flow/typecasts/generic-arrow-func-parenthesized/options.json b/packages/babel-parser/test/fixtures/flow/typecasts/generic-arrow-func-parenthesized/options.json new file mode 100644 index 000000000000..b4b44e71add9 --- /dev/null +++ b/packages/babel-parser/test/fixtures/flow/typecasts/generic-arrow-func-parenthesized/options.json @@ -0,0 +1,5 @@ +{ + "sourceType": "module", + "plugins": ["flow"], + "createParenthesizedExpressions": true +} diff --git a/packages/babel-parser/test/fixtures/flow/typecasts/generic-arrow-func-parenthesized/output.json b/packages/babel-parser/test/fixtures/flow/typecasts/generic-arrow-func-parenthesized/output.json new file mode 100644 index 000000000000..60cffacaf9a9 --- /dev/null +++ b/packages/babel-parser/test/fixtures/flow/typecasts/generic-arrow-func-parenthesized/output.json @@ -0,0 +1,109 @@ +{ + "type": "File", + "start":0,"end":41,"loc":{"start":{"line":1,"column":0},"end":{"line":2,"column":21}}, + "program": { + "type": "Program", + "start":0,"end":41,"loc":{"start":{"line":1,"column":0},"end":{"line":2,"column":21}}, + "sourceType": "module", + "interpreter": null, + "body": [ + { + "type": "ExpressionStatement", + "start":0,"end":19,"loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":19}}, + "expression": { + "type": "ParenthesizedExpression", + "start":0,"end":18,"loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":18}}, + "expression": { + "type": "TypeCastExpression", + "start":1,"end":17,"loc":{"start":{"line":1,"column":1},"end":{"line":1,"column":17}}, + "expression": { + "type": "ArrowFunctionExpression", + "start":1,"end":12,"loc":{"start":{"line":1,"column":1},"end":{"line":1,"column":12}}, + "id": null, + "generator": false, + "async": false, + "params": [], + "body": { + "type": "BlockStatement", + "start":10,"end":12,"loc":{"start":{"line":1,"column":10},"end":{"line":1,"column":12}}, + "body": [], + "directives": [] + }, + "typeParameters": { + "type": "TypeParameterDeclaration", + "start":1,"end":4,"loc":{"start":{"line":1,"column":1},"end":{"line":1,"column":4}}, + "params": [ + { + "type": "TypeParameter", + "start":2,"end":3,"loc":{"start":{"line":1,"column":2},"end":{"line":1,"column":3}}, + "name": "T", + "variance": null + } + ] + } + }, + "typeAnnotation": { + "type": "TypeAnnotation", + "start":12,"end":17,"loc":{"start":{"line":1,"column":12},"end":{"line":1,"column":17}}, + "typeAnnotation": { + "type": "AnyTypeAnnotation", + "start":14,"end":17,"loc":{"start":{"line":1,"column":14},"end":{"line":1,"column":17}} + } + } + } + } + }, + { + "type": "ExpressionStatement", + "start":20,"end":41,"loc":{"start":{"line":2,"column":0},"end":{"line":2,"column":21}}, + "expression": { + "type": "ParenthesizedExpression", + "start":20,"end":40,"loc":{"start":{"line":2,"column":0},"end":{"line":2,"column":20}}, + "expression": { + "type": "TypeCastExpression", + "start":21,"end":39,"loc":{"start":{"line":2,"column":1},"end":{"line":2,"column":19}}, + "expression": { + "type": "ParenthesizedExpression", + "start":21,"end":34,"loc":{"start":{"line":2,"column":1},"end":{"line":2,"column":14}}, + "expression": { + "type": "ArrowFunctionExpression", + "start":22,"end":33,"loc":{"start":{"line":2,"column":2},"end":{"line":2,"column":13}}, + "id": null, + "generator": false, + "async": false, + "params": [], + "body": { + "type": "BlockStatement", + "start":31,"end":33,"loc":{"start":{"line":2,"column":11},"end":{"line":2,"column":13}}, + "body": [], + "directives": [] + }, + "typeParameters": { + "type": "TypeParameterDeclaration", + "start":22,"end":25,"loc":{"start":{"line":2,"column":2},"end":{"line":2,"column":5}}, + "params": [ + { + "type": "TypeParameter", + "start":23,"end":24,"loc":{"start":{"line":2,"column":3},"end":{"line":2,"column":4}}, + "name": "T", + "variance": null + } + ] + } + } + }, + "typeAnnotation": { + "type": "TypeAnnotation", + "start":34,"end":39,"loc":{"start":{"line":2,"column":14},"end":{"line":2,"column":19}}, + "typeAnnotation": { + "type": "AnyTypeAnnotation", + "start":36,"end":39,"loc":{"start":{"line":2,"column":16},"end":{"line":2,"column":19}} + } + } + } + } + } + ], + "directives": [] + } +} \ No newline at end of file diff --git a/packages/babel-parser/test/fixtures/flow/typecasts/generic-arrow-func/input.js b/packages/babel-parser/test/fixtures/flow/typecasts/generic-arrow-func/input.js new file mode 100644 index 000000000000..28ae7c8caa5c --- /dev/null +++ b/packages/babel-parser/test/fixtures/flow/typecasts/generic-arrow-func/input.js @@ -0,0 +1,2 @@ +(() => {}: any); +((() => {}): any); diff --git a/packages/babel-parser/test/fixtures/flow/typecasts/generic-arrow-func/output.json b/packages/babel-parser/test/fixtures/flow/typecasts/generic-arrow-func/output.json new file mode 100644 index 000000000000..ccd99ab2c08d --- /dev/null +++ b/packages/babel-parser/test/fixtures/flow/typecasts/generic-arrow-func/output.json @@ -0,0 +1,109 @@ +{ + "type": "File", + "start":0,"end":41,"loc":{"start":{"line":1,"column":0},"end":{"line":2,"column":21}}, + "program": { + "type": "Program", + "start":0,"end":41,"loc":{"start":{"line":1,"column":0},"end":{"line":2,"column":21}}, + "sourceType": "module", + "interpreter": null, + "body": [ + { + "type": "ExpressionStatement", + "start":0,"end":19,"loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":19}}, + "expression": { + "type": "TypeCastExpression", + "start":1,"end":17,"loc":{"start":{"line":1,"column":1},"end":{"line":1,"column":17}}, + "expression": { + "type": "ArrowFunctionExpression", + "start":1,"end":12,"loc":{"start":{"line":1,"column":1},"end":{"line":1,"column":12}}, + "id": null, + "generator": false, + "async": false, + "params": [], + "body": { + "type": "BlockStatement", + "start":10,"end":12,"loc":{"start":{"line":1,"column":10},"end":{"line":1,"column":12}}, + "body": [], + "directives": [] + }, + "typeParameters": { + "type": "TypeParameterDeclaration", + "start":1,"end":4,"loc":{"start":{"line":1,"column":1},"end":{"line":1,"column":4}}, + "params": [ + { + "type": "TypeParameter", + "start":2,"end":3,"loc":{"start":{"line":1,"column":2},"end":{"line":1,"column":3}}, + "name": "T", + "variance": null + } + ] + } + }, + "typeAnnotation": { + "type": "TypeAnnotation", + "start":12,"end":17,"loc":{"start":{"line":1,"column":12},"end":{"line":1,"column":17}}, + "typeAnnotation": { + "type": "AnyTypeAnnotation", + "start":14,"end":17,"loc":{"start":{"line":1,"column":14},"end":{"line":1,"column":17}} + } + }, + "extra": { + "parenthesized": true, + "parenStart": 0 + } + } + }, + { + "type": "ExpressionStatement", + "start":20,"end":41,"loc":{"start":{"line":2,"column":0},"end":{"line":2,"column":21}}, + "expression": { + "type": "TypeCastExpression", + "start":21,"end":39,"loc":{"start":{"line":2,"column":1},"end":{"line":2,"column":19}}, + "expression": { + "type": "ArrowFunctionExpression", + "start":22,"end":33,"loc":{"start":{"line":2,"column":2},"end":{"line":2,"column":13}}, + "id": null, + "generator": false, + "async": false, + "params": [], + "body": { + "type": "BlockStatement", + "start":31,"end":33,"loc":{"start":{"line":2,"column":11},"end":{"line":2,"column":13}}, + "body": [], + "directives": [] + }, + "typeParameters": { + "type": "TypeParameterDeclaration", + "start":22,"end":25,"loc":{"start":{"line":2,"column":2},"end":{"line":2,"column":5}}, + "params": [ + { + "type": "TypeParameter", + "start":23,"end":24,"loc":{"start":{"line":2,"column":3},"end":{"line":2,"column":4}}, + "name": "T", + "variance": null + } + ] + }, + "extra": { + "parenthesized": true, + "parenStart": 21 + } + }, + "typeAnnotation": { + "type": "TypeAnnotation", + "start":34,"end":39,"loc":{"start":{"line":2,"column":14},"end":{"line":2,"column":19}}, + "typeAnnotation": { + "type": "AnyTypeAnnotation", + "start":36,"end":39,"loc":{"start":{"line":2,"column":16},"end":{"line":2,"column":19}} + } + }, + "extra": { + "parenthesized": true, + "parenStart": 20 + } + } + } + ], + "directives": [] + } +}