From 1befac39827889546e91a716c6ea30dc7208ac51 Mon Sep 17 00:00:00 2001 From: Jack Works Date: Sun, 6 Sep 2020 15:35:27 +0800 Subject: [PATCH 01/27] feat: introduce throw type --- src/compiler/checker.ts | 24 ++++++++++++++++++++++++ src/compiler/diagnosticMessages.json | 4 ++++ src/compiler/factory/nodeFactory.ts | 2 +- src/compiler/parser.ts | 3 ++- src/compiler/types.ts | 9 +++++++-- 5 files changed, 38 insertions(+), 4 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 246f3d1505020..ee99436af8c4c 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -4524,6 +4524,9 @@ namespace ts { if (type.flags & TypeFlags.Substitution) { return typeToTypeNodeHelper((type).baseType, context); } + if (type.flags & TypeFlags.ThrowType) { + return typeToTypeNodeHelper(errorType, context); + } return Debug.fail("Should be unreachable."); @@ -13434,6 +13437,9 @@ namespace ts { case SyntaxKind.ReadonlyKeyword: links.resolvedType = getTypeFromTypeNode(node.type); break; + case SyntaxKind.ThrowKeyword: + links.resolvedType = createThrowType(getTypeFromTypeNode(node.type)); + break; default: throw Debug.assertNever(node.operator); } @@ -14504,6 +14510,12 @@ namespace ts { return type; } + function createThrowType(containingType: Type) { + const type = createType(TypeFlags.ThrowType); + type.value = containingType; + return type; + } + function getESSymbolLikeTypeForNode(node: Node) { if (isValidESSymbolDeclaration(node)) { const symbol = getSymbolOfNode(node); @@ -15156,6 +15168,15 @@ namespace ts { return sub; } } + if (flags & TypeFlags.ThrowType) { + const innerType = instantiateType((type).value, mapper); + let errorMessage = "Unknown"; + if (innerType.flags & TypeFlags.StringLiteral) { + errorMessage = (innerType).value; + } + error(currentNode, Diagnostics.Type_instantiated_results_in_a_throw_type_saying_Colon_0, errorMessage); + return errorType; + } return type; } @@ -19366,6 +19387,9 @@ namespace ts { // results for union and intersection types for performance reasons. function couldContainTypeVariables(type: Type): boolean { const objectFlags = getObjectFlags(type); + if (type.flags & TypeFlags.ThrowType) { + return couldContainTypeVariables((type).value); + } if (objectFlags & ObjectFlags.CouldContainTypeVariablesComputed) { return !!(objectFlags & ObjectFlags.CouldContainTypeVariables); } diff --git a/src/compiler/diagnosticMessages.json b/src/compiler/diagnosticMessages.json index 7c90ce2006c6d..a3de03f3aa92e 100644 --- a/src/compiler/diagnosticMessages.json +++ b/src/compiler/diagnosticMessages.json @@ -3032,6 +3032,10 @@ "category": "Error", "code": 2793 }, + "Type instantiated results in a throw type saying: {0}": { + "category": "Error", + "code": 2794 + }, "Import declaration '{0}' is using private name '{1}'.": { "category": "Error", diff --git a/src/compiler/factory/nodeFactory.ts b/src/compiler/factory/nodeFactory.ts index 0e2cf25d28186..b9aaaa9bd7236 100644 --- a/src/compiler/factory/nodeFactory.ts +++ b/src/compiler/factory/nodeFactory.ts @@ -1975,7 +1975,7 @@ namespace ts { } // @api - function createTypeOperatorNode(operator: SyntaxKind.KeyOfKeyword | SyntaxKind.UniqueKeyword | SyntaxKind.ReadonlyKeyword, type: TypeNode): TypeOperatorNode { + function createTypeOperatorNode(operator: SyntaxKind.KeyOfKeyword | SyntaxKind.UniqueKeyword | SyntaxKind.ReadonlyKeyword | SyntaxKind.ThrowKeyword, type: TypeNode): TypeOperatorNode { const node = createBaseNode(SyntaxKind.TypeOperator); node.operator = operator; node.type = parenthesizerRules().parenthesizeMemberOfElementType(type); diff --git a/src/compiler/parser.ts b/src/compiler/parser.ts index a2ad539bef319..673b6bde16d17 100644 --- a/src/compiler/parser.ts +++ b/src/compiler/parser.ts @@ -3593,7 +3593,7 @@ namespace ts { return type; } - function parseTypeOperator(operator: SyntaxKind.KeyOfKeyword | SyntaxKind.UniqueKeyword | SyntaxKind.ReadonlyKeyword) { + function parseTypeOperator(operator: SyntaxKind.KeyOfKeyword | SyntaxKind.UniqueKeyword | SyntaxKind.ReadonlyKeyword | SyntaxKind.ThrowKeyword) { const pos = getNodePos(); parseExpected(operator); return finishNode(factory.createTypeOperatorNode(operator, parseTypeOperatorOrHigher()), pos); @@ -3623,6 +3623,7 @@ namespace ts { case SyntaxKind.KeyOfKeyword: case SyntaxKind.UniqueKeyword: case SyntaxKind.ReadonlyKeyword: + case SyntaxKind.ThrowKeyword: return parseTypeOperator(operator); case SyntaxKind.InferKeyword: return parseInferType(); diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 6a9e16eb2a24d..05248977bbbc9 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -1615,7 +1615,7 @@ namespace ts { export interface TypeOperatorNode extends TypeNode { readonly kind: SyntaxKind.TypeOperator; - readonly operator: SyntaxKind.KeyOfKeyword | SyntaxKind.UniqueKeyword | SyntaxKind.ReadonlyKeyword; + readonly operator: SyntaxKind.KeyOfKeyword | SyntaxKind.UniqueKeyword | SyntaxKind.ReadonlyKeyword | SyntaxKind.ThrowKeyword; readonly type: TypeNode; } @@ -4885,6 +4885,7 @@ namespace ts { Substitution = 1 << 25, // Type parameter substitution NonPrimitive = 1 << 26, // intrinsic object type TemplateLiteral = 1 << 27, // Template literal type + ThrowType = 1 << 28, // throw T /* @internal */ AnyOrUnknown = Any | Unknown, @@ -5020,6 +5021,10 @@ namespace ts { export interface EnumType extends Type { } + export interface ThrowType extends Type { + value: Type; + } + export const enum ObjectFlags { Class = 1 << 0, // Class Interface = 1 << 1, // Interface @@ -6801,7 +6806,7 @@ namespace ts { createParenthesizedType(type: TypeNode): ParenthesizedTypeNode; updateParenthesizedType(node: ParenthesizedTypeNode, type: TypeNode): ParenthesizedTypeNode; createThisTypeNode(): ThisTypeNode; - createTypeOperatorNode(operator: SyntaxKind.KeyOfKeyword | SyntaxKind.UniqueKeyword | SyntaxKind.ReadonlyKeyword, type: TypeNode): TypeOperatorNode; + createTypeOperatorNode(operator: SyntaxKind.KeyOfKeyword | SyntaxKind.UniqueKeyword | SyntaxKind.ReadonlyKeyword | SyntaxKind.ThrowKeyword, type: TypeNode): TypeOperatorNode; updateTypeOperatorNode(node: TypeOperatorNode, type: TypeNode): TypeOperatorNode; createIndexedAccessTypeNode(objectType: TypeNode, indexType: TypeNode): IndexedAccessTypeNode; updateIndexedAccessTypeNode(node: IndexedAccessTypeNode, objectType: TypeNode, indexType: TypeNode): IndexedAccessTypeNode; From 2a9f0670d35eda78bd07723a0b33e4d0e481836a Mon Sep 17 00:00:00 2001 From: Jack Works Date: Sun, 6 Sep 2020 16:00:28 +0800 Subject: [PATCH 02/27] feat: handle throw type in call expression --- src/compiler/checker.ts | 23 ++++++++++++++++------- 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index ee99436af8c4c..be2d151e51104 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -1059,6 +1059,17 @@ namespace ts { return diagnostic; } + function errorByThrowType(location: Node | undefined, value: Type) { + let message = "Unknown"; + if (value.flags & TypeFlags.ThrowType) { + value = (value).value; + } + if (value.flags & TypeFlags.StringLiteral) { + message = (value).value; + } + error(location, Diagnostics.Type_instantiated_results_in_a_throw_type_saying_Colon_0, message); + } + function addErrorOrSuggestion(isError: boolean, diagnostic: DiagnosticWithLocation) { if (isError) { diagnostics.add(diagnostic); @@ -4525,7 +4536,7 @@ namespace ts { return typeToTypeNodeHelper((type).baseType, context); } if (type.flags & TypeFlags.ThrowType) { - return typeToTypeNodeHelper(errorType, context); + return typeToTypeNodeHelper(neverType, context); } return Debug.fail("Should be unreachable."); @@ -15169,12 +15180,7 @@ namespace ts { } } if (flags & TypeFlags.ThrowType) { - const innerType = instantiateType((type).value, mapper); - let errorMessage = "Unknown"; - if (innerType.flags & TypeFlags.StringLiteral) { - errorMessage = (innerType).value; - } - error(currentNode, Diagnostics.Type_instantiated_results_in_a_throw_type_saying_Colon_0, errorMessage); + errorByThrowType(currentNode, instantiateType((type).value, mapper)); return errorType; } return type; @@ -27870,6 +27876,9 @@ namespace ts { } const returnType = getReturnTypeOfSignature(signature); + if (returnType.flags & TypeFlags.ThrowType) { + errorByThrowType(node, returnType); + } // Treat any call to the global 'Symbol' function that is part of a const variable or readonly property // as a fresh unique symbol literal type. if (returnType.flags & TypeFlags.ESSymbolLike && isSymbolOrSymbolForCall(node)) { From f1286b6eec0af3034e29709192bb8f0ec6170651 Mon Sep 17 00:00:00 2001 From: Jack Works Date: Sun, 6 Sep 2020 16:59:01 +0800 Subject: [PATCH 03/27] feat: add typeof modifier in template string --- src/compiler/checker.ts | 18 +++++++++++++----- src/compiler/emitter.ts | 1 + src/compiler/parser.ts | 1 + src/compiler/types.ts | 1 + 4 files changed, 16 insertions(+), 5 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index be2d151e51104..83bac969caead 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -13482,12 +13482,15 @@ namespace ts { let text = texts[0]; for (let i = 0; i < types.length; i++) { const t = types[i]; - if (t.flags & TypeFlags.Literal) { - const s = applyTemplateCasing(getTemplateStringForType(t) || "", casings[i]); + const casingType = casings[i]; + const isGeneric = isGenericIndexType(t); + const resolvable = (t.flags & TypeFlags.Literal) || (!isGeneric && casingType === TemplateCasing.TypeOf); + if (resolvable) { + const s = applyTemplateCasing(getTemplateStringForType(t, casingType) || "", casingType); text += s; text += texts[i + 1]; } - else if (isGenericIndexType(t)) { + else if (isGeneric) { newTypes.push(t); newCasings.push(casings[i]); newTexts.push(text); @@ -13509,7 +13512,10 @@ namespace ts { return type; } - function getTemplateStringForType(type: Type) { + function getTemplateStringForType(type: Type, casing: TemplateCasing) { + if (casing === TemplateCasing.TypeOf) { + return getTypeNameForErrorDisplay(type); + } return type.flags & TypeFlags.StringLiteral ? (type).value : type.flags & TypeFlags.NumberLiteral ? "" + (type).value : type.flags & TypeFlags.BigIntLiteral ? pseudoBigIntToString((type).value) : @@ -31518,7 +31524,9 @@ namespace ts { getTypeFromTypeNode(node); for (const span of node.templateSpans) { const type = getTypeFromTypeNode(span.type); - checkTypeAssignableTo(type, templateConstraintType, span.type); + if (span.casing !== TemplateCasing.TypeOf) { + checkTypeAssignableTo(type, templateConstraintType, span.type); + } if (!everyType(type, t => !!(t.flags & TypeFlags.Literal) || isGenericIndexType(t))) { error(span.type, Diagnostics.Template_literal_type_argument_0_is_not_literal_type_or_a_generic_type, typeToString(type)); } diff --git a/src/compiler/emitter.ts b/src/compiler/emitter.ts index f36ce3634c8c8..c97b8839fdddc 100644 --- a/src/compiler/emitter.ts +++ b/src/compiler/emitter.ts @@ -2019,6 +2019,7 @@ namespace ts { node.casing === TemplateCasing.Lowercase ? "lowercase" : node.casing === TemplateCasing.Capitalize ? "capitalize" : node.casing === TemplateCasing.Uncapitalize ? "uncapitalize" : + node.casing === TemplateCasing.TypeOf ? "typeof" : undefined; if (keyword) { writeKeyword(keyword); diff --git a/src/compiler/parser.ts b/src/compiler/parser.ts index 673b6bde16d17..73467bb477bd6 100644 --- a/src/compiler/parser.ts +++ b/src/compiler/parser.ts @@ -2629,6 +2629,7 @@ namespace ts { parseOptional(SyntaxKind.LowercaseKeyword) ? TemplateCasing.Lowercase : parseOptional(SyntaxKind.CapitalizeKeyword) ? TemplateCasing.Capitalize : parseOptional(SyntaxKind.UncapitalizeKeyword) ? TemplateCasing.Uncapitalize : + parseOptional(SyntaxKind.TypeOfKeyword) ? TemplateCasing.TypeOf : TemplateCasing.None; } diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 05248977bbbc9..a32ac7b8bb2fa 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -1674,6 +1674,7 @@ namespace ts { Lowercase, Capitalize, Uncapitalize, + TypeOf, } // Note: 'brands' in our syntax nodes serve to give us a small amount of nominal typing. From 1c1c6538f960f5a8765019012199a75ce4193680 Mon Sep 17 00:00:00 2001 From: Jack Works Date: Tue, 8 Sep 2020 10:07:39 +0800 Subject: [PATCH 04/27] chore: accept baseline --- tests/baselines/reference/api/tsserverlibrary.d.ts | 11 ++++++++--- tests/baselines/reference/api/typescript.d.ts | 11 ++++++++--- 2 files changed, 16 insertions(+), 6 deletions(-) diff --git a/tests/baselines/reference/api/tsserverlibrary.d.ts b/tests/baselines/reference/api/tsserverlibrary.d.ts index d498dc3ec7e0e..5fecf8d0b1469 100644 --- a/tests/baselines/reference/api/tsserverlibrary.d.ts +++ b/tests/baselines/reference/api/tsserverlibrary.d.ts @@ -938,7 +938,7 @@ declare namespace ts { } export interface TypeOperatorNode extends TypeNode { readonly kind: SyntaxKind.TypeOperator; - readonly operator: SyntaxKind.KeyOfKeyword | SyntaxKind.UniqueKeyword | SyntaxKind.ReadonlyKeyword; + readonly operator: SyntaxKind.KeyOfKeyword | SyntaxKind.UniqueKeyword | SyntaxKind.ReadonlyKeyword | SyntaxKind.ThrowKeyword; readonly type: TypeNode; } export interface IndexedAccessTypeNode extends TypeNode { @@ -980,7 +980,8 @@ declare namespace ts { Uppercase = 1, Lowercase = 2, Capitalize = 3, - Uncapitalize = 4 + Uncapitalize = 4, + TypeOf = 5 } export interface Expression extends Node { _expressionBrand: any; @@ -2487,6 +2488,7 @@ declare namespace ts { Substitution = 33554432, NonPrimitive = 67108864, TemplateLiteral = 134217728, + ThrowType = 268435456, Literal = 2944, Unit = 109440, StringOrNumberLiteral = 384, @@ -2535,6 +2537,9 @@ declare namespace ts { } export interface EnumType extends Type { } + export interface ThrowType extends Type { + value: Type; + } export enum ObjectFlags { Class = 1, Interface = 2, @@ -3256,7 +3261,7 @@ declare namespace ts { createParenthesizedType(type: TypeNode): ParenthesizedTypeNode; updateParenthesizedType(node: ParenthesizedTypeNode, type: TypeNode): ParenthesizedTypeNode; createThisTypeNode(): ThisTypeNode; - createTypeOperatorNode(operator: SyntaxKind.KeyOfKeyword | SyntaxKind.UniqueKeyword | SyntaxKind.ReadonlyKeyword, type: TypeNode): TypeOperatorNode; + createTypeOperatorNode(operator: SyntaxKind.KeyOfKeyword | SyntaxKind.UniqueKeyword | SyntaxKind.ReadonlyKeyword | SyntaxKind.ThrowKeyword, type: TypeNode): TypeOperatorNode; updateTypeOperatorNode(node: TypeOperatorNode, type: TypeNode): TypeOperatorNode; createIndexedAccessTypeNode(objectType: TypeNode, indexType: TypeNode): IndexedAccessTypeNode; updateIndexedAccessTypeNode(node: IndexedAccessTypeNode, objectType: TypeNode, indexType: TypeNode): IndexedAccessTypeNode; diff --git a/tests/baselines/reference/api/typescript.d.ts b/tests/baselines/reference/api/typescript.d.ts index 9ad992542116d..9673071d51cd2 100644 --- a/tests/baselines/reference/api/typescript.d.ts +++ b/tests/baselines/reference/api/typescript.d.ts @@ -938,7 +938,7 @@ declare namespace ts { } export interface TypeOperatorNode extends TypeNode { readonly kind: SyntaxKind.TypeOperator; - readonly operator: SyntaxKind.KeyOfKeyword | SyntaxKind.UniqueKeyword | SyntaxKind.ReadonlyKeyword; + readonly operator: SyntaxKind.KeyOfKeyword | SyntaxKind.UniqueKeyword | SyntaxKind.ReadonlyKeyword | SyntaxKind.ThrowKeyword; readonly type: TypeNode; } export interface IndexedAccessTypeNode extends TypeNode { @@ -980,7 +980,8 @@ declare namespace ts { Uppercase = 1, Lowercase = 2, Capitalize = 3, - Uncapitalize = 4 + Uncapitalize = 4, + TypeOf = 5 } export interface Expression extends Node { _expressionBrand: any; @@ -2487,6 +2488,7 @@ declare namespace ts { Substitution = 33554432, NonPrimitive = 67108864, TemplateLiteral = 134217728, + ThrowType = 268435456, Literal = 2944, Unit = 109440, StringOrNumberLiteral = 384, @@ -2535,6 +2537,9 @@ declare namespace ts { } export interface EnumType extends Type { } + export interface ThrowType extends Type { + value: Type; + } export enum ObjectFlags { Class = 1, Interface = 2, @@ -3256,7 +3261,7 @@ declare namespace ts { createParenthesizedType(type: TypeNode): ParenthesizedTypeNode; updateParenthesizedType(node: ParenthesizedTypeNode, type: TypeNode): ParenthesizedTypeNode; createThisTypeNode(): ThisTypeNode; - createTypeOperatorNode(operator: SyntaxKind.KeyOfKeyword | SyntaxKind.UniqueKeyword | SyntaxKind.ReadonlyKeyword, type: TypeNode): TypeOperatorNode; + createTypeOperatorNode(operator: SyntaxKind.KeyOfKeyword | SyntaxKind.UniqueKeyword | SyntaxKind.ReadonlyKeyword | SyntaxKind.ThrowKeyword, type: TypeNode): TypeOperatorNode; updateTypeOperatorNode(node: TypeOperatorNode, type: TypeNode): TypeOperatorNode; createIndexedAccessTypeNode(objectType: TypeNode, indexType: TypeNode): IndexedAccessTypeNode; updateIndexedAccessTypeNode(node: IndexedAccessTypeNode, objectType: TypeNode, indexType: TypeNode): IndexedAccessTypeNode; From 22c76cf357451d01911cb726dd7a34e914304ffd Mon Sep 17 00:00:00 2001 From: Jack Works Date: Thu, 10 Sep 2020 11:12:12 +0800 Subject: [PATCH 05/27] fix: un-instantiate throw type in return type --- src/compiler/checker.ts | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 83bac969caead..f580ebc21a849 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -1059,14 +1059,9 @@ namespace ts { return diagnostic; } - function errorByThrowType(location: Node | undefined, value: Type) { - let message = "Unknown"; - if (value.flags & TypeFlags.ThrowType) { - value = (value).value; - } - if (value.flags & TypeFlags.StringLiteral) { - message = (value).value; - } + function errorByThrowType(location: Node | undefined, type: Type) { + if (type.flags & TypeFlags.ThrowType) type = (type).value; + const message = getTypeNameForErrorDisplay(type); error(location, Diagnostics.Type_instantiated_results_in_a_throw_type_saying_Colon_0, message); } @@ -15118,6 +15113,7 @@ namespace ts { function instantiateType(type: Type | undefined, mapper: TypeMapper | undefined): Type | undefined; function instantiateType(type: Type | undefined, mapper: TypeMapper | undefined): Type | undefined { if (!(type && mapper && couldContainTypeVariables(type))) { + if (type && (type.flags & TypeFlags.ThrowType)) errorByThrowType(currentNode, type); return type; } if (instantiationDepth === 50 || instantiationCount >= 5000000) { @@ -15186,8 +15182,8 @@ namespace ts { } } if (flags & TypeFlags.ThrowType) { - errorByThrowType(currentNode, instantiateType((type).value, mapper)); - return errorType; + const errorMessage = instantiateType((type).value, mapper); + return createThrowType(errorMessage); } return type; } From 241cc97bc60000a31c1402484bae83e8ad2ef58d Mon Sep 17 00:00:00 2001 From: Jack Works Date: Thu, 10 Sep 2020 11:36:52 +0800 Subject: [PATCH 06/27] fix: throw type parse error at true branch of conditional type --- src/compiler/parser.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/compiler/parser.ts b/src/compiler/parser.ts index 73467bb477bd6..99e1b6c581f7b 100644 --- a/src/compiler/parser.ts +++ b/src/compiler/parser.ts @@ -3512,6 +3512,7 @@ namespace ts { case SyntaxKind.ReadonlyKeyword: case SyntaxKind.SymbolKeyword: case SyntaxKind.UniqueKeyword: + case SyntaxKind.ThrowKeyword: case SyntaxKind.VoidKeyword: case SyntaxKind.UndefinedKeyword: case SyntaxKind.NullKeyword: From 530c3958207d6149ec16fb537b4e6528815e413f Mon Sep 17 00:00:00 2001 From: Jack Works Date: Thu, 10 Sep 2020 12:30:31 +0800 Subject: [PATCH 07/27] feat: add throw type check for identifier --- src/compiler/checker.ts | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index f580ebc21a849..8de68a718d893 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -1061,7 +1061,12 @@ namespace ts { function errorByThrowType(location: Node | undefined, type: Type) { if (type.flags & TypeFlags.ThrowType) type = (type).value; - const message = getTypeNameForErrorDisplay(type); + let message = ""; + if (type.flags & TypeFlags.StringLiteral) { + message = (type).value; + } else { + message = getTypeNameForErrorDisplay(type) + }; error(location, Diagnostics.Type_instantiated_results_in_a_throw_type_saying_Colon_0, message); } @@ -22485,6 +22490,7 @@ namespace ts { checkNestedBlockScopedBinding(node, symbol); const type = getConstraintForLocation(getTypeOfSymbol(localOrExportSymbol), node); + if (type.flags & TypeFlags.ThrowType) errorByThrowType(node, type); const assignmentKind = getAssignmentTargetKind(node); if (assignmentKind) { From d69f2b00202eb004b6f0fce33542e07c7778e098 Mon Sep 17 00:00:00 2001 From: Jack Works Date: Thu, 10 Sep 2020 13:09:17 +0800 Subject: [PATCH 08/27] fix: lint error --- src/compiler/checker.ts | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 8de68a718d893..2fe8bb2f876cb 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -1062,11 +1062,8 @@ namespace ts { function errorByThrowType(location: Node | undefined, type: Type) { if (type.flags & TypeFlags.ThrowType) type = (type).value; let message = ""; - if (type.flags & TypeFlags.StringLiteral) { - message = (type).value; - } else { - message = getTypeNameForErrorDisplay(type) - }; + if (type.flags & TypeFlags.StringLiteral) message = (type).value; + else message = getTypeNameForErrorDisplay(type); error(location, Diagnostics.Type_instantiated_results_in_a_throw_type_saying_Colon_0, message); } From b5f4fce20e20fec60cd6d736e8f226998389f99f Mon Sep 17 00:00:00 2001 From: Jack Works Date: Fri, 11 Sep 2020 12:41:45 +0800 Subject: [PATCH 09/27] feat: able to reference translated diagnostic message --- src/compiler/checker.ts | 64 +++++++++++++++++++++++++++++++++++++++-- 1 file changed, 62 insertions(+), 2 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 2fe8bb2f876cb..f01609a2d4e45 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -1062,11 +1062,71 @@ namespace ts { function errorByThrowType(location: Node | undefined, type: Type) { if (type.flags & TypeFlags.ThrowType) type = (type).value; let message = ""; - if (type.flags & TypeFlags.StringLiteral) message = (type).value; - else message = getTypeNameForErrorDisplay(type); + const diagnostic = getDiagnosticFromThrowType(type); + if (diagnostic) { + const [base, ...args] = diagnostic; + message = "\n " + formatMessage(/*_dummy*/0, base, ...map(args, getTypeNameForErrorDisplay)); + } + else message = getMessageFromThrowType(type); error(location, Diagnostics.Type_instantiated_results_in_a_throw_type_saying_Colon_0, message); } + function getMessageFromThrowType(type: Type): string { + if (type.flags & TypeFlags.ThrowType) type = (type).value; + if (type.flags & TypeFlags.StringLiteral) return (type).value; + const message = getTypeOfPropertyOfType(type, <__String>"message"); + if (message) { + if (message.flags & TypeFlags.StringLiteral) return (message).value; + } + return getTypeNameForErrorDisplay(type); + } + // function getTypeFromThrowType(type: Type): Type { + // if (type.flags & TypeFlags.ThrowType) type = (type).value; + // return getTypeOfPropertyOfType(type, <__String>"type") || errorType; + // } + function getDiagnosticFromThrowType(type: Type): readonly [DiagnosticMessage, ...Type[]] | undefined { + if (type.flags & TypeFlags.ThrowType) type = (type).value; + const diag = getTypeOfPropertyOfType(type, <__String>"diagnostic"); + if (!diag) return undefined; + const message = getTupleElementType(diag, 0); + if (!message || !(message.flags & TypeFlags.StringLiteral)) return undefined; + if (!Diagnostics.hasOwnProperty(message.value)) return undefined; + // cause error() only accept 4 arguments at most. + return [ + Diagnostics[message.value as keyof typeof Diagnostics], + getTupleElementType(diag, 1) || undefinedType, + getTupleElementType(diag, 2) || undefinedType, + getTupleElementType(diag, 3) || undefinedType, + getTupleElementType(diag, 4) || undefinedType, + ] as const; + } + // function getCategoryFromThrowType(type: Type): DiagnosticCategory { + // if (type.flags & TypeFlags.ThrowType) type = (type).value; + // const category = getTypeOfPropertyOfType(type, <__String>"diagnostic"); + // if (!category || !(category.flags & TypeFlags.StringLiteral)) return DiagnosticCategory.Error; + // switch (category.value.toLowerCase()) { + // case "error": return DiagnosticCategory.Error; + // case "suggestion": return DiagnosticCategory.Suggestion; + // case "warning": return DiagnosticCategory.Warning; + // default: return DiagnosticCategory.Message; + // } + // } + // function getDeprecatedFromThrowType(type: Type): boolean { + // if (type.flags & TypeFlags.ThrowType) type = (type).value; + // const dep = getTypeOfPropertyOfType(type, <__String>"deprecated"); + // return dep === trueType; + // } + // function getSuggestionFromThrowType(type: Type): string | undefined { + // if (type.flags & TypeFlags.ThrowType) type = (type).value; + // const suggestion = getTypeOfPropertyOfType(type, <__String>"suggestion"); + // if (!suggestion || !(suggestion.flags & TypeFlags.StringLiteral)) return undefined; + // return suggestion.value; + // } + // function getMessageChainFromThrowType(type: Type): Type | undefined { + // if (type.flags & TypeFlags.ThrowType) type = (type).value; + // return getTypeOfPropertyOfType(type, <__String>"next"); + // } + function addErrorOrSuggestion(isError: boolean, diagnostic: DiagnosticWithLocation) { if (isError) { diagnostics.add(diagnostic); From b39ff3d9218c1c7a971f61baa31cd01e79426092 Mon Sep 17 00:00:00 2001 From: Jack Works Date: Fri, 11 Sep 2020 13:07:26 +0800 Subject: [PATCH 10/27] feat: support category in throw type --- src/compiler/checker.ts | 46 +++++++++++++++++++++++++++-------------- 1 file changed, 31 insertions(+), 15 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index f01609a2d4e45..2aaf42c92664f 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -1059,16 +1059,19 @@ namespace ts { return diagnostic; } - function errorByThrowType(location: Node | undefined, type: Type) { + function errorByThrowType(location: Node, type: Type) { if (type.flags & TypeFlags.ThrowType) type = (type).value; + let message = ""; const diagnostic = getDiagnosticFromThrowType(type); if (diagnostic) { const [base, ...args] = diagnostic; - message = "\n " + formatMessage(/*_dummy*/0, base, ...map(args, getTypeNameForErrorDisplay)); + message = formatMessage(/*_dummy*/0, base, ...map(args, getTypeNameForErrorDisplay)); } else message = getMessageFromThrowType(type); - error(location, Diagnostics.Type_instantiated_results_in_a_throw_type_saying_Colon_0, message); + + const category = getCategoryFromThrowType(type); + appendDiagnosticWithCategory(category, location, Diagnostics.Type_instantiated_results_in_a_throw_type_saying_Colon_0, "\n " + message); } function getMessageFromThrowType(type: Type): string { @@ -1100,17 +1103,17 @@ namespace ts { getTupleElementType(diag, 4) || undefinedType, ] as const; } - // function getCategoryFromThrowType(type: Type): DiagnosticCategory { - // if (type.flags & TypeFlags.ThrowType) type = (type).value; - // const category = getTypeOfPropertyOfType(type, <__String>"diagnostic"); - // if (!category || !(category.flags & TypeFlags.StringLiteral)) return DiagnosticCategory.Error; - // switch (category.value.toLowerCase()) { - // case "error": return DiagnosticCategory.Error; - // case "suggestion": return DiagnosticCategory.Suggestion; - // case "warning": return DiagnosticCategory.Warning; - // default: return DiagnosticCategory.Message; - // } - // } + function getCategoryFromThrowType(type: Type): DiagnosticCategory { + if (type.flags & TypeFlags.ThrowType) type = (type).value; + const category = getTypeOfPropertyOfType(type, <__String>"category"); + if (!category || !(category.flags & TypeFlags.StringLiteral)) return DiagnosticCategory.Error; + switch (category.value.toLowerCase()) { + case "error": return DiagnosticCategory.Error; + case "suggestion": return DiagnosticCategory.Suggestion; + case "warning": return DiagnosticCategory.Warning; + default: return DiagnosticCategory.Message; + } + } // function getDeprecatedFromThrowType(type: Type): boolean { // if (type.flags & TypeFlags.ThrowType) type = (type).value; // const dep = getTypeOfPropertyOfType(type, <__String>"deprecated"); @@ -1135,9 +1138,22 @@ namespace ts { suggestionDiagnostics.add({ ...diagnostic, category: DiagnosticCategory.Suggestion }); } } + /** @deprecated use appendDiagnosticWithCategory */ function errorOrSuggestion(isError: boolean, location: Node, message: DiagnosticMessage | DiagnosticMessageChain, arg0?: string | number, arg1?: string | number, arg2?: string | number, arg3?: string | number): void { addErrorOrSuggestion(isError, "message" in message ? createDiagnosticForNode(location, message, arg0, arg1, arg2, arg3) : createDiagnosticForNodeFromMessageChain(location, message)); // eslint-disable-line no-in-operator } + function appendDiagnosticWithCategory(category: DiagnosticCategory | undefined, location: Node, message: DiagnosticMessage | DiagnosticMessageChain, arg0?: string | number, arg1?: string | number, arg2?: string | number, arg3?: string | number): void { + const diag = "message" in message ? createDiagnosticForNode(location, message, arg0, arg1, arg2, arg3) : createDiagnosticForNodeFromMessageChain(location, message); // eslint-disable-line no-in-operator + diag.category = category ?? diag.category; + switch (category) { + case DiagnosticCategory.Error: + case DiagnosticCategory.Warning: + return diagnostics.add(diag); + case DiagnosticCategory.Suggestion: + case DiagnosticCategory.Message: + return suggestionDiagnostics.add(diag); + } + } function errorAndMaybeSuggestAwait( location: Node, @@ -15175,7 +15191,7 @@ namespace ts { function instantiateType(type: Type | undefined, mapper: TypeMapper | undefined): Type | undefined; function instantiateType(type: Type | undefined, mapper: TypeMapper | undefined): Type | undefined { if (!(type && mapper && couldContainTypeVariables(type))) { - if (type && (type.flags & TypeFlags.ThrowType)) errorByThrowType(currentNode, type); + if (type && (type.flags & TypeFlags.ThrowType) && currentNode) errorByThrowType(currentNode, type); return type; } if (instantiationDepth === 50 || instantiationCount >= 5000000) { From 1950b0fa1bf5f5b54540b6c1e06da29dc0bacc2c Mon Sep 17 00:00:00 2001 From: Jack Works Date: Fri, 11 Sep 2020 17:34:20 +0800 Subject: [PATCH 11/27] fix: base case of throw types --- src/compiler/checker.ts | 1 + .../throwType_type_reference.errors.txt | 12 ++++++++++++ .../reference/throwType_type_reference.js | 7 +++++++ .../reference/throwType_type_reference.symbols | 17 +++++++++++++++++ .../reference/throwType_type_reference.types | 11 +++++++++++ .../cases/compiler/throwType_type_reference.ts | 3 +++ 6 files changed, 51 insertions(+) create mode 100644 tests/baselines/reference/throwType_type_reference.errors.txt create mode 100644 tests/baselines/reference/throwType_type_reference.js create mode 100644 tests/baselines/reference/throwType_type_reference.symbols create mode 100644 tests/baselines/reference/throwType_type_reference.types create mode 100644 tests/cases/compiler/throwType_type_reference.ts diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 2aaf42c92664f..005d0f90046ab 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -31422,6 +31422,7 @@ namespace ts { } forEach(node.typeArguments, checkSourceElement); const type = getTypeFromTypeReference(node); + if (type.flags & TypeFlags.ThrowType) errorByThrowType(node, type); if (type !== errorType) { if (node.typeArguments && produceDiagnostics) { const typeParameters = getTypeParametersForTypeReference(node); diff --git a/tests/baselines/reference/throwType_type_reference.errors.txt b/tests/baselines/reference/throwType_type_reference.errors.txt new file mode 100644 index 0000000000000..92065a306963d --- /dev/null +++ b/tests/baselines/reference/throwType_type_reference.errors.txt @@ -0,0 +1,12 @@ +tests/cases/compiler/throwType_type_reference.ts(3,10): error TS2794: Type instantiated results in a throw type saying: + Expected number, but found "Window & typeof globalThis" + + +==== tests/cases/compiler/throwType_type_reference.ts (1 errors) ==== + type MustNumber = T extends number ? T : throw `Expected number, but found "${typeof T}"` + type A = MustNumber<1> + type B = MustNumber + ~~~~~~~~~~~~~~~~~~~~~~~~~ +!!! error TS2794: Type instantiated results in a throw type saying: +!!! error TS2794: Expected number, but found "Window & typeof globalThis" + \ No newline at end of file diff --git a/tests/baselines/reference/throwType_type_reference.js b/tests/baselines/reference/throwType_type_reference.js new file mode 100644 index 0000000000000..fc68ab87dc17e --- /dev/null +++ b/tests/baselines/reference/throwType_type_reference.js @@ -0,0 +1,7 @@ +//// [throwType_type_reference.ts] +type MustNumber = T extends number ? T : throw `Expected number, but found "${typeof T}"` +type A = MustNumber<1> +type B = MustNumber + + +//// [throwType_type_reference.js] diff --git a/tests/baselines/reference/throwType_type_reference.symbols b/tests/baselines/reference/throwType_type_reference.symbols new file mode 100644 index 0000000000000..17e91c620caeb --- /dev/null +++ b/tests/baselines/reference/throwType_type_reference.symbols @@ -0,0 +1,17 @@ +=== tests/cases/compiler/throwType_type_reference.ts === +type MustNumber = T extends number ? T : throw `Expected number, but found "${typeof T}"` +>MustNumber : Symbol(MustNumber, Decl(throwType_type_reference.ts, 0, 0)) +>T : Symbol(T, Decl(throwType_type_reference.ts, 0, 16)) +>T : Symbol(T, Decl(throwType_type_reference.ts, 0, 16)) +>T : Symbol(T, Decl(throwType_type_reference.ts, 0, 16)) +>T : Symbol(T, Decl(throwType_type_reference.ts, 0, 16)) + +type A = MustNumber<1> +>A : Symbol(A, Decl(throwType_type_reference.ts, 0, 92)) +>MustNumber : Symbol(MustNumber, Decl(throwType_type_reference.ts, 0, 0)) + +type B = MustNumber +>B : Symbol(B, Decl(throwType_type_reference.ts, 1, 22)) +>MustNumber : Symbol(MustNumber, Decl(throwType_type_reference.ts, 0, 0)) +>window : Symbol(window, Decl(lib.dom.d.ts, --, --)) + diff --git a/tests/baselines/reference/throwType_type_reference.types b/tests/baselines/reference/throwType_type_reference.types new file mode 100644 index 0000000000000..f73fee3f3b2cc --- /dev/null +++ b/tests/baselines/reference/throwType_type_reference.types @@ -0,0 +1,11 @@ +=== tests/cases/compiler/throwType_type_reference.ts === +type MustNumber = T extends number ? T : throw `Expected number, but found "${typeof T}"` +>MustNumber : MustNumber + +type A = MustNumber<1> +>A : 1 + +type B = MustNumber +>B : never +>window : Window & typeof globalThis + diff --git a/tests/cases/compiler/throwType_type_reference.ts b/tests/cases/compiler/throwType_type_reference.ts new file mode 100644 index 0000000000000..6f718e1d8de27 --- /dev/null +++ b/tests/cases/compiler/throwType_type_reference.ts @@ -0,0 +1,3 @@ +type MustNumber = T extends number ? T : throw `Expected number, but found "${typeof T}"` +type A = MustNumber<1> +type B = MustNumber From 9faf8c4608ffe403058a4ea10c615cdce8669537 Mon Sep 17 00:00:00 2001 From: Jack Works Date: Fri, 11 Sep 2020 17:53:09 +0800 Subject: [PATCH 12/27] test: add test case for prevent call expr usage --- .../throwType_function_return.errors.txt | 19 +++++++ .../reference/throwType_function_return.js | 27 ++++++++++ .../throwType_function_return.symbols | 43 +++++++++++++++ .../reference/throwType_function_return.types | 53 +++++++++++++++++++ .../compiler/throwType_function_return.ts | 10 ++++ 5 files changed, 152 insertions(+) create mode 100644 tests/baselines/reference/throwType_function_return.errors.txt create mode 100644 tests/baselines/reference/throwType_function_return.js create mode 100644 tests/baselines/reference/throwType_function_return.symbols create mode 100644 tests/baselines/reference/throwType_function_return.types create mode 100644 tests/cases/compiler/throwType_function_return.ts diff --git a/tests/baselines/reference/throwType_function_return.errors.txt b/tests/baselines/reference/throwType_function_return.errors.txt new file mode 100644 index 0000000000000..094bc9135fccc --- /dev/null +++ b/tests/baselines/reference/throwType_function_return.errors.txt @@ -0,0 +1,19 @@ +tests/cases/compiler/throwType_function_return.ts(10,1): error TS2794: Type instantiated results in a throw type saying: + Cannot apply + operator on this type + + +==== tests/cases/compiler/throwType_function_return.ts (1 errors) ==== + class X { + constructor(public item: T) { } + add(a: T): T extends number | string | bigint ? T : throw `Cannot apply + operator on this type` { + // @ts-ignore + return a + this.item + } + } + new X(1).add(2).toExponential() + new X("").add("").toLowerCase() + new X({}).add({}) + ~~~~~~~~~~~~~~~~~ +!!! error TS2794: Type instantiated results in a throw type saying: +!!! error TS2794: Cannot apply + operator on this type + \ No newline at end of file diff --git a/tests/baselines/reference/throwType_function_return.js b/tests/baselines/reference/throwType_function_return.js new file mode 100644 index 0000000000000..8ae4f293555b2 --- /dev/null +++ b/tests/baselines/reference/throwType_function_return.js @@ -0,0 +1,27 @@ +//// [throwType_function_return.ts] +class X { + constructor(public item: T) { } + add(a: T): T extends number | string | bigint ? T : throw `Cannot apply + operator on this type` { + // @ts-ignore + return a + this.item + } +} +new X(1).add(2).toExponential() +new X("").add("").toLowerCase() +new X({}).add({}) + + +//// [throwType_function_return.js] +var X = /** @class */ (function () { + function X(item) { + this.item = item; + } + X.prototype.add = function (a) { + // @ts-ignore + return a + this.item; + }; + return X; +}()); +new X(1).add(2).toExponential(); +new X("").add("").toLowerCase(); +new X({}).add({}); diff --git a/tests/baselines/reference/throwType_function_return.symbols b/tests/baselines/reference/throwType_function_return.symbols new file mode 100644 index 0000000000000..748b41cb3ca86 --- /dev/null +++ b/tests/baselines/reference/throwType_function_return.symbols @@ -0,0 +1,43 @@ +=== tests/cases/compiler/throwType_function_return.ts === +class X { +>X : Symbol(X, Decl(throwType_function_return.ts, 0, 0)) +>T : Symbol(T, Decl(throwType_function_return.ts, 0, 8)) + + constructor(public item: T) { } +>item : Symbol(X.item, Decl(throwType_function_return.ts, 1, 16)) +>T : Symbol(T, Decl(throwType_function_return.ts, 0, 8)) + + add(a: T): T extends number | string | bigint ? T : throw `Cannot apply + operator on this type` { +>add : Symbol(X.add, Decl(throwType_function_return.ts, 1, 35)) +>a : Symbol(a, Decl(throwType_function_return.ts, 2, 8)) +>T : Symbol(T, Decl(throwType_function_return.ts, 0, 8)) +>T : Symbol(T, Decl(throwType_function_return.ts, 0, 8)) +>T : Symbol(T, Decl(throwType_function_return.ts, 0, 8)) + + // @ts-ignore + return a + this.item +>a : Symbol(a, Decl(throwType_function_return.ts, 2, 8)) +>this.item : Symbol(X.item, Decl(throwType_function_return.ts, 1, 16)) +>this : Symbol(X, Decl(throwType_function_return.ts, 0, 0)) +>item : Symbol(X.item, Decl(throwType_function_return.ts, 1, 16)) + } +} +new X(1).add(2).toExponential() +>new X(1).add(2).toExponential : Symbol(Number.toExponential, Decl(lib.es5.d.ts, --, --)) +>new X(1).add : Symbol(X.add, Decl(throwType_function_return.ts, 1, 35)) +>X : Symbol(X, Decl(throwType_function_return.ts, 0, 0)) +>add : Symbol(X.add, Decl(throwType_function_return.ts, 1, 35)) +>toExponential : Symbol(Number.toExponential, Decl(lib.es5.d.ts, --, --)) + +new X("").add("").toLowerCase() +>new X("").add("").toLowerCase : Symbol(String.toLowerCase, Decl(lib.es5.d.ts, --, --)) +>new X("").add : Symbol(X.add, Decl(throwType_function_return.ts, 1, 35)) +>X : Symbol(X, Decl(throwType_function_return.ts, 0, 0)) +>add : Symbol(X.add, Decl(throwType_function_return.ts, 1, 35)) +>toLowerCase : Symbol(String.toLowerCase, Decl(lib.es5.d.ts, --, --)) + +new X({}).add({}) +>new X({}).add : Symbol(X.add, Decl(throwType_function_return.ts, 1, 35)) +>X : Symbol(X, Decl(throwType_function_return.ts, 0, 0)) +>add : Symbol(X.add, Decl(throwType_function_return.ts, 1, 35)) + diff --git a/tests/baselines/reference/throwType_function_return.types b/tests/baselines/reference/throwType_function_return.types new file mode 100644 index 0000000000000..91d1b858f576e --- /dev/null +++ b/tests/baselines/reference/throwType_function_return.types @@ -0,0 +1,53 @@ +=== tests/cases/compiler/throwType_function_return.ts === +class X { +>X : X + + constructor(public item: T) { } +>item : T + + add(a: T): T extends number | string | bigint ? T : throw `Cannot apply + operator on this type` { +>add : (a: T) => T extends number | string | bigint ? T : throw `Cannot apply + operator on this type` +>a : T + + // @ts-ignore + return a + this.item +>a + this.item : any +>a : T +>this.item : T +>this : this +>item : T + } +} +new X(1).add(2).toExponential() +>new X(1).add(2).toExponential() : string +>new X(1).add(2).toExponential : (fractionDigits?: number) => string +>new X(1).add(2) : number +>new X(1).add : (a: number) => number +>new X(1) : X +>X : typeof X +>1 : 1 +>add : (a: number) => number +>2 : 2 +>toExponential : (fractionDigits?: number) => string + +new X("").add("").toLowerCase() +>new X("").add("").toLowerCase() : string +>new X("").add("").toLowerCase : () => string +>new X("").add("") : string +>new X("").add : (a: string) => string +>new X("") : X +>X : typeof X +>"" : "" +>add : (a: string) => string +>"" : "" +>toLowerCase : () => string + +new X({}).add({}) +>new X({}).add({}) : never +>new X({}).add : (a: {}) => never +>new X({}) : X<{}> +>X : typeof X +>{} : {} +>add : (a: {}) => never +>{} : {} + diff --git a/tests/cases/compiler/throwType_function_return.ts b/tests/cases/compiler/throwType_function_return.ts new file mode 100644 index 0000000000000..bbf5beb540246 --- /dev/null +++ b/tests/cases/compiler/throwType_function_return.ts @@ -0,0 +1,10 @@ +class X { + constructor(public item: T) { } + add(a: T): T extends number | string | bigint ? T : throw `Cannot apply + operator on this type` { + // @ts-ignore + return a + this.item + } +} +new X(1).add(2).toExponential() +new X("").add("").toLowerCase() +new X({}).add({}) From daac7e799964bdb14c4e227a71915c35fc061ead Mon Sep 17 00:00:00 2001 From: Jack Works Date: Fri, 11 Sep 2020 17:54:37 +0800 Subject: [PATCH 13/27] test: add test for identifier use case --- .../reference/throwType_identifier.errors.txt | 11 +++++++++++ .../baselines/reference/throwType_identifier.js | 9 +++++++++ .../reference/throwType_identifier.symbols | 14 ++++++++++++++ .../reference/throwType_identifier.types | 16 ++++++++++++++++ tests/cases/compiler/throwType_identifier.ts | 3 +++ 5 files changed, 53 insertions(+) create mode 100644 tests/baselines/reference/throwType_identifier.errors.txt create mode 100644 tests/baselines/reference/throwType_identifier.js create mode 100644 tests/baselines/reference/throwType_identifier.symbols create mode 100644 tests/baselines/reference/throwType_identifier.types create mode 100644 tests/cases/compiler/throwType_identifier.ts diff --git a/tests/baselines/reference/throwType_identifier.errors.txt b/tests/baselines/reference/throwType_identifier.errors.txt new file mode 100644 index 0000000000000..5322ea132278c --- /dev/null +++ b/tests/baselines/reference/throwType_identifier.errors.txt @@ -0,0 +1,11 @@ +tests/cases/compiler/throwType_identifier.ts(2,13): error TS2794: Type instantiated results in a throw type saying: + please use window.name + + +==== tests/cases/compiler/throwType_identifier.ts (1 errors) ==== + declare const name: throw 'please use window.name' + console.log(name, 123, window.name) + ~~~~ +!!! error TS2794: Type instantiated results in a throw type saying: +!!! error TS2794: please use window.name + export {} \ No newline at end of file diff --git a/tests/baselines/reference/throwType_identifier.js b/tests/baselines/reference/throwType_identifier.js new file mode 100644 index 0000000000000..0f54f73f3f5d8 --- /dev/null +++ b/tests/baselines/reference/throwType_identifier.js @@ -0,0 +1,9 @@ +//// [throwType_identifier.ts] +declare const name: throw 'please use window.name' +console.log(name, 123, window.name) +export {} + +//// [throwType_identifier.js] +"use strict"; +exports.__esModule = true; +console.log(name, 123, window.name); diff --git a/tests/baselines/reference/throwType_identifier.symbols b/tests/baselines/reference/throwType_identifier.symbols new file mode 100644 index 0000000000000..92c3560cdfd32 --- /dev/null +++ b/tests/baselines/reference/throwType_identifier.symbols @@ -0,0 +1,14 @@ +=== tests/cases/compiler/throwType_identifier.ts === +declare const name: throw 'please use window.name' +>name : Symbol(name, Decl(throwType_identifier.ts, 0, 13)) + +console.log(name, 123, window.name) +>console.log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --)) +>console : Symbol(console, Decl(lib.dom.d.ts, --, --)) +>log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --)) +>name : Symbol(name, Decl(throwType_identifier.ts, 0, 13)) +>window.name : Symbol(Window.name, Decl(lib.dom.d.ts, --, --)) +>window : Symbol(window, Decl(lib.dom.d.ts, --, --)) +>name : Symbol(Window.name, Decl(lib.dom.d.ts, --, --)) + +export {} diff --git a/tests/baselines/reference/throwType_identifier.types b/tests/baselines/reference/throwType_identifier.types new file mode 100644 index 0000000000000..6962a79109e58 --- /dev/null +++ b/tests/baselines/reference/throwType_identifier.types @@ -0,0 +1,16 @@ +=== tests/cases/compiler/throwType_identifier.ts === +declare const name: throw 'please use window.name' +>name : never + +console.log(name, 123, window.name) +>console.log(name, 123, window.name) : void +>console.log : (...data: any[]) => void +>console : Console +>log : (...data: any[]) => void +>name : never +>123 : 123 +>window.name : string +>window : Window & typeof globalThis +>name : string + +export {} diff --git a/tests/cases/compiler/throwType_identifier.ts b/tests/cases/compiler/throwType_identifier.ts new file mode 100644 index 0000000000000..3244d0abca18f --- /dev/null +++ b/tests/cases/compiler/throwType_identifier.ts @@ -0,0 +1,3 @@ +declare const name: throw 'please use window.name' +console.log(name, 123, window.name) +export {} \ No newline at end of file From 7d785ebf979235dea869e272af8a661780d0350e Mon Sep 17 00:00:00 2001 From: Jack Works Date: Sat, 12 Sep 2020 09:45:43 +0800 Subject: [PATCH 14/27] feat: improve throw type on return type --- src/compiler/checker.ts | 16 +++- .../throwType_function_return.errors.txt | 31 ++++--- .../reference/throwType_function_return.js | 41 +++++----- .../throwType_function_return.symbols | 65 +++++++-------- .../reference/throwType_function_return.types | 82 +++++++++---------- .../compiler/throwType_function_return.ts | 18 ++-- 6 files changed, 126 insertions(+), 127 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 005d0f90046ab..9d85ff1ace68c 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -15191,7 +15191,6 @@ namespace ts { function instantiateType(type: Type | undefined, mapper: TypeMapper | undefined): Type | undefined; function instantiateType(type: Type | undefined, mapper: TypeMapper | undefined): Type | undefined { if (!(type && mapper && couldContainTypeVariables(type))) { - if (type && (type.flags & TypeFlags.ThrowType) && currentNode) errorByThrowType(currentNode, type); return type; } if (instantiationDepth === 50 || instantiationCount >= 5000000) { @@ -34398,9 +34397,22 @@ namespace ts { function unwrapReturnType(returnType: Type, functionFlags: FunctionFlags) { const isGenerator = !!(functionFlags & FunctionFlags.Generator); const isAsync = !!(functionFlags & FunctionFlags.Async); - return isGenerator ? getIterationTypeOfGeneratorFunctionReturnType(IterationTypeKind.Return, returnType, isAsync) ?? errorType : + const type = isGenerator ? getIterationTypeOfGeneratorFunctionReturnType(IterationTypeKind.Return, returnType, isAsync) ?? errorType : isAsync ? getAwaitedType(returnType) ?? errorType : returnType; + return dropThrowTypeInConditionalType(type); + } + function dropThrowTypeInConditionalType(type: Type): Type { + if (!(type.flags & TypeFlags.Conditional)) return type; + const cond = type; + // don't instatiate the type + const left = dropThrowTypeInConditionalType(getTypeFromTypeNode(cond.root.node.trueType)); + const right = dropThrowTypeInConditionalType(getTypeFromTypeNode(cond.root.node.falseType)); + if ((left.flags & TypeFlags.ThrowType) ^ (right.flags & TypeFlags.ThrowType)) { + if (left.flags & TypeFlags.ThrowType) return right; + else return left; + } + return cond; } function isUnwrappedReturnTypeVoidOrAny(func: SignatureDeclaration, returnType: Type): boolean { diff --git a/tests/baselines/reference/throwType_function_return.errors.txt b/tests/baselines/reference/throwType_function_return.errors.txt index 094bc9135fccc..547f3f1fc7e1e 100644 --- a/tests/baselines/reference/throwType_function_return.errors.txt +++ b/tests/baselines/reference/throwType_function_return.errors.txt @@ -1,19 +1,24 @@ +tests/cases/compiler/throwType_function_return.ts(5,1): error TS2794: Type instantiated results in a throw type saying: + Cannot divided by 0 tests/cases/compiler/throwType_function_return.ts(10,1): error TS2794: Type instantiated results in a throw type saying: - Cannot apply + operator on this type + Wrong -==== tests/cases/compiler/throwType_function_return.ts (1 errors) ==== - class X { - constructor(public item: T) { } - add(a: T): T extends number | string | bigint ? T : throw `Cannot apply + operator on this type` { - // @ts-ignore - return a + this.item - } +==== tests/cases/compiler/throwType_function_return.ts (2 errors) ==== + function checkedDivide(x: T): T extends 0 ? throw 'Cannot divided by 0' : number { + if (x === 0) throw new Error('') + return 5 / x } - new X(1).add(2).toExponential() - new X("").add("").toLowerCase() - new X({}).add({}) - ~~~~~~~~~~~~~~~~~ + checkedDivide(0) + ~~~~~~~~~~~~~~~~ !!! error TS2794: Type instantiated results in a throw type saying: -!!! error TS2794: Cannot apply + operator on this type +!!! error TS2794: Cannot divided by 0 + checkedDivide(1) + + const theAnswerToEverything = (x: T): T extends 42 ? T : throw "Wrong" => x + theAnswerToEverything(42 as const) + theAnswerToEverything('') + ~~~~~~~~~~~~~~~~~~~~~~~~~ +!!! error TS2794: Type instantiated results in a throw type saying: +!!! error TS2794: Wrong \ No newline at end of file diff --git a/tests/baselines/reference/throwType_function_return.js b/tests/baselines/reference/throwType_function_return.js index 8ae4f293555b2..4d24c73aecf43 100644 --- a/tests/baselines/reference/throwType_function_return.js +++ b/tests/baselines/reference/throwType_function_return.js @@ -1,27 +1,24 @@ //// [throwType_function_return.ts] -class X { - constructor(public item: T) { } - add(a: T): T extends number | string | bigint ? T : throw `Cannot apply + operator on this type` { - // @ts-ignore - return a + this.item - } +function checkedDivide(x: T): T extends 0 ? throw 'Cannot divided by 0' : number { + if (x === 0) throw new Error('') + return 5 / x } -new X(1).add(2).toExponential() -new X("").add("").toLowerCase() -new X({}).add({}) +checkedDivide(0) +checkedDivide(1) + +const theAnswerToEverything = (x: T): T extends 42 ? T : throw "Wrong" => x +theAnswerToEverything(42 as const) +theAnswerToEverything('') //// [throwType_function_return.js] -var X = /** @class */ (function () { - function X(item) { - this.item = item; - } - X.prototype.add = function (a) { - // @ts-ignore - return a + this.item; - }; - return X; -}()); -new X(1).add(2).toExponential(); -new X("").add("").toLowerCase(); -new X({}).add({}); +function checkedDivide(x) { + if (x === 0) + throw new Error(''); + return 5 / x; +} +checkedDivide(0); +checkedDivide(1); +var theAnswerToEverything = function (x) { return x; }; +theAnswerToEverything(42); +theAnswerToEverything(''); diff --git a/tests/baselines/reference/throwType_function_return.symbols b/tests/baselines/reference/throwType_function_return.symbols index 748b41cb3ca86..1d57b4d6d2f11 100644 --- a/tests/baselines/reference/throwType_function_return.symbols +++ b/tests/baselines/reference/throwType_function_return.symbols @@ -1,43 +1,36 @@ === tests/cases/compiler/throwType_function_return.ts === -class X { ->X : Symbol(X, Decl(throwType_function_return.ts, 0, 0)) ->T : Symbol(T, Decl(throwType_function_return.ts, 0, 8)) +function checkedDivide(x: T): T extends 0 ? throw 'Cannot divided by 0' : number { +>checkedDivide : Symbol(checkedDivide, Decl(throwType_function_return.ts, 0, 0)) +>T : Symbol(T, Decl(throwType_function_return.ts, 0, 23)) +>x : Symbol(x, Decl(throwType_function_return.ts, 0, 41)) +>T : Symbol(T, Decl(throwType_function_return.ts, 0, 23)) +>T : Symbol(T, Decl(throwType_function_return.ts, 0, 23)) - constructor(public item: T) { } ->item : Symbol(X.item, Decl(throwType_function_return.ts, 1, 16)) ->T : Symbol(T, Decl(throwType_function_return.ts, 0, 8)) + if (x === 0) throw new Error('') +>x : Symbol(x, Decl(throwType_function_return.ts, 0, 41)) +>Error : Symbol(Error, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --)) - add(a: T): T extends number | string | bigint ? T : throw `Cannot apply + operator on this type` { ->add : Symbol(X.add, Decl(throwType_function_return.ts, 1, 35)) ->a : Symbol(a, Decl(throwType_function_return.ts, 2, 8)) ->T : Symbol(T, Decl(throwType_function_return.ts, 0, 8)) ->T : Symbol(T, Decl(throwType_function_return.ts, 0, 8)) ->T : Symbol(T, Decl(throwType_function_return.ts, 0, 8)) - - // @ts-ignore - return a + this.item ->a : Symbol(a, Decl(throwType_function_return.ts, 2, 8)) ->this.item : Symbol(X.item, Decl(throwType_function_return.ts, 1, 16)) ->this : Symbol(X, Decl(throwType_function_return.ts, 0, 0)) ->item : Symbol(X.item, Decl(throwType_function_return.ts, 1, 16)) - } + return 5 / x +>x : Symbol(x, Decl(throwType_function_return.ts, 0, 41)) } -new X(1).add(2).toExponential() ->new X(1).add(2).toExponential : Symbol(Number.toExponential, Decl(lib.es5.d.ts, --, --)) ->new X(1).add : Symbol(X.add, Decl(throwType_function_return.ts, 1, 35)) ->X : Symbol(X, Decl(throwType_function_return.ts, 0, 0)) ->add : Symbol(X.add, Decl(throwType_function_return.ts, 1, 35)) ->toExponential : Symbol(Number.toExponential, Decl(lib.es5.d.ts, --, --)) +checkedDivide(0) +>checkedDivide : Symbol(checkedDivide, Decl(throwType_function_return.ts, 0, 0)) + +checkedDivide(1) +>checkedDivide : Symbol(checkedDivide, Decl(throwType_function_return.ts, 0, 0)) + +const theAnswerToEverything = (x: T): T extends 42 ? T : throw "Wrong" => x +>theAnswerToEverything : Symbol(theAnswerToEverything, Decl(throwType_function_return.ts, 7, 5)) +>T : Symbol(T, Decl(throwType_function_return.ts, 7, 31)) +>x : Symbol(x, Decl(throwType_function_return.ts, 7, 34)) +>T : Symbol(T, Decl(throwType_function_return.ts, 7, 31)) +>T : Symbol(T, Decl(throwType_function_return.ts, 7, 31)) +>T : Symbol(T, Decl(throwType_function_return.ts, 7, 31)) +>x : Symbol(x, Decl(throwType_function_return.ts, 7, 34)) -new X("").add("").toLowerCase() ->new X("").add("").toLowerCase : Symbol(String.toLowerCase, Decl(lib.es5.d.ts, --, --)) ->new X("").add : Symbol(X.add, Decl(throwType_function_return.ts, 1, 35)) ->X : Symbol(X, Decl(throwType_function_return.ts, 0, 0)) ->add : Symbol(X.add, Decl(throwType_function_return.ts, 1, 35)) ->toLowerCase : Symbol(String.toLowerCase, Decl(lib.es5.d.ts, --, --)) +theAnswerToEverything(42 as const) +>theAnswerToEverything : Symbol(theAnswerToEverything, Decl(throwType_function_return.ts, 7, 5)) -new X({}).add({}) ->new X({}).add : Symbol(X.add, Decl(throwType_function_return.ts, 1, 35)) ->X : Symbol(X, Decl(throwType_function_return.ts, 0, 0)) ->add : Symbol(X.add, Decl(throwType_function_return.ts, 1, 35)) +theAnswerToEverything('') +>theAnswerToEverything : Symbol(theAnswerToEverything, Decl(throwType_function_return.ts, 7, 5)) diff --git a/tests/baselines/reference/throwType_function_return.types b/tests/baselines/reference/throwType_function_return.types index 91d1b858f576e..572590f407454 100644 --- a/tests/baselines/reference/throwType_function_return.types +++ b/tests/baselines/reference/throwType_function_return.types @@ -1,53 +1,45 @@ === tests/cases/compiler/throwType_function_return.ts === -class X { ->X : X +function checkedDivide(x: T): T extends 0 ? throw 'Cannot divided by 0' : number { +>checkedDivide : (x: T) => T extends 0 ? throw 'Cannot divided by 0' : number +>x : T - constructor(public item: T) { } ->item : T + if (x === 0) throw new Error('') +>x === 0 : boolean +>x : T +>0 : 0 +>new Error('') : Error +>Error : ErrorConstructor +>'' : "" - add(a: T): T extends number | string | bigint ? T : throw `Cannot apply + operator on this type` { ->add : (a: T) => T extends number | string | bigint ? T : throw `Cannot apply + operator on this type` ->a : T - - // @ts-ignore - return a + this.item ->a + this.item : any ->a : T ->this.item : T ->this : this ->item : T - } + return 5 / x +>5 / x : number +>5 : 5 +>x : T } -new X(1).add(2).toExponential() ->new X(1).add(2).toExponential() : string ->new X(1).add(2).toExponential : (fractionDigits?: number) => string ->new X(1).add(2) : number ->new X(1).add : (a: number) => number ->new X(1) : X ->X : typeof X +checkedDivide(0) +>checkedDivide(0) : never +>checkedDivide : (x: T) => T extends 0 ? never : number +>0 : 0 + +checkedDivide(1) +>checkedDivide(1) : number +>checkedDivide : (x: T) => T extends 0 ? never : number >1 : 1 ->add : (a: number) => number ->2 : 2 ->toExponential : (fractionDigits?: number) => string -new X("").add("").toLowerCase() ->new X("").add("").toLowerCase() : string ->new X("").add("").toLowerCase : () => string ->new X("").add("") : string ->new X("").add : (a: string) => string ->new X("") : X ->X : typeof X ->"" : "" ->add : (a: string) => string ->"" : "" ->toLowerCase : () => string +const theAnswerToEverything = (x: T): T extends 42 ? T : throw "Wrong" => x +>theAnswerToEverything : (x: T) => T extends 42 ? T : never +>(x: T): T extends 42 ? T : throw "Wrong" => x : (x: T) => T extends 42 ? T : never +>x : T +>x : T + +theAnswerToEverything(42 as const) +>theAnswerToEverything(42 as const) : 42 +>theAnswerToEverything : (x: T) => T extends 42 ? T : never +>42 as const : 42 +>42 : 42 -new X({}).add({}) ->new X({}).add({}) : never ->new X({}).add : (a: {}) => never ->new X({}) : X<{}> ->X : typeof X ->{} : {} ->add : (a: {}) => never ->{} : {} +theAnswerToEverything('') +>theAnswerToEverything('') : never +>theAnswerToEverything : (x: T) => T extends 42 ? T : never +>'' : "" diff --git a/tests/cases/compiler/throwType_function_return.ts b/tests/cases/compiler/throwType_function_return.ts index bbf5beb540246..374bb69984e69 100644 --- a/tests/cases/compiler/throwType_function_return.ts +++ b/tests/cases/compiler/throwType_function_return.ts @@ -1,10 +1,10 @@ -class X { - constructor(public item: T) { } - add(a: T): T extends number | string | bigint ? T : throw `Cannot apply + operator on this type` { - // @ts-ignore - return a + this.item - } +function checkedDivide(x: T): T extends 0 ? throw 'Cannot divided by 0' : number { + if (x === 0) throw new Error('') + return 5 / x } -new X(1).add(2).toExponential() -new X("").add("").toLowerCase() -new X({}).add({}) +checkedDivide(0) +checkedDivide(1) + +const theAnswerToEverything = (x: T): T extends 42 ? T : throw "Wrong" => x +theAnswerToEverything(42 as const) +theAnswerToEverything('') From c22687f032d04dc392b043f8c2ecd97717b10d5d Mon Sep 17 00:00:00 2001 From: Jack Works Date: Sat, 12 Sep 2020 09:57:31 +0800 Subject: [PATCH 15/27] feat: improve throw type on argument position --- .../throwType_function_parameter.errors.txt | 15 +++++++++++++++ .../reference/throwType_function_parameter.js | 10 ++++++++++ .../throwType_function_parameter.symbols | 14 ++++++++++++++ .../reference/throwType_function_parameter.types | 15 +++++++++++++++ .../compiler/throwType_function_parameter.ts | 3 +++ 5 files changed, 57 insertions(+) create mode 100644 tests/baselines/reference/throwType_function_parameter.errors.txt create mode 100644 tests/baselines/reference/throwType_function_parameter.js create mode 100644 tests/baselines/reference/throwType_function_parameter.symbols create mode 100644 tests/baselines/reference/throwType_function_parameter.types create mode 100644 tests/cases/compiler/throwType_function_parameter.ts diff --git a/tests/baselines/reference/throwType_function_parameter.errors.txt b/tests/baselines/reference/throwType_function_parameter.errors.txt new file mode 100644 index 0000000000000..2e9393e092778 --- /dev/null +++ b/tests/baselines/reference/throwType_function_parameter.errors.txt @@ -0,0 +1,15 @@ +tests/cases/compiler/throwType_function_parameter.ts(2,24): error TS2345: Argument of type 'number' is not assignable to parameter of type 'never'. +tests/cases/compiler/throwType_function_parameter.ts(2,24): error TS2794: Type instantiated results in a throw type saying: + No zero + + +==== tests/cases/compiler/throwType_function_parameter.ts (2 errors) ==== + function checkParameterPosition(y: T extends 1234 ? throw 'No zero' : T) { } + checkParameterPosition(1234) + ~~~~ +!!! error TS2345: Argument of type 'number' is not assignable to parameter of type 'never'. + ~~~~ +!!! error TS2794: Type instantiated results in a throw type saying: +!!! error TS2794: No zero + checkParameterPosition(12345678) + \ No newline at end of file diff --git a/tests/baselines/reference/throwType_function_parameter.js b/tests/baselines/reference/throwType_function_parameter.js new file mode 100644 index 0000000000000..97dd2313df95d --- /dev/null +++ b/tests/baselines/reference/throwType_function_parameter.js @@ -0,0 +1,10 @@ +//// [throwType_function_parameter.ts] +function checkParameterPosition(y: T extends 1234 ? throw 'No zero' : T) { } +checkParameterPosition(1234) +checkParameterPosition(12345678) + + +//// [throwType_function_parameter.js] +function checkParameterPosition(y) { } +checkParameterPosition(1234); +checkParameterPosition(12345678); diff --git a/tests/baselines/reference/throwType_function_parameter.symbols b/tests/baselines/reference/throwType_function_parameter.symbols new file mode 100644 index 0000000000000..2283bd1c23996 --- /dev/null +++ b/tests/baselines/reference/throwType_function_parameter.symbols @@ -0,0 +1,14 @@ +=== tests/cases/compiler/throwType_function_parameter.ts === +function checkParameterPosition(y: T extends 1234 ? throw 'No zero' : T) { } +>checkParameterPosition : Symbol(checkParameterPosition, Decl(throwType_function_parameter.ts, 0, 0)) +>T : Symbol(T, Decl(throwType_function_parameter.ts, 0, 32)) +>y : Symbol(y, Decl(throwType_function_parameter.ts, 0, 50)) +>T : Symbol(T, Decl(throwType_function_parameter.ts, 0, 32)) +>T : Symbol(T, Decl(throwType_function_parameter.ts, 0, 32)) + +checkParameterPosition(1234) +>checkParameterPosition : Symbol(checkParameterPosition, Decl(throwType_function_parameter.ts, 0, 0)) + +checkParameterPosition(12345678) +>checkParameterPosition : Symbol(checkParameterPosition, Decl(throwType_function_parameter.ts, 0, 0)) + diff --git a/tests/baselines/reference/throwType_function_parameter.types b/tests/baselines/reference/throwType_function_parameter.types new file mode 100644 index 0000000000000..bb9351760c007 --- /dev/null +++ b/tests/baselines/reference/throwType_function_parameter.types @@ -0,0 +1,15 @@ +=== tests/cases/compiler/throwType_function_parameter.ts === +function checkParameterPosition(y: T extends 1234 ? throw 'No zero' : T) { } +>checkParameterPosition : (y: T extends 1234 ? throw 'No zero' : T) => void +>y : T extends 1234 ? never : T + +checkParameterPosition(1234) +>checkParameterPosition(1234) : void +>checkParameterPosition : (y: T extends 1234 ? never : T) => void +>1234 : 1234 + +checkParameterPosition(12345678) +>checkParameterPosition(12345678) : void +>checkParameterPosition : (y: T extends 1234 ? never : T) => void +>12345678 : 12345678 + diff --git a/tests/cases/compiler/throwType_function_parameter.ts b/tests/cases/compiler/throwType_function_parameter.ts new file mode 100644 index 0000000000000..a498603348b9a --- /dev/null +++ b/tests/cases/compiler/throwType_function_parameter.ts @@ -0,0 +1,3 @@ +function checkParameterPosition(y: T extends 1234 ? throw 'No zero' : T) { } +checkParameterPosition(1234) +checkParameterPosition(12345678) From c21c1b71d3e22eb04bd931fab28a197c30aabed6 Mon Sep 17 00:00:00 2001 From: Jack Works Date: Sat, 12 Sep 2020 10:16:43 +0800 Subject: [PATCH 16/27] feat: add property access check for throw type --- src/compiler/checker.ts | 36 ++++++++++--------- .../throwType_property_access.errors.txt | 12 +++++++ .../reference/throwType_property_access.js | 14 ++++++++ .../throwType_property_access.symbols | 14 ++++++++ .../reference/throwType_property_access.types | 15 ++++++++ .../compiler/throwType_property_access.ts | 5 +++ 6 files changed, 80 insertions(+), 16 deletions(-) create mode 100644 tests/baselines/reference/throwType_property_access.errors.txt create mode 100644 tests/baselines/reference/throwType_property_access.js create mode 100644 tests/baselines/reference/throwType_property_access.symbols create mode 100644 tests/baselines/reference/throwType_property_access.types create mode 100644 tests/cases/compiler/throwType_property_access.ts diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 9d85ff1ace68c..0d54268254b36 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -1059,8 +1059,11 @@ namespace ts { return diagnostic; } + function checkThrowType(location: Node, type: Type) { + if (isThrowType(type)) errorByThrowType(location, type.value); + } function errorByThrowType(location: Node, type: Type) { - if (type.flags & TypeFlags.ThrowType) type = (type).value; + if (isThrowType(type)) type = type.value; let message = ""; const diagnostic = getDiagnosticFromThrowType(type); @@ -1073,9 +1076,12 @@ namespace ts { const category = getCategoryFromThrowType(type); appendDiagnosticWithCategory(category, location, Diagnostics.Type_instantiated_results_in_a_throw_type_saying_Colon_0, "\n " + message); } + function isThrowType(type: Type): type is ThrowType { + return !!(type.flags & TypeFlags.ThrowType); + } function getMessageFromThrowType(type: Type): string { - if (type.flags & TypeFlags.ThrowType) type = (type).value; + if (isThrowType(type)) type = type.value; if (type.flags & TypeFlags.StringLiteral) return (type).value; const message = getTypeOfPropertyOfType(type, <__String>"message"); if (message) { @@ -1088,7 +1094,7 @@ namespace ts { // return getTypeOfPropertyOfType(type, <__String>"type") || errorType; // } function getDiagnosticFromThrowType(type: Type): readonly [DiagnosticMessage, ...Type[]] | undefined { - if (type.flags & TypeFlags.ThrowType) type = (type).value; + if (isThrowType(type)) type = type.value; const diag = getTypeOfPropertyOfType(type, <__String>"diagnostic"); if (!diag) return undefined; const message = getTupleElementType(diag, 0); @@ -1104,7 +1110,7 @@ namespace ts { ] as const; } function getCategoryFromThrowType(type: Type): DiagnosticCategory { - if (type.flags & TypeFlags.ThrowType) type = (type).value; + if (isThrowType(type)) type = type.value; const category = getTypeOfPropertyOfType(type, <__String>"category"); if (!category || !(category.flags & TypeFlags.StringLiteral)) return DiagnosticCategory.Error; switch (category.value.toLowerCase()) { @@ -15258,8 +15264,8 @@ namespace ts { return sub; } } - if (flags & TypeFlags.ThrowType) { - const errorMessage = instantiateType((type).value, mapper); + if (isThrowType(type)) { + const errorMessage = instantiateType(type.value, mapper); return createThrowType(errorMessage); } return type; @@ -19472,9 +19478,7 @@ namespace ts { // results for union and intersection types for performance reasons. function couldContainTypeVariables(type: Type): boolean { const objectFlags = getObjectFlags(type); - if (type.flags & TypeFlags.ThrowType) { - return couldContainTypeVariables((type).value); - } + if (isThrowType(type)) return couldContainTypeVariables(type.value); if (objectFlags & ObjectFlags.CouldContainTypeVariablesComputed) { return !!(objectFlags & ObjectFlags.CouldContainTypeVariables); } @@ -22562,7 +22566,7 @@ namespace ts { checkNestedBlockScopedBinding(node, symbol); const type = getConstraintForLocation(getTypeOfSymbol(localOrExportSymbol), node); - if (type.flags & TypeFlags.ThrowType) errorByThrowType(node, type); + checkThrowType(node, type); const assignmentKind = getAssignmentTargetKind(node); if (assignmentKind) { @@ -25538,6 +25542,7 @@ namespace ts { return errorType; } propType = isThisPropertyAccessInConstructor(node, prop) ? autoType : getConstraintForLocation(getTypeOfSymbol(prop), node); + checkThrowType(node, propType); } return getFlowTypeOfAccessExpression(node, prop, propType, right); } @@ -26571,6 +26576,7 @@ namespace ts { const checkArgType = checkMode & CheckMode.SkipContextSensitive ? getRegularTypeOfObjectLiteral(argType) : argType; if (!checkTypeRelatedToAndOptionallyElaborate(checkArgType, paramType, relation, reportErrors ? arg : undefined, arg, headMessage, containingMessageChain, errorOutputContainer)) { Debug.assert(!reportErrors || !!errorOutputContainer.errors, "parameter should have errors when reporting errors"); + checkThrowType(arg, paramType); maybeAddMissingAwaitInfo(arg, checkArgType, paramType); return errorOutputContainer.errors || emptyArray; } @@ -27956,9 +27962,7 @@ namespace ts { } const returnType = getReturnTypeOfSignature(signature); - if (returnType.flags & TypeFlags.ThrowType) { - errorByThrowType(node, returnType); - } + checkThrowType(node, returnType); // Treat any call to the global 'Symbol' function that is part of a const variable or readonly property // as a fresh unique symbol literal type. if (returnType.flags & TypeFlags.ESSymbolLike && isSymbolOrSymbolForCall(node)) { @@ -31421,7 +31425,7 @@ namespace ts { } forEach(node.typeArguments, checkSourceElement); const type = getTypeFromTypeReference(node); - if (type.flags & TypeFlags.ThrowType) errorByThrowType(node, type); + checkThrowType(node, type); if (type !== errorType) { if (node.typeArguments && produceDiagnostics) { const typeParameters = getTypeParametersForTypeReference(node); @@ -34408,8 +34412,8 @@ namespace ts { // don't instatiate the type const left = dropThrowTypeInConditionalType(getTypeFromTypeNode(cond.root.node.trueType)); const right = dropThrowTypeInConditionalType(getTypeFromTypeNode(cond.root.node.falseType)); - if ((left.flags & TypeFlags.ThrowType) ^ (right.flags & TypeFlags.ThrowType)) { - if (left.flags & TypeFlags.ThrowType) return right; + if (isThrowType(left) !== isThrowType(right)) { + if (isThrowType(left)) return right; else return left; } return cond; diff --git a/tests/baselines/reference/throwType_property_access.errors.txt b/tests/baselines/reference/throwType_property_access.errors.txt new file mode 100644 index 0000000000000..c1fd9a6205a89 --- /dev/null +++ b/tests/baselines/reference/throwType_property_access.errors.txt @@ -0,0 +1,12 @@ +tests/cases/compiler/throwType_property_access.ts(4,1): error TS2794: Type instantiated results in a throw type saying: + + + +==== tests/cases/compiler/throwType_property_access.ts (1 errors) ==== + class X { + i: T extends number ? throw '' : string = {} as any + } + new X<0>().i + ~~~~~~~~~~~~ +!!! error TS2794: Type instantiated results in a throw type saying: +!!! error TS2794: \ No newline at end of file diff --git a/tests/baselines/reference/throwType_property_access.js b/tests/baselines/reference/throwType_property_access.js new file mode 100644 index 0000000000000..f5e00cf291e2e --- /dev/null +++ b/tests/baselines/reference/throwType_property_access.js @@ -0,0 +1,14 @@ +//// [throwType_property_access.ts] +class X { + i: T extends number ? throw '' : string = {} as any +} +new X<0>().i + +//// [throwType_property_access.js] +var X = /** @class */ (function () { + function X() { + this.i = {}; + } + return X; +}()); +new X().i; diff --git a/tests/baselines/reference/throwType_property_access.symbols b/tests/baselines/reference/throwType_property_access.symbols new file mode 100644 index 0000000000000..ea1bea76634fd --- /dev/null +++ b/tests/baselines/reference/throwType_property_access.symbols @@ -0,0 +1,14 @@ +=== tests/cases/compiler/throwType_property_access.ts === +class X { +>X : Symbol(X, Decl(throwType_property_access.ts, 0, 0)) +>T : Symbol(T, Decl(throwType_property_access.ts, 0, 8)) + + i: T extends number ? throw '' : string = {} as any +>i : Symbol(X.i, Decl(throwType_property_access.ts, 0, 12)) +>T : Symbol(T, Decl(throwType_property_access.ts, 0, 8)) +} +new X<0>().i +>new X<0>().i : Symbol(X.i, Decl(throwType_property_access.ts, 0, 12)) +>X : Symbol(X, Decl(throwType_property_access.ts, 0, 0)) +>i : Symbol(X.i, Decl(throwType_property_access.ts, 0, 12)) + diff --git a/tests/baselines/reference/throwType_property_access.types b/tests/baselines/reference/throwType_property_access.types new file mode 100644 index 0000000000000..e9a8f1c41c8f4 --- /dev/null +++ b/tests/baselines/reference/throwType_property_access.types @@ -0,0 +1,15 @@ +=== tests/cases/compiler/throwType_property_access.ts === +class X { +>X : X + + i: T extends number ? throw '' : string = {} as any +>i : T extends number ? never : string +>{} as any : any +>{} : {} +} +new X<0>().i +>new X<0>().i : never +>new X<0>() : X<0> +>X : typeof X +>i : never + diff --git a/tests/cases/compiler/throwType_property_access.ts b/tests/cases/compiler/throwType_property_access.ts new file mode 100644 index 0000000000000..f9412780d1de6 --- /dev/null +++ b/tests/cases/compiler/throwType_property_access.ts @@ -0,0 +1,5 @@ + +class X { + i: T extends number ? throw '' : string = {} as any +} +new X<0>().i \ No newline at end of file From 94aa7314accebd7175fe79eaac93a867fb9a7cdc Mon Sep 17 00:00:00 2001 From: Jack Works Date: Sat, 12 Sep 2020 11:00:12 +0800 Subject: [PATCH 17/27] fix: infinite loop in dropThrowTypeInConditionalType --- src/compiler/checker.ts | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 0d54268254b36..15e3478154772 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -34407,16 +34407,17 @@ namespace ts { return dropThrowTypeInConditionalType(type); } function dropThrowTypeInConditionalType(type: Type): Type { - if (!(type.flags & TypeFlags.Conditional)) return type; - const cond = type; - // don't instatiate the type - const left = dropThrowTypeInConditionalType(getTypeFromTypeNode(cond.root.node.trueType)); - const right = dropThrowTypeInConditionalType(getTypeFromTypeNode(cond.root.node.falseType)); - if (isThrowType(left) !== isThrowType(right)) { - if (isThrowType(left)) return right; - else return left; - } - return cond; + let result = type; + while (true) { + if (!(result.flags & TypeFlags.Conditional)) return result; + const left = getTrueTypeFromConditionalType(result); + const right = getFalseTypeFromConditionalType(result); + if (isThrowType(left) !== isThrowType(right)) { + if (isThrowType(left)) result = right; + else result = left; + } + else return type; + } } function isUnwrappedReturnTypeVoidOrAny(func: SignatureDeclaration, returnType: Type): boolean { From 56bfcd76141141a59568da1d7042bbc1ac2af23b Mon Sep 17 00:00:00 2001 From: Jack Works Date: Wed, 16 Sep 2020 13:18:16 +0800 Subject: [PATCH 18/27] fix: throw type in fn param, co-assign in cond type --- src/compiler/checker.ts | 10 ++++-- .../throwType_function_parameter.errors.txt | 14 ++++++-- .../reference/throwType_function_parameter.js | 17 +++++++-- .../throwType_function_parameter.symbols | 36 ++++++++++++++++++- .../throwType_function_parameter.types | 25 ++++++++++++- .../compiler/throwType_function_parameter.ts | 10 +++++- 6 files changed, 102 insertions(+), 10 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 15e3478154772..42254ef75feda 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -17387,6 +17387,8 @@ namespace ts { // Two conditional types 'T1 extends U1 ? X1 : Y1' and 'T2 extends U2 ? X2 : Y2' are related if // one of T1 and T2 is related to the other, U1 and U2 are identical types, X1 is related to X2, // and Y1 is related to Y2. + // If at least one of X1 or X2 is throw type, they are considered related. + // If at least one of Y1 or Y2 is throw type, they are considered related. const sourceParams = (source as ConditionalType).root.inferTypeParameters; let sourceExtends = (source).extendsType; let mapper: TypeMapper | undefined; @@ -17399,8 +17401,12 @@ namespace ts { } if (isTypeIdenticalTo(sourceExtends, (target).extendsType) && (isRelatedTo((source).checkType, (target).checkType) || isRelatedTo((target).checkType, (source).checkType))) { - if (result = isRelatedTo(instantiateType(getTrueTypeFromConditionalType(source), mapper), getTrueTypeFromConditionalType(target), reportErrors)) { - result &= isRelatedTo(getFalseTypeFromConditionalType(source), getFalseTypeFromConditionalType(target), reportErrors); + const sourceTrueType = dropThrowTypeInConditionalType(instantiateType(getTrueTypeFromConditionalType(source), mapper)); + const targetTrueType = dropThrowTypeInConditionalType(getTrueTypeFromConditionalType(target)); + if (result = (sourceTrueType.flags | targetTrueType.flags) & TypeFlags.ThrowType ? Ternary.True : isRelatedTo(sourceTrueType, targetTrueType, reportErrors)) { + const sourceFalseType = dropThrowTypeInConditionalType(getFalseTypeFromConditionalType(source)); + const targetFalseType = dropThrowTypeInConditionalType(getFalseTypeFromConditionalType(target)); + result &= (sourceFalseType.flags | targetFalseType.flags) & TypeFlags.ThrowType ? Ternary.True : isRelatedTo(sourceFalseType, targetFalseType, reportErrors); } if (result) { resetErrorInfo(saveErrorInfo); diff --git a/tests/baselines/reference/throwType_function_parameter.errors.txt b/tests/baselines/reference/throwType_function_parameter.errors.txt index 2e9393e092778..4c42fd2bf9813 100644 --- a/tests/baselines/reference/throwType_function_parameter.errors.txt +++ b/tests/baselines/reference/throwType_function_parameter.errors.txt @@ -1,10 +1,12 @@ -tests/cases/compiler/throwType_function_parameter.ts(2,24): error TS2345: Argument of type 'number' is not assignable to parameter of type 'never'. -tests/cases/compiler/throwType_function_parameter.ts(2,24): error TS2794: Type instantiated results in a throw type saying: +tests/cases/compiler/throwType_function_parameter.ts(4,24): error TS2345: Argument of type 'number' is not assignable to parameter of type 'never'. +tests/cases/compiler/throwType_function_parameter.ts(4,24): error TS2794: Type instantiated results in a throw type saying: No zero ==== tests/cases/compiler/throwType_function_parameter.ts (2 errors) ==== - function checkParameterPosition(y: T extends 1234 ? throw 'No zero' : T) { } + function checkParameterPosition(y: T extends 1234 ? throw 'No zero' : T) { + y.toExponential() + } checkParameterPosition(1234) ~~~~ !!! error TS2345: Argument of type 'number' is not assignable to parameter of type 'never'. @@ -12,4 +14,10 @@ tests/cases/compiler/throwType_function_parameter.ts(2,24): error TS2794: Type i !!! error TS2794: Type instantiated results in a throw type saying: !!! error TS2794: No zero checkParameterPosition(12345678) + + type MustNumber = T extends number ? T : throw `"found "${typeof T}"` + type MustNumber2 = T extends number ? T : throw `"found "${typeof T}"` + function f2(a: MustNumber, b: MustNumber2) { + a = b + } \ No newline at end of file diff --git a/tests/baselines/reference/throwType_function_parameter.js b/tests/baselines/reference/throwType_function_parameter.js index 97dd2313df95d..eaa23aac21f69 100644 --- a/tests/baselines/reference/throwType_function_parameter.js +++ b/tests/baselines/reference/throwType_function_parameter.js @@ -1,10 +1,23 @@ //// [throwType_function_parameter.ts] -function checkParameterPosition(y: T extends 1234 ? throw 'No zero' : T) { } +function checkParameterPosition(y: T extends 1234 ? throw 'No zero' : T) { + y.toExponential() +} checkParameterPosition(1234) checkParameterPosition(12345678) + +type MustNumber = T extends number ? T : throw `"found "${typeof T}"` +type MustNumber2 = T extends number ? T : throw `"found "${typeof T}"` +function f2(a: MustNumber, b: MustNumber2) { + a = b +} //// [throwType_function_parameter.js] -function checkParameterPosition(y) { } +function checkParameterPosition(y) { + y.toExponential(); +} checkParameterPosition(1234); checkParameterPosition(12345678); +function f2(a, b) { + a = b; +} diff --git a/tests/baselines/reference/throwType_function_parameter.symbols b/tests/baselines/reference/throwType_function_parameter.symbols index 2283bd1c23996..dc2939addaa92 100644 --- a/tests/baselines/reference/throwType_function_parameter.symbols +++ b/tests/baselines/reference/throwType_function_parameter.symbols @@ -1,14 +1,48 @@ === tests/cases/compiler/throwType_function_parameter.ts === -function checkParameterPosition(y: T extends 1234 ? throw 'No zero' : T) { } +function checkParameterPosition(y: T extends 1234 ? throw 'No zero' : T) { >checkParameterPosition : Symbol(checkParameterPosition, Decl(throwType_function_parameter.ts, 0, 0)) >T : Symbol(T, Decl(throwType_function_parameter.ts, 0, 32)) >y : Symbol(y, Decl(throwType_function_parameter.ts, 0, 50)) >T : Symbol(T, Decl(throwType_function_parameter.ts, 0, 32)) >T : Symbol(T, Decl(throwType_function_parameter.ts, 0, 32)) + y.toExponential() +>y.toExponential : Symbol(Number.toExponential, Decl(lib.es5.d.ts, --, --)) +>y : Symbol(y, Decl(throwType_function_parameter.ts, 0, 50)) +>toExponential : Symbol(Number.toExponential, Decl(lib.es5.d.ts, --, --)) +} checkParameterPosition(1234) >checkParameterPosition : Symbol(checkParameterPosition, Decl(throwType_function_parameter.ts, 0, 0)) checkParameterPosition(12345678) >checkParameterPosition : Symbol(checkParameterPosition, Decl(throwType_function_parameter.ts, 0, 0)) +type MustNumber = T extends number ? T : throw `"found "${typeof T}"` +>MustNumber : Symbol(MustNumber, Decl(throwType_function_parameter.ts, 4, 32)) +>T : Symbol(T, Decl(throwType_function_parameter.ts, 6, 16)) +>T : Symbol(T, Decl(throwType_function_parameter.ts, 6, 16)) +>T : Symbol(T, Decl(throwType_function_parameter.ts, 6, 16)) +>T : Symbol(T, Decl(throwType_function_parameter.ts, 6, 16)) + +type MustNumber2 = T extends number ? T : throw `"found "${typeof T}"` +>MustNumber2 : Symbol(MustNumber2, Decl(throwType_function_parameter.ts, 6, 72)) +>T : Symbol(T, Decl(throwType_function_parameter.ts, 7, 17)) +>T : Symbol(T, Decl(throwType_function_parameter.ts, 7, 17)) +>T : Symbol(T, Decl(throwType_function_parameter.ts, 7, 17)) +>T : Symbol(T, Decl(throwType_function_parameter.ts, 7, 17)) + +function f2(a: MustNumber, b: MustNumber2) { +>f2 : Symbol(f2, Decl(throwType_function_parameter.ts, 7, 73)) +>T : Symbol(T, Decl(throwType_function_parameter.ts, 8, 12)) +>a : Symbol(a, Decl(throwType_function_parameter.ts, 8, 15)) +>MustNumber : Symbol(MustNumber, Decl(throwType_function_parameter.ts, 4, 32)) +>T : Symbol(T, Decl(throwType_function_parameter.ts, 8, 12)) +>b : Symbol(b, Decl(throwType_function_parameter.ts, 8, 32)) +>MustNumber2 : Symbol(MustNumber2, Decl(throwType_function_parameter.ts, 6, 72)) +>T : Symbol(T, Decl(throwType_function_parameter.ts, 8, 12)) + + a = b +>a : Symbol(a, Decl(throwType_function_parameter.ts, 8, 15)) +>b : Symbol(b, Decl(throwType_function_parameter.ts, 8, 32)) +} + diff --git a/tests/baselines/reference/throwType_function_parameter.types b/tests/baselines/reference/throwType_function_parameter.types index bb9351760c007..9b921db2cb1ff 100644 --- a/tests/baselines/reference/throwType_function_parameter.types +++ b/tests/baselines/reference/throwType_function_parameter.types @@ -1,8 +1,14 @@ === tests/cases/compiler/throwType_function_parameter.ts === -function checkParameterPosition(y: T extends 1234 ? throw 'No zero' : T) { } +function checkParameterPosition(y: T extends 1234 ? throw 'No zero' : T) { >checkParameterPosition : (y: T extends 1234 ? throw 'No zero' : T) => void >y : T extends 1234 ? never : T + y.toExponential() +>y.toExponential() : string +>y.toExponential : (fractionDigits?: number) => string +>y : T extends 1234 ? never : T +>toExponential : (fractionDigits?: number) => string +} checkParameterPosition(1234) >checkParameterPosition(1234) : void >checkParameterPosition : (y: T extends 1234 ? never : T) => void @@ -13,3 +19,20 @@ checkParameterPosition(12345678) >checkParameterPosition : (y: T extends 1234 ? never : T) => void >12345678 : 12345678 +type MustNumber = T extends number ? T : throw `"found "${typeof T}"` +>MustNumber : MustNumber + +type MustNumber2 = T extends number ? T : throw `"found "${typeof T}"` +>MustNumber2 : MustNumber2 + +function f2(a: MustNumber, b: MustNumber2) { +>f2 : (a: MustNumber, b: MustNumber2) => void +>a : MustNumber +>b : MustNumber2 + + a = b +>a = b : MustNumber2 +>a : MustNumber +>b : MustNumber2 +} + diff --git a/tests/cases/compiler/throwType_function_parameter.ts b/tests/cases/compiler/throwType_function_parameter.ts index a498603348b9a..acc46862c1350 100644 --- a/tests/cases/compiler/throwType_function_parameter.ts +++ b/tests/cases/compiler/throwType_function_parameter.ts @@ -1,3 +1,11 @@ -function checkParameterPosition(y: T extends 1234 ? throw 'No zero' : T) { } +function checkParameterPosition(y: T extends 1234 ? throw 'No zero' : T) { + y.toExponential() +} checkParameterPosition(1234) checkParameterPosition(12345678) + +type MustNumber = T extends number ? T : throw `"found "${typeof T}"` +type MustNumber2 = T extends number ? T : throw `"found "${typeof T}"` +function f2(a: MustNumber, b: MustNumber2) { + a = b +} From bd0f3307b5111d7ae81f0288f5e1deac7e8d85c7 Mon Sep 17 00:00:00 2001 From: Jack Works Date: Sat, 19 Sep 2020 16:52:25 +0800 Subject: [PATCH 19/27] feat: reduce throw type in intersection --- src/compiler/checker.ts | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 42254ef75feda..c3fd59fdeb451 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -11271,11 +11271,14 @@ namespace ts { return (type).resolvedReducedType || ((type).resolvedReducedType = getReducedUnionType(type)); } else if (type.flags & TypeFlags.Intersection) { - if (!((type).objectFlags & ObjectFlags.IsNeverIntersectionComputed)) { - (type).objectFlags |= ObjectFlags.IsNeverIntersectionComputed | - (some(getPropertiesOfUnionOrIntersectionType(type), isNeverReducedProperty) ? ObjectFlags.IsNeverIntersection : 0); + const intersectionType = (type); + const innerThrowType = find(intersectionType.types, isThrowType); + if (innerThrowType) return innerThrowType; + if (!(intersectionType.objectFlags & ObjectFlags.IsNeverIntersectionComputed)) { + intersectionType.objectFlags |= ObjectFlags.IsNeverIntersectionComputed | + (some(getPropertiesOfUnionOrIntersectionType(intersectionType), isNeverReducedProperty) ? ObjectFlags.IsNeverIntersection : 0); } - return (type).objectFlags & ObjectFlags.IsNeverIntersection ? neverType : type; + return intersectionType.objectFlags & ObjectFlags.IsNeverIntersection ? neverType : type; } return type; } @@ -22572,7 +22575,7 @@ namespace ts { checkNestedBlockScopedBinding(node, symbol); const type = getConstraintForLocation(getTypeOfSymbol(localOrExportSymbol), node); - checkThrowType(node, type); + checkThrowType(node, getReducedType(type)); const assignmentKind = getAssignmentTargetKind(node); if (assignmentKind) { From 800fb0c32759d2d362f67d5649405bc04f5ff008 Mon Sep 17 00:00:00 2001 From: Jack Works Date: Thu, 12 Nov 2020 15:42:09 +0800 Subject: [PATCH 20/27] chore: accept new baseline --- .../throwType_function_parameter.errors.txt | 14 ++++---------- .../reference/throwType_function_return.errors.txt | 12 ++++++------ .../reference/throwType_identifier.errors.txt | 6 +++--- .../reference/throwType_property_access.errors.txt | 6 +++--- .../reference/throwType_type_reference.errors.txt | 13 +++++-------- 5 files changed, 21 insertions(+), 30 deletions(-) diff --git a/tests/baselines/reference/throwType_function_parameter.errors.txt b/tests/baselines/reference/throwType_function_parameter.errors.txt index 4ff5718202394..4eb8ccae25be0 100644 --- a/tests/baselines/reference/throwType_function_parameter.errors.txt +++ b/tests/baselines/reference/throwType_function_parameter.errors.txt @@ -1,13 +1,11 @@ tests/cases/compiler/throwType_function_parameter.ts(4,24): error TS2345: Argument of type 'number' is not assignable to parameter of type 'never'. -tests/cases/compiler/throwType_function_parameter.ts(4,24): error TS2796: Type instantiated results in a throw type saying: +tests/cases/compiler/throwType_function_parameter.ts(4,24): error TS2797: Type instantiated results in a throw type saying: No zero -tests/cases/compiler/throwType_function_parameter.ts(7,62): error TS2793: Template literal type argument 'any' is not literal type or a generic type. tests/cases/compiler/throwType_function_parameter.ts(7,69): error TS2693: 'T' only refers to a type, but is being used as a value here. -tests/cases/compiler/throwType_function_parameter.ts(8,63): error TS2793: Template literal type argument 'any' is not literal type or a generic type. tests/cases/compiler/throwType_function_parameter.ts(8,70): error TS2693: 'T' only refers to a type, but is being used as a value here. -==== tests/cases/compiler/throwType_function_parameter.ts (6 errors) ==== +==== tests/cases/compiler/throwType_function_parameter.ts (4 errors) ==== function checkParameterPosition(y: T extends 1234 ? throw 'No zero' : T) { y.toExponential() } @@ -15,18 +13,14 @@ tests/cases/compiler/throwType_function_parameter.ts(8,70): error TS2693: 'T' on ~~~~ !!! error TS2345: Argument of type 'number' is not assignable to parameter of type 'never'. ~~~~ -!!! error TS2796: Type instantiated results in a throw type saying: -!!! error TS2796: No zero +!!! error TS2797: Type instantiated results in a throw type saying: +!!! error TS2797: No zero checkParameterPosition(12345678) type MustNumber = T extends number ? T : throw `"found "${typeof T}"` - ~~~~~~~~ -!!! error TS2793: Template literal type argument 'any' is not literal type or a generic type. ~ !!! error TS2693: 'T' only refers to a type, but is being used as a value here. type MustNumber2 = T extends number ? T : throw `"found "${typeof T}"` - ~~~~~~~~ -!!! error TS2793: Template literal type argument 'any' is not literal type or a generic type. ~ !!! error TS2693: 'T' only refers to a type, but is being used as a value here. function f2(a: MustNumber, b: MustNumber2) { diff --git a/tests/baselines/reference/throwType_function_return.errors.txt b/tests/baselines/reference/throwType_function_return.errors.txt index 10b2c39cd76e1..24c866fc4dc79 100644 --- a/tests/baselines/reference/throwType_function_return.errors.txt +++ b/tests/baselines/reference/throwType_function_return.errors.txt @@ -1,6 +1,6 @@ -tests/cases/compiler/throwType_function_return.ts(5,1): error TS2796: Type instantiated results in a throw type saying: +tests/cases/compiler/throwType_function_return.ts(5,1): error TS2797: Type instantiated results in a throw type saying: Cannot divided by 0 -tests/cases/compiler/throwType_function_return.ts(10,1): error TS2796: Type instantiated results in a throw type saying: +tests/cases/compiler/throwType_function_return.ts(10,1): error TS2797: Type instantiated results in a throw type saying: Wrong @@ -11,14 +11,14 @@ tests/cases/compiler/throwType_function_return.ts(10,1): error TS2796: Type inst } checkedDivide(0) ~~~~~~~~~~~~~~~~ -!!! error TS2796: Type instantiated results in a throw type saying: -!!! error TS2796: Cannot divided by 0 +!!! error TS2797: Type instantiated results in a throw type saying: +!!! error TS2797: Cannot divided by 0 checkedDivide(1) const theAnswerToEverything = (x: T): T extends 42 ? T : throw "Wrong" => x theAnswerToEverything(42 as const) theAnswerToEverything('') ~~~~~~~~~~~~~~~~~~~~~~~~~ -!!! error TS2796: Type instantiated results in a throw type saying: -!!! error TS2796: Wrong +!!! error TS2797: Type instantiated results in a throw type saying: +!!! error TS2797: Wrong \ No newline at end of file diff --git a/tests/baselines/reference/throwType_identifier.errors.txt b/tests/baselines/reference/throwType_identifier.errors.txt index 09ad86aa2e566..43f55ff1494ac 100644 --- a/tests/baselines/reference/throwType_identifier.errors.txt +++ b/tests/baselines/reference/throwType_identifier.errors.txt @@ -1,4 +1,4 @@ -tests/cases/compiler/throwType_identifier.ts(2,13): error TS2796: Type instantiated results in a throw type saying: +tests/cases/compiler/throwType_identifier.ts(2,13): error TS2797: Type instantiated results in a throw type saying: please use window.name @@ -6,6 +6,6 @@ tests/cases/compiler/throwType_identifier.ts(2,13): error TS2796: Type instantia declare const name: throw 'please use window.name' console.log(name, 123, window.name) ~~~~ -!!! error TS2796: Type instantiated results in a throw type saying: -!!! error TS2796: please use window.name +!!! error TS2797: Type instantiated results in a throw type saying: +!!! error TS2797: please use window.name export {} \ No newline at end of file diff --git a/tests/baselines/reference/throwType_property_access.errors.txt b/tests/baselines/reference/throwType_property_access.errors.txt index 95a181ef707d2..16858ebfedc20 100644 --- a/tests/baselines/reference/throwType_property_access.errors.txt +++ b/tests/baselines/reference/throwType_property_access.errors.txt @@ -1,4 +1,4 @@ -tests/cases/compiler/throwType_property_access.ts(4,1): error TS2796: Type instantiated results in a throw type saying: +tests/cases/compiler/throwType_property_access.ts(4,1): error TS2797: Type instantiated results in a throw type saying: @@ -8,5 +8,5 @@ tests/cases/compiler/throwType_property_access.ts(4,1): error TS2796: Type insta } new X<0>().i ~~~~~~~~~~~~ -!!! error TS2796: Type instantiated results in a throw type saying: -!!! error TS2796: \ No newline at end of file +!!! error TS2797: Type instantiated results in a throw type saying: +!!! error TS2797: \ No newline at end of file diff --git a/tests/baselines/reference/throwType_type_reference.errors.txt b/tests/baselines/reference/throwType_type_reference.errors.txt index a4ef5fd15cb2e..9a6846cfccea7 100644 --- a/tests/baselines/reference/throwType_type_reference.errors.txt +++ b/tests/baselines/reference/throwType_type_reference.errors.txt @@ -1,18 +1,15 @@ -tests/cases/compiler/throwType_type_reference.ts(1,82): error TS2793: Template literal type argument 'any' is not literal type or a generic type. tests/cases/compiler/throwType_type_reference.ts(1,89): error TS2693: 'T' only refers to a type, but is being used as a value here. -tests/cases/compiler/throwType_type_reference.ts(3,10): error TS2796: Type instantiated results in a throw type saying: - string +tests/cases/compiler/throwType_type_reference.ts(3,10): error TS2797: Type instantiated results in a throw type saying: + `Expected number, but found "${any}"` -==== tests/cases/compiler/throwType_type_reference.ts (3 errors) ==== +==== tests/cases/compiler/throwType_type_reference.ts (2 errors) ==== type MustNumber = T extends number ? T : throw `Expected number, but found "${typeof T}"` - ~~~~~~~~ -!!! error TS2793: Template literal type argument 'any' is not literal type or a generic type. ~ !!! error TS2693: 'T' only refers to a type, but is being used as a value here. type A = MustNumber<1> type B = MustNumber ~~~~~~~~~~~~~~~~~~~~~~~~~ -!!! error TS2796: Type instantiated results in a throw type saying: -!!! error TS2796: string +!!! error TS2797: Type instantiated results in a throw type saying: +!!! error TS2797: `Expected number, but found "${any}"` \ No newline at end of file From e391bc43efcd8c30a2732b38302481c0cea3729d Mon Sep 17 00:00:00 2001 From: Jack Works Date: Sat, 6 Feb 2021 15:44:26 +0800 Subject: [PATCH 21/27] feat: add intrinsic type --- src/compiler/checker.ts | 21 +++++++++++++-------- src/harness/fourslashInterfaceImpl.ts | 1 + src/lib/es5.d.ts | 5 +++++ 3 files changed, 19 insertions(+), 8 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index f5d2886f2f898..33a9203b8ea68 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -260,14 +260,16 @@ namespace ts { Uppercase, Lowercase, Capitalize, - Uncapitalize + Uncapitalize, + TypeToString } const intrinsicTypeKinds: ReadonlyESMap = new Map(getEntries({ Uppercase: IntrinsicTypeKind.Uppercase, Lowercase: IntrinsicTypeKind.Lowercase, Capitalize: IntrinsicTypeKind.Capitalize, - Uncapitalize: IntrinsicTypeKind.Uncapitalize + Uncapitalize: IntrinsicTypeKind.Uncapitalize, + TypeToString: IntrinsicTypeKind.TypeToString })); function SymbolLinks(this: SymbolLinks) { @@ -13828,18 +13830,21 @@ namespace ts { } function getStringMappingType(symbol: Symbol, type: Type): Type { - return type.flags & (TypeFlags.Union | TypeFlags.Never) ? mapType(type, t => getStringMappingType(symbol, t)) : - isGenericIndexType(type) ? getStringMappingTypeForGenericType(symbol, type) : - type.flags & TypeFlags.StringLiteral ? getLiteralType(applyStringMapping(symbol, (type).value)) : - type; + if (type.flags & (TypeFlags.Union | TypeFlags.Never)) return mapType(type, t => getStringMappingType(symbol, t)); + if (isGenericIndexType(type)) return getStringMappingTypeForGenericType(symbol, type); + const kind = intrinsicTypeKinds.get(symbol.escapedName as string); + if (kind === IntrinsicTypeKind.TypeToString || (type.flags & TypeFlags.StringLiteral)) return getLiteralType(applyStringMapping(kind, (type))); + return type; } - function applyStringMapping(symbol: Symbol, str: string) { - switch (intrinsicTypeKinds.get(symbol.escapedName as string)) { + function applyStringMapping(kind: IntrinsicTypeKind | undefined, type: Type) { + let str = kind === IntrinsicTypeKind.TypeToString ? typeToString(type) : (type).value; + switch (kind) { case IntrinsicTypeKind.Uppercase: return str.toUpperCase(); case IntrinsicTypeKind.Lowercase: return str.toLowerCase(); case IntrinsicTypeKind.Capitalize: return str.charAt(0).toUpperCase() + str.slice(1); case IntrinsicTypeKind.Uncapitalize: return str.charAt(0).toLowerCase() + str.slice(1); + case IntrinsicTypeKind.TypeToString: return str; } return str; } diff --git a/src/harness/fourslashInterfaceImpl.ts b/src/harness/fourslashInterfaceImpl.ts index f946e2d8bc336..44ceccda9df92 100644 --- a/src/harness/fourslashInterfaceImpl.ts +++ b/src/harness/fourslashInterfaceImpl.ts @@ -1069,6 +1069,7 @@ namespace FourSlashInterface { typeEntry("Lowercase"), typeEntry("Capitalize"), typeEntry("Uncapitalize"), + typeEntry("TypeToString"), interfaceEntry("ThisType"), varEntry("ArrayBuffer"), interfaceEntry("ArrayBufferTypes"), diff --git a/src/lib/es5.d.ts b/src/lib/es5.d.ts index 4c3c558916ff1..4e52e1b3aed07 100644 --- a/src/lib/es5.d.ts +++ b/src/lib/es5.d.ts @@ -1528,6 +1528,11 @@ type Capitalize = intrinsic; */ type Uncapitalize = intrinsic; +/** + * Get a string representation of a type + */ +type TypeToString = intrinsic; + /** * Marker for contextual 'this' type */ From 14c00cca4462cbcdf66b0d03003a6b2a338a636f Mon Sep 17 00:00:00 2001 From: Jack Works Date: Sat, 6 Feb 2021 15:50:04 +0800 Subject: [PATCH 22/27] chore: update baseline --- .../throwType_function_parameter.errors.txt | 6 +++--- .../reference/throwType_function_return.errors.txt | 12 ++++++------ .../reference/throwType_identifier.errors.txt | 6 +++--- .../reference/throwType_property_access.errors.txt | 6 +++--- .../reference/throwType_type_reference.errors.txt | 6 +++--- 5 files changed, 18 insertions(+), 18 deletions(-) diff --git a/tests/baselines/reference/throwType_function_parameter.errors.txt b/tests/baselines/reference/throwType_function_parameter.errors.txt index 4eb8ccae25be0..7f7b386053470 100644 --- a/tests/baselines/reference/throwType_function_parameter.errors.txt +++ b/tests/baselines/reference/throwType_function_parameter.errors.txt @@ -1,5 +1,5 @@ tests/cases/compiler/throwType_function_parameter.ts(4,24): error TS2345: Argument of type 'number' is not assignable to parameter of type 'never'. -tests/cases/compiler/throwType_function_parameter.ts(4,24): error TS2797: Type instantiated results in a throw type saying: +tests/cases/compiler/throwType_function_parameter.ts(4,24): error TS2801: Type instantiated results in a throw type saying: No zero tests/cases/compiler/throwType_function_parameter.ts(7,69): error TS2693: 'T' only refers to a type, but is being used as a value here. tests/cases/compiler/throwType_function_parameter.ts(8,70): error TS2693: 'T' only refers to a type, but is being used as a value here. @@ -13,8 +13,8 @@ tests/cases/compiler/throwType_function_parameter.ts(8,70): error TS2693: 'T' on ~~~~ !!! error TS2345: Argument of type 'number' is not assignable to parameter of type 'never'. ~~~~ -!!! error TS2797: Type instantiated results in a throw type saying: -!!! error TS2797: No zero +!!! error TS2801: Type instantiated results in a throw type saying: +!!! error TS2801: No zero checkParameterPosition(12345678) type MustNumber = T extends number ? T : throw `"found "${typeof T}"` diff --git a/tests/baselines/reference/throwType_function_return.errors.txt b/tests/baselines/reference/throwType_function_return.errors.txt index 24c866fc4dc79..c30fe33723a00 100644 --- a/tests/baselines/reference/throwType_function_return.errors.txt +++ b/tests/baselines/reference/throwType_function_return.errors.txt @@ -1,6 +1,6 @@ -tests/cases/compiler/throwType_function_return.ts(5,1): error TS2797: Type instantiated results in a throw type saying: +tests/cases/compiler/throwType_function_return.ts(5,1): error TS2801: Type instantiated results in a throw type saying: Cannot divided by 0 -tests/cases/compiler/throwType_function_return.ts(10,1): error TS2797: Type instantiated results in a throw type saying: +tests/cases/compiler/throwType_function_return.ts(10,1): error TS2801: Type instantiated results in a throw type saying: Wrong @@ -11,14 +11,14 @@ tests/cases/compiler/throwType_function_return.ts(10,1): error TS2797: Type inst } checkedDivide(0) ~~~~~~~~~~~~~~~~ -!!! error TS2797: Type instantiated results in a throw type saying: -!!! error TS2797: Cannot divided by 0 +!!! error TS2801: Type instantiated results in a throw type saying: +!!! error TS2801: Cannot divided by 0 checkedDivide(1) const theAnswerToEverything = (x: T): T extends 42 ? T : throw "Wrong" => x theAnswerToEverything(42 as const) theAnswerToEverything('') ~~~~~~~~~~~~~~~~~~~~~~~~~ -!!! error TS2797: Type instantiated results in a throw type saying: -!!! error TS2797: Wrong +!!! error TS2801: Type instantiated results in a throw type saying: +!!! error TS2801: Wrong \ No newline at end of file diff --git a/tests/baselines/reference/throwType_identifier.errors.txt b/tests/baselines/reference/throwType_identifier.errors.txt index 43f55ff1494ac..3a654582deeff 100644 --- a/tests/baselines/reference/throwType_identifier.errors.txt +++ b/tests/baselines/reference/throwType_identifier.errors.txt @@ -1,4 +1,4 @@ -tests/cases/compiler/throwType_identifier.ts(2,13): error TS2797: Type instantiated results in a throw type saying: +tests/cases/compiler/throwType_identifier.ts(2,13): error TS2801: Type instantiated results in a throw type saying: please use window.name @@ -6,6 +6,6 @@ tests/cases/compiler/throwType_identifier.ts(2,13): error TS2797: Type instantia declare const name: throw 'please use window.name' console.log(name, 123, window.name) ~~~~ -!!! error TS2797: Type instantiated results in a throw type saying: -!!! error TS2797: please use window.name +!!! error TS2801: Type instantiated results in a throw type saying: +!!! error TS2801: please use window.name export {} \ No newline at end of file diff --git a/tests/baselines/reference/throwType_property_access.errors.txt b/tests/baselines/reference/throwType_property_access.errors.txt index 16858ebfedc20..4726233bcc499 100644 --- a/tests/baselines/reference/throwType_property_access.errors.txt +++ b/tests/baselines/reference/throwType_property_access.errors.txt @@ -1,4 +1,4 @@ -tests/cases/compiler/throwType_property_access.ts(4,1): error TS2797: Type instantiated results in a throw type saying: +tests/cases/compiler/throwType_property_access.ts(4,1): error TS2801: Type instantiated results in a throw type saying: @@ -8,5 +8,5 @@ tests/cases/compiler/throwType_property_access.ts(4,1): error TS2797: Type insta } new X<0>().i ~~~~~~~~~~~~ -!!! error TS2797: Type instantiated results in a throw type saying: -!!! error TS2797: \ No newline at end of file +!!! error TS2801: Type instantiated results in a throw type saying: +!!! error TS2801: \ No newline at end of file diff --git a/tests/baselines/reference/throwType_type_reference.errors.txt b/tests/baselines/reference/throwType_type_reference.errors.txt index 9a6846cfccea7..4ca5d709db819 100644 --- a/tests/baselines/reference/throwType_type_reference.errors.txt +++ b/tests/baselines/reference/throwType_type_reference.errors.txt @@ -1,5 +1,5 @@ tests/cases/compiler/throwType_type_reference.ts(1,89): error TS2693: 'T' only refers to a type, but is being used as a value here. -tests/cases/compiler/throwType_type_reference.ts(3,10): error TS2797: Type instantiated results in a throw type saying: +tests/cases/compiler/throwType_type_reference.ts(3,10): error TS2801: Type instantiated results in a throw type saying: `Expected number, but found "${any}"` @@ -10,6 +10,6 @@ tests/cases/compiler/throwType_type_reference.ts(3,10): error TS2797: Type insta type A = MustNumber<1> type B = MustNumber ~~~~~~~~~~~~~~~~~~~~~~~~~ -!!! error TS2797: Type instantiated results in a throw type saying: -!!! error TS2797: `Expected number, but found "${any}"` +!!! error TS2801: Type instantiated results in a throw type saying: +!!! error TS2801: `Expected number, but found "${any}"` \ No newline at end of file From 2303958ae831e63b702f2074ce90048fcda66471 Mon Sep 17 00:00:00 2001 From: Jack Works Date: Sat, 6 Feb 2021 17:50:50 +0800 Subject: [PATCH 23/27] fix: linter --- src/compiler/checker.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 7eab505b9accc..c2b7607c1e002 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -14189,7 +14189,7 @@ namespace ts { } function applyStringMapping(kind: IntrinsicTypeKind | undefined, type: Type) { - let str = kind === IntrinsicTypeKind.TypeToString ? typeToString(type) : (type).value; + const str = kind === IntrinsicTypeKind.TypeToString ? typeToString(type) : (type).value; switch (kind) { case IntrinsicTypeKind.Uppercase: return str.toUpperCase(); case IntrinsicTypeKind.Lowercase: return str.toLowerCase(); From c2ae402de881e9130184466bf976abb5f623371d Mon Sep 17 00:00:00 2001 From: Jack Works Date: Sat, 27 Mar 2021 21:34:05 +0800 Subject: [PATCH 24/27] test: update tests --- .../throwType_function_parameter.errors.txt | 20 +++++++++++-------- .../reference/throwType_function_parameter.js | 7 +++++-- .../throwType_function_parameter.symbols | 17 +++++++++++----- .../throwType_function_parameter.types | 12 +++++++---- .../throwType_type_reference.errors.txt | 15 ++++++-------- .../reference/throwType_type_reference.js | 4 ++-- .../throwType_type_reference.symbols | 9 ++++++--- .../reference/throwType_type_reference.types | 5 ++--- .../compiler/throwType_function_parameter.ts | 6 ++++-- .../compiler/throwType_type_reference.ts | 4 ++-- 10 files changed, 59 insertions(+), 40 deletions(-) diff --git a/tests/baselines/reference/throwType_function_parameter.errors.txt b/tests/baselines/reference/throwType_function_parameter.errors.txt index 93ec16950333b..41c8dee14439f 100644 --- a/tests/baselines/reference/throwType_function_parameter.errors.txt +++ b/tests/baselines/reference/throwType_function_parameter.errors.txt @@ -1,8 +1,9 @@ tests/cases/compiler/throwType_function_parameter.ts(4,24): error TS2345: Argument of type 'number' is not assignable to parameter of type 'never'. tests/cases/compiler/throwType_function_parameter.ts(4,24): error TS2809: Type instantiated results in a throw type saying: No zero -tests/cases/compiler/throwType_function_parameter.ts(7,69): error TS2693: 'T' only refers to a type, but is being used as a value here. -tests/cases/compiler/throwType_function_parameter.ts(8,70): error TS2693: 'T' only refers to a type, but is being used as a value here. +tests/cases/compiler/throwType_function_parameter.ts(13,4): error TS2345: Argument of type 'string' is not assignable to parameter of type 'never'. +tests/cases/compiler/throwType_function_parameter.ts(13,4): error TS2809: Type instantiated results in a throw type saying: + "found ""str"" ==== tests/cases/compiler/throwType_function_parameter.ts (4 errors) ==== @@ -17,13 +18,16 @@ tests/cases/compiler/throwType_function_parameter.ts(8,70): error TS2693: 'T' on !!! error TS2809: No zero checkParameterPosition(12345678) - type MustNumber = T extends number ? T : throw `"found "${typeof T}"` - ~ -!!! error TS2693: 'T' only refers to a type, but is being used as a value here. - type MustNumber2 = T extends number ? T : throw `"found "${typeof T}"` - ~ -!!! error TS2693: 'T' only refers to a type, but is being used as a value here. + type MustNumber = T extends number ? T : throw `"found "${TypeToString}"` + type MustNumber2 = T extends number ? T : throw `"found "${TypeToString}"` function f2(a: MustNumber, b: MustNumber2) { a = b } + + f2('str', {}) + ~~~~~ +!!! error TS2345: Argument of type 'string' is not assignable to parameter of type 'never'. + ~~~~~ +!!! error TS2809: Type instantiated results in a throw type saying: +!!! error TS2809: "found ""str"" \ No newline at end of file diff --git a/tests/baselines/reference/throwType_function_parameter.js b/tests/baselines/reference/throwType_function_parameter.js index eaa23aac21f69..793fd77b0d436 100644 --- a/tests/baselines/reference/throwType_function_parameter.js +++ b/tests/baselines/reference/throwType_function_parameter.js @@ -5,11 +5,13 @@ function checkParameterPosition(y: T extends 1234 ? throw 'No checkParameterPosition(1234) checkParameterPosition(12345678) -type MustNumber = T extends number ? T : throw `"found "${typeof T}"` -type MustNumber2 = T extends number ? T : throw `"found "${typeof T}"` +type MustNumber = T extends number ? T : throw `"found "${TypeToString}"` +type MustNumber2 = T extends number ? T : throw `"found "${TypeToString}"` function f2(a: MustNumber, b: MustNumber2) { a = b } + +f2('str', {}) //// [throwType_function_parameter.js] @@ -21,3 +23,4 @@ checkParameterPosition(12345678); function f2(a, b) { a = b; } +f2('str', {}); diff --git a/tests/baselines/reference/throwType_function_parameter.symbols b/tests/baselines/reference/throwType_function_parameter.symbols index b3ad7c4260cbd..9f1a09f4a6e00 100644 --- a/tests/baselines/reference/throwType_function_parameter.symbols +++ b/tests/baselines/reference/throwType_function_parameter.symbols @@ -17,26 +17,30 @@ checkParameterPosition(1234) checkParameterPosition(12345678) >checkParameterPosition : Symbol(checkParameterPosition, Decl(throwType_function_parameter.ts, 0, 0)) -type MustNumber = T extends number ? T : throw `"found "${typeof T}"` +type MustNumber = T extends number ? T : throw `"found "${TypeToString}"` >MustNumber : Symbol(MustNumber, Decl(throwType_function_parameter.ts, 4, 32)) >T : Symbol(T, Decl(throwType_function_parameter.ts, 6, 16)) >T : Symbol(T, Decl(throwType_function_parameter.ts, 6, 16)) >T : Symbol(T, Decl(throwType_function_parameter.ts, 6, 16)) +>TypeToString : Symbol(TypeToString, Decl(lib.es5.d.ts, --, --)) +>T : Symbol(T, Decl(throwType_function_parameter.ts, 6, 16)) -type MustNumber2 = T extends number ? T : throw `"found "${typeof T}"` ->MustNumber2 : Symbol(MustNumber2, Decl(throwType_function_parameter.ts, 6, 72)) +type MustNumber2 = T extends number ? T : throw `"found "${TypeToString}"` +>MustNumber2 : Symbol(MustNumber2, Decl(throwType_function_parameter.ts, 6, 79)) +>T : Symbol(T, Decl(throwType_function_parameter.ts, 7, 17)) >T : Symbol(T, Decl(throwType_function_parameter.ts, 7, 17)) >T : Symbol(T, Decl(throwType_function_parameter.ts, 7, 17)) +>TypeToString : Symbol(TypeToString, Decl(lib.es5.d.ts, --, --)) >T : Symbol(T, Decl(throwType_function_parameter.ts, 7, 17)) function f2(a: MustNumber, b: MustNumber2) { ->f2 : Symbol(f2, Decl(throwType_function_parameter.ts, 7, 73)) +>f2 : Symbol(f2, Decl(throwType_function_parameter.ts, 7, 80)) >T : Symbol(T, Decl(throwType_function_parameter.ts, 8, 12)) >a : Symbol(a, Decl(throwType_function_parameter.ts, 8, 15)) >MustNumber : Symbol(MustNumber, Decl(throwType_function_parameter.ts, 4, 32)) >T : Symbol(T, Decl(throwType_function_parameter.ts, 8, 12)) >b : Symbol(b, Decl(throwType_function_parameter.ts, 8, 32)) ->MustNumber2 : Symbol(MustNumber2, Decl(throwType_function_parameter.ts, 6, 72)) +>MustNumber2 : Symbol(MustNumber2, Decl(throwType_function_parameter.ts, 6, 79)) >T : Symbol(T, Decl(throwType_function_parameter.ts, 8, 12)) a = b @@ -44,3 +48,6 @@ function f2(a: MustNumber, b: MustNumber2) { >b : Symbol(b, Decl(throwType_function_parameter.ts, 8, 32)) } +f2('str', {}) +>f2 : Symbol(f2, Decl(throwType_function_parameter.ts, 7, 80)) + diff --git a/tests/baselines/reference/throwType_function_parameter.types b/tests/baselines/reference/throwType_function_parameter.types index 7863154bb6440..b96de39fb718c 100644 --- a/tests/baselines/reference/throwType_function_parameter.types +++ b/tests/baselines/reference/throwType_function_parameter.types @@ -19,13 +19,11 @@ checkParameterPosition(12345678) >checkParameterPosition : (y: T extends 1234 ? never : T) => void >12345678 : 12345678 -type MustNumber = T extends number ? T : throw `"found "${typeof T}"` +type MustNumber = T extends number ? T : throw `"found "${TypeToString}"` >MustNumber : MustNumber ->T : any -type MustNumber2 = T extends number ? T : throw `"found "${typeof T}"` +type MustNumber2 = T extends number ? T : throw `"found "${TypeToString}"` >MustNumber2 : MustNumber2 ->T : any function f2(a: MustNumber, b: MustNumber2) { >f2 : (a: MustNumber, b: MustNumber2) => void @@ -38,3 +36,9 @@ function f2(a: MustNumber, b: MustNumber2) { >b : MustNumber2 } +f2('str', {}) +>f2('str', {}) : void +>f2 : (a: MustNumber, b: MustNumber2) => void +>'str' : "str" +>{} : {} + diff --git a/tests/baselines/reference/throwType_type_reference.errors.txt b/tests/baselines/reference/throwType_type_reference.errors.txt index d0ee546e944c2..c321228e17b07 100644 --- a/tests/baselines/reference/throwType_type_reference.errors.txt +++ b/tests/baselines/reference/throwType_type_reference.errors.txt @@ -1,15 +1,12 @@ -tests/cases/compiler/throwType_type_reference.ts(1,89): error TS2693: 'T' only refers to a type, but is being used as a value here. tests/cases/compiler/throwType_type_reference.ts(3,10): error TS2809: Type instantiated results in a throw type saying: - `Expected number, but found "${any}"` + Expected number, but found ""Window & typeof globalThis"" -==== tests/cases/compiler/throwType_type_reference.ts (2 errors) ==== - type MustNumber = T extends number ? T : throw `Expected number, but found "${typeof T}"` - ~ -!!! error TS2693: 'T' only refers to a type, but is being used as a value here. +==== tests/cases/compiler/throwType_type_reference.ts (1 errors) ==== + type MustNumber = T extends number ? T : throw `Expected number, but found "${TypeToString}"` type A = MustNumber<1> - type B = MustNumber - ~~~~~~~~~~~~~~~~~~~~~~~~~ + type B = MustNumber> + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ !!! error TS2809: Type instantiated results in a throw type saying: -!!! error TS2809: `Expected number, but found "${any}"` +!!! error TS2809: Expected number, but found ""Window & typeof globalThis"" \ No newline at end of file diff --git a/tests/baselines/reference/throwType_type_reference.js b/tests/baselines/reference/throwType_type_reference.js index fc68ab87dc17e..f243935286360 100644 --- a/tests/baselines/reference/throwType_type_reference.js +++ b/tests/baselines/reference/throwType_type_reference.js @@ -1,7 +1,7 @@ //// [throwType_type_reference.ts] -type MustNumber = T extends number ? T : throw `Expected number, but found "${typeof T}"` +type MustNumber = T extends number ? T : throw `Expected number, but found "${TypeToString}"` type A = MustNumber<1> -type B = MustNumber +type B = MustNumber> //// [throwType_type_reference.js] diff --git a/tests/baselines/reference/throwType_type_reference.symbols b/tests/baselines/reference/throwType_type_reference.symbols index 211691acbb66d..b425d843ec655 100644 --- a/tests/baselines/reference/throwType_type_reference.symbols +++ b/tests/baselines/reference/throwType_type_reference.symbols @@ -1,16 +1,19 @@ === tests/cases/compiler/throwType_type_reference.ts === -type MustNumber = T extends number ? T : throw `Expected number, but found "${typeof T}"` +type MustNumber = T extends number ? T : throw `Expected number, but found "${TypeToString}"` >MustNumber : Symbol(MustNumber, Decl(throwType_type_reference.ts, 0, 0)) >T : Symbol(T, Decl(throwType_type_reference.ts, 0, 16)) >T : Symbol(T, Decl(throwType_type_reference.ts, 0, 16)) >T : Symbol(T, Decl(throwType_type_reference.ts, 0, 16)) +>TypeToString : Symbol(TypeToString, Decl(lib.es5.d.ts, --, --)) +>T : Symbol(T, Decl(throwType_type_reference.ts, 0, 16)) type A = MustNumber<1> ->A : Symbol(A, Decl(throwType_type_reference.ts, 0, 92)) +>A : Symbol(A, Decl(throwType_type_reference.ts, 0, 99)) >MustNumber : Symbol(MustNumber, Decl(throwType_type_reference.ts, 0, 0)) -type B = MustNumber +type B = MustNumber> >B : Symbol(B, Decl(throwType_type_reference.ts, 1, 22)) >MustNumber : Symbol(MustNumber, Decl(throwType_type_reference.ts, 0, 0)) +>TypeToString : Symbol(TypeToString, Decl(lib.es5.d.ts, --, --)) >window : Symbol(window, Decl(lib.dom.d.ts, --, --)) diff --git a/tests/baselines/reference/throwType_type_reference.types b/tests/baselines/reference/throwType_type_reference.types index 666fb3522a851..debf6043ab71e 100644 --- a/tests/baselines/reference/throwType_type_reference.types +++ b/tests/baselines/reference/throwType_type_reference.types @@ -1,12 +1,11 @@ === tests/cases/compiler/throwType_type_reference.ts === -type MustNumber = T extends number ? T : throw `Expected number, but found "${typeof T}"` +type MustNumber = T extends number ? T : throw `Expected number, but found "${TypeToString}"` >MustNumber : MustNumber ->T : any type A = MustNumber<1> >A : 1 -type B = MustNumber +type B = MustNumber> >B : never >window : Window & typeof globalThis diff --git a/tests/cases/compiler/throwType_function_parameter.ts b/tests/cases/compiler/throwType_function_parameter.ts index acc46862c1350..37f99475bcadd 100644 --- a/tests/cases/compiler/throwType_function_parameter.ts +++ b/tests/cases/compiler/throwType_function_parameter.ts @@ -4,8 +4,10 @@ function checkParameterPosition(y: T extends 1234 ? throw 'No checkParameterPosition(1234) checkParameterPosition(12345678) -type MustNumber = T extends number ? T : throw `"found "${typeof T}"` -type MustNumber2 = T extends number ? T : throw `"found "${typeof T}"` +type MustNumber = T extends number ? T : throw `"found "${TypeToString}"` +type MustNumber2 = T extends number ? T : throw `"found "${TypeToString}"` function f2(a: MustNumber, b: MustNumber2) { a = b } + +f2('str', {}) diff --git a/tests/cases/compiler/throwType_type_reference.ts b/tests/cases/compiler/throwType_type_reference.ts index 6f718e1d8de27..46444690da3df 100644 --- a/tests/cases/compiler/throwType_type_reference.ts +++ b/tests/cases/compiler/throwType_type_reference.ts @@ -1,3 +1,3 @@ -type MustNumber = T extends number ? T : throw `Expected number, but found "${typeof T}"` +type MustNumber = T extends number ? T : throw `Expected number, but found "${TypeToString}"` type A = MustNumber<1> -type B = MustNumber +type B = MustNumber> From e7684dcf141799807ae5a3c8debbee618478a908 Mon Sep 17 00:00:00 2001 From: Jack Works Date: Mon, 14 Feb 2022 13:39:36 +0800 Subject: [PATCH 25/27] fix: test failed --- src/compiler/checker.ts | 13 ++++++------- .../throwType_function_parameter.errors.txt | 12 ++++++------ .../reference/throwType_function_return.errors.txt | 12 ++++++------ .../reference/throwType_function_return.symbols | 1 + .../reference/throwType_identifier.errors.txt | 6 +++--- .../reference/throwType_property_access.errors.txt | 6 +++--- .../reference/throwType_type_reference.errors.txt | 6 +++--- 7 files changed, 28 insertions(+), 28 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 8b4535e4c1a0e..a9af648c6c309 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -18446,10 +18446,6 @@ namespace ts { * * Ternary.False if they are not related. */ function isRelatedTo(originalSource: Type, originalTarget: Type, recursionFlags: RecursionFlags = RecursionFlags.Both, reportErrors = false, headMessage?: DiagnosticMessage, intersectionState = IntersectionState.None): Ternary { - // throw types are considered related with any type, they'll be reported as type error in the use site. - if ((originalSource.flags | originalTarget.flags) & TypeFlags.ThrowType) { - return Ternary.True; - } // Before normalization: if `source` is type an object type, and `target` is primitive, // skip all the checks we don't need and just return `isSimpleTypeRelatedTo` result if (originalSource.flags & TypeFlags.Object && originalTarget.flags & TypeFlags.Primitive) { @@ -19493,8 +19489,12 @@ namespace ts { } if (isTypeIdenticalTo(sourceExtends, (target as ConditionalType).extendsType) && (isRelatedTo((source as ConditionalType).checkType, (target as ConditionalType).checkType, RecursionFlags.Both) || isRelatedTo((target as ConditionalType).checkType, (source as ConditionalType).checkType, RecursionFlags.Both))) { - if (result = isRelatedTo(instantiateType(getTrueTypeFromConditionalType(source as ConditionalType), mapper), getTrueTypeFromConditionalType(target as ConditionalType), RecursionFlags.Both, reportErrors)) { - result &= isRelatedTo(getFalseTypeFromConditionalType(source as ConditionalType), getFalseTypeFromConditionalType(target as ConditionalType), RecursionFlags.Both, reportErrors); + const lTrueType = dropThrowTypeInConditionalType(instantiateType(getTrueTypeFromConditionalType(source as ConditionalType), mapper)); + const rTrueType = dropThrowTypeInConditionalType(getTrueTypeFromConditionalType(target as ConditionalType)); + if (result = (lTrueType.flags | rTrueType.flags) & TypeFlags.ThrowType ? Ternary.True : isRelatedTo(lTrueType, rTrueType, RecursionFlags.Both, reportErrors)) { + const lFalseType = dropThrowTypeInConditionalType(getFalseTypeFromConditionalType(source as ConditionalType)); + const rFalseType = dropThrowTypeInConditionalType(getFalseTypeFromConditionalType(target as ConditionalType)); + result &= (lFalseType.flags | rFalseType.flags) & TypeFlags.ThrowType ? Ternary.True : isRelatedTo(lFalseType, rFalseType, RecursionFlags.Both, reportErrors); } if (result) { resetErrorInfo(saveErrorInfo); @@ -29836,7 +29836,6 @@ namespace ts { reportErrors: boolean, containingMessageChain: (() => DiagnosticMessageChain | undefined) | undefined, ): readonly Diagnostic[] | undefined { - const errorOutputContainer: { errors?: Diagnostic[], skipLogging?: boolean } = { errors: undefined, skipLogging: true }; if (isJsxOpeningLikeElement(node)) { if (!checkApplicableSignatureForJsxOpeningLikeElement(node, signature, relation, checkMode, reportErrors, containingMessageChain, errorOutputContainer)) { diff --git a/tests/baselines/reference/throwType_function_parameter.errors.txt b/tests/baselines/reference/throwType_function_parameter.errors.txt index f9727b7f7630d..8ca707fde7a59 100644 --- a/tests/baselines/reference/throwType_function_parameter.errors.txt +++ b/tests/baselines/reference/throwType_function_parameter.errors.txt @@ -1,8 +1,8 @@ tests/cases/compiler/throwType_function_parameter.ts(4,24): error TS2345: Argument of type 'number' is not assignable to parameter of type 'never'. -tests/cases/compiler/throwType_function_parameter.ts(4,24): error TS2820: Type instantiated results in a throw type saying: +tests/cases/compiler/throwType_function_parameter.ts(4,24): error TS2838: Type instantiated results in a throw type saying: No zero tests/cases/compiler/throwType_function_parameter.ts(13,4): error TS2345: Argument of type 'string' is not assignable to parameter of type 'never'. -tests/cases/compiler/throwType_function_parameter.ts(13,4): error TS2820: Type instantiated results in a throw type saying: +tests/cases/compiler/throwType_function_parameter.ts(13,4): error TS2838: Type instantiated results in a throw type saying: "found ""str"" @@ -14,8 +14,8 @@ tests/cases/compiler/throwType_function_parameter.ts(13,4): error TS2820: Type i ~~~~ !!! error TS2345: Argument of type 'number' is not assignable to parameter of type 'never'. ~~~~ -!!! error TS2820: Type instantiated results in a throw type saying: -!!! error TS2820: No zero +!!! error TS2838: Type instantiated results in a throw type saying: +!!! error TS2838: No zero checkParameterPosition(12345678) type MustNumber = T extends number ? T : throw `"found "${TypeToString}"` @@ -28,6 +28,6 @@ tests/cases/compiler/throwType_function_parameter.ts(13,4): error TS2820: Type i ~~~~~ !!! error TS2345: Argument of type 'string' is not assignable to parameter of type 'never'. ~~~~~ -!!! error TS2820: Type instantiated results in a throw type saying: -!!! error TS2820: "found ""str"" +!!! error TS2838: Type instantiated results in a throw type saying: +!!! error TS2838: "found ""str"" \ No newline at end of file diff --git a/tests/baselines/reference/throwType_function_return.errors.txt b/tests/baselines/reference/throwType_function_return.errors.txt index 5d209ed580315..3f28dea4dd86b 100644 --- a/tests/baselines/reference/throwType_function_return.errors.txt +++ b/tests/baselines/reference/throwType_function_return.errors.txt @@ -1,6 +1,6 @@ -tests/cases/compiler/throwType_function_return.ts(5,1): error TS2820: Type instantiated results in a throw type saying: +tests/cases/compiler/throwType_function_return.ts(5,1): error TS2838: Type instantiated results in a throw type saying: Cannot divided by 0 -tests/cases/compiler/throwType_function_return.ts(10,1): error TS2820: Type instantiated results in a throw type saying: +tests/cases/compiler/throwType_function_return.ts(10,1): error TS2838: Type instantiated results in a throw type saying: Wrong @@ -11,14 +11,14 @@ tests/cases/compiler/throwType_function_return.ts(10,1): error TS2820: Type inst } checkedDivide(0) ~~~~~~~~~~~~~~~~ -!!! error TS2820: Type instantiated results in a throw type saying: -!!! error TS2820: Cannot divided by 0 +!!! error TS2838: Type instantiated results in a throw type saying: +!!! error TS2838: Cannot divided by 0 checkedDivide(1) const theAnswerToEverything = (x: T): T extends 42 ? T : throw "Wrong" => x theAnswerToEverything(42 as const) theAnswerToEverything('') ~~~~~~~~~~~~~~~~~~~~~~~~~ -!!! error TS2820: Type instantiated results in a throw type saying: -!!! error TS2820: Wrong +!!! error TS2838: Type instantiated results in a throw type saying: +!!! error TS2838: Wrong \ No newline at end of file diff --git a/tests/baselines/reference/throwType_function_return.symbols b/tests/baselines/reference/throwType_function_return.symbols index 1d57b4d6d2f11..617afab04c6e7 100644 --- a/tests/baselines/reference/throwType_function_return.symbols +++ b/tests/baselines/reference/throwType_function_return.symbols @@ -30,6 +30,7 @@ const theAnswerToEverything = (x: T): T extends 42 ? T : throw "Wrong" => x theAnswerToEverything(42 as const) >theAnswerToEverything : Symbol(theAnswerToEverything, Decl(throwType_function_return.ts, 7, 5)) +>const : Symbol(const) theAnswerToEverything('') >theAnswerToEverything : Symbol(theAnswerToEverything, Decl(throwType_function_return.ts, 7, 5)) diff --git a/tests/baselines/reference/throwType_identifier.errors.txt b/tests/baselines/reference/throwType_identifier.errors.txt index 1c2b2842a77dd..fc347a201b04b 100644 --- a/tests/baselines/reference/throwType_identifier.errors.txt +++ b/tests/baselines/reference/throwType_identifier.errors.txt @@ -1,4 +1,4 @@ -tests/cases/compiler/throwType_identifier.ts(2,13): error TS2820: Type instantiated results in a throw type saying: +tests/cases/compiler/throwType_identifier.ts(2,13): error TS2838: Type instantiated results in a throw type saying: please use window.name @@ -6,6 +6,6 @@ tests/cases/compiler/throwType_identifier.ts(2,13): error TS2820: Type instantia declare const name: throw 'please use window.name' console.log(name, 123, window.name) ~~~~ -!!! error TS2820: Type instantiated results in a throw type saying: -!!! error TS2820: please use window.name +!!! error TS2838: Type instantiated results in a throw type saying: +!!! error TS2838: please use window.name export {} \ No newline at end of file diff --git a/tests/baselines/reference/throwType_property_access.errors.txt b/tests/baselines/reference/throwType_property_access.errors.txt index 3f02a9b8b1b74..6855abd18b535 100644 --- a/tests/baselines/reference/throwType_property_access.errors.txt +++ b/tests/baselines/reference/throwType_property_access.errors.txt @@ -1,4 +1,4 @@ -tests/cases/compiler/throwType_property_access.ts(4,1): error TS2820: Type instantiated results in a throw type saying: +tests/cases/compiler/throwType_property_access.ts(4,1): error TS2838: Type instantiated results in a throw type saying: @@ -8,5 +8,5 @@ tests/cases/compiler/throwType_property_access.ts(4,1): error TS2820: Type insta } new X<0>().i ~~~~~~~~~~~~ -!!! error TS2820: Type instantiated results in a throw type saying: -!!! error TS2820: \ No newline at end of file +!!! error TS2838: Type instantiated results in a throw type saying: +!!! error TS2838: \ No newline at end of file diff --git a/tests/baselines/reference/throwType_type_reference.errors.txt b/tests/baselines/reference/throwType_type_reference.errors.txt index ba1ff9c99b5d2..6038e7db5059e 100644 --- a/tests/baselines/reference/throwType_type_reference.errors.txt +++ b/tests/baselines/reference/throwType_type_reference.errors.txt @@ -1,4 +1,4 @@ -tests/cases/compiler/throwType_type_reference.ts(3,10): error TS2820: Type instantiated results in a throw type saying: +tests/cases/compiler/throwType_type_reference.ts(3,10): error TS2838: Type instantiated results in a throw type saying: Expected number, but found ""Window & typeof globalThis"" @@ -7,6 +7,6 @@ tests/cases/compiler/throwType_type_reference.ts(3,10): error TS2820: Type insta type A = MustNumber<1> type B = MustNumber> ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -!!! error TS2820: Type instantiated results in a throw type saying: -!!! error TS2820: Expected number, but found ""Window & typeof globalThis"" +!!! error TS2838: Type instantiated results in a throw type saying: +!!! error TS2838: Expected number, but found ""Window & typeof globalThis"" \ No newline at end of file From ea2c58dde2d7e56c84a1a988924f3c931ffcde1c Mon Sep 17 00:00:00 2001 From: Jack Works Date: Sun, 25 Sep 2022 18:06:30 +0800 Subject: [PATCH 26/27] fix: lint --- src/compiler/checker.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 25106b321bc43..9191570366378 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -1299,8 +1299,7 @@ namespace ts { addErrorOrSuggestion(isError, "message" in message ? createDiagnosticForNode(location, message, arg0, arg1, arg2, arg3) : createDiagnosticForNodeFromMessageChain(location, message)); // eslint-disable-line local/no-in-operator } function appendDiagnosticWithCategory(category: DiagnosticCategory | undefined, location: Node, message: DiagnosticMessage | DiagnosticMessageChain, arg0?: string | number, arg1?: string | number, arg2?: string | number, arg3?: string | number): void { - // eslint-disable-line local/no-in-operator - const diag = "message" in message ? createDiagnosticForNode(location, message, arg0, arg1, arg2, arg3) : createDiagnosticForNodeFromMessageChain(location, message); + const diag = "message" in message ? createDiagnosticForNode(location, message, arg0, arg1, arg2, arg3) : createDiagnosticForNodeFromMessageChain(location, message); // eslint-disable-line local/no-in-operator diag.category = category ?? diag.category; switch (category) { case DiagnosticCategory.Error: From a995c42d3f999025e53bea0c653635732886a9b7 Mon Sep 17 00:00:00 2001 From: Jack Works Date: Mon, 26 Sep 2022 10:56:14 +0800 Subject: [PATCH 27/27] fix: test failed --- src/compiler/checker.ts | 20 +++++++++++++------ .../throwType_function_parameter.errors.txt | 4 ++-- .../throwType_type_reference.errors.txt | 4 ++-- 3 files changed, 18 insertions(+), 10 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 9191570366378..c170e2f7a6430 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -258,7 +258,7 @@ namespace ts { } const enum IntrinsicTypeKind { - Uppercase, + Uppercase = 1, Lowercase, Capitalize, Uncapitalize, @@ -15745,7 +15745,7 @@ namespace ts { return getStringMappingTypeForGenericType(symbol, isPatternLiteralPlaceholderType(type) && !(type.flags & TypeFlags.StringMapping) ? getTemplateLiteralType(["", ""], [type]) : type); } else if (type.flags & TypeFlags.StringLiteral) { - return getStringLiteralType(applyStringMapping(/** intrinsicKind */ undefined, type)); + return getStringLiteralType(applyStringMapping(symbol, type)); } else if (type.flags & TypeFlags.TemplateLiteral) { return getTemplateLiteralType(...applyTemplateStringMapping(symbol, (type as TemplateLiteralType).texts, (type as TemplateLiteralType).types)); @@ -15759,16 +15759,24 @@ namespace ts { } } - function applyStringMapping(kind: IntrinsicTypeKind | undefined, type: Type) { - const str = kind === IntrinsicTypeKind.TypeToString ? typeToString(type) : (type as StringLiteralType).value; + function applyStringMapping(kind: IntrinsicTypeKind | Symbol | undefined, type: Type) { + if (typeof kind === "object") kind = intrinsicTypeKinds.get(kind.escapedName as string); + let str = ""; + if (kind === IntrinsicTypeKind.TypeToString) { + str = typeToString(type); + } + else if (type.flags & TypeFlags.StringLiteral) { + str = (type as StringLiteralType).value; + } + if (!kind) return str; switch (kind) { case IntrinsicTypeKind.Uppercase: return str.toUpperCase(); case IntrinsicTypeKind.Lowercase: return str.toLowerCase(); case IntrinsicTypeKind.Capitalize: return str.charAt(0).toUpperCase() + str.slice(1); case IntrinsicTypeKind.Uncapitalize: return str.charAt(0).toLowerCase() + str.slice(1); case IntrinsicTypeKind.TypeToString: return str; + default: Debug.assertNever(kind); } - return str; } function applyTemplateStringMapping(symbol: Symbol, texts: readonly string[], types: readonly Type[]): [texts: readonly string[], types: readonly Type[]] { @@ -23282,7 +23290,7 @@ namespace ts { !(right.flags & allTypeFlags) ? left : left.flags & TypeFlags.String ? left : right.flags & TypeFlags.String ? source : left.flags & TypeFlags.TemplateLiteral ? left : right.flags & TypeFlags.TemplateLiteral && isTypeMatchedByTemplateLiteralType(source, right as TemplateLiteralType) ? source : - left.flags & TypeFlags.StringMapping ? left : right.flags & TypeFlags.StringMapping && str === applyStringMapping(intrinsicTypeKinds.get(right.symbol.escapedName as string), source) ? source : + left.flags & TypeFlags.StringMapping ? left : right.flags & TypeFlags.StringMapping && str === applyStringMapping(right.symbol, source) ? source : left.flags & TypeFlags.StringLiteral ? left : right.flags & TypeFlags.StringLiteral && (right as StringLiteralType).value === str ? right : left.flags & TypeFlags.Number ? left : right.flags & TypeFlags.Number ? getNumberLiteralType(+str) : left.flags & TypeFlags.Enum ? left : right.flags & TypeFlags.Enum ? getNumberLiteralType(+str) : diff --git a/tests/baselines/reference/throwType_function_parameter.errors.txt b/tests/baselines/reference/throwType_function_parameter.errors.txt index 1856bdc9c77ad..b8e3e85936906 100644 --- a/tests/baselines/reference/throwType_function_parameter.errors.txt +++ b/tests/baselines/reference/throwType_function_parameter.errors.txt @@ -3,7 +3,7 @@ tests/cases/compiler/throwType_function_parameter.ts(4,24): error TS2899: Type i No zero tests/cases/compiler/throwType_function_parameter.ts(13,4): error TS2345: Argument of type 'string' is not assignable to parameter of type 'never'. tests/cases/compiler/throwType_function_parameter.ts(13,4): error TS2899: Type instantiated results in a throw type saying: - "found "str" + "found ""str"" ==== tests/cases/compiler/throwType_function_parameter.ts (4 errors) ==== @@ -29,5 +29,5 @@ tests/cases/compiler/throwType_function_parameter.ts(13,4): error TS2899: Type i !!! error TS2345: Argument of type 'string' is not assignable to parameter of type 'never'. ~~~~~ !!! error TS2899: Type instantiated results in a throw type saying: -!!! error TS2899: "found "str" +!!! error TS2899: "found ""str"" \ No newline at end of file diff --git a/tests/baselines/reference/throwType_type_reference.errors.txt b/tests/baselines/reference/throwType_type_reference.errors.txt index 56f9d16b83302..1211126badf5c 100644 --- a/tests/baselines/reference/throwType_type_reference.errors.txt +++ b/tests/baselines/reference/throwType_type_reference.errors.txt @@ -1,5 +1,5 @@ tests/cases/compiler/throwType_type_reference.ts(3,10): error TS2899: Type instantiated results in a throw type saying: - Expected number, but found "Window & typeof globalThis" + Expected number, but found ""Window & typeof globalThis"" ==== tests/cases/compiler/throwType_type_reference.ts (1 errors) ==== @@ -8,5 +8,5 @@ tests/cases/compiler/throwType_type_reference.ts(3,10): error TS2899: Type insta type B = MustNumber> ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ !!! error TS2899: Type instantiated results in a throw type saying: -!!! error TS2899: Expected number, but found "Window & typeof globalThis" +!!! error TS2899: Expected number, but found ""Window & typeof globalThis"" \ No newline at end of file