Skip to content

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

Merged
merged 5 commits into from
Jul 12, 2017
Merged

Conversation

sandersn
Copy link
Member

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 named string. 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:

let f = (x: number) => number => x + 1;
                    ~~
                    Should be ':'

But the parser doesn't know that 'number' isn't an argument named 'number'.

sandersn added 4 commits July 11, 2017 09:51
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.
@@ -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;
Copy link
Member

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.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

@@ -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);
Copy link
Member

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

@@ -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;
Copy link
Member

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

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;
Copy link
Member

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

@@ -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);
Copy link
Member

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

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;
Copy link
Member

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

@@ -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);
Copy link
Member

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

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);
Copy link
Member

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?

Copy link
Member Author

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
@sandersn sandersn merged commit 50f3910 into master Jul 12, 2017
@sandersn sandersn deleted the improve-return-type-parse-error branch July 12, 2017 14:18
@microsoft microsoft locked and limited conversation to collaborators Jun 14, 2018
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants