Skip to content

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.
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

// 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


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

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

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