Skip to content

Commit

Permalink
Separate unmeasurable from unreliable to reduce the impact of this ch…
Browse files Browse the repository at this point in the history
…ange, for now
  • Loading branch information
weswigham committed Apr 29, 2019
1 parent 093cc72 commit 4e96d98
Show file tree
Hide file tree
Showing 8 changed files with 448 additions and 61 deletions.
92 changes: 48 additions & 44 deletions src/compiler/checker.ts

Large diffs are not rendered by default.

21 changes: 12 additions & 9 deletions src/compiler/types.ts
Expand Up @@ -3735,7 +3735,7 @@ namespace ts {
specifierCache?: Map<string>; // For symbols corresponding to external modules, a cache of incoming path -> module specifier name mappings
extendedContainers?: Symbol[]; // Containers (other than the parent) which this symbol is aliased in
extendedContainersByFile?: Map<Symbol[]>; // Containers (other than the parent) which this symbol is aliased in
variances?: Variance[]; // Alias symbol type argument variance cache
variances?: VarianceFlags[]; // Alias symbol type argument variance cache
}

/* @internal */
Expand Down Expand Up @@ -4131,21 +4131,24 @@ namespace ts {
}

/* @internal */
export const enum Variance {
Invariant = 0, // Neither covariant nor contravariant
Covariant = 1, // Covariant
Contravariant = 2, // Contravariant
Bivariant = 3, // Both covariant and contravariant
Independent = 4, // Unwitnessed type parameter
Unmeasurable = 5, // Variance result is unusable - relationship relies on structural comparisons which are not reflected in generic relationships
export const enum VarianceFlags {
Invariant = 0, // Neither covariant nor contravariant
Covariant = 1 << 0, // Covariant
Contravariant = 1 << 1, // Contravariant
Bivariant = Covariant | Contravariant, // Both covariant and contravariant
Independent = 1 << 2, // Unwitnessed type parameter
VarianceMask = Invariant | Covariant | Contravariant | Independent, // Mask containing all measured variances without the unmeasurable flag
Unmeasurable = 1 << 3, // Variance result is unusable - relationship relies on structural comparisons which are not reflected in generic relationships
Unreliable = 1 << 4, // Variance result is unreliable - relationship relies on structural comparisons which are not reflected in generic relationships
AllowsStructuralFallback = Unmeasurable | Unreliable,
}

// Generic class and interface types
export interface GenericType extends InterfaceType, TypeReference {
/* @internal */
instantiations: Map<TypeReference>; // Generic instantiation cache
/* @internal */
variances?: Variance[]; // Variance of each type parameter
variances?: VarianceFlags[]; // Variance of each type parameter
}

export interface TupleType extends GenericType {
Expand Down
8 changes: 0 additions & 8 deletions tests/baselines/reference/conditionalTypes1.errors.txt
Expand Up @@ -17,12 +17,8 @@ tests/cases/conformance/types/conditional/conditionalTypes1.ts(103,5): error TS2
tests/cases/conformance/types/conditional/conditionalTypes1.ts(104,5): error TS2322: Type 'Pick<T, { [K in keyof T]: T[K] extends Function ? never : K; }[keyof T]>' is not assignable to type 'T'.
tests/cases/conformance/types/conditional/conditionalTypes1.ts(106,5): error TS2322: Type 'Pick<T, { [K in keyof T]: T[K] extends Function ? never : K; }[keyof T]>' is not assignable to type 'Pick<T, { [K in keyof T]: T[K] extends Function ? K : never; }[keyof T]>'.
Type 'T[keyof T] extends Function ? keyof T : never' is not assignable to type 'T[keyof T] extends Function ? never : keyof T'.
Type 'keyof T' is not assignable to type 'never'.
Type 'string | number | symbol' is not assignable to type 'never'.
Type 'string' is not assignable to type 'never'.
tests/cases/conformance/types/conditional/conditionalTypes1.ts(108,5): error TS2322: Type 'Pick<T, { [K in keyof T]: T[K] extends Function ? K : never; }[keyof T]>' is not assignable to type 'Pick<T, { [K in keyof T]: T[K] extends Function ? never : K; }[keyof T]>'.
Type 'T[keyof T] extends Function ? never : keyof T' is not assignable to type 'T[keyof T] extends Function ? keyof T : never'.
Type 'keyof T' is not assignable to type 'never'.
tests/cases/conformance/types/conditional/conditionalTypes1.ts(114,5): error TS2322: Type 'keyof T' is not assignable to type 'T[keyof T] extends Function ? keyof T : never'.
Type 'string | number | symbol' is not assignable to type 'T[keyof T] extends Function ? keyof T : never'.
Type 'string' is not assignable to type 'T[keyof T] extends Function ? keyof T : never'.
Expand Down Expand Up @@ -187,15 +183,11 @@ tests/cases/conformance/types/conditional/conditionalTypes1.ts(288,43): error TS
~
!!! error TS2322: Type 'Pick<T, { [K in keyof T]: T[K] extends Function ? never : K; }[keyof T]>' is not assignable to type 'Pick<T, { [K in keyof T]: T[K] extends Function ? K : never; }[keyof T]>'.
!!! error TS2322: Type 'T[keyof T] extends Function ? keyof T : never' is not assignable to type 'T[keyof T] extends Function ? never : keyof T'.
!!! error TS2322: Type 'keyof T' is not assignable to type 'never'.
!!! error TS2322: Type 'string | number | symbol' is not assignable to type 'never'.
!!! error TS2322: Type 'string' is not assignable to type 'never'.
z = x;
z = y; // Error
~
!!! error TS2322: Type 'Pick<T, { [K in keyof T]: T[K] extends Function ? K : never; }[keyof T]>' is not assignable to type 'Pick<T, { [K in keyof T]: T[K] extends Function ? never : K; }[keyof T]>'.
!!! error TS2322: Type 'T[keyof T] extends Function ? never : keyof T' is not assignable to type 'T[keyof T] extends Function ? keyof T : never'.
!!! error TS2322: Type 'keyof T' is not assignable to type 'never'.
}

function f8<T>(x: keyof T, y: FunctionPropertyNames<T>, z: NonFunctionPropertyNames<T>) {
Expand Down
@@ -0,0 +1,55 @@
tests/cases/compiler/consistentAliasVsNonAliasRecordBehavior.ts(18,5): error TS2741: Property 'a' is missing in type 'Record<string, string>' but required in type 'Record2<"a", string>'.
tests/cases/compiler/consistentAliasVsNonAliasRecordBehavior.ts(22,5): error TS2741: Property 'a' is missing in type 'Record2<string, string>' but required in type 'Record<"a", string>'.
tests/cases/compiler/consistentAliasVsNonAliasRecordBehavior.ts(34,5): error TS2741: Property 'a' is missing in type 'Record<string, T>' but required in type 'Record2<"a", T>'.
tests/cases/compiler/consistentAliasVsNonAliasRecordBehavior.ts(38,5): error TS2741: Property 'a' is missing in type 'Record2<string, T>' but required in type 'Record<"a", T>'.


==== tests/cases/compiler/consistentAliasVsNonAliasRecordBehavior.ts (4 errors) ====
// TODO: FIXME: All the below cases labeled `no error` _should be an error_, and are only prevented from so being
// by incorrect variance-based relationships
// Ref: https://github.com/Microsoft/TypeScript/issues/29698

type Record2<K extends keyof any, T> = {
[P in K]: T;
};

function defaultRecord(x: Record<'a', string>, y: Record<string, string>) {
x = y; // no error, but error expected.
}

function customRecord(x: Record2<'a', string>, y: Record2<string, string>) {
x = y; // no error, but error expected.
}

function mixed1(x: Record2<'a', string>, y: Record<string, string>) {
x = y; // error
~
!!! error TS2741: Property 'a' is missing in type 'Record<string, string>' but required in type 'Record2<"a", string>'.
}

function mixed2(x: Record<'a', string>, y: Record2<string, string>) {
x = y; // error
~
!!! error TS2741: Property 'a' is missing in type 'Record2<string, string>' but required in type 'Record<"a", string>'.
}

function defaultRecord2<T>(x: Record<'a', T>, y: Record<string, T>) {
x = y; // no error, but error expected.
}

function customRecord2<T>(x: Record2<'a', T>, y: Record2<string, T>) {
x = y; // no error, but error expected.
}

function mixed3<T>(x: Record2<'a', T>, y: Record<string, T>) {
x = y; // error
~
!!! error TS2741: Property 'a' is missing in type 'Record<string, T>' but required in type 'Record2<"a", T>'.
}

function mixed4<T>(x: Record<'a', T>, y: Record2<string, T>) {
x = y; // error
~
!!! error TS2741: Property 'a' is missing in type 'Record2<string, T>' but required in type 'Record<"a", T>'.
}

@@ -0,0 +1,70 @@
//// [consistentAliasVsNonAliasRecordBehavior.ts]
// TODO: FIXME: All the below cases labeled `no error` _should be an error_, and are only prevented from so being
// by incorrect variance-based relationships
// Ref: https://github.com/Microsoft/TypeScript/issues/29698

type Record2<K extends keyof any, T> = {
[P in K]: T;
};

function defaultRecord(x: Record<'a', string>, y: Record<string, string>) {
x = y; // no error, but error expected.
}

function customRecord(x: Record2<'a', string>, y: Record2<string, string>) {
x = y; // no error, but error expected.
}

function mixed1(x: Record2<'a', string>, y: Record<string, string>) {
x = y; // error
}

function mixed2(x: Record<'a', string>, y: Record2<string, string>) {
x = y; // error
}

function defaultRecord2<T>(x: Record<'a', T>, y: Record<string, T>) {
x = y; // no error, but error expected.
}

function customRecord2<T>(x: Record2<'a', T>, y: Record2<string, T>) {
x = y; // no error, but error expected.
}

function mixed3<T>(x: Record2<'a', T>, y: Record<string, T>) {
x = y; // error
}

function mixed4<T>(x: Record<'a', T>, y: Record2<string, T>) {
x = y; // error
}


//// [consistentAliasVsNonAliasRecordBehavior.js]
// TODO: FIXME: All the below cases labeled `no error` _should be an error_, and are only prevented from so being
// by incorrect variance-based relationships
// Ref: https://github.com/Microsoft/TypeScript/issues/29698
function defaultRecord(x, y) {
x = y; // no error, but error expected.
}
function customRecord(x, y) {
x = y; // no error, but error expected.
}
function mixed1(x, y) {
x = y; // error
}
function mixed2(x, y) {
x = y; // error
}
function defaultRecord2(x, y) {
x = y; // no error, but error expected.
}
function customRecord2(x, y) {
x = y; // no error, but error expected.
}
function mixed3(x, y) {
x = y; // error
}
function mixed4(x, y) {
x = y; // error
}
@@ -0,0 +1,125 @@
=== tests/cases/compiler/consistentAliasVsNonAliasRecordBehavior.ts ===
// TODO: FIXME: All the below cases labeled `no error` _should be an error_, and are only prevented from so being
// by incorrect variance-based relationships
// Ref: https://github.com/Microsoft/TypeScript/issues/29698

type Record2<K extends keyof any, T> = {
>Record2 : Symbol(Record2, Decl(consistentAliasVsNonAliasRecordBehavior.ts, 0, 0))
>K : Symbol(K, Decl(consistentAliasVsNonAliasRecordBehavior.ts, 4, 13))
>T : Symbol(T, Decl(consistentAliasVsNonAliasRecordBehavior.ts, 4, 33))

[P in K]: T;
>P : Symbol(P, Decl(consistentAliasVsNonAliasRecordBehavior.ts, 5, 5))
>K : Symbol(K, Decl(consistentAliasVsNonAliasRecordBehavior.ts, 4, 13))
>T : Symbol(T, Decl(consistentAliasVsNonAliasRecordBehavior.ts, 4, 33))

};

function defaultRecord(x: Record<'a', string>, y: Record<string, string>) {
>defaultRecord : Symbol(defaultRecord, Decl(consistentAliasVsNonAliasRecordBehavior.ts, 6, 2))
>x : Symbol(x, Decl(consistentAliasVsNonAliasRecordBehavior.ts, 8, 23))
>Record : Symbol(Record, Decl(lib.es5.d.ts, --, --))
>y : Symbol(y, Decl(consistentAliasVsNonAliasRecordBehavior.ts, 8, 46))
>Record : Symbol(Record, Decl(lib.es5.d.ts, --, --))

x = y; // no error, but error expected.
>x : Symbol(x, Decl(consistentAliasVsNonAliasRecordBehavior.ts, 8, 23))
>y : Symbol(y, Decl(consistentAliasVsNonAliasRecordBehavior.ts, 8, 46))
}

function customRecord(x: Record2<'a', string>, y: Record2<string, string>) {
>customRecord : Symbol(customRecord, Decl(consistentAliasVsNonAliasRecordBehavior.ts, 10, 1))
>x : Symbol(x, Decl(consistentAliasVsNonAliasRecordBehavior.ts, 12, 22))
>Record2 : Symbol(Record2, Decl(consistentAliasVsNonAliasRecordBehavior.ts, 0, 0))
>y : Symbol(y, Decl(consistentAliasVsNonAliasRecordBehavior.ts, 12, 46))
>Record2 : Symbol(Record2, Decl(consistentAliasVsNonAliasRecordBehavior.ts, 0, 0))

x = y; // no error, but error expected.
>x : Symbol(x, Decl(consistentAliasVsNonAliasRecordBehavior.ts, 12, 22))
>y : Symbol(y, Decl(consistentAliasVsNonAliasRecordBehavior.ts, 12, 46))
}

function mixed1(x: Record2<'a', string>, y: Record<string, string>) {
>mixed1 : Symbol(mixed1, Decl(consistentAliasVsNonAliasRecordBehavior.ts, 14, 1))
>x : Symbol(x, Decl(consistentAliasVsNonAliasRecordBehavior.ts, 16, 16))
>Record2 : Symbol(Record2, Decl(consistentAliasVsNonAliasRecordBehavior.ts, 0, 0))
>y : Symbol(y, Decl(consistentAliasVsNonAliasRecordBehavior.ts, 16, 40))
>Record : Symbol(Record, Decl(lib.es5.d.ts, --, --))

x = y; // error
>x : Symbol(x, Decl(consistentAliasVsNonAliasRecordBehavior.ts, 16, 16))
>y : Symbol(y, Decl(consistentAliasVsNonAliasRecordBehavior.ts, 16, 40))
}

function mixed2(x: Record<'a', string>, y: Record2<string, string>) {
>mixed2 : Symbol(mixed2, Decl(consistentAliasVsNonAliasRecordBehavior.ts, 18, 1))
>x : Symbol(x, Decl(consistentAliasVsNonAliasRecordBehavior.ts, 20, 16))
>Record : Symbol(Record, Decl(lib.es5.d.ts, --, --))
>y : Symbol(y, Decl(consistentAliasVsNonAliasRecordBehavior.ts, 20, 39))
>Record2 : Symbol(Record2, Decl(consistentAliasVsNonAliasRecordBehavior.ts, 0, 0))

x = y; // error
>x : Symbol(x, Decl(consistentAliasVsNonAliasRecordBehavior.ts, 20, 16))
>y : Symbol(y, Decl(consistentAliasVsNonAliasRecordBehavior.ts, 20, 39))
}

function defaultRecord2<T>(x: Record<'a', T>, y: Record<string, T>) {
>defaultRecord2 : Symbol(defaultRecord2, Decl(consistentAliasVsNonAliasRecordBehavior.ts, 22, 1))
>T : Symbol(T, Decl(consistentAliasVsNonAliasRecordBehavior.ts, 24, 24))
>x : Symbol(x, Decl(consistentAliasVsNonAliasRecordBehavior.ts, 24, 27))
>Record : Symbol(Record, Decl(lib.es5.d.ts, --, --))
>T : Symbol(T, Decl(consistentAliasVsNonAliasRecordBehavior.ts, 24, 24))
>y : Symbol(y, Decl(consistentAliasVsNonAliasRecordBehavior.ts, 24, 45))
>Record : Symbol(Record, Decl(lib.es5.d.ts, --, --))
>T : Symbol(T, Decl(consistentAliasVsNonAliasRecordBehavior.ts, 24, 24))

x = y; // no error, but error expected.
>x : Symbol(x, Decl(consistentAliasVsNonAliasRecordBehavior.ts, 24, 27))
>y : Symbol(y, Decl(consistentAliasVsNonAliasRecordBehavior.ts, 24, 45))
}

function customRecord2<T>(x: Record2<'a', T>, y: Record2<string, T>) {
>customRecord2 : Symbol(customRecord2, Decl(consistentAliasVsNonAliasRecordBehavior.ts, 26, 1))
>T : Symbol(T, Decl(consistentAliasVsNonAliasRecordBehavior.ts, 28, 23))
>x : Symbol(x, Decl(consistentAliasVsNonAliasRecordBehavior.ts, 28, 26))
>Record2 : Symbol(Record2, Decl(consistentAliasVsNonAliasRecordBehavior.ts, 0, 0))
>T : Symbol(T, Decl(consistentAliasVsNonAliasRecordBehavior.ts, 28, 23))
>y : Symbol(y, Decl(consistentAliasVsNonAliasRecordBehavior.ts, 28, 45))
>Record2 : Symbol(Record2, Decl(consistentAliasVsNonAliasRecordBehavior.ts, 0, 0))
>T : Symbol(T, Decl(consistentAliasVsNonAliasRecordBehavior.ts, 28, 23))

x = y; // no error, but error expected.
>x : Symbol(x, Decl(consistentAliasVsNonAliasRecordBehavior.ts, 28, 26))
>y : Symbol(y, Decl(consistentAliasVsNonAliasRecordBehavior.ts, 28, 45))
}

function mixed3<T>(x: Record2<'a', T>, y: Record<string, T>) {
>mixed3 : Symbol(mixed3, Decl(consistentAliasVsNonAliasRecordBehavior.ts, 30, 1))
>T : Symbol(T, Decl(consistentAliasVsNonAliasRecordBehavior.ts, 32, 16))
>x : Symbol(x, Decl(consistentAliasVsNonAliasRecordBehavior.ts, 32, 19))
>Record2 : Symbol(Record2, Decl(consistentAliasVsNonAliasRecordBehavior.ts, 0, 0))
>T : Symbol(T, Decl(consistentAliasVsNonAliasRecordBehavior.ts, 32, 16))
>y : Symbol(y, Decl(consistentAliasVsNonAliasRecordBehavior.ts, 32, 38))
>Record : Symbol(Record, Decl(lib.es5.d.ts, --, --))
>T : Symbol(T, Decl(consistentAliasVsNonAliasRecordBehavior.ts, 32, 16))

x = y; // error
>x : Symbol(x, Decl(consistentAliasVsNonAliasRecordBehavior.ts, 32, 19))
>y : Symbol(y, Decl(consistentAliasVsNonAliasRecordBehavior.ts, 32, 38))
}

function mixed4<T>(x: Record<'a', T>, y: Record2<string, T>) {
>mixed4 : Symbol(mixed4, Decl(consistentAliasVsNonAliasRecordBehavior.ts, 34, 1))
>T : Symbol(T, Decl(consistentAliasVsNonAliasRecordBehavior.ts, 36, 16))
>x : Symbol(x, Decl(consistentAliasVsNonAliasRecordBehavior.ts, 36, 19))
>Record : Symbol(Record, Decl(lib.es5.d.ts, --, --))
>T : Symbol(T, Decl(consistentAliasVsNonAliasRecordBehavior.ts, 36, 16))
>y : Symbol(y, Decl(consistentAliasVsNonAliasRecordBehavior.ts, 36, 37))
>Record2 : Symbol(Record2, Decl(consistentAliasVsNonAliasRecordBehavior.ts, 0, 0))
>T : Symbol(T, Decl(consistentAliasVsNonAliasRecordBehavior.ts, 36, 16))

x = y; // error
>x : Symbol(x, Decl(consistentAliasVsNonAliasRecordBehavior.ts, 36, 19))
>y : Symbol(y, Decl(consistentAliasVsNonAliasRecordBehavior.ts, 36, 37))
}

0 comments on commit 4e96d98

Please sign in to comment.