-
Notifications
You must be signed in to change notification settings - Fork 13k
Improve return type parse error #17096
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
It's very ambiguous in expression position, so impossible to give a better message from the parser. For example: let f = (x: number) => number => x + 1; ~~ Should be ':' But the parser doesn't know that 'number' isn't an expression now.
src/compiler/parser.ts
Outdated
@@ -3254,7 +3268,7 @@ namespace ts { | |||
function parseParenthesizedArrowFunctionExpressionHead(allowAmbiguity: boolean): ArrowFunction { | |||
const node = <ArrowFunction>createNode(SyntaxKind.ArrowFunction); | |||
node.modifiers = parseModifiersForArrowFunction(); | |||
const isAsync = !!(getModifierFlags(node) & ModifierFlags.Async); | |||
const isAsync = (getModifierFlags(node) & ModifierFlags.Async) ? SignatureContext.Await : 0; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Rather than 0
, could you add a SignatureContext.None
member of value 0
and use it here? We do this with many of our other enums. Helps with finding references, refactoring and such.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
src/compiler/parser.ts
Outdated
@@ -3263,7 +3277,7 @@ namespace ts { | |||
// a => (b => c) | |||
// And think that "(b =>" was actually a parenthesized arrow function with a missing | |||
// close paren. | |||
fillSignature(SyntaxKind.ColonToken, /*yieldContext*/ false, /*awaitContext*/ isAsync, /*requireCompleteParameterList*/ !allowAmbiguity, node); | |||
fillSignature(SyntaxKind.ColonToken, isAsync | (allowAmbiguity ? 0 : SignatureContext.RequireCompleteParameterList), node); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
SignatureContext.None
in place of 0
again
src/compiler/parser.ts
Outdated
@@ -4386,16 +4400,16 @@ namespace ts { | |||
parseExpected(SyntaxKind.FunctionKeyword); | |||
node.asteriskToken = parseOptionalToken(SyntaxKind.AsteriskToken); | |||
|
|||
const isGenerator = !!node.asteriskToken; | |||
const isAsync = !!(getModifierFlags(node) & ModifierFlags.Async); | |||
const isGenerator = node.asteriskToken ? SignatureContext.Yield : 0; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
SignatureContext.None
in place of 0
again
src/compiler/parser.ts
Outdated
const isAsync = hasModifier(node, ModifierFlags.Async); | ||
fillSignature(SyntaxKind.ColonToken, /*yieldContext*/ isGenerator, /*awaitContext*/ isAsync, /*requireCompleteParameterList*/ false, node); | ||
node.body = parseFunctionBlockOrSemicolon(isGenerator, isAsync, Diagnostics.or_expected); | ||
const isGenerator = node.asteriskToken ? SignatureContext.Yield : 0; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
SignatureContext.None
in place of 0
again
src/compiler/parser.ts
Outdated
@@ -5158,7 +5172,7 @@ namespace ts { | |||
node.decorators = decorators; | |||
node.modifiers = modifiers; | |||
parseExpected(SyntaxKind.ConstructorKeyword); | |||
fillSignature(SyntaxKind.ColonToken, /*yieldContext*/ false, /*awaitContext*/ false, /*requireCompleteParameterList*/ false, node); | |||
fillSignature(SyntaxKind.ColonToken, /*context*/ 0, node); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
SignatureContext.None
in place of 0
again
src/compiler/parser.ts
Outdated
const isAsync = hasModifier(method, ModifierFlags.Async); | ||
fillSignature(SyntaxKind.ColonToken, /*yieldContext*/ isGenerator, /*awaitContext*/ isAsync, /*requireCompleteParameterList*/ false, method); | ||
method.body = parseFunctionBlockOrSemicolon(isGenerator, isAsync, diagnosticMessage); | ||
const isGenerator = asteriskToken ? SignatureContext.Yield : 0; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
SignatureContext.None
in place of 0
again
src/compiler/parser.ts
Outdated
@@ -5226,7 +5240,7 @@ namespace ts { | |||
node.decorators = decorators; | |||
node.modifiers = modifiers; | |||
node.name = parsePropertyName(); | |||
fillSignature(SyntaxKind.ColonToken, /*yieldContext*/ false, /*awaitContext*/ false, /*requireCompleteParameterList*/ false, node); | |||
fillSignature(SyntaxKind.ColonToken, /*context*/ 0, node); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
SignatureContext.None
in place of 0
again
src/compiler/parser.ts
Outdated
const isGenerator = asteriskToken ? SignatureContext.Yield : 0; | ||
const isAsync = hasModifier(method, ModifierFlags.Async) ? SignatureContext.Await : 0; | ||
fillSignature(SyntaxKind.ColonToken, isGenerator | isAsync, method); | ||
method.body = parseFunctionBlockOrSemicolon(!!isGenerator, !!isAsync, diagnosticMessage); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is it not worth having parseFunctionBlockOrSemicolon
just take flags, too?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Well, it delegates immediately to parseFunction
for the flags, so I changed that one too, and added another member to the flags enum.
As requested in the PR comments
Better error for wrong return token (
:
vs=>
) in types.Who really remembers the right return token to use for
{ (): string }
vs() => string
? Now the compiler (1) suggests the right token (2) parses the return type as a return type.This is a huge improvement from the previous behaviour when the first example was wrongly written as
{ () => string }
. Before,=>
was parsed sort of like;
.{ (); string }
gives you a type literal with a call signature and a member namedstring
. Very confusing.Note that parsing both tokens would be ambiguous in expression position, so impossible to give a better message from the parser in this context. For example:
But the parser doesn't know that 'number' isn't an argument named 'number'.