Skip to content

Commit 13c08ab

Browse files
authored
Use identity with the permissive instantation to detect nongenric instances and disable variance probing on nongeneric instances (#29981)
* Use identity with the restrictive instantation to detect nongenric instances and disable variance probing on nongeneric instances * Generalize to also include interfaces, add test case, still perform argument comparisons for postive comparisons if possible * Actually accept baselines, lol * Reduce deep nesting limit just a bit so yargs still builds * Handle circular identities in isNonGeneric * Use a simple traversal of the types rather than the restrictive instantiation * Cache the bits using an existing field to further reduce any time nongeneric check takes * Revert to using an existing mapper, use permissive > restrictive * Revert constant change * And revert the comment, too
1 parent 0d93eb9 commit 13c08ab

18 files changed

+430
-294
lines changed

src/compiler/checker.ts

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12822,20 +12822,30 @@ namespace ts {
1282212822
}
1282312823
return Ternary.False;
1282412824

12825+
function isNonGeneric(type: Type) {
12826+
// If we're already in identity relationship checking, we should use `isRelatedTo`
12827+
// to catch the `Maybe` from an excessively deep type (which we then assume means
12828+
// that the type could possibly contain a generic)
12829+
if (relation === identityRelation) {
12830+
return isRelatedTo(type, getPermissiveInstantiation(type)) === Ternary.True;
12831+
}
12832+
return isTypeIdenticalTo(type, getPermissiveInstantiation(type));
12833+
}
12834+
1282512835
function relateVariances(sourceTypeArguments: ReadonlyArray<Type> | undefined, targetTypeArguments: ReadonlyArray<Type> | undefined, variances: Variance[]) {
1282612836
if (result = typeArgumentsRelatedTo(sourceTypeArguments, targetTypeArguments, variances, reportErrors)) {
1282712837
return result;
1282812838
}
12829-
const isCovariantVoid = targetTypeArguments && hasCovariantVoidArgument(targetTypeArguments, variances);
12830-
varianceCheckFailed = !isCovariantVoid;
12839+
const allowStructuralFallback = (targetTypeArguments && hasCovariantVoidArgument(targetTypeArguments, variances)) || isNonGeneric(source) || isNonGeneric(target);
12840+
varianceCheckFailed = !allowStructuralFallback;
1283112841
// The type arguments did not relate appropriately, but it may be because we have no variance
1283212842
// information (in which case typeArgumentsRelatedTo defaulted to covariance for all type
1283312843
// arguments). It might also be the case that the target type has a 'void' type argument for
1283412844
// a covariant type parameter that is only used in return positions within the generic type
1283512845
// (in which case any type argument is permitted on the source side). In those cases we proceed
1283612846
// with a structural comparison. Otherwise, we know for certain the instantiations aren't
1283712847
// related and we can return here.
12838-
if (variances !== emptyArray && !isCovariantVoid) {
12848+
if (variances !== emptyArray && !allowStructuralFallback) {
1283912849
// In some cases generic types that are covariant in regular type checking mode become
1284012850
// invariant in --strictFunctionTypes mode because one or more type parameters are used in
1284112851
// both co- and contravariant positions. In order to make it easier to diagnose *why* such

tests/baselines/reference/checkInfiniteExpansionTermination.errors.txt

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

tests/baselines/reference/invariantGenericErrorElaboration.errors.txt

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

tests/baselines/reference/invariantGenericErrorElaboration.types

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,8 @@ const wat: Runtype<any> = Num;
66
>Num : Num
77

88
const Foo = Obj({ foo: Num })
9-
>Foo : any
10-
>Obj({ foo: Num }) : any
9+
>Foo : Obj<{ foo: Num; }>
10+
>Obj({ foo: Num }) : Obj<{ foo: Num; }>
1111
>Obj : <O extends { [_: string]: Runtype<any>; }>(fields: O) => Obj<O>
1212
>{ foo: Num } : { foo: Num; }
1313
>foo : Num

tests/baselines/reference/mappedTypeRelationships.errors.txt

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -34,9 +34,7 @@ tests/cases/conformance/types/mapped/mappedTypeRelationships.ts(66,5): error TS2
3434
tests/cases/conformance/types/mapped/mappedTypeRelationships.ts(66,5): error TS2542: Index signature in type 'Readonly<U>' only permits reading.
3535
tests/cases/conformance/types/mapped/mappedTypeRelationships.ts(72,5): error TS2322: Type 'Partial<T>' is not assignable to type 'T'.
3636
tests/cases/conformance/types/mapped/mappedTypeRelationships.ts(78,5): error TS2322: Type 'Partial<Thing>' is not assignable to type 'Partial<T>'.
37-
Type 'Thing' is not assignable to type 'T'.
3837
tests/cases/conformance/types/mapped/mappedTypeRelationships.ts(88,5): error TS2322: Type 'Readonly<Thing>' is not assignable to type 'Readonly<T>'.
39-
Type 'Thing' is not assignable to type 'T'.
4038
tests/cases/conformance/types/mapped/mappedTypeRelationships.ts(127,5): error TS2322: Type 'Partial<U>' is not assignable to type 'Identity<U>'.
4139
tests/cases/conformance/types/mapped/mappedTypeRelationships.ts(143,5): error TS2322: Type '{ [P in keyof T]: T[P]; }' is not assignable to type '{ [P in keyof T]: U[P]; }'.
4240
Type 'T[P]' is not assignable to type 'U[P]'.
@@ -199,7 +197,6 @@ tests/cases/conformance/types/mapped/mappedTypeRelationships.ts(168,5): error TS
199197
y = x; // Error
200198
~
201199
!!! error TS2322: Type 'Partial<Thing>' is not assignable to type 'Partial<T>'.
202-
!!! error TS2322: Type 'Thing' is not assignable to type 'T'.
203200
}
204201

205202
function f40<T>(x: T, y: Readonly<T>) {
@@ -212,7 +209,6 @@ tests/cases/conformance/types/mapped/mappedTypeRelationships.ts(168,5): error TS
212209
y = x; // Error
213210
~
214211
!!! error TS2322: Type 'Readonly<Thing>' is not assignable to type 'Readonly<T>'.
215-
!!! error TS2322: Type 'Thing' is not assignable to type 'T'.
216212
}
217213

218214
type Item = {
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
//// [nongenericPartialInstantiationsRelatedInBothDirections.ts]
2+
interface Foo {
3+
a: number;
4+
b: number;
5+
bar: string;
6+
}
7+
interface ObjectContaining<T> {
8+
new (sample: Partial<T>): Partial<T>
9+
}
10+
declare let cafoo: ObjectContaining<{ a: number, foo: number }>;
11+
declare let cfoo: ObjectContaining<Foo>;
12+
cfoo = cafoo;
13+
cafoo = cfoo;
14+
15+
16+
//// [nongenericPartialInstantiationsRelatedInBothDirections.js]
17+
cfoo = cafoo;
18+
cafoo = cfoo;
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
=== tests/cases/compiler/nongenericPartialInstantiationsRelatedInBothDirections.ts ===
2+
interface Foo {
3+
>Foo : Symbol(Foo, Decl(nongenericPartialInstantiationsRelatedInBothDirections.ts, 0, 0))
4+
5+
a: number;
6+
>a : Symbol(Foo.a, Decl(nongenericPartialInstantiationsRelatedInBothDirections.ts, 0, 15))
7+
8+
b: number;
9+
>b : Symbol(Foo.b, Decl(nongenericPartialInstantiationsRelatedInBothDirections.ts, 1, 14))
10+
11+
bar: string;
12+
>bar : Symbol(Foo.bar, Decl(nongenericPartialInstantiationsRelatedInBothDirections.ts, 2, 14))
13+
}
14+
interface ObjectContaining<T> {
15+
>ObjectContaining : Symbol(ObjectContaining, Decl(nongenericPartialInstantiationsRelatedInBothDirections.ts, 4, 1))
16+
>T : Symbol(T, Decl(nongenericPartialInstantiationsRelatedInBothDirections.ts, 5, 27))
17+
18+
new (sample: Partial<T>): Partial<T>
19+
>sample : Symbol(sample, Decl(nongenericPartialInstantiationsRelatedInBothDirections.ts, 6, 7))
20+
>Partial : Symbol(Partial, Decl(lib.es5.d.ts, --, --))
21+
>T : Symbol(T, Decl(nongenericPartialInstantiationsRelatedInBothDirections.ts, 5, 27))
22+
>Partial : Symbol(Partial, Decl(lib.es5.d.ts, --, --))
23+
>T : Symbol(T, Decl(nongenericPartialInstantiationsRelatedInBothDirections.ts, 5, 27))
24+
}
25+
declare let cafoo: ObjectContaining<{ a: number, foo: number }>;
26+
>cafoo : Symbol(cafoo, Decl(nongenericPartialInstantiationsRelatedInBothDirections.ts, 8, 11))
27+
>ObjectContaining : Symbol(ObjectContaining, Decl(nongenericPartialInstantiationsRelatedInBothDirections.ts, 4, 1))
28+
>a : Symbol(a, Decl(nongenericPartialInstantiationsRelatedInBothDirections.ts, 8, 37))
29+
>foo : Symbol(foo, Decl(nongenericPartialInstantiationsRelatedInBothDirections.ts, 8, 48))
30+
31+
declare let cfoo: ObjectContaining<Foo>;
32+
>cfoo : Symbol(cfoo, Decl(nongenericPartialInstantiationsRelatedInBothDirections.ts, 9, 11))
33+
>ObjectContaining : Symbol(ObjectContaining, Decl(nongenericPartialInstantiationsRelatedInBothDirections.ts, 4, 1))
34+
>Foo : Symbol(Foo, Decl(nongenericPartialInstantiationsRelatedInBothDirections.ts, 0, 0))
35+
36+
cfoo = cafoo;
37+
>cfoo : Symbol(cfoo, Decl(nongenericPartialInstantiationsRelatedInBothDirections.ts, 9, 11))
38+
>cafoo : Symbol(cafoo, Decl(nongenericPartialInstantiationsRelatedInBothDirections.ts, 8, 11))
39+
40+
cafoo = cfoo;
41+
>cafoo : Symbol(cafoo, Decl(nongenericPartialInstantiationsRelatedInBothDirections.ts, 8, 11))
42+
>cfoo : Symbol(cfoo, Decl(nongenericPartialInstantiationsRelatedInBothDirections.ts, 9, 11))
43+
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
=== tests/cases/compiler/nongenericPartialInstantiationsRelatedInBothDirections.ts ===
2+
interface Foo {
3+
a: number;
4+
>a : number
5+
6+
b: number;
7+
>b : number
8+
9+
bar: string;
10+
>bar : string
11+
}
12+
interface ObjectContaining<T> {
13+
new (sample: Partial<T>): Partial<T>
14+
>sample : Partial<T>
15+
}
16+
declare let cafoo: ObjectContaining<{ a: number, foo: number }>;
17+
>cafoo : ObjectContaining<{ a: number; foo: number; }>
18+
>a : number
19+
>foo : number
20+
21+
declare let cfoo: ObjectContaining<Foo>;
22+
>cfoo : ObjectContaining<Foo>
23+
24+
cfoo = cafoo;
25+
>cfoo = cafoo : ObjectContaining<{ a: number; foo: number; }>
26+
>cfoo : ObjectContaining<Foo>
27+
>cafoo : ObjectContaining<{ a: number; foo: number; }>
28+
29+
cafoo = cfoo;
30+
>cafoo = cfoo : ObjectContaining<Foo>
31+
>cafoo : ObjectContaining<{ a: number; foo: number; }>
32+
>cfoo : ObjectContaining<Foo>
33+

tests/baselines/reference/recursiveTypeComparison.errors.txt

Lines changed: 0 additions & 27 deletions
This file was deleted.
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
//// [specedNoStackBlown.ts]
2+
// Type definitions for spected 0.7
3+
// Project: https://github.com/25th-floor/spected
4+
// Definitions by: Benjamin Makus <https://github.com/benneq>
5+
// Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped
6+
// TypeScript Version: 2.8
7+
8+
declare function spected<ROOTINPUT, SPEC extends SpecValue<ROOTINPUT, ROOTINPUT> = SpecValue<ROOTINPUT, ROOTINPUT>>(spec: SPEC, input: ROOTINPUT): Result<ROOTINPUT, SPEC>;
9+
10+
type Predicate<INPUT, ROOTINPUT> = (value: INPUT, inputs: ROOTINPUT) => boolean;
11+
12+
type ErrorMsg<INPUT> =
13+
| (string | number | boolean | symbol | null | undefined | object)
14+
| ((value: INPUT, field: string) => any);
15+
16+
export type Spec<INPUT, ROOTINPUT = any> = [Predicate<INPUT, ROOTINPUT>, ErrorMsg<INPUT>];
17+
18+
export type SpecArray<INPUT, ROOTINPUT = any> = Array<Spec<INPUT, ROOTINPUT>>;
19+
20+
export type SpecFunction<INPUT, ROOTINPUT = any> = [INPUT] extends [ReadonlyArray<infer U>]
21+
? (value: INPUT) => ReadonlyArray<SpecArray<U, ROOTINPUT>>
22+
: [INPUT] extends [object]
23+
? (value: INPUT) => SpecObject<INPUT, ROOTINPUT>
24+
: (value: INPUT) => SpecArray<INPUT, ROOTINPUT>;
25+
26+
export type SpecObject<INPUT, ROOTINPUT = any> = Partial<{[key in keyof INPUT]: SpecValue<INPUT[key], ROOTINPUT>}>;
27+
28+
export type SpecValue<INPUT, ROOTINPUT = any> = [INPUT] extends [ReadonlyArray<any>]
29+
? SpecArray<INPUT, ROOTINPUT> | SpecFunction<INPUT, ROOTINPUT>
30+
: [INPUT] extends [object]
31+
? SpecArray<INPUT, ROOTINPUT> | SpecFunction<INPUT, ROOTINPUT> | SpecObject<INPUT, ROOTINPUT>
32+
: SpecArray<INPUT, ROOTINPUT> | SpecFunction<INPUT, ROOTINPUT>;
33+
34+
export type Result<INPUT, SPEC> = {[key in keyof INPUT]: true | any[] | Result<INPUT[key], any>};
35+
36+
export default spected;
37+
38+
39+
//// [specedNoStackBlown.js]
40+
"use strict";
41+
// Type definitions for spected 0.7
42+
// Project: https://github.com/25th-floor/spected
43+
// Definitions by: Benjamin Makus <https://github.com/benneq>
44+
// Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped
45+
// TypeScript Version: 2.8
46+
exports.__esModule = true;
47+
exports["default"] = spected;

0 commit comments

Comments
 (0)