Skip to content

Do not erase signature constraints when calculating variance #55864

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

Draft
wants to merge 4 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
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
2 changes: 1 addition & 1 deletion src/compiler/checker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22914,7 +22914,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
// of the much more expensive N * M comparison matrix we explore below. We erase type parameters
// as they are known to always be the same.
for (let i = 0; i < targetSignatures.length; i++) {
const related = signatureRelatedTo(sourceSignatures[i], targetSignatures[i], /*erase*/ true, reportErrors, intersectionState, incompatibleReporter(sourceSignatures[i], targetSignatures[i]));
const related = signatureRelatedTo(sourceSignatures[i], targetSignatures[i], /*erase*/ !inVarianceComputation, reportErrors, intersectionState, incompatibleReporter(sourceSignatures[i], targetSignatures[i]));
if (!related) {
return Ternary.False;
}
Expand Down
4 changes: 2 additions & 2 deletions src/compiler/corePublic.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,11 @@ export interface MapLike<T> {
[index: string]: T;
}

export interface SortedReadonlyArray<T> extends ReadonlyArray<T> {
export interface SortedReadonlyArray<out T> extends ReadonlyArray<T> {
" __sortedArrayBrand": any;
}

export interface SortedArray<T> extends Array<T> {
export interface SortedArray<out T> extends Array<T> {
" __sortedArrayBrand": any;
}

Expand Down
4 changes: 2 additions & 2 deletions src/compiler/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1535,12 +1535,12 @@ export type HasContainerFlags =
| IsObjectLiteralOrClassExpressionMethodOrAccessor;

/** @internal */
export interface MutableNodeArray<T extends Node> extends Array<T>, TextRange {
export interface MutableNodeArray<out T extends Node> extends Array<T>, TextRange {
hasTrailingComma: boolean;
/** @internal */ transformFlags: TransformFlags; // Flags for transforms, possibly undefined
}

export interface NodeArray<T extends Node> extends ReadonlyArray<T>, ReadonlyTextRange {
export interface NodeArray<out T extends Node> extends ReadonlyArray<T>, ReadonlyTextRange {
readonly hasTrailingComma: boolean;
/** @internal */ transformFlags: TransformFlags; // Flags for transforms, possibly undefined
}
Expand Down
6 changes: 3 additions & 3 deletions tests/baselines/reference/api/typescript.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4145,10 +4145,10 @@ declare namespace ts {
interface MapLike<T> {
[index: string]: T;
}
interface SortedReadonlyArray<T> extends ReadonlyArray<T> {
interface SortedReadonlyArray<out T> extends ReadonlyArray<T> {
" __sortedArrayBrand": any;
}
interface SortedArray<T> extends Array<T> {
interface SortedArray<out T> extends Array<T> {
" __sortedArrayBrand": any;
}
type Path = string & {
Expand Down Expand Up @@ -4889,7 +4889,7 @@ declare namespace ts {
type HasExpressionInitializer = VariableDeclaration | ParameterDeclaration | BindingElement | PropertyDeclaration | PropertyAssignment | EnumMember;
type HasDecorators = ParameterDeclaration | PropertyDeclaration | MethodDeclaration | GetAccessorDeclaration | SetAccessorDeclaration | ClassExpression | ClassDeclaration;
type HasModifiers = TypeParameterDeclaration | ParameterDeclaration | ConstructorTypeNode | PropertySignature | PropertyDeclaration | MethodSignature | MethodDeclaration | ConstructorDeclaration | GetAccessorDeclaration | SetAccessorDeclaration | IndexSignatureDeclaration | FunctionExpression | ArrowFunction | ClassExpression | VariableStatement | FunctionDeclaration | ClassDeclaration | InterfaceDeclaration | TypeAliasDeclaration | EnumDeclaration | ModuleDeclaration | ImportEqualsDeclaration | ImportDeclaration | ExportAssignment | ExportDeclaration;
interface NodeArray<T extends Node> extends ReadonlyArray<T>, ReadonlyTextRange {
interface NodeArray<out T extends Node> extends ReadonlyArray<T>, ReadonlyTextRange {
readonly hasTrailingComma: boolean;
}
interface Token<TKind extends SyntaxKind> extends Node {
Expand Down
19 changes: 18 additions & 1 deletion tests/baselines/reference/complexRecursiveCollections.errors.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1,11 @@
immutable.ts(305,22): error TS2430: Interface 'Set<T>' incorrectly extends interface 'Seq<never, T>'.
The types of 'map(...).filter(...).concat(...).toMap().toSeq().toOrderedMap().keySeq().toMap().mapKeys(...).toSeq().toOrderedMap().toSet().union' are incompatible between these types.
Type '(...collections: (never[] | Collection<any, never>)[]) => Set<never>' is not assignable to type '(...collections: (any[] | Collection<any, any>)[]) => Set<any>'.
Types of parameters 'collections' and 'collections' are incompatible.
Type 'any[] | Collection<any, any>' is not assignable to type 'never[] | Collection<any, never>'.
Type 'any[]' is not assignable to type 'never[] | Collection<any, never>'.
Type 'any[]' is not assignable to type 'never[]'.
Type 'any' is not assignable to type 'never'.
immutable.ts(341,22): error TS2430: Interface 'Keyed<K, V>' incorrectly extends interface 'Collection<K, V>'.
The types returned by 'toSeq()' are incompatible between these types.
Type 'Keyed<K, V>' is not assignable to type 'this'.
Expand Down Expand Up @@ -33,7 +41,7 @@ immutable.ts(391,22): error TS2430: Interface 'Set<T>' incorrectly extends inter
flatMap<M>(mapper: (value: T, key: void, iter: this) => Ara<M>, context?: any): N2<M>;
toSeq(): N2<T>;
}
==== immutable.ts (3 errors) ====
==== immutable.ts (4 errors) ====
// Test that complex recursive collections can pass the `extends` assignability check without
// running out of memory. This bug was exposed in Typescript 2.4 when more generic signatures
// started being checked.
Expand Down Expand Up @@ -339,6 +347,15 @@ immutable.ts(391,22): error TS2430: Interface 'Set<T>' incorrectly extends inter
export function Set<T>(): Seq.Set<T>;
export function Set<T>(collection: Iterable<T>): Seq.Set<T>;
export interface Set<T> extends Seq<never, T>, Collection.Set<T> {
~~~
!!! error TS2430: Interface 'Set<T>' incorrectly extends interface 'Seq<never, T>'.
!!! error TS2430: The types of 'map(...).filter(...).concat(...).toMap().toSeq().toOrderedMap().keySeq().toMap().mapKeys(...).toSeq().toOrderedMap().toSet().union' are incompatible between these types.
Copy link
Member

Choose a reason for hiding this comment

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

😵

Copy link
Member Author

Choose a reason for hiding this comment

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

We go hard at finding the incompatibility, don't we. 😆

Guess there's an any somewhere in this type definition that should be a never (or vice-versa, depending on intent).

!!! error TS2430: Type '(...collections: (never[] | Collection<any, never>)[]) => Set<never>' is not assignable to type '(...collections: (any[] | Collection<any, any>)[]) => Set<any>'.
!!! error TS2430: Types of parameters 'collections' and 'collections' are incompatible.
!!! error TS2430: Type 'any[] | Collection<any, any>' is not assignable to type 'never[] | Collection<any, never>'.
!!! error TS2430: Type 'any[]' is not assignable to type 'never[] | Collection<any, never>'.
!!! error TS2430: Type 'any[]' is not assignable to type 'never[]'.
!!! error TS2430: Type 'any' is not assignable to type 'never'.
toJS(): Array<any>;
toJSON(): Array<T>;
toSeq(): this;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1139,7 +1139,7 @@ declare module Immutable {
>Seq : typeof Seq

function isSeq(maybeSeq: any): maybeSeq is Seq.Indexed<any> | Seq.Keyed<any, any>;
>isSeq : (maybeSeq: any) => maybeSeq is Indexed<any> | Keyed<any, any>
>isSeq : (maybeSeq: any) => maybeSeq is Keyed<any, any> | Indexed<any>
>maybeSeq : any
>Seq : any
>Seq : any
Expand Down
19 changes: 18 additions & 1 deletion tests/baselines/reference/conditionalTypes2.errors.txt
Original file line number Diff line number Diff line change
Expand Up @@ -33,9 +33,16 @@ conditionalTypes2.ts(74,12): error TS2345: Argument of type 'Extract<T, Foo & Ba
conditionalTypes2.ts(75,12): error TS2345: Argument of type 'Extract2<T, Foo, Bar>' is not assignable to parameter of type '{ foo: string; bat: string; }'.
Type 'T extends Bar ? T : never' 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; }'.
conditionalTypes2.ts(91,5): error TS2416: Property 'tail' in type 'Vector<T>' is not assignable to the same property in base type 'Seq<T>'.
Type '() => Opt<Vector<T>>' is not assignable to type '() => Opt<Seq<T>>'.
Call signature return types 'Opt<Vector<T>>' and 'Opt<Seq<T>>' are incompatible.
The types returned by 'toVector().tail().toVector()' are incompatible between these types.
Type 'Vector<Vector<Vector<T>>>' is not assignable to type 'Vector<Vector<Seq<T>>>'.
Type 'Vector<Seq<T>>' is not assignable to type 'Vector<Vector<T>>'.
conditionalTypes2.ts(94,5): error TS2394: This overload signature is not compatible with its implementation signature.


==== conditionalTypes2.ts (7 errors) ====
==== conditionalTypes2.ts (9 errors) ====
interface Covariant<T> {
foo: T extends string ? T : number;
}
Expand Down Expand Up @@ -177,9 +184,19 @@ conditionalTypes2.ts(75,12): error TS2345: Argument of type 'Extract2<T, Foo, Ba

class Vector<T> implements Seq<T> {
tail(): Opt<Vector<T>> {
~~~~
!!! error TS2416: Property 'tail' in type 'Vector<T>' is not assignable to the same property in base type 'Seq<T>'.
!!! error TS2416: Type '() => Opt<Vector<T>>' is not assignable to type '() => Opt<Seq<T>>'.
!!! error TS2416: Call signature return types 'Opt<Vector<T>>' and 'Opt<Seq<T>>' are incompatible.
!!! error TS2416: The types returned by 'toVector().tail().toVector()' are incompatible between these types.
!!! error TS2416: Type 'Vector<Vector<Vector<T>>>' is not assignable to type 'Vector<Vector<Seq<T>>>'.
!!! error TS2416: Type 'Vector<Seq<T>>' is not assignable to type 'Vector<Vector<T>>'.
return <any>undefined;
}
partition2<U extends T>(predicate:(v:T)=>v is U): [Vector<U>,Vector<Exclude<T, U>>];
~~~~~~~~~~
!!! error TS2394: This overload signature is not compatible with its implementation signature.
!!! related TS2750 conditionalTypes2.ts:96:5: The implementation signature is declared here.
partition2(predicate:(x:T)=>boolean): [Vector<T>,Vector<T>];
partition2<U extends T>(predicate:(v:T)=>boolean): [Vector<U>,Vector<any>] {
return <any>undefined;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
genericSignaturesConstrainedToDifferingGenericsNotCompatible.ts(9,5): error TS2322: Type 'Fn<T2>' is not assignable to type 'Fn<T1>'.
Type 'T1' is not assignable to type 'T2'.
'T2' could be instantiated with an arbitrary type which could be unrelated to 'T1'.
genericSignaturesConstrainedToDifferingGenericsNotCompatible.ts(10,5): error TS2322: Type 'Fn<T1>' is not assignable to type 'Fn<T2>'.
Type 'T2' is not assignable to type 'T1'.
'T1' could be instantiated with an arbitrary type which could be unrelated to 'T2'.
genericSignaturesConstrainedToDifferingGenericsNotCompatible.ts(12,5): error TS2322: Type 'Concrete2' is not assignable to type 'Concrete1'.
Types of parameters 'x' and 'x' are incompatible.
Type 'U' is not assignable to type 'string'.
Type 'number' is not assignable to type 'string'.
genericSignaturesConstrainedToDifferingGenericsNotCompatible.ts(13,5): error TS2322: Type 'Concrete1' is not assignable to type 'Concrete2'.
Types of parameters 'x' and 'x' are incompatible.
Type 'U' is not assignable to type 'number'.
Type 'string' is not assignable to type 'number'.
genericSignaturesConstrainedToDifferingGenericsNotCompatible.ts(15,5): error TS2322: Type 'Concrete1' is not assignable to type 'Fn<T1>'.
Types of parameters 'x' and 'x' are incompatible.
Type 'U' is not assignable to type 'number'.
Type 'T1' is not assignable to type 'number'.
genericSignaturesConstrainedToDifferingGenericsNotCompatible.ts(16,5): error TS2322: Type 'Fn<T1>' is not assignable to type 'Concrete1'.
Types of parameters 'x' and 'x' are incompatible.
Type 'U' is not assignable to type 'T1'.
'T1' could be instantiated with an arbitrary type which could be unrelated to 'U'.


==== genericSignaturesConstrainedToDifferingGenericsNotCompatible.ts (6 errors) ====
type Fn<T> = <U extends T>(x: U) => U;

type Concrete1 = <U extends number>(x: U) => U;
type Concrete2 = <U extends string>(x: U) => U;

function f<T1, T2>(t1: Fn<T1>, t2: Fn<T2>, c1: Concrete1, c2: Concrete2) {
// every single one of these assignments should error

t1 = t2;
~~
!!! error TS2322: Type 'Fn<T2>' is not assignable to type 'Fn<T1>'.
!!! error TS2322: Type 'T1' is not assignable to type 'T2'.
!!! error TS2322: 'T2' could be instantiated with an arbitrary type which could be unrelated to 'T1'.
!!! related TS2208 genericSignaturesConstrainedToDifferingGenericsNotCompatible.ts:6:12: This type parameter might need an `extends T2` constraint.
t2 = t1;
~~
!!! error TS2322: Type 'Fn<T1>' is not assignable to type 'Fn<T2>'.
!!! error TS2322: Type 'T2' is not assignable to type 'T1'.
!!! error TS2322: 'T1' could be instantiated with an arbitrary type which could be unrelated to 'T2'.
!!! related TS2208 genericSignaturesConstrainedToDifferingGenericsNotCompatible.ts:6:16: This type parameter might need an `extends T1` constraint.

c1 = c2;
~~
!!! error TS2322: Type 'Concrete2' is not assignable to type 'Concrete1'.
!!! error TS2322: Types of parameters 'x' and 'x' are incompatible.
!!! error TS2322: Type 'U' is not assignable to type 'string'.
!!! error TS2322: Type 'number' is not assignable to type 'string'.
c2 = c1;
~~
!!! error TS2322: Type 'Concrete1' is not assignable to type 'Concrete2'.
!!! error TS2322: Types of parameters 'x' and 'x' are incompatible.
!!! error TS2322: Type 'U' is not assignable to type 'number'.
!!! error TS2322: Type 'string' is not assignable to type 'number'.

t1 = c1;
~~
!!! error TS2322: Type 'Concrete1' is not assignable to type 'Fn<T1>'.
!!! error TS2322: Types of parameters 'x' and 'x' are incompatible.
!!! error TS2322: Type 'U' is not assignable to type 'number'.
!!! error TS2322: Type 'T1' is not assignable to type 'number'.
!!! related TS2208 genericSignaturesConstrainedToDifferingGenericsNotCompatible.ts:6:12: This type parameter might need an `extends number` constraint.
c1 = t1;
~~
!!! error TS2322: Type 'Fn<T1>' is not assignable to type 'Concrete1'.
!!! error TS2322: Types of parameters 'x' and 'x' are incompatible.
!!! error TS2322: Type 'U' is not assignable to type 'T1'.
!!! error TS2322: 'T1' could be instantiated with an arbitrary type which could be unrelated to 'U'.
}

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

//// [genericSignaturesConstrainedToDifferingGenericsNotCompatible.ts]
type Fn<T> = <U extends T>(x: U) => U;

type Concrete1 = <U extends number>(x: U) => U;
type Concrete2 = <U extends string>(x: U) => U;

function f<T1, T2>(t1: Fn<T1>, t2: Fn<T2>, c1: Concrete1, c2: Concrete2) {
// every single one of these assignments should error

t1 = t2;
t2 = t1;

c1 = c2;
c2 = c1;

t1 = c1;
c1 = t1;
}


//// [genericSignaturesConstrainedToDifferingGenericsNotCompatible.js]
"use strict";
function f(t1, t2, c1, c2) {
// every single one of these assignments should error
t1 = t2;
t2 = t1;
c1 = c2;
c2 = c1;
t1 = c1;
c1 = t1;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
//// [tests/cases/compiler/genericSignaturesConstrainedToDifferingGenericsNotCompatible.ts] ////

=== genericSignaturesConstrainedToDifferingGenericsNotCompatible.ts ===
type Fn<T> = <U extends T>(x: U) => U;
>Fn : Symbol(Fn, Decl(genericSignaturesConstrainedToDifferingGenericsNotCompatible.ts, 0, 0))
>T : Symbol(T, Decl(genericSignaturesConstrainedToDifferingGenericsNotCompatible.ts, 0, 8))
>U : Symbol(U, Decl(genericSignaturesConstrainedToDifferingGenericsNotCompatible.ts, 0, 14))
>T : Symbol(T, Decl(genericSignaturesConstrainedToDifferingGenericsNotCompatible.ts, 0, 8))
>x : Symbol(x, Decl(genericSignaturesConstrainedToDifferingGenericsNotCompatible.ts, 0, 27))
>U : Symbol(U, Decl(genericSignaturesConstrainedToDifferingGenericsNotCompatible.ts, 0, 14))
>U : Symbol(U, Decl(genericSignaturesConstrainedToDifferingGenericsNotCompatible.ts, 0, 14))

type Concrete1 = <U extends number>(x: U) => U;
>Concrete1 : Symbol(Concrete1, Decl(genericSignaturesConstrainedToDifferingGenericsNotCompatible.ts, 0, 38))
>U : Symbol(U, Decl(genericSignaturesConstrainedToDifferingGenericsNotCompatible.ts, 2, 18))
>x : Symbol(x, Decl(genericSignaturesConstrainedToDifferingGenericsNotCompatible.ts, 2, 36))
>U : Symbol(U, Decl(genericSignaturesConstrainedToDifferingGenericsNotCompatible.ts, 2, 18))
>U : Symbol(U, Decl(genericSignaturesConstrainedToDifferingGenericsNotCompatible.ts, 2, 18))

type Concrete2 = <U extends string>(x: U) => U;
>Concrete2 : Symbol(Concrete2, Decl(genericSignaturesConstrainedToDifferingGenericsNotCompatible.ts, 2, 47))
>U : Symbol(U, Decl(genericSignaturesConstrainedToDifferingGenericsNotCompatible.ts, 3, 18))
>x : Symbol(x, Decl(genericSignaturesConstrainedToDifferingGenericsNotCompatible.ts, 3, 36))
>U : Symbol(U, Decl(genericSignaturesConstrainedToDifferingGenericsNotCompatible.ts, 3, 18))
>U : Symbol(U, Decl(genericSignaturesConstrainedToDifferingGenericsNotCompatible.ts, 3, 18))

function f<T1, T2>(t1: Fn<T1>, t2: Fn<T2>, c1: Concrete1, c2: Concrete2) {
>f : Symbol(f, Decl(genericSignaturesConstrainedToDifferingGenericsNotCompatible.ts, 3, 47))
>T1 : Symbol(T1, Decl(genericSignaturesConstrainedToDifferingGenericsNotCompatible.ts, 5, 11))
>T2 : Symbol(T2, Decl(genericSignaturesConstrainedToDifferingGenericsNotCompatible.ts, 5, 14))
>t1 : Symbol(t1, Decl(genericSignaturesConstrainedToDifferingGenericsNotCompatible.ts, 5, 19))
>Fn : Symbol(Fn, Decl(genericSignaturesConstrainedToDifferingGenericsNotCompatible.ts, 0, 0))
>T1 : Symbol(T1, Decl(genericSignaturesConstrainedToDifferingGenericsNotCompatible.ts, 5, 11))
>t2 : Symbol(t2, Decl(genericSignaturesConstrainedToDifferingGenericsNotCompatible.ts, 5, 30))
>Fn : Symbol(Fn, Decl(genericSignaturesConstrainedToDifferingGenericsNotCompatible.ts, 0, 0))
>T2 : Symbol(T2, Decl(genericSignaturesConstrainedToDifferingGenericsNotCompatible.ts, 5, 14))
>c1 : Symbol(c1, Decl(genericSignaturesConstrainedToDifferingGenericsNotCompatible.ts, 5, 42))
>Concrete1 : Symbol(Concrete1, Decl(genericSignaturesConstrainedToDifferingGenericsNotCompatible.ts, 0, 38))
>c2 : Symbol(c2, Decl(genericSignaturesConstrainedToDifferingGenericsNotCompatible.ts, 5, 57))
>Concrete2 : Symbol(Concrete2, Decl(genericSignaturesConstrainedToDifferingGenericsNotCompatible.ts, 2, 47))

// every single one of these assignments should error

t1 = t2;
>t1 : Symbol(t1, Decl(genericSignaturesConstrainedToDifferingGenericsNotCompatible.ts, 5, 19))
>t2 : Symbol(t2, Decl(genericSignaturesConstrainedToDifferingGenericsNotCompatible.ts, 5, 30))

t2 = t1;
>t2 : Symbol(t2, Decl(genericSignaturesConstrainedToDifferingGenericsNotCompatible.ts, 5, 30))
>t1 : Symbol(t1, Decl(genericSignaturesConstrainedToDifferingGenericsNotCompatible.ts, 5, 19))

c1 = c2;
>c1 : Symbol(c1, Decl(genericSignaturesConstrainedToDifferingGenericsNotCompatible.ts, 5, 42))
>c2 : Symbol(c2, Decl(genericSignaturesConstrainedToDifferingGenericsNotCompatible.ts, 5, 57))

c2 = c1;
>c2 : Symbol(c2, Decl(genericSignaturesConstrainedToDifferingGenericsNotCompatible.ts, 5, 57))
>c1 : Symbol(c1, Decl(genericSignaturesConstrainedToDifferingGenericsNotCompatible.ts, 5, 42))

t1 = c1;
>t1 : Symbol(t1, Decl(genericSignaturesConstrainedToDifferingGenericsNotCompatible.ts, 5, 19))
>c1 : Symbol(c1, Decl(genericSignaturesConstrainedToDifferingGenericsNotCompatible.ts, 5, 42))

c1 = t1;
>c1 : Symbol(c1, Decl(genericSignaturesConstrainedToDifferingGenericsNotCompatible.ts, 5, 42))
>t1 : Symbol(t1, Decl(genericSignaturesConstrainedToDifferingGenericsNotCompatible.ts, 5, 19))
}

Loading