From 3c7741fe20ce102e32140e962d3c858d3aa2a792 Mon Sep 17 00:00:00 2001 From: Ron Buckton Date: Fri, 6 Jan 2017 20:13:05 -0800 Subject: [PATCH] Add PromisesClause --- src/compiler/binder.ts | 5 +- src/compiler/checker.ts | 163 +++++++++++++++++++------------------- src/compiler/factory.ts | 15 +++- src/compiler/parser.ts | 21 ++++- src/compiler/types.ts | 13 ++- src/compiler/utilities.ts | 5 -- src/compiler/visitor.ts | 4 + 7 files changed, 135 insertions(+), 91 deletions(-) diff --git a/src/compiler/binder.ts b/src/compiler/binder.ts index 2427c4d31fd..1f5db4c4e1a 100644 --- a/src/compiler/binder.ts +++ b/src/compiler/binder.ts @@ -256,6 +256,8 @@ namespace ts { return "__index"; case SyntaxKind.ExportDeclaration: return "__export"; + case SyntaxKind.PromisesClause: + return "__promises"; case SyntaxKind.ExportAssignment: return (node).isExportEquals ? "export=" : "default"; case SyntaxKind.BinaryExpression: @@ -1944,6 +1946,7 @@ namespace ts { case SyntaxKind.TypePredicate: return checkTypePredicate(node as TypePredicateNode); case SyntaxKind.TypeParameter: + case SyntaxKind.PromisesClause: return declareSymbolAndAddToSymbolTable(node, SymbolFlags.TypeParameter, SymbolFlags.TypeParameterExcludes); case SyntaxKind.Parameter: return bindParameter(node); @@ -2710,7 +2713,6 @@ namespace ts { break; case SyntaxKind.ImplementsKeyword: - case SyntaxKind.PromisesKeyword: // An `implements` HeritageClause is TypeScript syntax. transformFlags |= TransformFlags.AssertTypeScript; break; @@ -3106,6 +3108,7 @@ namespace ts { case SyntaxKind.AsExpression: case SyntaxKind.NonNullExpression: case SyntaxKind.ReadonlyKeyword: + case SyntaxKind.PromisesClause: // These nodes are TypeScript syntax. transformFlags |= TransformFlags.AssertTypeScript; break; diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 55ef6bd7318..7c0fa8fa612 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -1723,19 +1723,20 @@ namespace ts { return result || emptyArray; } - function setStructuredTypeMembers(type: StructuredType, members: SymbolTable, callSignatures: Signature[], constructSignatures: Signature[], stringIndexInfo: IndexInfo, numberIndexInfo: IndexInfo): ResolvedType { + function setStructuredTypeMembers(type: StructuredType, members: SymbolTable, callSignatures: Signature[], constructSignatures: Signature[], stringIndexInfo: IndexInfo, numberIndexInfo: IndexInfo, promisesClause: Symbol | undefined): ResolvedType { (type).members = members; (type).properties = getNamedMembers(members); (type).callSignatures = callSignatures; (type).constructSignatures = constructSignatures; if (stringIndexInfo) (type).stringIndexInfo = stringIndexInfo; if (numberIndexInfo) (type).numberIndexInfo = numberIndexInfo; + if (promisesClause) (type).promisesClause = promisesClause; return type; } function createAnonymousType(symbol: Symbol, members: SymbolTable, callSignatures: Signature[], constructSignatures: Signature[], stringIndexInfo: IndexInfo, numberIndexInfo: IndexInfo): ResolvedType { return setStructuredTypeMembers(createObjectType(ObjectFlags.Anonymous, symbol), - members, callSignatures, constructSignatures, stringIndexInfo, numberIndexInfo); + members, callSignatures, constructSignatures, stringIndexInfo, numberIndexInfo, /*promisesClause*/ undefined); } function forEachSymbolTableInScope(enclosingDeclaration: Node, callback: (symbolTable: SymbolTable) => T): T { @@ -3702,9 +3703,17 @@ namespace ts { if (symbol.flags & SymbolFlags.Alias) { return getTypeOfAlias(symbol); } + if (symbol.flags & SymbolFlags.TypeParameter && symbol.name === "__promises") { + return getTypeOfPromisesClause(symbol); + } return unknownType; } + function getTypeOfPromisesClause(symbol: Symbol): Type { + const declaration = getDeclarationOfKind(symbol, SyntaxKind.PromisesClause); + return declaration ? getTypeFromTypeNode(declaration.type) : unknownType; + } + function isReferenceToType(type: Type, target: Type) { return type !== undefined && target !== undefined @@ -4294,6 +4303,7 @@ namespace ts { (type).declaredConstructSignatures = getSignaturesOfSymbol(symbol.members["__new"]); (type).declaredStringIndexInfo = getIndexInfoOfSymbol(symbol, IndexKind.String); (type).declaredNumberIndexInfo = getIndexInfoOfSymbol(symbol, IndexKind.Number); + (type).declaredPromisesClause = symbol.members["__promises"]; } return type; } @@ -4313,6 +4323,7 @@ namespace ts { let constructSignatures: Signature[]; let stringIndexInfo: IndexInfo; let numberIndexInfo: IndexInfo; + let promisesClause: Symbol; if (rangeEquals(typeParameters, typeArguments, 0, typeParameters.length)) { mapper = identityMapper; members = source.symbol ? source.symbol.members : createSymbolTable(source.declaredProperties); @@ -4320,6 +4331,7 @@ namespace ts { constructSignatures = source.declaredConstructSignatures; stringIndexInfo = source.declaredStringIndexInfo; numberIndexInfo = source.declaredNumberIndexInfo; + promisesClause = source.declaredPromisesClause; } else { mapper = createTypeMapper(typeParameters, typeArguments); @@ -4328,6 +4340,7 @@ namespace ts { constructSignatures = instantiateSignatures(source.declaredConstructSignatures, mapper); stringIndexInfo = instantiateIndexInfo(source.declaredStringIndexInfo, mapper); numberIndexInfo = instantiateIndexInfo(source.declaredNumberIndexInfo, mapper); + promisesClause = source.declaredPromisesClause && instantiateSymbol(source.declaredPromisesClause, mapper); } const baseTypes = getBaseTypes(source); if (baseTypes.length) { @@ -4342,9 +4355,10 @@ namespace ts { constructSignatures = concatenate(constructSignatures, getSignaturesOfType(instantiatedBaseType, SignatureKind.Construct)); stringIndexInfo = stringIndexInfo || getIndexInfoOfType(instantiatedBaseType, IndexKind.String); numberIndexInfo = numberIndexInfo || getIndexInfoOfType(instantiatedBaseType, IndexKind.Number); + promisesClause = promisesClause || getPromisesClauseOfType(instantiatedBaseType); } } - setStructuredTypeMembers(type, members, callSignatures, constructSignatures, stringIndexInfo, numberIndexInfo); + setStructuredTypeMembers(type, members, callSignatures, constructSignatures, stringIndexInfo, numberIndexInfo, promisesClause); } function resolveClassOrInterfaceMembers(type: InterfaceType): void { @@ -4491,7 +4505,7 @@ namespace ts { const constructSignatures = getUnionSignatures(type.types, SignatureKind.Construct); const stringIndexInfo = getUnionIndexInfo(type.types, IndexKind.String); const numberIndexInfo = getUnionIndexInfo(type.types, IndexKind.Number); - setStructuredTypeMembers(type, emptySymbols, callSignatures, constructSignatures, stringIndexInfo, numberIndexInfo); + setStructuredTypeMembers(type, emptySymbols, callSignatures, constructSignatures, stringIndexInfo, numberIndexInfo, /*promisesClause*/ undefined); } function intersectTypes(type1: Type, type2: Type): Type { @@ -4521,7 +4535,7 @@ namespace ts { stringIndexInfo = intersectIndexInfos(stringIndexInfo, getIndexInfoOfType(t, IndexKind.String)); numberIndexInfo = intersectIndexInfos(numberIndexInfo, getIndexInfoOfType(t, IndexKind.Number)); } - setStructuredTypeMembers(type, emptySymbols, callSignatures, constructSignatures, stringIndexInfo, numberIndexInfo); + setStructuredTypeMembers(type, emptySymbols, callSignatures, constructSignatures, stringIndexInfo, numberIndexInfo, /*promisesClause*/ undefined); } /** @@ -4535,7 +4549,9 @@ namespace ts { const constructSignatures = instantiateSignatures(getSignaturesOfType(type.target, SignatureKind.Construct), type.mapper); const stringIndexInfo = instantiateIndexInfo(getIndexInfoOfType(type.target, IndexKind.String), type.mapper); const numberIndexInfo = instantiateIndexInfo(getIndexInfoOfType(type.target, IndexKind.Number), type.mapper); - setStructuredTypeMembers(type, members, callSignatures, constructSignatures, stringIndexInfo, numberIndexInfo); + const promisesClause = getPromisesClauseOfType(type.target); + const instantiatedPromisesClause = promisesClause && instantiateSymbol(promisesClause, type.mapper); + setStructuredTypeMembers(type, members, callSignatures, constructSignatures, stringIndexInfo, numberIndexInfo, instantiatedPromisesClause); } else if (symbol.flags & SymbolFlags.TypeLiteral) { const members = symbol.members; @@ -4543,7 +4559,8 @@ namespace ts { const constructSignatures = getSignaturesOfSymbol(members["__new"]); const stringIndexInfo = getIndexInfoOfSymbol(symbol, IndexKind.String); const numberIndexInfo = getIndexInfoOfSymbol(symbol, IndexKind.Number); - setStructuredTypeMembers(type, members, callSignatures, constructSignatures, stringIndexInfo, numberIndexInfo); + const promisesClause = members["__promises"]; + setStructuredTypeMembers(type, members, callSignatures, constructSignatures, stringIndexInfo, numberIndexInfo, promisesClause); } else { // Combinations of function, class, enum and module @@ -4565,7 +4582,7 @@ namespace ts { } } const numberIndexInfo = symbol.flags & SymbolFlags.Enum ? enumNumberIndexInfo : undefined; - setStructuredTypeMembers(type, members, emptyArray, constructSignatures, undefined, numberIndexInfo); + setStructuredTypeMembers(type, members, emptyArray, constructSignatures, undefined, numberIndexInfo, /*promisesClause*/ undefined); // We resolve the members before computing the signatures because a signature may use // typeof with a qualified name expression that circularly references the type we are // in the process of resolving (see issue #6072). The temporarily empty signature list @@ -4581,7 +4598,7 @@ namespace ts { const members: SymbolTable = createMap(); let stringIndexInfo: IndexInfo; // Resolve upfront such that recursive references see an empty object type. - setStructuredTypeMembers(type, emptySymbols, emptyArray, emptyArray, undefined, undefined); + setStructuredTypeMembers(type, emptySymbols, emptyArray, emptyArray, undefined, undefined, undefined); // In { [P in K]: T }, we refer to P as the type parameter type, K as the constraint type, // and T as the template type. const typeParameter = getTypeParameterFromMappedType(type); @@ -4605,7 +4622,7 @@ namespace ts { const iterationType = keyType.flags & TypeFlags.Index ? getIndexType(getApparentType((keyType).type)) : keyType; forEachType(iterationType, addMemberForKeyType); } - setStructuredTypeMembers(type, members, emptyArray, emptyArray, stringIndexInfo, undefined); + setStructuredTypeMembers(type, members, emptyArray, emptyArray, stringIndexInfo, undefined, undefined); function addMemberForKeyType(t: Type) { // Create a mapper from T to the current iteration type constituent. Then, if the @@ -4960,6 +4977,17 @@ namespace ts { return undefined; } + function getPromisesClauseOfStructuredType(type: Type): Symbol | undefined { + if (type.flags & TypeFlags.StructuredType) { + const resolved = resolveStructuredTypeMembers(type); + return resolved.promisesClause; + } + } + + function getPromisesClauseOfType(type: Type): Symbol | undefined { + return getPromisesClauseOfStructuredType(getApparentType(type)); + } + function getTypeParametersFromJSDocTemplate(declaration: SignatureDeclaration): TypeParameter[] { if (declaration.flags & NodeFlags.JavaScriptFile) { const templateTag = getJSDocTemplateTag(declaration); @@ -7740,7 +7768,7 @@ namespace ts { result = mappedTypeRelatedTo(source, target, reportErrors); } else { - result = promisesRelatedTo(source, target, reportErrors); + result = promisesClausesRelatedTo(source, target, reportErrors); if (result) { result = propertiesRelatedTo(source, target, reportErrors); if (result) { @@ -7805,8 +7833,20 @@ namespace ts { return Ternary.False; } - function promisesRelatedTo(_source: Type, _target: Type, _reportErrors: boolean): Ternary { - return Ternary.Maybe; + function promisesClausesRelatedTo(source: Type, target: Type, reportErrors: boolean): Ternary { + // const sourceClause = getPromisesClauseOfType(source); + const sourceClause = resolveStructuredTypeMembers(source).promisesClause; + const sourceType = sourceClause && getTypeOfSymbol(sourceClause); + // const targetClause = getPromisesClauseOfType(target); + const targetClause = resolveStructuredTypeMembers(target).promisesClause; + const targetType = targetClause && getTypeOfSymbol(targetClause); + if (!sourceType && !targetType) { + return Ternary.Maybe; + } + if (!sourceType || !targetType) { + return Ternary.False; + } + return isRelatedTo(sourceType, targetType, reportErrors); } function propertiesRelatedTo(source: Type, target: Type, reportErrors: boolean): Ternary { @@ -16356,6 +16396,22 @@ namespace ts { } } + // function getPromisesClauseConstraint(type: Type): Type | undefined { + // if (isTypeAny(type) || !type.symbol) { + // return undefined; + // } + + // const typeAsPromise = type; + // if (typeAsPromise.promisesClauseConstraintType) { + // return typeAsPromise.promisesClauseConstraintType; + // } + + // for (const decl of type.symbol.declarations) { + // if (decl.kind === SyntaxKind.ClassDeclaration || decl.kind === SyntaxKind) + // } + + // } + function getAwaitedTypeOfPromise(type: Type, errorNode?: Node): Type | undefined { const promisedType = getPromisedTypeOfPromise(type, errorNode); return promisedType && getAwaitedType(promisedType, errorNode); @@ -18224,11 +18280,12 @@ namespace ts { } /** Check that type parameter lists are identical across multiple declarations */ - function checkTypeParameterListsIdentical(node: ClassLikeDeclaration | InterfaceDeclaration, symbol: Symbol) { + function checkTypeParameterListsAndPromisesTypesIdentical(node: ClassLikeDeclaration | InterfaceDeclaration, symbol: Symbol) { if (symbol.declarations.length === 1) { return; } let firstDecl: ClassLikeDeclaration | InterfaceDeclaration; + let firstPromisesType: Type; for (const declaration of symbol.declarations) { if (declaration.kind === SyntaxKind.ClassDeclaration || declaration.kind === SyntaxKind.InterfaceDeclaration) { if (!firstDecl) { @@ -18237,25 +18294,14 @@ namespace ts { else if (!areTypeParametersIdentical(firstDecl.typeParameters, node.typeParameters)) { error(node.name, Diagnostics.All_declarations_of_0_must_have_identical_type_parameters, node.name.text); } - } - } - } - function checkPromisesTypesIdentical(node: ClassLikeDeclaration | InterfaceDeclaration, symbol: Symbol) { - if (symbol.declarations.length === 1) { - return; - } - let firstPromisesType: Type; - for (const declaration of symbol.declarations) { - if (declaration.kind === SyntaxKind.ClassDeclaration || declaration.kind === SyntaxKind.InterfaceDeclaration) { + const promisesClause = (declaration).promisesClause; + const promisesType = promisesClause && getTypeFromTypeNode(promisesClause.type); if (!firstPromisesType) { - const firstPromisesTypeNode = getPromisesHeritageClauseElement(declaration); - firstPromisesType = firstPromisesTypeNode && getTypeFromTypeNode(firstPromisesTypeNode); + firstPromisesType = promisesType; } else { - const promisesTypeNode = getPromisesHeritageClauseElement(declaration); - const promisesType = promisesTypeNode && getTypeFromTypeNode(promisesTypeNode); - if (promisesTypeNode && !isTypeIdenticalTo(firstPromisesType, promisesType)) { + if (promisesType && !isTypeIdenticalTo(firstPromisesType, promisesType)) { error(node.name, Diagnostics.Any_declarations_of_0_that_promise_a_type_must_promise_the_same_type, node.name.text); } } @@ -18300,8 +18346,7 @@ namespace ts { const type = getDeclaredTypeOfSymbol(symbol); const typeWithThis = getTypeWithThisArgument(type); const staticType = getTypeOfSymbol(symbol); - checkTypeParameterListsIdentical(node, symbol); - checkPromisesTypesIdentical(node, symbol); + checkTypeParameterListsAndPromisesTypesIdentical(node, symbol); checkClassForDuplicateDeclarations(node); const baseTypeNode = getClassExtendsHeritageClauseElement(node); @@ -18372,14 +18417,10 @@ namespace ts { } } - const promisesTypeNode = getPromisesHeritageClauseElement(node); - if (promisesTypeNode) { - if (!isEntityNameExpression(promisesTypeNode.expression)) { - error(promisesTypeNode.expression, Diagnostics.A_class_or_interface_can_only_promise_an_identifier_Slashqualified_name_with_optional_type_arguments); - } - checkTypeReferenceNode(promisesTypeNode); + const promisesClause = node.promisesClause; + if (promisesClause) { if (produceDiagnostics) { - const t = getTypeFromTypeNode(promisesTypeNode); + const t = getTypeFromTypeNode(promisesClause.type); if (t !== unknownType) { const promisedType = getPromisedTypeOfPromise(type); if (!promisedType) { @@ -18591,22 +18632,14 @@ namespace ts { // Grammar checking checkGrammarDecorators(node) || checkGrammarModifiers(node) || checkGrammarInterfaceDeclaration(node); - const promisesTypeNode = getPromisesHeritageClauseElement(node); - if (promisesTypeNode) { - if (!isEntityNameExpression(promisesTypeNode.expression)) { - error(promisesTypeNode.expression, Diagnostics.A_class_or_interface_can_only_promise_an_identifier_Slashqualified_name_with_optional_type_arguments); - } - checkTypeReferenceNode(promisesTypeNode); - } - + const promisesClause = node.promisesClause; checkTypeParameters(node.typeParameters); if (produceDiagnostics) { checkTypeNameIsReserved(node.name, Diagnostics.Interface_name_cannot_be_0); checkExportsOnMergedDeclarations(node); const symbol = getSymbolOfNode(node); - checkTypeParameterListsIdentical(node, symbol); - checkPromisesTypesIdentical(node, symbol); + checkTypeParameterListsAndPromisesTypesIdentical(node, symbol); // Only check this symbol once const firstInterfaceDecl = getDeclarationOfKind(symbol, SyntaxKind.InterfaceDeclaration); @@ -18621,8 +18654,8 @@ namespace ts { checkIndexConstraints(type); } - if (promisesTypeNode) { - const promisesType = getTypeFromTypeNode(promisesTypeNode); + if (promisesClause) { + const promisesType = getTypeFromTypeNode(promisesClause.type); if (promisesType !== unknownType) { const promisedType = getPromisedTypeOfPromise(type); if (!promisedType) { @@ -21415,7 +21448,6 @@ namespace ts { function checkGrammarClassDeclarationHeritageClauses(node: ClassLikeDeclaration) { let seenExtendsClause = false; let seenImplementsClause = false; - let seenPromisesClause = false; if (!checkGrammarDecorators(node) && !checkGrammarModifiers(node) && node.heritageClauses) { for (const heritageClause of node.heritageClauses) { @@ -21427,9 +21459,6 @@ namespace ts { if (seenImplementsClause) { return grammarErrorOnFirstToken(heritageClause, Diagnostics._0_clause_must_precede_0_clause, "extends", "implements"); } - if (seenPromisesClause) { - return grammarErrorOnFirstToken(heritageClause, Diagnostics._0_clause_must_precede_0_clause, "extends", "promises"); - } if (heritageClause.types.length > 1) { return grammarErrorOnFirstToken(heritageClause.types[1], Diagnostics.Classes_can_only_extend_a_single_class); } @@ -21440,21 +21469,8 @@ namespace ts { if (seenImplementsClause) { return grammarErrorOnFirstToken(heritageClause, Diagnostics._0_clause_already_seen, "implements"); } - if (seenPromisesClause) { - return grammarErrorOnFirstToken(heritageClause, Diagnostics._0_clause_must_precede_0_clause, "implements", "promises"); - } seenImplementsClause = true; break; - - case SyntaxKind.PromisesKeyword: - if (seenPromisesClause) { - return grammarErrorOnFirstToken(heritageClause, Diagnostics._0_clause_already_seen, "promises"); - } - if (heritageClause.types.length > 1) { - return grammarErrorOnFirstToken(heritageClause.types[1], Diagnostics.Classes_and_interfaces_can_only_promise_a_single_type); - } - seenPromisesClause = true; - break; } // Grammar checking heritageClause inside class declaration @@ -21465,7 +21481,6 @@ namespace ts { function checkGrammarInterfaceDeclaration(node: InterfaceDeclaration) { let seenExtendsClause = false; - let seenPromisesClause = false; if (node.heritageClauses) { for (const heritageClause of node.heritageClauses) { @@ -21474,22 +21489,10 @@ namespace ts { if (seenExtendsClause) { return grammarErrorOnFirstToken(heritageClause, Diagnostics._0_clause_already_seen, "extends"); } - if (seenPromisesClause) { - return grammarErrorOnFirstToken(heritageClause, Diagnostics._0_clause_must_precede_0_clause, "extends", "promises"); - } seenExtendsClause = true; break; case SyntaxKind.ImplementsKeyword: return grammarErrorOnFirstToken(heritageClause, Diagnostics.Interface_declaration_cannot_have_implements_clause); - case SyntaxKind.PromisesKeyword: - if (seenPromisesClause) { - return grammarErrorOnFirstToken(heritageClause, Diagnostics._0_clause_already_seen, "promises"); - } - if (heritageClause.types.length > 1) { - return grammarErrorOnFirstToken(heritageClause.types[1], Diagnostics.Classes_and_interfaces_can_only_promise_a_single_type); - } - seenPromisesClause = true; - break; } // Grammar checking heritageClause inside class declaration diff --git a/src/compiler/factory.ts b/src/compiler/factory.ts index 22f1c8f022d..046eb3e08d5 100644 --- a/src/compiler/factory.ts +++ b/src/compiler/factory.ts @@ -1333,7 +1333,7 @@ namespace ts { // Clauses - export function createHeritageClause(token: SyntaxKind.ExtendsKeyword | SyntaxKind.ImplementsKeyword | SyntaxKind.PromisesKeyword, types: ExpressionWithTypeArguments[], location?: TextRange) { + export function createHeritageClause(token: SyntaxKind.ExtendsKeyword | SyntaxKind.ImplementsKeyword, types: ExpressionWithTypeArguments[], location?: TextRange) { const node = createNode(SyntaxKind.HeritageClause, location); node.token = token; node.types = createNodeArray(types); @@ -1347,6 +1347,19 @@ namespace ts { return node; } + export function createPromisesClause(type: TypeNode, location?: TextRange) { + const node = createNode(SyntaxKind.PromisesClause, location); + node.type = type; + return node; + } + + export function updatePromisesClause(node: PromisesClause, type: TypeNode) { + if (node.type !== type) { + return updateNode(createPromisesClause(type, node), node); + } + return node; + } + export function createCaseClause(expression: Expression, statements: Statement[], location?: TextRange) { const node = createNode(SyntaxKind.CaseClause, location); node.expression = parenthesizeExpressionForList(expression); diff --git a/src/compiler/parser.ts b/src/compiler/parser.ts index 75a2b0e7de8..0f2fb802afd 100644 --- a/src/compiler/parser.ts +++ b/src/compiler/parser.ts @@ -284,13 +284,15 @@ namespace ts { visitNode(cbNode, (node).name) || visitNodes(cbNodes, (node).typeParameters) || visitNodes(cbNodes, (node).heritageClauses) || + visitNode(cbNode, (node).promisesClause) || visitNodes(cbNodes, (node).members); case SyntaxKind.InterfaceDeclaration: return visitNodes(cbNodes, node.decorators) || visitNodes(cbNodes, node.modifiers) || visitNode(cbNode, (node).name) || visitNodes(cbNodes, (node).typeParameters) || - visitNodes(cbNodes, (node).heritageClauses) || + visitNodes(cbNodes, (node).heritageClauses) || + visitNode(cbNode, (node).promisesClause) || visitNodes(cbNodes, (node).members); case SyntaxKind.TypeAliasDeclaration: return visitNodes(cbNodes, node.decorators) || @@ -353,6 +355,8 @@ namespace ts { return visitNode(cbNode, (node).expression); case SyntaxKind.HeritageClause: return visitNodes(cbNodes, (node).types); + case SyntaxKind.PromisesClause: + return visitNode(cbNode, (node).type); case SyntaxKind.ExpressionWithTypeArguments: return visitNode(cbNode, (node).expression) || visitNodes(cbNodes, (node).typeArguments); @@ -5371,6 +5375,7 @@ namespace ts { node.name = parseNameOfClassDeclarationOrExpression(); node.typeParameters = parseTypeParameters(); node.heritageClauses = parseHeritageClauses(); + node.promisesClause = parsePromisesClause(); if (parseExpected(SyntaxKind.OpenBraceToken)) { // ClassTail[Yield,Await] : (Modified) See 14.5 @@ -5413,7 +5418,7 @@ namespace ts { function parseHeritageClause() { const keyword = token(); - if (keyword === SyntaxKind.ExtendsKeyword || keyword === SyntaxKind.ImplementsKeyword || keyword === SyntaxKind.PromisesKeyword) { + if (keyword === SyntaxKind.ExtendsKeyword || keyword === SyntaxKind.ImplementsKeyword) { const node = createNode(SyntaxKind.HeritageClause); node.token = keyword; nextToken(); @@ -5438,12 +5443,21 @@ namespace ts { switch (token()) { case SyntaxKind.ExtendsKeyword: case SyntaxKind.ImplementsKeyword: - case SyntaxKind.PromisesKeyword: return true; } return false; } + function parsePromisesClause(): PromisesClause { + if (token() === SyntaxKind.PromisesKeyword) { + const node = createNode(SyntaxKind.PromisesClause); + nextToken(); + node.type = parseType(); + return finishNode(node); + } + return undefined; + } + function parseClassMembers() { return parseList(ParsingContext.ClassMembers, parseClassElement); } @@ -5456,6 +5470,7 @@ namespace ts { node.name = parseIdentifier(); node.typeParameters = parseTypeParameters(); node.heritageClauses = parseHeritageClauses(); + node.promisesClause = parsePromisesClause(); node.members = parseObjectTypeMembers(); return addJSDocComment(finishNode(node)); } diff --git a/src/compiler/types.ts b/src/compiler/types.ts index c245641924b..c841d4695bc 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -318,6 +318,7 @@ namespace ts { CaseClause, DefaultClause, HeritageClause, + PromisesClause, CatchClause, // Property assignments @@ -1694,6 +1695,7 @@ namespace ts { name?: Identifier; typeParameters?: NodeArray; heritageClauses?: NodeArray; + promisesClause?: PromisesClause; members: NodeArray; } @@ -1722,15 +1724,21 @@ namespace ts { name: Identifier; typeParameters?: NodeArray; heritageClauses?: NodeArray; + promisesClause?: PromisesClause; members: NodeArray; } export interface HeritageClause extends Node { kind: SyntaxKind.HeritageClause; - token: SyntaxKind.ExtendsKeyword | SyntaxKind.ImplementsKeyword | SyntaxKind.PromisesKeyword; + token: SyntaxKind.ExtendsKeyword | SyntaxKind.ImplementsKeyword; types?: NodeArray; } + export interface PromisesClause extends Declaration { + kind: SyntaxKind.PromisesClause; + type: TypeNode; + } + export interface TypeAliasDeclaration extends DeclarationStatement { kind: SyntaxKind.TypeAliasDeclaration; name: Identifier; @@ -2890,6 +2898,7 @@ namespace ts { declaredConstructSignatures: Signature[]; // Declared construct signatures declaredStringIndexInfo: IndexInfo; // Declared string indexing info declaredNumberIndexInfo: IndexInfo; // Declared numeric indexing info + declaredPromisesClause?: Symbol; // Declared promises clause } /** @@ -2960,6 +2969,7 @@ namespace ts { constructSignatures: Signature[]; // Construct signatures of type stringIndexInfo?: IndexInfo; // String indexing info numberIndexInfo?: IndexInfo; // Numeric indexing info + promisesClause?: Symbol; // Promises clause } /* @internal */ @@ -2982,6 +2992,7 @@ namespace ts { promiseTypeOfPromiseConstructor?: Type; promisedTypeOfPromise?: Type; awaitedTypeOfType?: Type; + promisesClauseConstraintType?: Type; } export interface TypeVariable extends Type { diff --git a/src/compiler/utilities.ts b/src/compiler/utilities.ts index 7bf9f0b299f..192ef888b11 100644 --- a/src/compiler/utilities.ts +++ b/src/compiler/utilities.ts @@ -1806,11 +1806,6 @@ namespace ts { return heritageClause ? heritageClause.types : undefined; } - export function getPromisesHeritageClauseElement(node: ClassLikeDeclaration | InterfaceDeclaration) { - const heritageClause = getHeritageClause(node.heritageClauses, SyntaxKind.PromisesKeyword); - return heritageClause && heritageClause.types.length > 0 ? heritageClause.types[0] : undefined; - } - export function getInterfaceBaseTypeNodes(node: InterfaceDeclaration) { const heritageClause = getHeritageClause(node.heritageClauses, SyntaxKind.ExtendsKeyword); return heritageClause ? heritageClause.types : undefined; diff --git a/src/compiler/visitor.ts b/src/compiler/visitor.ts index 5fc80bb014d..d7748308aba 100644 --- a/src/compiler/visitor.ts +++ b/src/compiler/visitor.ts @@ -1156,6 +1156,10 @@ namespace ts { return updateHeritageClause(node, visitNodes((node).types, visitor, isExpressionWithTypeArguments)); + case SyntaxKind.PromisesClause: + return updatePromisesClause(node, + visitNode((node).type, visitor, isTypeNode)); + case SyntaxKind.CatchClause: return updateCatchClause(node, visitNode((node).variableDeclaration, visitor, isVariableDeclaration),