ts: Check if param is assignable when parsing arrow return type (#13581)

This commit is contained in:
Nicolò Ribaudo 2021-07-26 17:58:10 +02:00 committed by GitHub
parent 1d48bb0d8c
commit 4a56387330
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 405 additions and 47 deletions

View File

@ -1503,7 +1503,7 @@ export default class ExpressionParser extends LValParser {
let arrowNode = this.startNodeAt(startPos, startLoc); let arrowNode = this.startNodeAt(startPos, startLoc);
if ( if (
canBeArrow && canBeArrow &&
this.shouldParseArrow() && this.shouldParseArrow(exprList) &&
(arrowNode = this.parseArrow(arrowNode)) (arrowNode = this.parseArrow(arrowNode))
) { ) {
this.expressionScope.validateAsPattern(); this.expressionScope.validateAsPattern();
@ -1544,7 +1544,8 @@ export default class ExpressionParser extends LValParser {
return parenExpression; return parenExpression;
} }
shouldParseArrow(): boolean { // eslint-disable-next-line no-unused-vars -- `params` is used in typescript plugin
shouldParseArrow(params: Array<N.Node>): boolean {
return !this.canInsertSemicolon(); return !this.canInsertSemicolon();
} }

View File

@ -60,7 +60,7 @@ export default class LValParser extends NodeUtils {
- RestElement is not the last element - RestElement is not the last element
- Missing `=` in assignment pattern - Missing `=` in assignment pattern
NOTE: There is a corresponding "isAssignable" method in flow.js. NOTE: There is a corresponding "isAssignable" method.
When this one is updated, please check if also that one needs to be updated. When this one is updated, please check if also that one needs to be updated.
* @param {Node} node The expression atom * @param {Node} node The expression atom
@ -100,6 +100,7 @@ export default class LValParser extends NodeUtils {
case "ObjectPattern": case "ObjectPattern":
case "ArrayPattern": case "ArrayPattern":
case "AssignmentPattern": case "AssignmentPattern":
case "RestElement":
break; break;
case "ObjectExpression": case "ObjectExpression":
@ -229,6 +230,50 @@ export default class LValParser extends NodeUtils {
return exprList; return exprList;
} }
isAssignable(node: Node, isBinding?: boolean): boolean {
switch (node.type) {
case "Identifier":
case "ObjectPattern":
case "ArrayPattern":
case "AssignmentPattern":
case "RestElement":
return true;
case "ObjectExpression": {
const last = node.properties.length - 1;
return node.properties.every((prop, i) => {
return (
prop.type !== "ObjectMethod" &&
(i === last || prop.type !== "SpreadElement") &&
this.isAssignable(prop)
);
});
}
case "ObjectProperty":
return this.isAssignable(node.value);
case "SpreadElement":
return this.isAssignable(node.argument);
case "ArrayExpression":
return node.elements.every(element => this.isAssignable(element));
case "AssignmentExpression":
return node.operator === "=";
case "ParenthesizedExpression":
return this.isAssignable(node.expression);
case "MemberExpression":
case "OptionalMemberExpression":
return !isBinding;
default:
return false;
}
}
// Convert list of expression atoms to a list of // Convert list of expression atoms to a list of
toReferencedList( toReferencedList(

View File

@ -330,6 +330,13 @@ export default (superClass: Class<Parser>): Class<Parser> =>
return (node: any); return (node: any);
} }
isAssignable(node: N.Node, isBinding?: boolean): boolean {
if (node != null && this.isObjectProperty(node)) {
return this.isAssignable(node.value, isBinding);
}
return super.isAssignable(node, isBinding);
}
toAssignable(node: N.Node, isLHS: boolean = false): N.Node { toAssignable(node: N.Node, isLHS: boolean = false): N.Node {
if (node != null && this.isObjectProperty(node)) { if (node != null && this.isObjectProperty(node)) {
this.toAssignable(node.value, isLHS); this.toAssignable(node.value, isLHS);

View File

@ -2257,46 +2257,10 @@ export default (superClass: Class<Parser>): Class<Parser> =>
} }
isAssignable(node: N.Node, isBinding?: boolean): boolean { isAssignable(node: N.Node, isBinding?: boolean): boolean {
switch (node.type) { if (node.type === "TypeCastExpression") {
case "Identifier": return this.isAssignable(node.expression, isBinding);
case "ObjectPattern": } else {
case "ArrayPattern": return super.isAssignable(node, isBinding);
case "AssignmentPattern":
return true;
case "ObjectExpression": {
const last = node.properties.length - 1;
return node.properties.every((prop, i) => {
return (
prop.type !== "ObjectMethod" &&
(i === last || prop.type === "SpreadElement") &&
this.isAssignable(prop)
);
});
}
case "ObjectProperty":
return this.isAssignable(node.value);
case "SpreadElement":
return this.isAssignable(node.argument);
case "ArrayExpression":
return node.elements.every(element => this.isAssignable(element));
case "AssignmentExpression":
return node.operator === "=";
case "ParenthesizedExpression":
case "TypeCastExpression":
return this.isAssignable(node.expression);
case "MemberExpression":
case "OptionalMemberExpression":
return !isBinding;
default:
return false;
} }
} }
@ -2989,8 +2953,8 @@ export default (superClass: Class<Parser>): Class<Parser> =>
return super.parseArrow(node); return super.parseArrow(node);
} }
shouldParseArrow(): boolean { shouldParseArrow(params: Array<N.Node>): boolean {
return this.match(tt.colon) || super.shouldParseArrow(); return this.match(tt.colon) || super.shouldParseArrow(params);
} }
setArrowFunctionParameters( setArrowFunctionParameters(

View File

@ -2877,6 +2877,17 @@ export default (superClass: Class<Parser>): Class<Parser> =>
return param; return param;
} }
isAssignable(node: N.Node, isBinding?: boolean): boolean {
switch (node.type) {
case "TSTypeCastExpression":
return this.isAssignable(node.expression, isBinding);
case "TSParameterProperty":
return true;
default:
return super.isAssignable(node, isBinding);
}
}
toAssignable(node: N.Node, isLHS: boolean = false): N.Node { toAssignable(node: N.Node, isLHS: boolean = false): N.Node {
switch (node.type) { switch (node.type) {
case "TSTypeCastExpression": case "TSTypeCastExpression":
@ -3071,8 +3082,11 @@ export default (superClass: Class<Parser>): Class<Parser> =>
return node.expression; return node.expression;
} }
shouldParseArrow() { shouldParseArrow(params: Array<N.Node>) {
return this.match(tt.colon) || super.shouldParseArrow(); if (this.match(tt.colon)) {
return params.every(expr => this.isAssignable(expr, true));
}
return super.shouldParseArrow(params);
} }
shouldParseAsyncArrow(): boolean { shouldParseAsyncArrow(): boolean {

View File

@ -0,0 +1,2 @@
// https://github.com/babel/babel/issues/11038
0 ? v => (sum += v) : v => 0;

View File

@ -0,0 +1,100 @@
{
"type": "File",
"start":0,"end":76,"loc":{"start":{"line":1,"column":0},"end":{"line":2,"column":29}},
"program": {
"type": "Program",
"start":0,"end":76,"loc":{"start":{"line":1,"column":0},"end":{"line":2,"column":29}},
"sourceType": "module",
"interpreter": null,
"body": [
{
"type": "ExpressionStatement",
"start":47,"end":76,"loc":{"start":{"line":2,"column":0},"end":{"line":2,"column":29}},
"leadingComments": [
{
"type": "CommentLine",
"value": " https://github.com/babel/babel/issues/11038",
"start":0,"end":46,"loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":46}}
}
],
"expression": {
"type": "ConditionalExpression",
"start":47,"end":75,"loc":{"start":{"line":2,"column":0},"end":{"line":2,"column":28}},
"test": {
"type": "NumericLiteral",
"start":47,"end":48,"loc":{"start":{"line":2,"column":0},"end":{"line":2,"column":1}},
"extra": {
"rawValue": 0,
"raw": "0"
},
"value": 0
},
"consequent": {
"type": "ArrowFunctionExpression",
"start":51,"end":66,"loc":{"start":{"line":2,"column":4},"end":{"line":2,"column":19}},
"id": null,
"generator": false,
"async": false,
"params": [
{
"type": "Identifier",
"start":51,"end":52,"loc":{"start":{"line":2,"column":4},"end":{"line":2,"column":5},"identifierName":"v"},
"name": "v"
}
],
"body": {
"type": "AssignmentExpression",
"start":57,"end":65,"loc":{"start":{"line":2,"column":10},"end":{"line":2,"column":18}},
"extra": {
"parenthesized": true,
"parenStart": 56
},
"operator": "+=",
"left": {
"type": "Identifier",
"start":57,"end":60,"loc":{"start":{"line":2,"column":10},"end":{"line":2,"column":13},"identifierName":"sum"},
"name": "sum"
},
"right": {
"type": "Identifier",
"start":64,"end":65,"loc":{"start":{"line":2,"column":17},"end":{"line":2,"column":18},"identifierName":"v"},
"name": "v"
}
}
},
"alternate": {
"type": "ArrowFunctionExpression",
"start":69,"end":75,"loc":{"start":{"line":2,"column":22},"end":{"line":2,"column":28}},
"id": null,
"generator": false,
"async": false,
"params": [
{
"type": "Identifier",
"start":69,"end":70,"loc":{"start":{"line":2,"column":22},"end":{"line":2,"column":23},"identifierName":"v"},
"name": "v"
}
],
"body": {
"type": "NumericLiteral",
"start":74,"end":75,"loc":{"start":{"line":2,"column":27},"end":{"line":2,"column":28}},
"extra": {
"rawValue": 0,
"raw": "0"
},
"value": 0
}
}
}
}
],
"directives": []
},
"comments": [
{
"type": "CommentLine",
"value": " https://github.com/babel/babel/issues/11038",
"start":0,"end":46,"loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":46}}
}
]
}

View File

@ -0,0 +1 @@
0 ? v => (sum = v) : v => 0;

View File

@ -0,0 +1,3 @@
{
"throws": "Unexpected token, expected \":\" (1:27)"
}

View File

@ -0,0 +1 @@
0 ? v => (sum = v) : v => 0 : v => 0;

View File

@ -0,0 +1,112 @@
{
"type": "File",
"start":0,"end":37,"loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":37}},
"program": {
"type": "Program",
"start":0,"end":37,"loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":37}},
"sourceType": "module",
"interpreter": null,
"body": [
{
"type": "ExpressionStatement",
"start":0,"end":37,"loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":37}},
"expression": {
"type": "ConditionalExpression",
"start":0,"end":36,"loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":36}},
"test": {
"type": "NumericLiteral",
"start":0,"end":1,"loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":1}},
"extra": {
"rawValue": 0,
"raw": "0"
},
"value": 0
},
"consequent": {
"type": "ArrowFunctionExpression",
"start":4,"end":27,"loc":{"start":{"line":1,"column":4},"end":{"line":1,"column":27}},
"id": null,
"generator": false,
"async": false,
"params": [
{
"type": "Identifier",
"start":4,"end":5,"loc":{"start":{"line":1,"column":4},"end":{"line":1,"column":5},"identifierName":"v"},
"name": "v"
}
],
"body": {
"type": "ArrowFunctionExpression",
"start":9,"end":27,"loc":{"start":{"line":1,"column":9},"end":{"line":1,"column":27}},
"returnType": {
"type": "TSTypeAnnotation",
"start":19,"end":22,"loc":{"start":{"line":1,"column":19},"end":{"line":1,"column":22}},
"typeAnnotation": {
"type": "TSTypeReference",
"start":21,"end":22,"loc":{"start":{"line":1,"column":21},"end":{"line":1,"column":22}},
"typeName": {
"type": "Identifier",
"start":21,"end":22,"loc":{"start":{"line":1,"column":21},"end":{"line":1,"column":22},"identifierName":"v"},
"name": "v"
}
}
},
"id": null,
"generator": false,
"async": false,
"params": [
{
"type": "AssignmentPattern",
"start":10,"end":17,"loc":{"start":{"line":1,"column":10},"end":{"line":1,"column":17}},
"left": {
"type": "Identifier",
"start":10,"end":13,"loc":{"start":{"line":1,"column":10},"end":{"line":1,"column":13},"identifierName":"sum"},
"name": "sum"
},
"right": {
"type": "Identifier",
"start":16,"end":17,"loc":{"start":{"line":1,"column":16},"end":{"line":1,"column":17},"identifierName":"v"},
"name": "v"
}
}
],
"body": {
"type": "NumericLiteral",
"start":26,"end":27,"loc":{"start":{"line":1,"column":26},"end":{"line":1,"column":27}},
"extra": {
"rawValue": 0,
"raw": "0"
},
"value": 0
}
}
},
"alternate": {
"type": "ArrowFunctionExpression",
"start":30,"end":36,"loc":{"start":{"line":1,"column":30},"end":{"line":1,"column":36}},
"id": null,
"generator": false,
"async": false,
"params": [
{
"type": "Identifier",
"start":30,"end":31,"loc":{"start":{"line":1,"column":30},"end":{"line":1,"column":31},"identifierName":"v"},
"name": "v"
}
],
"body": {
"type": "NumericLiteral",
"start":35,"end":36,"loc":{"start":{"line":1,"column":35},"end":{"line":1,"column":36}},
"extra": {
"rawValue": 0,
"raw": "0"
},
"value": 0
}
}
}
}
],
"directives": []
}
}

View File

@ -0,0 +1 @@
0 ? v => (...rest) : v => 0 : v => 0;

View File

@ -0,0 +1,107 @@
{
"type": "File",
"start":0,"end":37,"loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":37}},
"program": {
"type": "Program",
"start":0,"end":37,"loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":37}},
"sourceType": "module",
"interpreter": null,
"body": [
{
"type": "ExpressionStatement",
"start":0,"end":37,"loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":37}},
"expression": {
"type": "ConditionalExpression",
"start":0,"end":36,"loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":36}},
"test": {
"type": "NumericLiteral",
"start":0,"end":1,"loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":1}},
"extra": {
"rawValue": 0,
"raw": "0"
},
"value": 0
},
"consequent": {
"type": "ArrowFunctionExpression",
"start":4,"end":27,"loc":{"start":{"line":1,"column":4},"end":{"line":1,"column":27}},
"id": null,
"generator": false,
"async": false,
"params": [
{
"type": "Identifier",
"start":4,"end":5,"loc":{"start":{"line":1,"column":4},"end":{"line":1,"column":5},"identifierName":"v"},
"name": "v"
}
],
"body": {
"type": "ArrowFunctionExpression",
"start":9,"end":27,"loc":{"start":{"line":1,"column":9},"end":{"line":1,"column":27}},
"returnType": {
"type": "TSTypeAnnotation",
"start":19,"end":22,"loc":{"start":{"line":1,"column":19},"end":{"line":1,"column":22}},
"typeAnnotation": {
"type": "TSTypeReference",
"start":21,"end":22,"loc":{"start":{"line":1,"column":21},"end":{"line":1,"column":22}},
"typeName": {
"type": "Identifier",
"start":21,"end":22,"loc":{"start":{"line":1,"column":21},"end":{"line":1,"column":22},"identifierName":"v"},
"name": "v"
}
}
},
"id": null,
"generator": false,
"async": false,
"params": [
{
"type": "RestElement",
"start":10,"end":17,"loc":{"start":{"line":1,"column":10},"end":{"line":1,"column":17}},
"argument": {
"type": "Identifier",
"start":13,"end":17,"loc":{"start":{"line":1,"column":13},"end":{"line":1,"column":17},"identifierName":"rest"},
"name": "rest"
}
}
],
"body": {
"type": "NumericLiteral",
"start":26,"end":27,"loc":{"start":{"line":1,"column":26},"end":{"line":1,"column":27}},
"extra": {
"rawValue": 0,
"raw": "0"
},
"value": 0
}
}
},
"alternate": {
"type": "ArrowFunctionExpression",
"start":30,"end":36,"loc":{"start":{"line":1,"column":30},"end":{"line":1,"column":36}},
"id": null,
"generator": false,
"async": false,
"params": [
{
"type": "Identifier",
"start":30,"end":31,"loc":{"start":{"line":1,"column":30},"end":{"line":1,"column":31},"identifierName":"v"},
"name": "v"
}
],
"body": {
"type": "NumericLiteral",
"start":35,"end":36,"loc":{"start":{"line":1,"column":35},"end":{"line":1,"column":36}},
"extra": {
"rawValue": 0,
"raw": "0"
},
"value": 0
}
}
}
}
],
"directives": []
}
}