From 1175676a747355df74c685fd754a2032e777a748 Mon Sep 17 00:00:00 2001 From: Gabriela Araujo Britto Date: Fri, 12 May 2023 13:02:58 -0700 Subject: [PATCH 1/7] Cache expression type --- src/compiler/checker.ts | 9 +++++---- src/compiler/types.ts | 1 + 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 086bbb4b8cb4d..ea9abc5237787 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -34516,13 +34516,14 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { function checkAssertionWorker(node: JSDocTypeAssertion | AssertionExpression, checkMode: CheckMode | undefined) { const { type, expression } = getAssertionTypeAndExpression(node); - const exprType = checkExpression(expression, checkMode); if (isConstTypeReference(type)) { if (!isValidConstAssertionArgument(expression)) { error(expression, Diagnostics.A_const_assertions_can_only_be_applied_to_references_to_enum_members_or_string_number_boolean_array_or_object_literals); } - return getRegularTypeOfLiteralType(exprType); + return getRegularTypeOfLiteralType(checkExpression(expression, checkMode)); } + const links = getNodeLinks(node); + links.assertionExpressionType = checkExpression(expression, checkMode); checkSourceElement(type); checkNodeDeferred(node); return getTypeFromTypeNode(type); @@ -34547,9 +34548,9 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } function checkAssertionDeferred(node: JSDocTypeAssertion | AssertionExpression) { - const { type, expression } = getAssertionTypeAndExpression(node); + const { type } = getAssertionTypeAndExpression(node); const errNode = isParenthesizedExpression(node) ? type : node; - const exprType = getRegularTypeOfObjectLiteral(getBaseTypeOfLiteralType(checkExpression(expression))); + const exprType = getRegularTypeOfObjectLiteral(getBaseTypeOfLiteralType(getNodeLinks(node).assertionExpressionType!)); const targetType = getTypeFromTypeNode(type); if (!isErrorType(targetType)) { addLazyDiagnostic(() => { diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 097efb5cc3eed..b30bd455d5c3f 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -6060,6 +6060,7 @@ export interface NodeLinks { spreadIndices?: { first: number | undefined, last: number | undefined }; // Indices of first and last spread elements in array literal parameterInitializerContainsUndefined?: boolean; // True if this is a parameter declaration whose type annotation contains "undefined". fakeScopeForSignatureDeclaration?: boolean; // True if this is a fake scope injected into an enclosing declaration chain. + assertionExpressionType?: Type; // Cached type of the expression of a type assertion } /** @internal */ From c7905793344a75ebafb6c7ee6e74deda9b3bcc64 Mon Sep 17 00:00:00 2001 From: Gabriela Araujo Britto Date: Fri, 12 May 2023 14:54:24 -0700 Subject: [PATCH 2/7] use assertIsDefined --- src/compiler/checker.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index ea9abc5237787..f32e6c4a4b1d2 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -34550,7 +34550,9 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { function checkAssertionDeferred(node: JSDocTypeAssertion | AssertionExpression) { const { type } = getAssertionTypeAndExpression(node); const errNode = isParenthesizedExpression(node) ? type : node; - const exprType = getRegularTypeOfObjectLiteral(getBaseTypeOfLiteralType(getNodeLinks(node).assertionExpressionType!)); + const links = getNodeLinks(node); + Debug.assertIsDefined(links.assertionExpressionType); + const exprType = getRegularTypeOfObjectLiteral(getBaseTypeOfLiteralType(links.assertionExpressionType)); const targetType = getTypeFromTypeNode(type); if (!isErrorType(targetType)) { addLazyDiagnostic(() => { From 372a1ab310204370b2f3c520f466a7daf5a1cfac Mon Sep 17 00:00:00 2001 From: Gabriela Araujo Britto Date: Fri, 12 May 2023 15:48:30 -0700 Subject: [PATCH 3/7] inline helper --- src/compiler/checker.ts | 32 ++++++++++++++------------------ 1 file changed, 14 insertions(+), 18 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index f32e6c4a4b1d2..820a02226c0c0 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -34515,21 +34515,6 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } function checkAssertionWorker(node: JSDocTypeAssertion | AssertionExpression, checkMode: CheckMode | undefined) { - const { type, expression } = getAssertionTypeAndExpression(node); - if (isConstTypeReference(type)) { - if (!isValidConstAssertionArgument(expression)) { - error(expression, Diagnostics.A_const_assertions_can_only_be_applied_to_references_to_enum_members_or_string_number_boolean_array_or_object_literals); - } - return getRegularTypeOfLiteralType(checkExpression(expression, checkMode)); - } - const links = getNodeLinks(node); - links.assertionExpressionType = checkExpression(expression, checkMode); - checkSourceElement(type); - checkNodeDeferred(node); - return getTypeFromTypeNode(type); - } - - function getAssertionTypeAndExpression(node: JSDocTypeAssertion | AssertionExpression) { let type: TypeNode; let expression: Expression; switch (node.kind) { @@ -34543,12 +34528,23 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { expression = node.expression; break; } - - return { type, expression }; + if (isConstTypeReference(type)) { + if (!isValidConstAssertionArgument(expression)) { + error(expression, Diagnostics.A_const_assertions_can_only_be_applied_to_references_to_enum_members_or_string_number_boolean_array_or_object_literals); + } + return getRegularTypeOfLiteralType(checkExpression(expression, checkMode)); + } + const links = getNodeLinks(node); + links.assertionExpressionType = checkExpression(expression, checkMode); + checkSourceElement(type); + checkNodeDeferred(node); + return getTypeFromTypeNode(type); } function checkAssertionDeferred(node: JSDocTypeAssertion | AssertionExpression) { - const { type } = getAssertionTypeAndExpression(node); + const type = node.kind === SyntaxKind.ParenthesizedExpression + ? getJSDocTypeAssertionType(node) + : node.type; const errNode = isParenthesizedExpression(node) ? type : node; const links = getNodeLinks(node); Debug.assertIsDefined(links.assertionExpressionType); From bb148384d1f438c107cc30e7e7befa71a0043230 Mon Sep 17 00:00:00 2001 From: Gabriela Araujo Britto Date: Fri, 12 May 2023 15:50:04 -0700 Subject: [PATCH 4/7] style change --- src/compiler/checker.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 820a02226c0c0..fe8ee0d215cc3 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -34528,14 +34528,15 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { expression = node.expression; break; } + const exprType = checkExpression(expression, checkMode); if (isConstTypeReference(type)) { if (!isValidConstAssertionArgument(expression)) { error(expression, Diagnostics.A_const_assertions_can_only_be_applied_to_references_to_enum_members_or_string_number_boolean_array_or_object_literals); } - return getRegularTypeOfLiteralType(checkExpression(expression, checkMode)); + return getRegularTypeOfLiteralType(exprType); } const links = getNodeLinks(node); - links.assertionExpressionType = checkExpression(expression, checkMode); + links.assertionExpressionType = exprType; checkSourceElement(type); checkNodeDeferred(node); return getTypeFromTypeNode(type); From 5b536d50886e45f5ac2da98b4346cc51e86562b2 Mon Sep 17 00:00:00 2001 From: Gabriela Araujo Britto Date: Fri, 12 May 2023 16:28:06 -0700 Subject: [PATCH 5/7] avoid assertion check when possible --- src/compiler/checker.ts | 38 ++++++++++++++++++++------------------ 1 file changed, 20 insertions(+), 18 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index fe8ee0d215cc3..8f6756e8c9c09 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -34515,31 +34515,35 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } function checkAssertionWorker(node: JSDocTypeAssertion | AssertionExpression, checkMode: CheckMode | undefined) { - let type: TypeNode; + let typeNode: TypeNode; let expression: Expression; switch (node.kind) { case SyntaxKind.AsExpression: case SyntaxKind.TypeAssertionExpression: - type = node.type; + typeNode = node.type; expression = node.expression; break; case SyntaxKind.ParenthesizedExpression: - type = getJSDocTypeAssertionType(node); + typeNode = getJSDocTypeAssertionType(node); expression = node.expression; break; } const exprType = checkExpression(expression, checkMode); - if (isConstTypeReference(type)) { + if (isConstTypeReference(typeNode)) { if (!isValidConstAssertionArgument(expression)) { error(expression, Diagnostics.A_const_assertions_can_only_be_applied_to_references_to_enum_members_or_string_number_boolean_array_or_object_literals); } return getRegularTypeOfLiteralType(exprType); } - const links = getNodeLinks(node); - links.assertionExpressionType = exprType; - checkSourceElement(type); - checkNodeDeferred(node); - return getTypeFromTypeNode(type); + checkSourceElement(typeNode); + const type = getTypeFromTypeNode(typeNode); + // See if we need to check whether the expression and asserted types are comparable. + if (!isErrorType(type) && !((exprType.flags | type.flags) & (TypeFlags.AnyOrUnknown | TypeFlags.Never))) { + const links = getNodeLinks(node); + links.assertionExpressionType = exprType; + checkNodeDeferred(node); + } + return type; } function checkAssertionDeferred(node: JSDocTypeAssertion | AssertionExpression) { @@ -34551,15 +34555,13 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { Debug.assertIsDefined(links.assertionExpressionType); const exprType = getRegularTypeOfObjectLiteral(getBaseTypeOfLiteralType(links.assertionExpressionType)); const targetType = getTypeFromTypeNode(type); - if (!isErrorType(targetType)) { - addLazyDiagnostic(() => { - const widenedType = getWidenedType(exprType); - if (!isTypeComparableTo(targetType, widenedType)) { - checkTypeComparableTo(exprType, targetType, errNode, - Diagnostics.Conversion_of_type_0_to_type_1_may_be_a_mistake_because_neither_type_sufficiently_overlaps_with_the_other_If_this_was_intentional_convert_the_expression_to_unknown_first); - } - }); - } + addLazyDiagnostic(() => { + const widenedType = getWidenedType(exprType); + if (!isTypeComparableTo(targetType, widenedType)) { + checkTypeComparableTo(exprType, targetType, errNode, + Diagnostics.Conversion_of_type_0_to_type_1_may_be_a_mistake_because_neither_type_sufficiently_overlaps_with_the_other_If_this_was_intentional_convert_the_expression_to_unknown_first); + } + }); } function checkNonNullChain(node: NonNullChain) { From 460c36bac20dd8d47edf127658237051dbcf2590 Mon Sep 17 00:00:00 2001 From: Gabriela Araujo Britto Date: Fri, 12 May 2023 16:53:58 -0700 Subject: [PATCH 6/7] Revert "avoid assertion check when possible" This reverts commit 5b536d50886e45f5ac2da98b4346cc51e86562b2. --- src/compiler/checker.ts | 38 ++++++++++++++++++-------------------- 1 file changed, 18 insertions(+), 20 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 8f6756e8c9c09..fe8ee0d215cc3 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -34515,35 +34515,31 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } function checkAssertionWorker(node: JSDocTypeAssertion | AssertionExpression, checkMode: CheckMode | undefined) { - let typeNode: TypeNode; + let type: TypeNode; let expression: Expression; switch (node.kind) { case SyntaxKind.AsExpression: case SyntaxKind.TypeAssertionExpression: - typeNode = node.type; + type = node.type; expression = node.expression; break; case SyntaxKind.ParenthesizedExpression: - typeNode = getJSDocTypeAssertionType(node); + type = getJSDocTypeAssertionType(node); expression = node.expression; break; } const exprType = checkExpression(expression, checkMode); - if (isConstTypeReference(typeNode)) { + if (isConstTypeReference(type)) { if (!isValidConstAssertionArgument(expression)) { error(expression, Diagnostics.A_const_assertions_can_only_be_applied_to_references_to_enum_members_or_string_number_boolean_array_or_object_literals); } return getRegularTypeOfLiteralType(exprType); } - checkSourceElement(typeNode); - const type = getTypeFromTypeNode(typeNode); - // See if we need to check whether the expression and asserted types are comparable. - if (!isErrorType(type) && !((exprType.flags | type.flags) & (TypeFlags.AnyOrUnknown | TypeFlags.Never))) { - const links = getNodeLinks(node); - links.assertionExpressionType = exprType; - checkNodeDeferred(node); - } - return type; + const links = getNodeLinks(node); + links.assertionExpressionType = exprType; + checkSourceElement(type); + checkNodeDeferred(node); + return getTypeFromTypeNode(type); } function checkAssertionDeferred(node: JSDocTypeAssertion | AssertionExpression) { @@ -34555,13 +34551,15 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { Debug.assertIsDefined(links.assertionExpressionType); const exprType = getRegularTypeOfObjectLiteral(getBaseTypeOfLiteralType(links.assertionExpressionType)); const targetType = getTypeFromTypeNode(type); - addLazyDiagnostic(() => { - const widenedType = getWidenedType(exprType); - if (!isTypeComparableTo(targetType, widenedType)) { - checkTypeComparableTo(exprType, targetType, errNode, - Diagnostics.Conversion_of_type_0_to_type_1_may_be_a_mistake_because_neither_type_sufficiently_overlaps_with_the_other_If_this_was_intentional_convert_the_expression_to_unknown_first); - } - }); + if (!isErrorType(targetType)) { + addLazyDiagnostic(() => { + const widenedType = getWidenedType(exprType); + if (!isTypeComparableTo(targetType, widenedType)) { + checkTypeComparableTo(exprType, targetType, errNode, + Diagnostics.Conversion_of_type_0_to_type_1_may_be_a_mistake_because_neither_type_sufficiently_overlaps_with_the_other_If_this_was_intentional_convert_the_expression_to_unknown_first); + } + }); + } } function checkNonNullChain(node: NonNullChain) { From bb2b5f740f1ed8bb80ef8721a208cf7276002d1f Mon Sep 17 00:00:00 2001 From: Gabriela Araujo Britto Date: Fri, 12 May 2023 16:55:48 -0700 Subject: [PATCH 7/7] Revert "inline helper" This reverts commit 372a1ab310204370b2f3c520f466a7daf5a1cfac. --- src/compiler/checker.ts | 34 +++++++++++++++++++--------------- 1 file changed, 19 insertions(+), 15 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index fe8ee0d215cc3..ca6ab49708c75 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -34515,6 +34515,22 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } function checkAssertionWorker(node: JSDocTypeAssertion | AssertionExpression, checkMode: CheckMode | undefined) { + const { type, expression } = getAssertionTypeAndExpression(node); + const exprType = checkExpression(expression, checkMode); + if (isConstTypeReference(type)) { + if (!isValidConstAssertionArgument(expression)) { + error(expression, Diagnostics.A_const_assertions_can_only_be_applied_to_references_to_enum_members_or_string_number_boolean_array_or_object_literals); + } + return getRegularTypeOfLiteralType(exprType); + } + const links = getNodeLinks(node); + links.assertionExpressionType = exprType; + checkSourceElement(type); + checkNodeDeferred(node); + return getTypeFromTypeNode(type); + } + + function getAssertionTypeAndExpression(node: JSDocTypeAssertion | AssertionExpression) { let type: TypeNode; let expression: Expression; switch (node.kind) { @@ -34528,24 +34544,12 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { expression = node.expression; break; } - const exprType = checkExpression(expression, checkMode); - if (isConstTypeReference(type)) { - if (!isValidConstAssertionArgument(expression)) { - error(expression, Diagnostics.A_const_assertions_can_only_be_applied_to_references_to_enum_members_or_string_number_boolean_array_or_object_literals); - } - return getRegularTypeOfLiteralType(exprType); - } - const links = getNodeLinks(node); - links.assertionExpressionType = exprType; - checkSourceElement(type); - checkNodeDeferred(node); - return getTypeFromTypeNode(type); + + return { type, expression }; } function checkAssertionDeferred(node: JSDocTypeAssertion | AssertionExpression) { - const type = node.kind === SyntaxKind.ParenthesizedExpression - ? getJSDocTypeAssertionType(node) - : node.type; + const { type } = getAssertionTypeAndExpression(node); const errNode = isParenthesizedExpression(node) ? type : node; const links = getNodeLinks(node); Debug.assertIsDefined(links.assertionExpressionType);