Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
46 commits
Select commit Hold shift + click to select a range
d19a200
Added types, scan, parse, and check for async functions
rbuckton May 6, 2015
e82e841
Added emit for async functions in ES6
rbuckton May 7, 2015
80edb2d
Bug fixes and baselines
rbuckton May 7, 2015
1718ff2
Merge branch 'master' into asyncFunctions
rbuckton May 8, 2015
bca21ec
Updated baselines
rbuckton May 8, 2015
655f2ec
Cleanup and PR feedback
rbuckton May 8, 2015
2391666
Updated declaration and symbol baselines
rbuckton May 9, 2015
39a6cce
Cleaned up diagnostic messages
rbuckton May 9, 2015
daa7793
Additional clean up of diagnostic messages
rbuckton May 9, 2015
2ee5beb
PR feedback
rbuckton May 9, 2015
3d0991d
Better name for bitmask in ParserContextFlags
rbuckton May 13, 2015
9a6d308
Simplified parenthesis check for await as yield.
rbuckton May 13, 2015
117b07b
Added comments for emitAsyncSignatureAndBodyForES6
rbuckton May 13, 2015
e5df2e2
Merge branch 'asyncFunctions' of https://github.com/Microsoft/TypeScr…
rbuckton May 13, 2015
5e2d48c
Merge branch 'master' into asyncFunctions
rbuckton May 13, 2015
379704f
Cleaned up checker, added comments to parser based on PR feedback.
rbuckton May 13, 2015
b70e6a1
Added parseModifiersForArrowFunction
rbuckton May 13, 2015
890a5d8
Fixed missing call to nextToken()
rbuckton May 13, 2015
a565a02
Fixes missing check in isParenthesizedArrowFunctionExpressionWorker
rbuckton May 14, 2015
a2c5073
Some cleanup and additional comments following PR feedback
rbuckton May 19, 2015
b5df4b1
Merge branch 'master' into asyncFunctions
rbuckton May 21, 2015
9560d6f
Merge branch 'master' into asyncFunctions
rbuckton Jun 4, 2015
72a6865
Updated emit to align with current proposal for ES7 async functions
rbuckton Jun 4, 2015
02557b1
Emit awaiter arguments on new line
weswigham Jun 9, 2015
371583b
Update baselines for emit change
weswigham Jun 10, 2015
6fc07e6
Merged branch 'master' into asyncFunctions
rbuckton Jun 10, 2015
c259d7e
Merge pull request #3455 from weswigham/asyncFunctions
rbuckton Jun 10, 2015
5ebad58
Merge branch 'master' into asyncFunctions
rbuckton Jun 15, 2015
9a57e6f
Updated baselines
rbuckton Jun 15, 2015
f1c99f3
Remove generatorParameter and asyncParameter contexts.
CyrusNajmabadi Jun 16, 2015
009c3ee
Merge branch 'master' into removeGeneratorParameter
CyrusNajmabadi Jun 16, 2015
2e16680
Re-number enum.
CyrusNajmabadi Jun 16, 2015
1b93265
Merge pull request #3526 from Microsoft/removeGeneratorParameter
CyrusNajmabadi Jun 16, 2015
b25d855
Removed unused getContainingParameter function
rbuckton Jun 17, 2015
82eae19
Inlined checks for NodeFlags.Async in parser
rbuckton Jun 17, 2015
c74bb84
Moved getContainingFunction call in checkIdentifier
rbuckton Jun 17, 2015
b00a957
Removed unneeded capture for lexical this
rbuckton Jun 17, 2015
02f6622
Changed createPromiseType to return emptyObjectType
rbuckton Jun 17, 2015
7443ecc
Cleaned up diagnostics
rbuckton Jun 17, 2015
2891a1d
Cleaned up async return type check
rbuckton Jun 18, 2015
c4876d5
Add support for awaiting union types with mixed promise and non-promi…
rbuckton Jun 18, 2015
379d74a
Minor function rename
rbuckton Jun 18, 2015
eb03ae8
Added shortcut in checkAwaitedType for isolatedModules
rbuckton Jun 18, 2015
5b32903
Fix async function emit for lexical arguments
rbuckton Jun 19, 2015
76c0d32
Moved async functions for ES6 behind experimental flag
rbuckton Jun 20, 2015
4b4a96b
Merge branch 'master' into asyncFunctions
rbuckton Jul 1, 2015
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Updated emit to align with current proposal for ES7 async functions
  • Loading branch information
rbuckton committed Jun 4, 2015
commit 72a6865f93debeb72f8bf4c17f7929808f5a90fc
173 changes: 108 additions & 65 deletions src/compiler/checker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -824,7 +824,7 @@ module ts {
}

// Resolves a qualified name and any involved aliases
function resolveEntityName(name: EntityName | Expression, meaning: SymbolFlags): Symbol {
function resolveEntityName(name: EntityName | Expression, meaning: SymbolFlags, location?: Node): Symbol {
if (nodeIsMissing(name)) {
return undefined;
}
Expand All @@ -833,7 +833,7 @@ module ts {
if (name.kind === SyntaxKind.Identifier) {
let message = meaning === SymbolFlags.Namespace ? Diagnostics.Cannot_find_namespace_0 : Diagnostics.Cannot_find_name_0;

symbol = resolveName(name, (<Identifier>name).text, meaning, message, <Identifier>name);
symbol = resolveName(location || name, (<Identifier>name).text, meaning, message, <Identifier>name);
if (!symbol) {
return undefined;
}
Expand All @@ -842,7 +842,7 @@ module ts {
let left = name.kind === SyntaxKind.QualifiedName ? (<QualifiedName>name).left : (<PropertyAccessExpression>name).expression;
let right = name.kind === SyntaxKind.QualifiedName ? (<QualifiedName>name).right : (<PropertyAccessExpression>name).name;

let namespace = resolveEntityName(left, SymbolFlags.Namespace);
let namespace = resolveEntityName(left, SymbolFlags.Namespace, location);
if (!namespace || namespace === unknownSymbol || nodeIsMissing(right)) {
return undefined;
}
Expand Down Expand Up @@ -3834,6 +3834,20 @@ module ts {
}
return links.resolvedType;
}

function getEntityNameFromTypeNode(node: TypeNode): EntityName | Expression {
switch (node.kind) {
case SyntaxKind.TypeReference:
return (<TypeReferenceNode>node).typeName;
case SyntaxKind.ExpressionWithTypeArguments:
return (<ExpressionWithTypeArguments>node).expression
case SyntaxKind.Identifier:
case SyntaxKind.QualifiedName:
return (<EntityName><Node>node);
default:
return undefined;
}
}

function getTypeFromTypeNode(node: TypeNode): Type {
switch (node.kind) {
Expand Down Expand Up @@ -5643,9 +5657,10 @@ module ts {
if (languageVersion < ScriptTarget.ES6) {
error(node, Diagnostics.The_arguments_object_cannot_be_referenced_in_an_arrow_function_in_ES3_and_ES5_Consider_using_a_standard_function_expression);
}
else if (node.parserContextFlags & ParserContextFlags.Await) {
error(node, Diagnostics.The_arguments_object_cannot_be_referenced_in_an_async_arrow_function_Consider_using_a_standard_async_function_expression);
}
}

if (node.parserContextFlags & ParserContextFlags.Await) {
getNodeLinks(container).flags |= NodeCheckFlags.CaptureArguments;
}
}

Expand Down Expand Up @@ -7746,11 +7761,14 @@ module ts {
Debug.assert(node.kind !== SyntaxKind.MethodDeclaration || isObjectLiteralMethod(node));

let isAsync = isAsyncFunctionLike(node);
if (isAsync) {
emitAwaiter = true;
}

let returnType = node.type && getTypeFromTypeNode(node.type);

let promisedType: Type;
if (returnType && isAsync) {
promisedType = checkAsyncFunctionReturnType(node, returnType);
promisedType = checkAsyncFunctionReturnType(node);
}

if (returnType && !node.asteriskToken) {
Expand Down Expand Up @@ -9440,56 +9458,71 @@ module ts {
* a `resolve` function as one of its arguments and results in an object with a
* callable `then` signature.
*/
function checkAsyncFunctionReturnType(node: SignatureDeclaration, returnType: Type): Type {
function checkAsyncFunctionReturnType(node: SignatureDeclaration): Type {
let globalPromiseConstructorLikeType = getGlobalPromiseConstructorLikeType();
Copy link
Contributor

Choose a reason for hiding this comment

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

we have already reported the error. so i would not bother here re reporting.

if (globalPromiseConstructorLikeType !== emptyObjectType) {
// The return type of an async function will be the type of the instance. For this
// to be a type compatible with our async function emit, we must also check that
// the type of the declaration (e.g. the static side or "constructor" type of the
// promise) is a compatible `PromiseConstructorLike`.
//
// An example might be (from lib.es6.d.ts):
//
// interface Promise<T> { ... }
// interface PromiseConstructor {
// new <T>(...): Promise<T>;
// }
// declare var Promise: PromiseConstructor;
//
// When an async function declares a return type annotation of `Promise<T>`, we
// need to get the type of the `Promise` variable declaration above, which would
// be `PromiseConstructor`.
//
// The same case applies to a class:
//
// declare class Promise<T> {
// constructor(...);
// then<U>(...): Promise<U>;
// }
//
// When we get the type of the `Promise` symbol here, we get the type of the static
// side of the `Promise` class, which would be `{ new <T>(...): Promise<T> }`.
let declaredType = returnType.symbol ? getTypeOfSymbol(returnType.symbol) : emptyObjectType;
if (isTypeAssignableTo(declaredType, globalPromiseConstructorLikeType)) {
// Ensure we will emit the `__awaiter` helper.
emitAwaiter = true;

// When we emit the async function, we need to ensure we emit any imports that might
// otherwise have been elided if the return type were only ever referenced in a type
// position. As such, we get the entity name of the type reference from the return
// type and check it as an expression.
let promiseConstructor = getPromiseConstructor(node);
if (promiseConstructor) {
checkExpressionOrQualifiedName(promiseConstructor);
}

// Get and return the awaited type of the return type.
return getAwaitedType(returnType, node, Diagnostics.An_async_function_or_method_must_have_a_valid_awaitable_return_type);
}
if (globalPromiseConstructorLikeType === emptyObjectType) {
// If we couldn't resolve the global PromiseConstructorLike type we cannot verify
// compatibility with __awaiter, so we report an error.
error(node, Diagnostics.An_async_function_or_method_must_have_a_valid_awaitable_return_type);
return unknownType;
}

// The return type of an async function will be the type of the instance. For this
Copy link
Contributor

Choose a reason for hiding this comment

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

what does "instance" mean in this context.

// to be a type compatible with our async function emit, we must also check that
// the type of the declaration (e.g. the static side or "constructor" type of the
// promise) is a compatible `PromiseConstructorLike`.
//
// An example might be (from lib.es6.d.ts):
//
// interface Promise<T> { ... }
// interface PromiseConstructor {
// new <T>(...): Promise<T>;
// }
// declare var Promise: PromiseConstructor;
//
// When an async function declares a return type annotation of `Promise<T>`, we
// need to get the type of the `Promise` variable declaration above, which would
// be `PromiseConstructor`.
//
// The same case applies to a class:
//
// declare class Promise<T> {
// constructor(...);
// then<U>(...): Promise<U>;
// }
//
// When we get the type of the `Promise` symbol here, we get the type of the static
// side of the `Promise` class, which would be `{ new <T>(...): Promise<T> }`.
let returnType = getTypeFromTypeNode(node.type);
let entityName = getEntityNameFromTypeNode(node.type);
let resolvedName = entityName ? resolveEntityName(entityName, SymbolFlags.Value, node) : undefined;
if (!resolvedName || !returnType.symbol) {
error(node, Diagnostics.An_async_function_or_method_must_have_a_valid_awaitable_return_type);
return unknownType;
}

if (getMergedSymbol(resolvedName) !== getMergedSymbol(returnType.symbol)) {
// If we were unable to resolve the return type as a value, report an error.
let identifier = getFirstIdentifier(entityName);
error(resolvedName.valueDeclaration, Diagnostics.Duplicate_identifier_0_Compiler_uses_declaration_1_to_support_async_functions,
identifier.text,
identifier.text);
return unknownType;
}

// When we emit the async function, we need to ensure we emit any imports that might
// otherwise have been elided if the return type were only ever referenced in a type
// position. As such, we check the entity name as an expression.
let declaredType = checkExpressionOrQualifiedName(entityName);

if (!isTypeAssignableTo(declaredType, globalPromiseConstructorLikeType)) {
// If the declared type of the return type is not assignable to a PromiseConstructorLike, report an error.
error(node, ts.Diagnostics.An_async_function_or_method_must_have_a_valid_awaitable_return_type);
return unknownType;
}

error(node, ts.Diagnostics.An_async_function_or_method_must_have_a_valid_awaitable_return_type);
return unknownType;
// Get and return the awaited type of the return type.
return getAwaitedType(returnType, node, Diagnostics.An_async_function_or_method_must_have_a_valid_awaitable_return_type);
}

/** Check a decorator */
Expand Down Expand Up @@ -9635,6 +9668,10 @@ module ts {
checkGrammarDeclarationNameInStrictMode(node);
checkDecorators(node);
checkSignatureDeclaration(node);
let isAsync = isAsyncFunctionLike(node);
if (isAsync) {
emitAwaiter = true;
}

// Do not use hasDynamicName here, because that returns false for well known symbols.
// We want to perform checkComputedPropertyName for all computed properties, including
Expand Down Expand Up @@ -9670,10 +9707,9 @@ module ts {
checkSourceElement(node.body);
if (node.type && !isAccessor(node.kind) && !node.asteriskToken) {
let returnType = getTypeFromTypeNode(node.type);
let isAsync = isAsyncFunctionLike(node);
let promisedType: Type;
if (isAsync) {
promisedType = checkAsyncFunctionReturnType(node, returnType);
promisedType = checkAsyncFunctionReturnType(node);
}

checkIfNonVoidFunctionHasReturnExpressionsOrSingleThrowStatment(node, isAsync ? promisedType : returnType);
Expand Down Expand Up @@ -9888,13 +9924,11 @@ module ts {
}
}

function getPromiseConstructor(node: SignatureDeclaration): EntityName {
if (isAsyncFunctionLike(node)) {
function getPromiseConstructor(node: SignatureDeclaration): EntityName | Expression {
if (isAsyncFunctionLike(node) && node.type) {
let links = getNodeLinks(node);
if (!links.promiseConstructor) {
if (node.type && node.type.kind === SyntaxKind.TypeReference) {
links.promiseConstructor = (<TypeReferenceNode>node.type).typeName;
}
links.promiseConstructor = getEntityNameFromTypeNode(node.type);
}

return links.promiseConstructor;
Expand Down Expand Up @@ -10037,8 +10071,12 @@ module ts {
function checkGrammarDisallowedModifiersInBlockOrObjectLiteralExpression(node: Node) {
if (node.modifiers) {
if (inBlockOrObjectLiteralExpression(node)) {
// disallow all but the `async` modifier here
if (isAccessor(node.kind) || !isFunctionLike(node) || (node.modifiers.flags & ~NodeFlags.Async)) {
if (isAsyncFunctionLike(node)) {
if (node.modifiers.length > 1) {
return grammarErrorOnFirstToken(node, Diagnostics.Modifiers_cannot_appear_here);
}
}
else {
return grammarErrorOnFirstToken(node, Diagnostics.Modifiers_cannot_appear_here);
}
}
Expand Down Expand Up @@ -12973,10 +13011,15 @@ module ts {
case SyntaxKind.ExportAssignment:
case SyntaxKind.Parameter:
break;
case SyntaxKind.FunctionDeclaration:
if (node.modifiers && (node.modifiers.length > 1 || node.modifiers[0].kind !== SyntaxKind.AsyncKeyword) &&
node.parent.kind !== SyntaxKind.ModuleBlock && node.parent.kind !== SyntaxKind.SourceFile) {
return grammarErrorOnFirstToken(node, Diagnostics.Modifiers_cannot_appear_here);
}
break;
case SyntaxKind.ClassDeclaration:
case SyntaxKind.InterfaceDeclaration:
case SyntaxKind.VariableStatement:
case SyntaxKind.FunctionDeclaration:
case SyntaxKind.TypeAliasDeclaration:
if (node.modifiers && node.parent.kind !== SyntaxKind.ModuleBlock && node.parent.kind !== SyntaxKind.SourceFile) {
return grammarErrorOnFirstToken(node, Diagnostics.Modifiers_cannot_appear_here);
Expand Down
Loading