Skip to content

Commit 46c61b3

Browse files
committed
WIP: defer type comparability check in assertions
1 parent 6c1d25e commit 46c61b3

5 files changed

+76
-61
lines changed

src/compiler/checker.ts

Lines changed: 72 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ import {
2424
arrayToMultiMap,
2525
ArrayTypeNode,
2626
ArrowFunction,
27+
AsExpression,
2728
AssertionExpression,
2829
AssignmentDeclarationKind,
2930
AssignmentKind,
@@ -758,6 +759,7 @@ import {
758759
JSDocSatisfiesTag,
759760
JSDocSignature,
760761
JSDocTemplateTag,
762+
JSDocTypeAssertion,
761763
JSDocTypedefTag,
762764
JSDocTypeExpression,
763765
JSDocTypeLiteral,
@@ -1033,7 +1035,6 @@ import {
10331035
TypeReferenceSerializationKind,
10341036
TypeReferenceType,
10351037
TypeVariable,
1036-
UnaryExpression,
10371038
unescapeLeadingUnderscores,
10381039
UnionOrIntersectionType,
10391040
UnionOrIntersectionTypeNode,
@@ -34210,7 +34211,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
3421034211
grammarErrorOnNode(node, Diagnostics.This_syntax_is_reserved_in_files_with_the_mts_or_cts_extension_Use_an_as_expression_instead);
3421134212
}
3421234213
}
34213-
return checkAssertionWorker(node, node.type, node.expression);
34214+
// return checkAssertionWorker(node, node.type, node.expression);
34215+
return checkAssertionWorker(node);
3421434216
}
3421534217

3421634218
function isValidConstAssertionArgument(node: Node): boolean {
@@ -34241,27 +34243,74 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
3424134243
return false;
3424234244
}
3424334245

34244-
function checkAssertionWorker(errNode: Node, type: TypeNode, expression: UnaryExpression | Expression, checkMode?: CheckMode) {
34245-
let exprType = checkExpression(expression, checkMode);
34246+
function checkAssertionWorker(node: JSDocTypeAssertion | AssertionExpression) {
34247+
// TODO: maybe we don't need this? maybe can be helper?
34248+
let type: TypeNode;
34249+
let expression: Expression;
34250+
switch (node.kind) {
34251+
case SyntaxKind.AsExpression:
34252+
case SyntaxKind.TypeAssertionExpression:
34253+
type = node.type;
34254+
expression = node.expression;
34255+
break;
34256+
case SyntaxKind.ParenthesizedExpression:
34257+
type = getJSDocTypeAssertionType(node);
34258+
expression = node.expression;
34259+
break;
34260+
}
34261+
34262+
// function checkAssertionWorker(errNode: Node, type: TypeNode, expression: UnaryExpression | Expression, checkMode?: CheckMode) {
34263+
// let exprType = checkExpression(expression, checkMode);
3424634264
if (isConstTypeReference(type)) {
3424734265
if (!isValidConstAssertionArgument(expression)) {
3424834266
error(expression, Diagnostics.A_const_assertions_can_only_be_applied_to_references_to_enum_members_or_string_number_boolean_array_or_object_literals);
3424934267
}
34250-
return getRegularTypeOfLiteralType(exprType);
34268+
// return getRegularTypeOfLiteralType(exprType);
34269+
return getRegularTypeOfLiteralType(checkExpression(expression));
3425134270
}
3425234271
checkSourceElement(type);
34253-
exprType = getRegularTypeOfObjectLiteral(getBaseTypeOfLiteralType(exprType));
34272+
checkNodeDeferred(node); // >> TODO: get node
34273+
// exprType = getRegularTypeOfObjectLiteral(getBaseTypeOfLiteralType(exprType));
34274+
// const targetType = getTypeFromTypeNode(type);
34275+
// if (!isErrorType(targetType)) {
34276+
// addLazyDiagnostic(() => { // TODO: defer this check
34277+
// const widenedType = getWidenedType(exprType);
34278+
// if (!isTypeComparableTo(targetType, widenedType)) {
34279+
// checkTypeComparableTo(exprType, targetType, errNode,
34280+
// 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);
34281+
// }
34282+
// });
34283+
// }
34284+
// return targetType;
34285+
return getTypeFromTypeNode(type);
34286+
}
34287+
34288+
function checkAssertionDeferred(node: JSDocTypeAssertion | AssertionExpression) {
34289+
let type: TypeNode;
34290+
let expression: Expression;
34291+
let errNode: Node;
34292+
switch (node.kind) {
34293+
case SyntaxKind.AsExpression:
34294+
case SyntaxKind.TypeAssertionExpression:
34295+
type = (node as TypeAssertion | AsExpression).type;
34296+
expression = (node as TypeAssertion | AsExpression).expression;
34297+
errNode = node;
34298+
break;
34299+
case SyntaxKind.ParenthesizedExpression:
34300+
type = getJSDocTypeAssertionType(node);
34301+
expression = node.expression;
34302+
errNode = type;
34303+
break;
34304+
}
34305+
const exprType = getRegularTypeOfObjectLiteral(getBaseTypeOfLiteralType(checkExpression(expression)));
3425434306
const targetType = getTypeFromTypeNode(type);
3425534307
if (!isErrorType(targetType)) {
34256-
addLazyDiagnostic(() => {
34257-
const widenedType = getWidenedType(exprType);
34258-
if (!isTypeComparableTo(targetType, widenedType)) {
34259-
checkTypeComparableTo(exprType, targetType, errNode,
34260-
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);
34261-
}
34262-
});
34308+
const widenedType = getWidenedType(exprType);
34309+
if (!isTypeComparableTo(targetType, widenedType)) {
34310+
checkTypeComparableTo(exprType, targetType, errNode,
34311+
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);
34312+
}
3426334313
}
34264-
return targetType;
3426534314
}
3426634315

3426734316
function checkNonNullChain(node: NonNullChain) {
@@ -37483,8 +37532,9 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
3748337532
return checkSatisfiesExpressionWorker(node.expression, getJSDocSatisfiesExpressionType(node), checkMode);
3748437533
}
3748537534
if (isJSDocTypeAssertion(node)) {
37486-
const type = getJSDocTypeAssertionType(node);
37487-
return checkAssertionWorker(type, type, node.expression, checkMode);
37535+
// const type = getJSDocTypeAssertionType(node);
37536+
// return checkAssertionWorker(type, type, node.expression);
37537+
return checkAssertionWorker(node);
3748837538
}
3748937539
}
3749037540
return checkExpression(node.expression, checkMode);
@@ -44606,7 +44656,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
4460644656
// Here, performing a full type check of the body of the function expression whilst in the process of
4460744657
// determining the type of foo would cause foo to be given type any because of the recursive reference.
4460844658
// Delaying the type check of the body ensures foo has been assigned a type.
44609-
function checkNodeDeferred(node: Node) {
44659+
function checkNodeDeferred(node: Node) { // >>
4461044660
const enclosingFile = getSourceFileOfNode(node);
4461144661
const links = getNodeLinks(enclosingFile);
4461244662
if (!(links.flags & NodeCheckFlags.TypeChecked)) {
@@ -44626,7 +44676,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
4462644676
links.deferredNodes = undefined;
4462744677
}
4462844678

44629-
function checkDeferredNode(node: Node) {
44679+
function checkDeferredNode(node: Node) { // >>
4463044680
tracing?.push(tracing.Phase.Check, "checkDeferredNode", { kind: node.kind, pos: node.pos, end: node.end, path: (node as TracingNode).tracingPath });
4463144681
const saveCurrentNode = currentNode;
4463244682
currentNode = node;
@@ -44664,6 +44714,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
4466444714
case SyntaxKind.JsxElement:
4466544715
checkJsxElementDeferred(node as JsxElement);
4466644716
break;
44717+
case SyntaxKind.TypeAssertionExpression:
44718+
case SyntaxKind.AsExpression:
44719+
case SyntaxKind.ParenthesizedExpression:
44720+
checkAssertionDeferred(node as AssertionExpression | JSDocTypeAssertion);
4466744721
}
4466844722
currentNode = saveCurrentNode;
4466944723
tracing?.pop();

tests/baselines/reference/classVarianceCircularity.errors.txt

Lines changed: 0 additions & 20 deletions
This file was deleted.

tests/baselines/reference/classVarianceCircularity.types

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,9 @@ function f() {
1515
>console.log : (...data: any[]) => void
1616
>console : Console
1717
>log : (...data: any[]) => void
18-
>b.Value : any
18+
>b.Value : number
1919
>b : Bar<unknown>
20-
>Value : any
20+
>Value : number
2121
}
2222

2323
class Bar<T> {
@@ -36,7 +36,7 @@ class Bar<T> {
3636
>num : number
3737

3838
Value = (this as Bar<any>).num;
39-
>Value : any
39+
>Value : number
4040
>(this as Bar<any>).num : number
4141
>(this as Bar<any>) : Bar<any>
4242
>this as Bar<any> : Bar<any>

tests/baselines/reference/trivialSubtypeReductionNoStructuralCheck.errors.txt

Lines changed: 0 additions & 19 deletions
This file was deleted.

tests/baselines/reference/trivialSubtypeReductionNoStructuralCheck.types

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ export class Wizard {
66
>Wizard : Wizard
77

88
get steps() {
9-
>steps : any
9+
>steps : WizardStepProps
1010

1111
return {
1212
>{ wizard: this, ...props, } as WizardStepProps : WizardStepProps

0 commit comments

Comments
 (0)