mirror of
https://github.com/microsoft/TypeScript.git
synced 2026-02-06 20:14:01 -06:00
WIP promises type
This commit is contained in:
parent
46622740b2
commit
4af87e1efc
@ -2710,6 +2710,7 @@ namespace ts {
|
||||
break;
|
||||
|
||||
case SyntaxKind.ImplementsKeyword:
|
||||
case SyntaxKind.PromisesKeyword:
|
||||
// An `implements` HeritageClause is TypeScript syntax.
|
||||
transformFlags |= TransformFlags.AssertTypeScript;
|
||||
break;
|
||||
|
||||
@ -7740,15 +7740,18 @@ namespace ts {
|
||||
result = mappedTypeRelatedTo(source, target, reportErrors);
|
||||
}
|
||||
else {
|
||||
result = propertiesRelatedTo(source, target, reportErrors);
|
||||
result = promisesRelatedTo(source, target, reportErrors);
|
||||
if (result) {
|
||||
result &= signaturesRelatedTo(source, target, SignatureKind.Call, reportErrors);
|
||||
result = propertiesRelatedTo(source, target, reportErrors);
|
||||
if (result) {
|
||||
result &= signaturesRelatedTo(source, target, SignatureKind.Construct, reportErrors);
|
||||
result &= signaturesRelatedTo(source, target, SignatureKind.Call, reportErrors);
|
||||
if (result) {
|
||||
result &= indexTypesRelatedTo(source, originalSource, target, IndexKind.String, reportErrors);
|
||||
result &= signaturesRelatedTo(source, target, SignatureKind.Construct, reportErrors);
|
||||
if (result) {
|
||||
result &= indexTypesRelatedTo(source, originalSource, target, IndexKind.Number, reportErrors);
|
||||
result &= indexTypesRelatedTo(source, originalSource, target, IndexKind.String, reportErrors);
|
||||
if (result) {
|
||||
result &= indexTypesRelatedTo(source, originalSource, target, IndexKind.Number, reportErrors);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -7802,6 +7805,10 @@ namespace ts {
|
||||
return Ternary.False;
|
||||
}
|
||||
|
||||
function promisesRelatedTo(_source: Type, _target: Type, _reportErrors: boolean): Ternary {
|
||||
return Ternary.Maybe;
|
||||
}
|
||||
|
||||
function propertiesRelatedTo(source: Type, target: Type, reportErrors: boolean): Ternary {
|
||||
if (relation === identityRelation) {
|
||||
return propertiesIdenticalTo(source, target);
|
||||
@ -18234,6 +18241,28 @@ namespace ts {
|
||||
}
|
||||
}
|
||||
|
||||
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) {
|
||||
if (!firstPromisesType) {
|
||||
const firstPromisesTypeNode = getPromisesHeritageClauseElement(<ClassLikeDeclaration | InterfaceDeclaration>declaration);
|
||||
firstPromisesType = firstPromisesTypeNode && getTypeFromTypeNode(firstPromisesTypeNode);
|
||||
}
|
||||
else {
|
||||
const promisesTypeNode = getPromisesHeritageClauseElement(<ClassLikeDeclaration | InterfaceDeclaration>declaration);
|
||||
const promisesType = promisesTypeNode && getTypeFromTypeNode(promisesTypeNode);
|
||||
if (promisesTypeNode && !isTypeIdenticalTo(firstPromisesType, promisesType)) {
|
||||
error(node.name, Diagnostics.Any_declarations_of_0_that_promise_a_type_must_promise_the_same_type, node.name.text);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function checkClassExpression(node: ClassExpression): Type {
|
||||
checkClassLikeDeclaration(node);
|
||||
checkNodeDeferred(node);
|
||||
@ -18272,6 +18301,7 @@ namespace ts {
|
||||
const typeWithThis = getTypeWithThisArgument(type);
|
||||
const staticType = <ObjectType>getTypeOfSymbol(symbol);
|
||||
checkTypeParameterListsIdentical(node, symbol);
|
||||
checkPromisesTypesIdentical(node, symbol);
|
||||
checkClassForDuplicateDeclarations(node);
|
||||
|
||||
const baseTypeNode = getClassExtendsHeritageClauseElement(node);
|
||||
@ -18342,6 +18372,26 @@ 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);
|
||||
if (produceDiagnostics) {
|
||||
const t = getTypeFromTypeNode(promisesTypeNode);
|
||||
if (t !== unknownType) {
|
||||
const promisedType = getPromisedTypeOfPromise(type);
|
||||
if (!promisedType) {
|
||||
error(node.name || node, Diagnostics.Class_or_interface_0_incorrectly_promises_type_1_A_compatible_then_signature_could_not_be_found, typeToString(type), typeToString(t));
|
||||
}
|
||||
else {
|
||||
checkTypeAssignableTo(t, promisedType, node.name || node, Diagnostics.Class_or_interface_promises_type_0_which_is_not_compatible_with_the_type_1_used_by_the_fulfillment_callbacks_of_its_then_members);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (produceDiagnostics) {
|
||||
checkIndexConstraints(type);
|
||||
checkTypeForDuplicateIndexSignatures(node);
|
||||
@ -18541,6 +18591,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);
|
||||
}
|
||||
|
||||
checkTypeParameters(node.typeParameters);
|
||||
if (produceDiagnostics) {
|
||||
checkTypeNameIsReserved(node.name, Diagnostics.Interface_name_cannot_be_0);
|
||||
@ -18548,6 +18606,7 @@ namespace ts {
|
||||
checkExportsOnMergedDeclarations(node);
|
||||
const symbol = getSymbolOfNode(node);
|
||||
checkTypeParameterListsIdentical(node, symbol);
|
||||
checkPromisesTypesIdentical(node, symbol);
|
||||
|
||||
// Only check this symbol once
|
||||
const firstInterfaceDecl = <InterfaceDeclaration>getDeclarationOfKind(symbol, SyntaxKind.InterfaceDeclaration);
|
||||
@ -18561,6 +18620,19 @@ namespace ts {
|
||||
}
|
||||
checkIndexConstraints(type);
|
||||
}
|
||||
|
||||
if (promisesTypeNode) {
|
||||
const promisesType = getTypeFromTypeNode(promisesTypeNode);
|
||||
if (promisesType !== unknownType) {
|
||||
const promisedType = getPromisedTypeOfPromise(type);
|
||||
if (!promisedType) {
|
||||
error(node.name || node, Diagnostics.Class_or_interface_0_incorrectly_promises_type_1_A_compatible_then_signature_could_not_be_found, typeToString(type), typeToString(promisesType));
|
||||
}
|
||||
else {
|
||||
checkTypeAssignableTo(promisesType, promisedType, node.name || node, Diagnostics.Class_or_interface_promises_type_0_which_is_not_compatible_with_the_type_1_used_by_the_fulfillment_callbacks_of_its_then_members);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
checkObjectTypeForDuplicateDeclarations(node);
|
||||
}
|
||||
@ -21343,31 +21415,46 @@ 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) {
|
||||
if (heritageClause.token === SyntaxKind.ExtendsKeyword) {
|
||||
if (seenExtendsClause) {
|
||||
return grammarErrorOnFirstToken(heritageClause, Diagnostics.extends_clause_already_seen);
|
||||
}
|
||||
switch (heritageClause.token) {
|
||||
case SyntaxKind.ExtendsKeyword:
|
||||
if (seenExtendsClause) {
|
||||
return grammarErrorOnFirstToken(heritageClause, Diagnostics._0_clause_already_seen, "extends");
|
||||
}
|
||||
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);
|
||||
}
|
||||
seenExtendsClause = true;
|
||||
break;
|
||||
|
||||
if (seenImplementsClause) {
|
||||
return grammarErrorOnFirstToken(heritageClause, Diagnostics.extends_clause_must_precede_implements_clause);
|
||||
}
|
||||
case SyntaxKind.ImplementsKeyword:
|
||||
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;
|
||||
|
||||
if (heritageClause.types.length > 1) {
|
||||
return grammarErrorOnFirstToken(heritageClause.types[1], Diagnostics.Classes_can_only_extend_a_single_class);
|
||||
}
|
||||
|
||||
seenExtendsClause = true;
|
||||
}
|
||||
else {
|
||||
Debug.assert(heritageClause.token === SyntaxKind.ImplementsKeyword);
|
||||
if (seenImplementsClause) {
|
||||
return grammarErrorOnFirstToken(heritageClause, Diagnostics.implements_clause_already_seen);
|
||||
}
|
||||
|
||||
seenImplementsClause = true;
|
||||
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
|
||||
@ -21378,19 +21465,31 @@ namespace ts {
|
||||
|
||||
function checkGrammarInterfaceDeclaration(node: InterfaceDeclaration) {
|
||||
let seenExtendsClause = false;
|
||||
let seenPromisesClause = false;
|
||||
|
||||
if (node.heritageClauses) {
|
||||
for (const heritageClause of node.heritageClauses) {
|
||||
if (heritageClause.token === SyntaxKind.ExtendsKeyword) {
|
||||
if (seenExtendsClause) {
|
||||
return grammarErrorOnFirstToken(heritageClause, Diagnostics.extends_clause_already_seen);
|
||||
}
|
||||
|
||||
seenExtendsClause = true;
|
||||
}
|
||||
else {
|
||||
Debug.assert(heritageClause.token === SyntaxKind.ImplementsKeyword);
|
||||
return grammarErrorOnFirstToken(heritageClause, Diagnostics.Interface_declaration_cannot_have_implements_clause);
|
||||
switch (heritageClause.token) {
|
||||
case SyntaxKind.ExtendsKeyword:
|
||||
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
|
||||
|
||||
@ -511,11 +511,11 @@
|
||||
"category": "Error",
|
||||
"code": 1171
|
||||
},
|
||||
"'extends' clause already seen.": {
|
||||
"'{0}' clause already seen.": {
|
||||
"category": "Error",
|
||||
"code": 1172
|
||||
},
|
||||
"'extends' clause must precede 'implements' clause.": {
|
||||
"'{0}' clause must precede '{0}' clause.": {
|
||||
"category": "Error",
|
||||
"code": 1173
|
||||
},
|
||||
@ -523,7 +523,7 @@
|
||||
"category": "Error",
|
||||
"code": 1174
|
||||
},
|
||||
"'implements' clause already seen.": {
|
||||
"Classes and interfaces can only promise a single type.": {
|
||||
"category": "Error",
|
||||
"code": 1175
|
||||
},
|
||||
@ -1323,6 +1323,10 @@
|
||||
"category": "Error",
|
||||
"code": 2420
|
||||
},
|
||||
"Class or interface '{0}' incorrectly promises type '{1}'. A compatible 'then()' signature could not be found.": {
|
||||
"category": "Error",
|
||||
"code": 2421
|
||||
},
|
||||
"A class may only implement another class or interface.": {
|
||||
"category": "Error",
|
||||
"code": 2422
|
||||
@ -1351,6 +1355,10 @@
|
||||
"category": "Error",
|
||||
"code": 2428
|
||||
},
|
||||
"Class or interface promises type '{0}' which is not compatible with the type '{1}' used by the fulfillment callbacks of its 'then()' members.": {
|
||||
"category": "Error",
|
||||
"code": 2429
|
||||
},
|
||||
"Interface '{0}' incorrectly extends interface '{1}'.": {
|
||||
"category": "Error",
|
||||
"code": 2430
|
||||
@ -1427,6 +1435,10 @@
|
||||
"category": "Error",
|
||||
"code": 2448
|
||||
},
|
||||
"Any declarations of '{0}' that promise a type must promise the same type.": {
|
||||
"category": "Error",
|
||||
"code": 2449
|
||||
},
|
||||
"Cannot redeclare block-scoped variable '{0}'.": {
|
||||
"category": "Error",
|
||||
"code": 2451
|
||||
@ -1627,6 +1639,10 @@
|
||||
"category": "Error",
|
||||
"code": 2503
|
||||
},
|
||||
"A class or interface can only promise an identifier/qualified-name with optional type arguments.": {
|
||||
"category": "Error",
|
||||
"code": 2504
|
||||
},
|
||||
"A generator cannot have a 'void' type annotation.": {
|
||||
"category": "Error",
|
||||
"code": 2505
|
||||
|
||||
@ -1333,7 +1333,7 @@ namespace ts {
|
||||
|
||||
// Clauses
|
||||
|
||||
export function createHeritageClause(token: SyntaxKind, types: ExpressionWithTypeArguments[], location?: TextRange) {
|
||||
export function createHeritageClause(token: SyntaxKind.ExtendsKeyword | SyntaxKind.ImplementsKeyword | SyntaxKind.PromisesKeyword, types: ExpressionWithTypeArguments[], location?: TextRange) {
|
||||
const node = <HeritageClause>createNode(SyntaxKind.HeritageClause, location);
|
||||
node.token = token;
|
||||
node.types = createNodeArray(types);
|
||||
|
||||
@ -5412,9 +5412,10 @@ namespace ts {
|
||||
}
|
||||
|
||||
function parseHeritageClause() {
|
||||
if (token() === SyntaxKind.ExtendsKeyword || token() === SyntaxKind.ImplementsKeyword) {
|
||||
const keyword = token();
|
||||
if (keyword === SyntaxKind.ExtendsKeyword || keyword === SyntaxKind.ImplementsKeyword || keyword === SyntaxKind.PromisesKeyword) {
|
||||
const node = <HeritageClause>createNode(SyntaxKind.HeritageClause);
|
||||
node.token = token();
|
||||
node.token = keyword;
|
||||
nextToken();
|
||||
node.types = parseDelimitedList(ParsingContext.HeritageClauseElement, parseExpressionWithTypeArguments);
|
||||
return finishNode(node);
|
||||
@ -5434,7 +5435,13 @@ namespace ts {
|
||||
}
|
||||
|
||||
function isHeritageClause(): boolean {
|
||||
return token() === SyntaxKind.ExtendsKeyword || token() === SyntaxKind.ImplementsKeyword;
|
||||
switch (token()) {
|
||||
case SyntaxKind.ExtendsKeyword:
|
||||
case SyntaxKind.ImplementsKeyword:
|
||||
case SyntaxKind.PromisesKeyword:
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
function parseClassMembers() {
|
||||
|
||||
@ -101,6 +101,7 @@ namespace ts {
|
||||
"package": SyntaxKind.PackageKeyword,
|
||||
"private": SyntaxKind.PrivateKeyword,
|
||||
"protected": SyntaxKind.ProtectedKeyword,
|
||||
"promises": SyntaxKind.PromisesKeyword,
|
||||
"public": SyntaxKind.PublicKeyword,
|
||||
"readonly": SyntaxKind.ReadonlyKeyword,
|
||||
"require": SyntaxKind.RequireKeyword,
|
||||
|
||||
@ -172,6 +172,7 @@ namespace ts {
|
||||
ModuleKeyword,
|
||||
NamespaceKeyword,
|
||||
NeverKeyword,
|
||||
PromisesKeyword,
|
||||
ReadonlyKeyword,
|
||||
RequireKeyword,
|
||||
NumberKeyword,
|
||||
@ -1726,7 +1727,7 @@ namespace ts {
|
||||
|
||||
export interface HeritageClause extends Node {
|
||||
kind: SyntaxKind.HeritageClause;
|
||||
token: SyntaxKind;
|
||||
token: SyntaxKind.ExtendsKeyword | SyntaxKind.ImplementsKeyword | SyntaxKind.PromisesKeyword;
|
||||
types?: NodeArray<ExpressionWithTypeArguments>;
|
||||
}
|
||||
|
||||
|
||||
@ -1806,6 +1806,11 @@ 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;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user