diff --git a/src/parser/expression.js b/src/parser/expression.js index bc89b4bdf5..e01df389c1 100644 --- a/src/parser/expression.js +++ b/src/parser/expression.js @@ -531,12 +531,12 @@ pp.parseParenExpression = function () { return val; }; -pp.parseParenAndDistinguishExpression = function (startPos, startLoc, canBeArrow, isAsync, allowOptionalCommaStart) { +pp.parseParenAndDistinguishExpression = function (startPos, startLoc, canBeArrow, isAsync) { startPos = startPos || this.state.start; startLoc = startLoc || this.state.startLoc; let val; - this.next(); + this.expect(tt.parenL); let innerStartPos = this.state.start, innerStartLoc = this.state.startLoc; let exprList = [], first = true; @@ -566,12 +566,13 @@ pp.parseParenAndDistinguishExpression = function (startPos, startLoc, canBeArrow let innerEndLoc = this.state.startLoc; this.expect(tt.parenR); - if (canBeArrow && !this.canInsertSemicolon() && this.eat(tt.arrow)) { + let arrowNode = this.startNodeAt(startPos, startLoc); + if (canBeArrow && !this.canInsertSemicolon() && (arrowNode = this.parseArrow(arrowNode))) { for (let param of exprList) { if (param.extra && param.extra.parenthesized) this.unexpected(param.extra.parenStart); } - return this.parseArrowExpression(this.startNodeAt(startPos, startLoc), exprList, isAsync); + return this.parseArrowExpression(arrowNode, exprList, isAsync); } if (!exprList.length) { @@ -581,7 +582,7 @@ pp.parseParenAndDistinguishExpression = function (startPos, startLoc, canBeArrow this.unexpected(this.state.lastTokStart); } } - if (optionalCommaStart && !allowOptionalCommaStart) this.unexpected(optionalCommaStart); + if (optionalCommaStart) this.unexpected(optionalCommaStart); if (spreadStart) this.unexpected(spreadStart); if (refShorthandDefaultPos.start) this.unexpected(refShorthandDefaultPos.start); @@ -601,6 +602,12 @@ pp.parseParenAndDistinguishExpression = function (startPos, startLoc, canBeArrow return val; }; +pp.parseArrow = function (node) { + if (this.eat(tt.arrow)) { + return node; + } +}; + pp.parseParenItem = function (node) { return node; }; diff --git a/src/plugins/flow.js b/src/plugins/flow.js index 3ecaeb84e2..f9d65b7e73 100644 --- a/src/plugins/flow.js +++ b/src/plugins/flow.js @@ -717,30 +717,19 @@ export default function (instance) { }; }); - instance.extend("parseParenItem", function () { - return function (node, startLoc, startPos, forceArrow?) { - let canBeArrow = this.state.potentialArrowAt = startPos; + instance.extend("parseParenItem", function (inner) { + return function (node, startLoc, startPos) { + node = inner.call(this, node, startLoc, startPos); + if (this.match(tt.colon)) { let typeCastNode = this.startNodeAt(startLoc, startPos); typeCastNode.expression = node; typeCastNode.typeAnnotation = this.flowParseTypeAnnotation(); - if (forceArrow && !this.match(tt.arrow)) { - this.unexpected(); - } - - if (canBeArrow && this.eat(tt.arrow)) { - // ((lol): number => {}); - let params = node.type === "SequenceExpression" ? node.expressions : [node]; - let func = this.parseArrowExpression(this.startNodeAt(startLoc, startPos), params); - func.returnType = typeCastNode.typeAnnotation; - return func; - } else { - return this.finishNode(typeCastNode, "TypeCastExpression"); - } - } else { - return node; + return this.finishNode(typeCastNode, "TypeCastExpression"); } + + return node; }; }); @@ -1038,40 +1027,25 @@ export default function (instance) { }); // handle return types for arrow functions - instance.extend("parseParenAndDistinguishExpression", function (inner) { - return function (startPos, startLoc, canBeArrow, isAsync) { - startPos = startPos || this.state.start; - startLoc = startLoc || this.state.startLoc; - - if (canBeArrow && this.lookahead().type === tt.parenR) { - // let foo = (): number => {}; - this.expect(tt.parenL); - this.expect(tt.parenR); - - let node = this.startNodeAt(startPos, startLoc); - if (this.match(tt.colon)) node.returnType = this.flowParseTypeAnnotation(); - this.expect(tt.arrow); - return this.parseArrowExpression(node, [], isAsync); - } else { - // let foo = (foo): number => {}; - let node = inner.call(this, startPos, startLoc, canBeArrow, isAsync, this.hasPlugin("trailingFunctionCommas")); - - if (this.match(tt.colon)) { - let state = this.state.clone(); - try { - return this.parseParenItem(node, startPos, startLoc, true); - } catch (err) { - if (err instanceof SyntaxError) { - this.state = state; - return node; - } else { - throw err; - } + instance.extend("parseArrow", function (inner) { + return function (node) { + if (this.match(tt.colon)) { + let state = this.state.clone(); + try { + let returnType = this.flowParseTypeAnnotation(); + if (!this.match(tt.arrow)) this.unexpected(); + // assign after it is clear it is an arrow + node.returnType = returnType; + } catch (err) { + if (err instanceof SyntaxError) { + this.state = state; + } else { + throw err; } - } else { - return node; } } + + return inner.call(this, node); }; }); } diff --git a/test/fixtures/flow/regression/issue-2493/expected.json b/test/fixtures/flow/regression/issue-2493/expected.json index cba658c02f..3cd5ae4637 100644 --- a/test/fixtures/flow/regression/issue-2493/expected.json +++ b/test/fixtures/flow/regression/issue-2493/expected.json @@ -171,10 +171,6 @@ "raw": "' world'" }, "value": " world" - }, - "extra": { - "parenthesized": true, - "parenStart": 12 } } ], diff --git a/test/fixtures/flow/type-annotations/101/actual.js b/test/fixtures/flow/type-annotations/101/actual.js new file mode 100644 index 0000000000..be74d7b115 --- /dev/null +++ b/test/fixtures/flow/type-annotations/101/actual.js @@ -0,0 +1 @@ +( ...props: SomeType ) : ?ReturnType => ( 3 ); diff --git a/test/fixtures/flow/type-annotations/101/expected.json b/test/fixtures/flow/type-annotations/101/expected.json new file mode 100644 index 0000000000..7cc317bf8f --- /dev/null +++ b/test/fixtures/flow/type-annotations/101/expected.json @@ -0,0 +1,232 @@ +{ + "type": "File", + "start": 0, + "end": 46, + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 1, + "column": 46 + } + }, + "program": { + "type": "Program", + "start": 0, + "end": 46, + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 1, + "column": 46 + } + }, + "sourceType": "module", + "body": [ + { + "type": "ExpressionStatement", + "start": 0, + "end": 46, + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 1, + "column": 46 + } + }, + "expression": { + "type": "ArrowFunctionExpression", + "start": 0, + "end": 45, + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 1, + "column": 45 + } + }, + "returnType": { + "type": "TypeAnnotation", + "start": 23, + "end": 36, + "loc": { + "start": { + "line": 1, + "column": 23 + }, + "end": { + "line": 1, + "column": 36 + } + }, + "typeAnnotation": { + "type": "NullableTypeAnnotation", + "start": 25, + "end": 36, + "loc": { + "start": { + "line": 1, + "column": 25 + }, + "end": { + "line": 1, + "column": 36 + } + }, + "typeAnnotation": { + "type": "GenericTypeAnnotation", + "start": 26, + "end": 36, + "loc": { + "start": { + "line": 1, + "column": 26 + }, + "end": { + "line": 1, + "column": 36 + } + }, + "typeParameters": null, + "id": { + "type": "Identifier", + "start": 26, + "end": 36, + "loc": { + "start": { + "line": 1, + "column": 26 + }, + "end": { + "line": 1, + "column": 36 + } + }, + "name": "ReturnType" + } + } + } + }, + "id": null, + "generator": false, + "expression": true, + "async": false, + "params": [ + { + "type": "RestElement", + "start": 2, + "end": 10, + "loc": { + "start": { + "line": 1, + "column": 2 + }, + "end": { + "line": 1, + "column": 10 + } + }, + "argument": { + "type": "Identifier", + "start": 5, + "end": 10, + "loc": { + "start": { + "line": 1, + "column": 5 + }, + "end": { + "line": 1, + "column": 10 + } + }, + "name": "props" + }, + "typeAnnotation": { + "type": "TypeAnnotation", + "start": 10, + "end": 20, + "loc": { + "start": { + "line": 1, + "column": 10 + }, + "end": { + "line": 1, + "column": 20 + } + }, + "typeAnnotation": { + "type": "GenericTypeAnnotation", + "start": 12, + "end": 20, + "loc": { + "start": { + "line": 1, + "column": 12 + }, + "end": { + "line": 1, + "column": 20 + } + }, + "typeParameters": null, + "id": { + "type": "Identifier", + "start": 12, + "end": 20, + "loc": { + "start": { + "line": 1, + "column": 12 + }, + "end": { + "line": 1, + "column": 20 + } + }, + "name": "SomeType" + } + } + } + } + ], + "body": { + "type": "NumericLiteral", + "start": 42, + "end": 43, + "loc": { + "start": { + "line": 1, + "column": 42 + }, + "end": { + "line": 1, + "column": 43 + } + }, + "extra": { + "rawValue": 3, + "raw": "3", + "parenthesized": true, + "parenStart": 40 + }, + "value": 3 + } + } + } + ], + "directives": [] + } +} \ No newline at end of file diff --git a/test/fixtures/flow/type-annotations/102/actual.js b/test/fixtures/flow/type-annotations/102/actual.js new file mode 100644 index 0000000000..406c4a703d --- /dev/null +++ b/test/fixtures/flow/type-annotations/102/actual.js @@ -0,0 +1 @@ +export default (...modifiers): Array => {}; diff --git a/test/fixtures/flow/type-annotations/102/expected.json b/test/fixtures/flow/type-annotations/102/expected.json new file mode 100644 index 0000000000..4af93bb673 --- /dev/null +++ b/test/fixtures/flow/type-annotations/102/expected.json @@ -0,0 +1,196 @@ +{ + "type": "File", + "start": 0, + "end": 51, + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 1, + "column": 51 + } + }, + "program": { + "type": "Program", + "start": 0, + "end": 51, + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 1, + "column": 51 + } + }, + "sourceType": "module", + "body": [ + { + "type": "ExportDefaultDeclaration", + "start": 0, + "end": 51, + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 1, + "column": 51 + } + }, + "declaration": { + "type": "ArrowFunctionExpression", + "start": 15, + "end": 50, + "loc": { + "start": { + "line": 1, + "column": 15 + }, + "end": { + "line": 1, + "column": 50 + } + }, + "returnType": { + "type": "TypeAnnotation", + "start": 29, + "end": 44, + "loc": { + "start": { + "line": 1, + "column": 29 + }, + "end": { + "line": 1, + "column": 44 + } + }, + "typeAnnotation": { + "type": "GenericTypeAnnotation", + "start": 31, + "end": 44, + "loc": { + "start": { + "line": 1, + "column": 31 + }, + "end": { + "line": 1, + "column": 44 + } + }, + "typeParameters": { + "type": "TypeParameterInstantiation", + "start": 36, + "end": 44, + "loc": { + "start": { + "line": 1, + "column": 36 + }, + "end": { + "line": 1, + "column": 44 + } + }, + "params": [ + { + "type": "StringTypeAnnotation", + "start": 37, + "end": 43, + "loc": { + "start": { + "line": 1, + "column": 37 + }, + "end": { + "line": 1, + "column": 43 + } + } + } + ] + }, + "id": { + "type": "Identifier", + "start": 31, + "end": 36, + "loc": { + "start": { + "line": 1, + "column": 31 + }, + "end": { + "line": 1, + "column": 36 + } + }, + "name": "Array" + } + } + }, + "id": null, + "generator": false, + "expression": false, + "async": false, + "params": [ + { + "type": "RestElement", + "start": 16, + "end": 28, + "loc": { + "start": { + "line": 1, + "column": 16 + }, + "end": { + "line": 1, + "column": 28 + } + }, + "argument": { + "type": "Identifier", + "start": 19, + "end": 28, + "loc": { + "start": { + "line": 1, + "column": 19 + }, + "end": { + "line": 1, + "column": 28 + } + }, + "name": "modifiers" + } + } + ], + "body": { + "type": "BlockStatement", + "start": 48, + "end": 50, + "loc": { + "start": { + "line": 1, + "column": 48 + }, + "end": { + "line": 1, + "column": 50 + } + }, + "body": [], + "directives": [] + } + } + } + ], + "directives": [] + } +} diff --git a/test/fixtures/flow/type-annotations/103/actual.js b/test/fixtures/flow/type-annotations/103/actual.js new file mode 100644 index 0000000000..b6a472b531 --- /dev/null +++ b/test/fixtures/flow/type-annotations/103/actual.js @@ -0,0 +1 @@ +const parser = (rootPath: string, ...filesToParse: Array):a => {} diff --git a/test/fixtures/flow/type-annotations/103/expected.json b/test/fixtures/flow/type-annotations/103/expected.json new file mode 100644 index 0000000000..5eda80448f --- /dev/null +++ b/test/fixtures/flow/type-annotations/103/expected.json @@ -0,0 +1,323 @@ +{ + "type": "File", + "start": 0, + "end": 73, + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 1, + "column": 73 + } + }, + "program": { + "type": "Program", + "start": 0, + "end": 73, + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 1, + "column": 73 + } + }, + "sourceType": "module", + "body": [ + { + "type": "VariableDeclaration", + "start": 0, + "end": 73, + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 1, + "column": 73 + } + }, + "declarations": [ + { + "type": "VariableDeclarator", + "start": 6, + "end": 73, + "loc": { + "start": { + "line": 1, + "column": 6 + }, + "end": { + "line": 1, + "column": 73 + } + }, + "id": { + "type": "Identifier", + "start": 6, + "end": 12, + "loc": { + "start": { + "line": 1, + "column": 6 + }, + "end": { + "line": 1, + "column": 12 + } + }, + "name": "parser" + }, + "init": { + "type": "ArrowFunctionExpression", + "start": 15, + "end": 73, + "loc": { + "start": { + "line": 1, + "column": 15 + }, + "end": { + "line": 1, + "column": 73 + } + }, + "returnType": { + "type": "TypeAnnotation", + "start": 65, + "end": 67, + "loc": { + "start": { + "line": 1, + "column": 65 + }, + "end": { + "line": 1, + "column": 67 + } + }, + "typeAnnotation": { + "type": "GenericTypeAnnotation", + "start": 66, + "end": 67, + "loc": { + "start": { + "line": 1, + "column": 66 + }, + "end": { + "line": 1, + "column": 67 + } + }, + "typeParameters": null, + "id": { + "type": "Identifier", + "start": 66, + "end": 67, + "loc": { + "start": { + "line": 1, + "column": 66 + }, + "end": { + "line": 1, + "column": 67 + } + }, + "name": "a" + } + } + }, + "id": null, + "generator": false, + "expression": false, + "async": false, + "params": [ + { + "type": "Identifier", + "start": 16, + "end": 24, + "loc": { + "start": { + "line": 1, + "column": 16 + }, + "end": { + "line": 1, + "column": 24 + } + }, + "name": "rootPath", + "typeAnnotation": { + "type": "TypeAnnotation", + "start": 24, + "end": 32, + "loc": { + "start": { + "line": 1, + "column": 24 + }, + "end": { + "line": 1, + "column": 32 + } + }, + "typeAnnotation": { + "type": "StringTypeAnnotation", + "start": 26, + "end": 32, + "loc": { + "start": { + "line": 1, + "column": 26 + }, + "end": { + "line": 1, + "column": 32 + } + } + } + } + }, + { + "type": "RestElement", + "start": 34, + "end": 49, + "loc": { + "start": { + "line": 1, + "column": 34 + }, + "end": { + "line": 1, + "column": 49 + } + }, + "argument": { + "type": "Identifier", + "start": 37, + "end": 49, + "loc": { + "start": { + "line": 1, + "column": 37 + }, + "end": { + "line": 1, + "column": 49 + } + }, + "name": "filesToParse" + }, + "typeAnnotation": { + "type": "TypeAnnotation", + "start": 49, + "end": 64, + "loc": { + "start": { + "line": 1, + "column": 49 + }, + "end": { + "line": 1, + "column": 64 + } + }, + "typeAnnotation": { + "type": "GenericTypeAnnotation", + "start": 51, + "end": 64, + "loc": { + "start": { + "line": 1, + "column": 51 + }, + "end": { + "line": 1, + "column": 64 + } + }, + "typeParameters": { + "type": "TypeParameterInstantiation", + "start": 56, + "end": 64, + "loc": { + "start": { + "line": 1, + "column": 56 + }, + "end": { + "line": 1, + "column": 64 + } + }, + "params": [ + { + "type": "StringTypeAnnotation", + "start": 57, + "end": 63, + "loc": { + "start": { + "line": 1, + "column": 57 + }, + "end": { + "line": 1, + "column": 63 + } + } + } + ] + }, + "id": { + "type": "Identifier", + "start": 51, + "end": 56, + "loc": { + "start": { + "line": 1, + "column": 51 + }, + "end": { + "line": 1, + "column": 56 + } + }, + "name": "Array" + } + } + } + } + ], + "body": { + "type": "BlockStatement", + "start": 71, + "end": 73, + "loc": { + "start": { + "line": 1, + "column": 71 + }, + "end": { + "line": 1, + "column": 73 + } + }, + "body": [], + "directives": [] + } + } + } + ], + "kind": "const" + } + ], + "directives": [] + } +} \ No newline at end of file diff --git a/test/fixtures/flow/type-annotations/68/expected.json b/test/fixtures/flow/type-annotations/68/expected.json index 0947eeb733..433bc78a8f 100644 --- a/test/fixtures/flow/type-annotations/68/expected.json +++ b/test/fixtures/flow/type-annotations/68/expected.json @@ -105,10 +105,7 @@ "column": 14 } }, - "name": "bar", - "extra": { - "parenthesized": true - } + "name": "bar" } ], "body": { diff --git a/test/fixtures/flow/type-annotations/73/expected.json b/test/fixtures/flow/type-annotations/73/expected.json index a14ef97682..3b2f689738 100644 --- a/test/fixtures/flow/type-annotations/73/expected.json +++ b/test/fixtures/flow/type-annotations/73/expected.json @@ -105,10 +105,7 @@ "column": 15 } }, - "name": "bar", - "extra": { - "parenthesized": true - } + "name": "bar" } ], "body": { diff --git a/test/fixtures/flow/type-annotations/74/expected.json b/test/fixtures/flow/type-annotations/74/expected.json index c22c079ced..2abdde67da 100644 --- a/test/fixtures/flow/type-annotations/74/expected.json +++ b/test/fixtures/flow/type-annotations/74/expected.json @@ -119,10 +119,7 @@ "column": 16 } }, - "name": "bar", - "extra": { - "parenthesized": true - } + "name": "bar" } ], "body": { diff --git a/test/fixtures/flow/type-annotations/79/expected.json b/test/fixtures/flow/type-annotations/79/expected.json index 30439bfe89..fe1dab6354 100644 --- a/test/fixtures/flow/type-annotations/79/expected.json +++ b/test/fixtures/flow/type-annotations/79/expected.json @@ -135,10 +135,7 @@ "column": 20 } }, - "name": "foo", - "extra": { - "parenthesized": true - } + "name": "foo" } ], "body": {