Skip to content

Implement(60881): Added detailed diagnostic for parent to child assignment #61145

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 32 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
a010044
.
NamHaiBui Jan 31, 2025
3d632b3
new check
NamHaiBui Feb 3, 2025
ef0dd9d
new diagnostic message
NamHaiBui Feb 6, 2025
e16f35f
Merge branch 'main' of https://github.com/microsoft/TypeScript
NamHaiBui Feb 7, 2025
63e6b4c
#60881
NamHaiBui Feb 7, 2025
09022f3
#60881
NamHaiBui Feb 7, 2025
8def683
#60881 Minor typo change
NamHaiBui Feb 7, 2025
ce15fd8
Normalize line endings
NamHaiBui Feb 7, 2025
01e2bfc
Merge branch 'main' of https://github.com/microsoft/TypeScript into 6…
NamHaiBui Feb 7, 2025
85dc004
#60881 reformat
NamHaiBui Feb 7, 2025
47acf44
removed old comments
Alexandrialexie Feb 9, 2025
65fdfc1
generic check before hand
NamHaiBui Feb 10, 2025
4f8eeb6
Merge branch '60881' of https://github.com/SeniorSeminarGroup/TypeScr…
Alexandrialexie Feb 10, 2025
4db251b
new approach and all changed tests reviewed
NamHaiBui Feb 14, 2025
6505632
formatting
NamHaiBui Feb 14, 2025
c0b8e55
Merge branch 'main' of https://github.com/microsoft/TypeScript into 6…
NamHaiBui Feb 14, 2025
d62eed1
Merge branch '60881' of https://github.com/SeniorSeminarGroup/TypeScr…
Alexandrialexie Feb 14, 2025
753d8c1
Merge branch 'main' of https://github.com/microsoft/TypeScript into 6…
NamHaiBui Feb 14, 2025
694b893
Merge branch '60881' of https://github.com/SeniorSeminarGroup/TypeScr…
Alexandrialexie Feb 14, 2025
ef4e281
removed unnecessary comments
Alexandrialexie Feb 14, 2025
dd6ab9a
added more informative test language and extra test case.
RolandLocke Feb 17, 2025
2a56797
added diagnostic message to the 'semantic messages' area in diagnosti…
RolandLocke Feb 17, 2025
a697946
accepted baseline changes
RolandLocke Feb 17, 2025
c662343
Merge branch 'main' of https://github.com/microsoft/TypeScript into 6…
NamHaiBui Feb 19, 2025
cad1a24
Merge branch 'main' of https://github.com/microsoft/TypeScript into 6…
NamHaiBui Feb 25, 2025
b3664f8
Revert "#60881 reformat"
NamHaiBui Feb 25, 2025
b285ebc
reverted formatting errors
RolandLocke Feb 25, 2025
95b249f
added trailing comma
RolandLocke Feb 25, 2025
c88940c
Merge branch 'microsoft:main' into 60881
maitnngo2002 Mar 6, 2025
8933230
Revert "Merge branch 'microsoft:main' into 60881"
ngothingocmaiclht Mar 6, 2025
eab824d
Revert "Revert "Merge branch 'microsoft:main' into 60881""
ngothingocmaiclht Apr 13, 2025
c741d1e
Updated test function parameters
RolandLocke Apr 16, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions src/compiler/checker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21966,6 +21966,13 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
typeToString(constraint),
);
}
else if ((source.flags & TypeFlags.TypeParameter) && (isTypeAssignableTo(target, getBaseConstraintOrType(generalizedSource)) || (needsOriginalSource = isTypeAssignableTo(target, getBaseConstraintOrType(source))))) {
reportError(
Diagnostics._1_is_constrained_to_be_a_subtype_of_0,
needsOriginalSource ? sourceType : generalizedSourceType,
targetType,
);
}
else {
errorInfo = undefined;
reportError(
Expand Down
4 changes: 4 additions & 0 deletions src/compiler/diagnosticMessages.json
Original file line number Diff line number Diff line change
Expand Up @@ -3991,6 +3991,10 @@
"category": "Error",
"code": 2881
},
"'{1}' is constrained to be a subtype of '{0}'.": {
"category": "Error",
"code": 2882
},

"Import declaration '{0}' is using private name '{1}'.": {
"category": "Error",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
better_subType_assignable_to_superType_error_messsage.ts(3,3): error TS2322: Type 'SuperType' is not assignable to type 'SubType'.
'SubType' is constrained to be a subtype of 'SuperType'.
better_subType_assignable_to_superType_error_messsage.ts(6,3): error TS2322: Type 'SuperType' is not assignable to type 'SubType2'.
'SubType2' is constrained to be a subtype of 'SuperType'.


==== better_subType_assignable_to_superType_error_messsage.ts (2 errors) ====
function parameterExtendsOtherParameter<SuperType, SubType extends SuperType, SubType2 extends SubType>(superType: SuperType, subtype: SubType, subType2: SubType2) {
//ensures that supertypes are not assignable to subtypes
subtype = superType;//error
~~~~~~~
!!! error TS2322: Type 'SuperType' is not assignable to type 'SubType'.
!!! error TS2322: 'SubType' is constrained to be a subtype of 'SuperType'.
!!! related TS2208 better_subType_assignable_to_superType_error_messsage.ts:1:41: This type parameter might need an `extends SubType` constraint.

//ensures that supertypes are not assignable to 'grandchild' subtypes
subType2 = superType;//error
~~~~~~~~
!!! error TS2322: Type 'SuperType' is not assignable to type 'SubType2'.
!!! error TS2322: 'SubType2' is constrained to be a subtype of 'SuperType'.
!!! related TS2208 better_subType_assignable_to_superType_error_messsage.ts:1:41: This type parameter might need an `extends SubType2` constraint.

superType = subType2;//ok
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
//// [tests/cases/compiler/better_subType_assignable_to_superType_error_messsage.ts] ////

//// [better_subType_assignable_to_superType_error_messsage.ts]
function parameterExtendsOtherParameter<SuperType, SubType extends SuperType, SubType2 extends SubType>(superType: SuperType, subtype: SubType, subType2: SubType2) {
//ensures that supertypes are not assignable to subtypes
subtype = superType;//error

//ensures that supertypes are not assignable to 'grandchild' subtypes
subType2 = superType;//error

superType = subType2;//ok
}


//// [better_subType_assignable_to_superType_error_messsage.js]
function parameterExtendsOtherParameter(superType, subtype, subType2) {
//ensures that supertypes are not assignable to subtypes
subtype = superType; //error
//ensures that supertypes are not assignable to 'grandchild' subtypes
subType2 = superType; //error
superType = subType2; //ok
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
//// [tests/cases/compiler/better_subType_assignable_to_superType_error_messsage.ts] ////

=== better_subType_assignable_to_superType_error_messsage.ts ===
function parameterExtendsOtherParameter<SuperType, SubType extends SuperType, SubType2 extends SubType>(superType: SuperType, subtype: SubType, subType2: SubType2) {
>parameterExtendsOtherParameter : Symbol(parameterExtendsOtherParameter, Decl(better_subType_assignable_to_superType_error_messsage.ts, 0, 0))
>SuperType : Symbol(SuperType, Decl(better_subType_assignable_to_superType_error_messsage.ts, 0, 40))
>SubType : Symbol(SubType, Decl(better_subType_assignable_to_superType_error_messsage.ts, 0, 50))
>SuperType : Symbol(SuperType, Decl(better_subType_assignable_to_superType_error_messsage.ts, 0, 40))
>SubType2 : Symbol(SubType2, Decl(better_subType_assignable_to_superType_error_messsage.ts, 0, 77))
>SubType : Symbol(SubType, Decl(better_subType_assignable_to_superType_error_messsage.ts, 0, 50))
>superType : Symbol(superType, Decl(better_subType_assignable_to_superType_error_messsage.ts, 0, 104))
>SuperType : Symbol(SuperType, Decl(better_subType_assignable_to_superType_error_messsage.ts, 0, 40))
>subtype : Symbol(subtype, Decl(better_subType_assignable_to_superType_error_messsage.ts, 0, 125))
>SubType : Symbol(SubType, Decl(better_subType_assignable_to_superType_error_messsage.ts, 0, 50))
>subType2 : Symbol(subType2, Decl(better_subType_assignable_to_superType_error_messsage.ts, 0, 143))
>SubType2 : Symbol(SubType2, Decl(better_subType_assignable_to_superType_error_messsage.ts, 0, 77))

//ensures that supertypes are not assignable to subtypes
subtype = superType;//error
>subtype : Symbol(subtype, Decl(better_subType_assignable_to_superType_error_messsage.ts, 0, 125))
>superType : Symbol(superType, Decl(better_subType_assignable_to_superType_error_messsage.ts, 0, 104))

//ensures that supertypes are not assignable to 'grandchild' subtypes
subType2 = superType;//error
>subType2 : Symbol(subType2, Decl(better_subType_assignable_to_superType_error_messsage.ts, 0, 143))
>superType : Symbol(superType, Decl(better_subType_assignable_to_superType_error_messsage.ts, 0, 104))

superType = subType2;//ok
>superType : Symbol(superType, Decl(better_subType_assignable_to_superType_error_messsage.ts, 0, 104))
>subType2 : Symbol(subType2, Decl(better_subType_assignable_to_superType_error_messsage.ts, 0, 143))
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
//// [tests/cases/compiler/better_subType_assignable_to_superType_error_messsage.ts] ////

=== better_subType_assignable_to_superType_error_messsage.ts ===
function parameterExtendsOtherParameter<SuperType, SubType extends SuperType, SubType2 extends SubType>(superType: SuperType, subtype: SubType, subType2: SubType2) {
>parameterExtendsOtherParameter : <SuperType, SubType extends SuperType, SubType2 extends SubType>(superType: SuperType, subtype: SubType, subType2: SubType2) => void
> : ^ ^^ ^^^^^^^^^ ^^ ^^^^^^^^^ ^^ ^^ ^^ ^^ ^^ ^^ ^^^^^^^^^
>superType : SuperType
> : ^^^^^^^^^
>subtype : SubType
> : ^^^^^^^
>subType2 : SubType2
> : ^^^^^^^^

//ensures that supertypes are not assignable to subtypes
subtype = superType;//error
>subtype = superType : SuperType
> : ^^^^^^^^^
>subtype : SubType
> : ^^^^^^^
>superType : SuperType
> : ^^^^^^^^^

//ensures that supertypes are not assignable to 'grandchild' subtypes
subType2 = superType;//error
>subType2 = superType : SuperType
> : ^^^^^^^^^
>subType2 : SubType2
> : ^^^^^^^^
>superType : SuperType
> : ^^^^^^^^^

superType = subType2;//ok
>superType = subType2 : SubType2
> : ^^^^^^^^
>superType : SuperType
> : ^^^^^^^^^
>subType2 : SubType2
> : ^^^^^^^^
}

Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
chainedCallsWithTypeParameterConstrainedToOtherTypeParameter2.ts(7,49): error TS2322: Type 'T' is not assignable to type 'S'.
'S' could be instantiated with an arbitrary type which could be unrelated to 'T'.
'S' is constrained to be a subtype of 'T'.
chainedCallsWithTypeParameterConstrainedToOtherTypeParameter2.ts(10,35): error TS2322: Type 'T' is not assignable to type 'S'.
'S' could be instantiated with an arbitrary type which could be unrelated to 'T'.
'S' is constrained to be a subtype of 'T'.
chainedCallsWithTypeParameterConstrainedToOtherTypeParameter2.ts(32,9): error TS2322: Type 'string' is not assignable to type 'number'.
chainedCallsWithTypeParameterConstrainedToOtherTypeParameter2.ts(36,9): error TS2322: Type 'string' is not assignable to type 'number'.
chainedCallsWithTypeParameterConstrainedToOtherTypeParameter2.ts(37,9): error TS2322: Type 'string' is not assignable to type 'number'.
Expand All @@ -17,15 +17,15 @@ chainedCallsWithTypeParameterConstrainedToOtherTypeParameter2.ts(37,9): error TS
(new Chain(t)).then(tt => s).then(ss => t);
~
!!! error TS2322: Type 'T' is not assignable to type 'S'.
!!! error TS2322: 'S' could be instantiated with an arbitrary type which could be unrelated to 'T'.
!!! error TS2322: 'S' is constrained to be a subtype of 'T'.
!!! related TS2208 chainedCallsWithTypeParameterConstrainedToOtherTypeParameter2.ts:1:13: This type parameter might need an `extends S` constraint.
!!! related TS6502 chainedCallsWithTypeParameterConstrainedToOtherTypeParameter2.ts:3:27: The expected type comes from the return type of this signature.

// But error to try to climb up the chain
(new Chain(s)).then(ss => t);
~
!!! error TS2322: Type 'T' is not assignable to type 'S'.
!!! error TS2322: 'S' could be instantiated with an arbitrary type which could be unrelated to 'T'.
!!! error TS2322: 'S' is constrained to be a subtype of 'T'.
!!! related TS2208 chainedCallsWithTypeParameterConstrainedToOtherTypeParameter2.ts:1:13: This type parameter might need an `extends S` constraint.
!!! related TS6502 chainedCallsWithTypeParameterConstrainedToOtherTypeParameter2.ts:3:27: The expected type comes from the return type of this signature.

Expand Down
12 changes: 6 additions & 6 deletions tests/baselines/reference/conditionalTypes2.errors.txt
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
conditionalTypes2.ts(15,5): error TS2322: Type 'Covariant<A>' is not assignable to type 'Covariant<B>'.
Type 'A' is not assignable to type 'B'.
'B' could be instantiated with an arbitrary type which could be unrelated to 'A'.
'B' is constrained to be a subtype of 'A'.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not understanding why this error message is an improvement. What's the smallest example where this error is going to be easier to understand?

Copy link

@Alexandrialexie Alexandrialexie Apr 18, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@RyanCavanaugh This error message is an improvement because the original error message says that the two types could be unrelated but we know they are related in a parent child relationship, you just can't assign a parent to a child. We tried to pick a new error message that was similar to the suggestion in the original issue. This is the simplest example we looked at:

function example<SuperType, SubType extends SuperType>(superType: SuperType, subType: SubType) {
  subType = superType;
}

conditionalTypes2.ts(19,5): error TS2322: Type 'Contravariant<B>' is not assignable to type 'Contravariant<A>'.
Type 'A' is not assignable to type 'B'.
'B' could be instantiated with an arbitrary type which could be unrelated to 'A'.
'B' is constrained to be a subtype of 'A'.
conditionalTypes2.ts(24,5): error TS2322: Type 'Invariant<B>' is not assignable to type 'Invariant<A>'.
Types of property 'foo' are incompatible.
Type 'B extends string ? keyof B : B' is not assignable to type 'A extends string ? keyof A : A'.
Expand All @@ -23,7 +23,7 @@ conditionalTypes2.ts(25,5): error TS2322: Type 'Invariant<A>' is not assignable
Type 'A | keyof A' is not assignable to type 'B extends string ? keyof B : B'.
Type 'A' is not assignable to type 'B extends string ? keyof B : B'.
Type 'A' is not assignable to type 'B'.
'B' could be instantiated with an arbitrary type which could be unrelated to 'A'.
'B' is constrained to be a subtype of 'A'.
conditionalTypes2.ts(73,12): error TS2345: Argument of type 'Extract<Extract<T, Foo>, Bar>' is not assignable to parameter of type '{ foo: string; bat: string; }'.
Type 'Extract<T, Bar>' is not assignable to type '{ foo: string; bat: string; }'.
Property 'bat' is missing in type 'Bar & Foo' but required in type '{ foo: string; bat: string; }'.
Expand Down Expand Up @@ -53,7 +53,7 @@ conditionalTypes2.ts(75,12): error TS2345: Argument of type 'Extract2<T, Foo, Ba
~
!!! error TS2322: Type 'Covariant<A>' is not assignable to type 'Covariant<B>'.
!!! error TS2322: Type 'A' is not assignable to type 'B'.
!!! error TS2322: 'B' could be instantiated with an arbitrary type which could be unrelated to 'A'.
!!! error TS2322: 'B' is constrained to be a subtype of 'A'.
!!! related TS2208 conditionalTypes2.ts:13:13: This type parameter might need an `extends B` constraint.
}

Expand All @@ -62,7 +62,7 @@ conditionalTypes2.ts(75,12): error TS2345: Argument of type 'Extract2<T, Foo, Ba
~
!!! error TS2322: Type 'Contravariant<B>' is not assignable to type 'Contravariant<A>'.
!!! error TS2322: Type 'A' is not assignable to type 'B'.
!!! error TS2322: 'B' could be instantiated with an arbitrary type which could be unrelated to 'A'.
!!! error TS2322: 'B' is constrained to be a subtype of 'A'.
!!! related TS2208 conditionalTypes2.ts:18:13: This type parameter might need an `extends B` constraint.
b = a;
}
Expand Down Expand Up @@ -91,7 +91,7 @@ conditionalTypes2.ts(75,12): error TS2345: Argument of type 'Extract2<T, Foo, Ba
!!! error TS2322: Type 'A | keyof A' is not assignable to type 'B extends string ? keyof B : B'.
!!! error TS2322: Type 'A' is not assignable to type 'B extends string ? keyof B : B'.
!!! error TS2322: Type 'A' is not assignable to type 'B'.
!!! error TS2322: 'B' could be instantiated with an arbitrary type which could be unrelated to 'A'.
!!! error TS2322: 'B' is constrained to be a subtype of 'A'.
!!! related TS2208 conditionalTypes2.ts:23:13: This type parameter might need an `extends B` constraint.
!!! related TS2208 conditionalTypes2.ts:23:13: This type parameter might need an `extends B extends string ? keyof B : B` constraint.
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
genericCallWithObjectTypeArgsAndInitializers.ts(5,33): error TS2322: Type 'number' is not assignable to type 'T'.
'number' is assignable to the constraint of type 'T', but 'T' could be instantiated with a different subtype of constraint 'Number'.
genericCallWithObjectTypeArgsAndInitializers.ts(6,37): error TS2322: Type 'T' is not assignable to type 'U'.
'U' could be instantiated with an arbitrary type which could be unrelated to 'T'.
'U' is constrained to be a subtype of 'T'.
genericCallWithObjectTypeArgsAndInitializers.ts(8,56): error TS2322: Type 'U' is not assignable to type 'V'.
'V' could be instantiated with an arbitrary type which could be unrelated to 'U'.
'V' is constrained to be a subtype of 'U'.


==== genericCallWithObjectTypeArgsAndInitializers.ts (3 errors) ====
Expand All @@ -18,11 +18,11 @@ genericCallWithObjectTypeArgsAndInitializers.ts(8,56): error TS2322: Type 'U' is
function foo4<T, U extends T>(x: T, y: U = x) { } // error
~~~~~~~~
!!! error TS2322: Type 'T' is not assignable to type 'U'.
!!! error TS2322: 'U' could be instantiated with an arbitrary type which could be unrelated to 'T'.
!!! error TS2322: 'U' is constrained to be a subtype of 'T'.
!!! related TS2208 genericCallWithObjectTypeArgsAndInitializers.ts:6:15: This type parameter might need an `extends U` constraint.
function foo5<T, U extends T>(x: U, y: T = x) { } // ok
function foo6<T, U extends T, V extends U>(x: T, y: U, z: V = y) { } // error
~~~~~~~~
!!! error TS2322: Type 'U' is not assignable to type 'V'.
!!! error TS2322: 'V' could be instantiated with an arbitrary type which could be unrelated to 'U'.
!!! error TS2322: 'V' is constrained to be a subtype of 'U'.
function foo7<T, U extends T, V extends U>(x: V, y: U = x) { } // should be ok
12 changes: 6 additions & 6 deletions tests/baselines/reference/keyofAndIndexedAccessErrors.errors.txt
Original file line number Diff line number Diff line change
Expand Up @@ -68,16 +68,16 @@ keyofAndIndexedAccessErrors.ts(105,9): error TS2322: Type 'T[Extract<keyof T, st
'string' is assignable to the constraint of type 'K', but 'K' could be instantiated with a different subtype of constraint 'string'.
keyofAndIndexedAccessErrors.ts(108,5): error TS2322: Type 'T[K]' is not assignable to type 'U[K]'.
Type 'T' is not assignable to type 'U'.
'U' could be instantiated with an arbitrary type which could be unrelated to 'T'.
'U' is constrained to be a subtype of 'T'.
keyofAndIndexedAccessErrors.ts(111,5): error TS2322: Type 'T[J]' is not assignable to type 'U[J]'.
Type 'T' is not assignable to type 'U'.
'U' could be instantiated with an arbitrary type which could be unrelated to 'T'.
'U' is constrained to be a subtype of 'T'.
keyofAndIndexedAccessErrors.ts(114,5): error TS2322: Type 'T[K]' is not assignable to type 'T[J]'.
Type 'K' is not assignable to type 'J'.
'K' is assignable to the constraint of type 'J', but 'J' could be instantiated with a different subtype of constraint 'string'.
keyofAndIndexedAccessErrors.ts(117,5): error TS2322: Type 'T[K]' is not assignable to type 'U[J]'.
Type 'T' is not assignable to type 'U'.
'U' could be instantiated with an arbitrary type which could be unrelated to 'T'.
'U' is constrained to be a subtype of 'T'.
keyofAndIndexedAccessErrors.ts(122,5): error TS2322: Type 'number' is not assignable to type 'keyof T'.
keyofAndIndexedAccessErrors.ts(123,5): error TS2322: Type 'string' is not assignable to type 'keyof T'.
keyofAndIndexedAccessErrors.ts(140,5): error TS2322: Type 'number' is not assignable to type 'T[K]'.
Expand Down Expand Up @@ -301,15 +301,15 @@ keyofAndIndexedAccessErrors.ts(165,5): error TS2322: Type 'number' is not assign
~~
!!! error TS2322: Type 'T[K]' is not assignable to type 'U[K]'.
!!! error TS2322: Type 'T' is not assignable to type 'U'.
!!! error TS2322: 'U' could be instantiated with an arbitrary type which could be unrelated to 'T'.
!!! error TS2322: 'U' is constrained to be a subtype of 'T'.
!!! related TS2208 keyofAndIndexedAccessErrors.ts:99:13: This type parameter might need an `extends U` constraint.

tj = uj;
uj = tj; // error
~~
!!! error TS2322: Type 'T[J]' is not assignable to type 'U[J]'.
!!! error TS2322: Type 'T' is not assignable to type 'U'.
!!! error TS2322: 'U' could be instantiated with an arbitrary type which could be unrelated to 'T'.
!!! error TS2322: 'U' is constrained to be a subtype of 'T'.
!!! related TS2208 keyofAndIndexedAccessErrors.ts:99:13: This type parameter might need an `extends U` constraint.

tk = tj;
Expand All @@ -324,7 +324,7 @@ keyofAndIndexedAccessErrors.ts(165,5): error TS2322: Type 'number' is not assign
~~
!!! error TS2322: Type 'T[K]' is not assignable to type 'U[J]'.
!!! error TS2322: Type 'T' is not assignable to type 'U'.
!!! error TS2322: 'U' could be instantiated with an arbitrary type which could be unrelated to 'T'.
!!! error TS2322: 'U' is constrained to be a subtype of 'T'.
!!! related TS2208 keyofAndIndexedAccessErrors.ts:99:13: This type parameter might need an `extends U` constraint.
}

Expand Down
Loading