Skip to content

Commit c392b0f

Browse files
committed
Always subtitute on type parameter types
1 parent 6abbc96 commit c392b0f

File tree

5 files changed

+58
-23
lines changed

5 files changed

+58
-23
lines changed

src/compiler/checker.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12857,7 +12857,9 @@ namespace ts {
1285712857
if (parent.kind === SyntaxKind.Parameter) {
1285812858
covariant = !covariant;
1285912859
}
12860-
if (covariant && parent.kind === SyntaxKind.ConditionalType && node === (<ConditionalTypeNode>parent).trueType) {
12860+
// Always substitute on type parameters, regardless of variance, since even
12861+
// in contravarrying positions, they may be reliant on subtuted constraints to be valid
12862+
if ((covariant || type.flags & TypeFlags.TypeParameter) && parent.kind === SyntaxKind.ConditionalType && node === (<ConditionalTypeNode>parent).trueType) {
1286112863
const constraint = getImpliedConstraint(type, (<ConditionalTypeNode>parent).checkType, (<ConditionalTypeNode>parent).extendsType);
1286212864
if (constraint) {
1286312865
constraints = append(constraints, constraint);

tests/baselines/reference/callOfConditionalTypeWithConcreteBranches.js

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ type ExtractParameters<T> = "parameters" extends keyof T
1818
}[keyof T["parameters"]]
1919
: {};
2020
21+
// Original example, but with inverted variance
2122
type Q2<T> = number extends T ? (cb: (n: number) => void) => void : never;
2223
function fn2<T>(arg: Q2<T>) {
2324
function useT(_arg: T): void {}
@@ -27,7 +28,11 @@ function fn2<T>(arg: Q2<T>) {
2728
// Legal invocations are not problematic
2829
fn2<string | number>(m => m(42));
2930
fn2<number>(m => m(42));
30-
31+
32+
// webidl-conversions example where substituion must occur, despite contravariance of the position
33+
// due to the invariant usage in `Parameters`
34+
35+
type X<V> = V extends (...args: any[]) => any ? (...args: Parameters<V>) => void : Function;
3136

3237
//// [callOfConditionalTypeWithConcreteBranches.js]
3338
function fn(arg) {

tests/baselines/reference/callOfConditionalTypeWithConcreteBranches.symbols

Lines changed: 35 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -52,40 +52,54 @@ type ExtractParameters<T> = "parameters" extends keyof T
5252

5353
: {};
5454

55+
// Original example, but with inverted variance
5556
type Q2<T> = number extends T ? (cb: (n: number) => void) => void : never;
5657
>Q2 : Symbol(Q2, Decl(callOfConditionalTypeWithConcreteBranches.ts, 17, 7))
57-
>T : Symbol(T, Decl(callOfConditionalTypeWithConcreteBranches.ts, 19, 8))
58-
>T : Symbol(T, Decl(callOfConditionalTypeWithConcreteBranches.ts, 19, 8))
59-
>cb : Symbol(cb, Decl(callOfConditionalTypeWithConcreteBranches.ts, 19, 33))
60-
>n : Symbol(n, Decl(callOfConditionalTypeWithConcreteBranches.ts, 19, 38))
58+
>T : Symbol(T, Decl(callOfConditionalTypeWithConcreteBranches.ts, 20, 8))
59+
>T : Symbol(T, Decl(callOfConditionalTypeWithConcreteBranches.ts, 20, 8))
60+
>cb : Symbol(cb, Decl(callOfConditionalTypeWithConcreteBranches.ts, 20, 33))
61+
>n : Symbol(n, Decl(callOfConditionalTypeWithConcreteBranches.ts, 20, 38))
6162

6263
function fn2<T>(arg: Q2<T>) {
63-
>fn2 : Symbol(fn2, Decl(callOfConditionalTypeWithConcreteBranches.ts, 19, 74))
64-
>T : Symbol(T, Decl(callOfConditionalTypeWithConcreteBranches.ts, 20, 13))
65-
>arg : Symbol(arg, Decl(callOfConditionalTypeWithConcreteBranches.ts, 20, 16))
64+
>fn2 : Symbol(fn2, Decl(callOfConditionalTypeWithConcreteBranches.ts, 20, 74))
65+
>T : Symbol(T, Decl(callOfConditionalTypeWithConcreteBranches.ts, 21, 13))
66+
>arg : Symbol(arg, Decl(callOfConditionalTypeWithConcreteBranches.ts, 21, 16))
6667
>Q2 : Symbol(Q2, Decl(callOfConditionalTypeWithConcreteBranches.ts, 17, 7))
67-
>T : Symbol(T, Decl(callOfConditionalTypeWithConcreteBranches.ts, 20, 13))
68+
>T : Symbol(T, Decl(callOfConditionalTypeWithConcreteBranches.ts, 21, 13))
6869

6970
function useT(_arg: T): void {}
70-
>useT : Symbol(useT, Decl(callOfConditionalTypeWithConcreteBranches.ts, 20, 29))
71-
>_arg : Symbol(_arg, Decl(callOfConditionalTypeWithConcreteBranches.ts, 21, 16))
72-
>T : Symbol(T, Decl(callOfConditionalTypeWithConcreteBranches.ts, 20, 13))
71+
>useT : Symbol(useT, Decl(callOfConditionalTypeWithConcreteBranches.ts, 21, 29))
72+
>_arg : Symbol(_arg, Decl(callOfConditionalTypeWithConcreteBranches.ts, 22, 16))
73+
>T : Symbol(T, Decl(callOfConditionalTypeWithConcreteBranches.ts, 21, 13))
7374

7475
// Expected: OK
7576
arg(arg => useT(arg));
76-
>arg : Symbol(arg, Decl(callOfConditionalTypeWithConcreteBranches.ts, 20, 16))
77-
>arg : Symbol(arg, Decl(callOfConditionalTypeWithConcreteBranches.ts, 23, 6))
78-
>useT : Symbol(useT, Decl(callOfConditionalTypeWithConcreteBranches.ts, 20, 29))
79-
>arg : Symbol(arg, Decl(callOfConditionalTypeWithConcreteBranches.ts, 23, 6))
77+
>arg : Symbol(arg, Decl(callOfConditionalTypeWithConcreteBranches.ts, 21, 16))
78+
>arg : Symbol(arg, Decl(callOfConditionalTypeWithConcreteBranches.ts, 24, 6))
79+
>useT : Symbol(useT, Decl(callOfConditionalTypeWithConcreteBranches.ts, 21, 29))
80+
>arg : Symbol(arg, Decl(callOfConditionalTypeWithConcreteBranches.ts, 24, 6))
8081
}
8182
// Legal invocations are not problematic
8283
fn2<string | number>(m => m(42));
83-
>fn2 : Symbol(fn2, Decl(callOfConditionalTypeWithConcreteBranches.ts, 19, 74))
84-
>m : Symbol(m, Decl(callOfConditionalTypeWithConcreteBranches.ts, 26, 21))
85-
>m : Symbol(m, Decl(callOfConditionalTypeWithConcreteBranches.ts, 26, 21))
84+
>fn2 : Symbol(fn2, Decl(callOfConditionalTypeWithConcreteBranches.ts, 20, 74))
85+
>m : Symbol(m, Decl(callOfConditionalTypeWithConcreteBranches.ts, 27, 21))
86+
>m : Symbol(m, Decl(callOfConditionalTypeWithConcreteBranches.ts, 27, 21))
8687

8788
fn2<number>(m => m(42));
88-
>fn2 : Symbol(fn2, Decl(callOfConditionalTypeWithConcreteBranches.ts, 19, 74))
89-
>m : Symbol(m, Decl(callOfConditionalTypeWithConcreteBranches.ts, 27, 12))
90-
>m : Symbol(m, Decl(callOfConditionalTypeWithConcreteBranches.ts, 27, 12))
89+
>fn2 : Symbol(fn2, Decl(callOfConditionalTypeWithConcreteBranches.ts, 20, 74))
90+
>m : Symbol(m, Decl(callOfConditionalTypeWithConcreteBranches.ts, 28, 12))
91+
>m : Symbol(m, Decl(callOfConditionalTypeWithConcreteBranches.ts, 28, 12))
92+
93+
// webidl-conversions example where substituion must occur, despite contravariance of the position
94+
// due to the invariant usage in `Parameters`
95+
96+
type X<V> = V extends (...args: any[]) => any ? (...args: Parameters<V>) => void : Function;
97+
>X : Symbol(X, Decl(callOfConditionalTypeWithConcreteBranches.ts, 28, 24))
98+
>V : Symbol(V, Decl(callOfConditionalTypeWithConcreteBranches.ts, 33, 7))
99+
>V : Symbol(V, Decl(callOfConditionalTypeWithConcreteBranches.ts, 33, 7))
100+
>args : Symbol(args, Decl(callOfConditionalTypeWithConcreteBranches.ts, 33, 23))
101+
>args : Symbol(args, Decl(callOfConditionalTypeWithConcreteBranches.ts, 33, 49))
102+
>Parameters : Symbol(Parameters, Decl(lib.es5.d.ts, --, --))
103+
>V : Symbol(V, Decl(callOfConditionalTypeWithConcreteBranches.ts, 33, 7))
104+
>Function : Symbol(Function, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --))
91105

tests/baselines/reference/callOfConditionalTypeWithConcreteBranches.types

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ type ExtractParameters<T> = "parameters" extends keyof T
4646
}[keyof T["parameters"]]
4747
: {};
4848

49+
// Original example, but with inverted variance
4950
type Q2<T> = number extends T ? (cb: (n: number) => void) => void : never;
5051
>Q2 : Q2<T>
5152
>cb : (n: number) => void
@@ -88,3 +89,11 @@ fn2<number>(m => m(42));
8889
>m : (n: number) => void
8990
>42 : 42
9091

92+
// webidl-conversions example where substituion must occur, despite contravariance of the position
93+
// due to the invariant usage in `Parameters`
94+
95+
type X<V> = V extends (...args: any[]) => any ? (...args: Parameters<V>) => void : Function;
96+
>X : X<V>
97+
>args : any[]
98+
>args : Parameters<V>
99+

tests/cases/compiler/callOfConditionalTypeWithConcreteBranches.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,3 +27,8 @@ function fn2<T>(arg: Q2<T>) {
2727
// Legal invocations are not problematic
2828
fn2<string | number>(m => m(42));
2929
fn2<number>(m => m(42));
30+
31+
// webidl-conversions example where substituion must occur, despite contravariance of the position
32+
// due to the invariant usage in `Parameters`
33+
34+
type X<V> = V extends (...args: any[]) => any ? (...args: Parameters<V>) => void : Function;

0 commit comments

Comments
 (0)