From 1de8c656784e77768f39b876682aa0328ce8ee08 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Tue, 1 May 2018 12:38:29 -0700 Subject: [PATCH 1/5] Unconstrained type parameter not assignable to 'object' --- src/compiler/checker.ts | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index d825b0d971758..dfb1a4c8c4e89 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -10716,19 +10716,18 @@ namespace ts { return result; } } - let constraint = getConstraintForRelation(source); - // A type variable with no constraint is not related to the non-primitive object type. - if (constraint || !(target.flags & TypeFlags.NonPrimitive)) { - if (!constraint || constraint.flags & TypeFlags.Any) { - constraint = emptyObjectType; - } - // Report constraint errors only if the constraint is not the empty object type - const reportConstraintErrors = reportErrors && constraint !== emptyObjectType; - if (result = isRelatedTo(constraint, target, reportConstraintErrors)) { + const constraint = getConstraintForRelation(source); + if (!constraint || constraint.flags & TypeFlags.Any) { + // A type variable with no constraint is not related to the non-primitive object type. + if (result = isRelatedTo(emptyObjectType, extractTypesOfKind(target, ~TypeFlags.NonPrimitive))) { errorInfo = saveErrorInfo; return result; } } + else if (result = isRelatedTo(constraint, target, reportErrors)) { + errorInfo = saveErrorInfo; + return result; + } } else if (source.flags & TypeFlags.Index) { if (result = isRelatedTo(keyofConstraintType, target, reportErrors)) { From 59355cbfdbadac489255425f62b44a1d5c80287f Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Tue, 1 May 2018 12:44:46 -0700 Subject: [PATCH 2/5] Add regression tests --- .../nonPrimitive/nonPrimitiveAndTypeVariables.ts | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 tests/cases/conformance/types/nonPrimitive/nonPrimitiveAndTypeVariables.ts diff --git a/tests/cases/conformance/types/nonPrimitive/nonPrimitiveAndTypeVariables.ts b/tests/cases/conformance/types/nonPrimitive/nonPrimitiveAndTypeVariables.ts new file mode 100644 index 0000000000000..a5b0c2e76383d --- /dev/null +++ b/tests/cases/conformance/types/nonPrimitive/nonPrimitiveAndTypeVariables.ts @@ -0,0 +1,14 @@ +// @strict: true + +// Repros from #23800 + +type A = { [P in keyof T]: T[P] extends V ? 1 : 0; }; +type B = { [P in keyof T]: T[P] extends V | object ? 1 : 0; }; + +type a = A<{ a: 0 | 1 }, 0>; // { a: 0; } +type b = B<{ a: 0 | 1 }, 0>; // { a: 0; } + +function foo(x: T) { + let a: object = x; // Error + let b: U | object = x; // Error +} From ce2dea98ca77135bb487648e1870260d50b52f84 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Tue, 1 May 2018 12:44:55 -0700 Subject: [PATCH 3/5] Accept new baselines --- .../nonPrimitiveAndTypeVariables.errors.txt | 24 +++++++++ .../reference/nonPrimitiveAndTypeVariables.js | 22 ++++++++ .../nonPrimitiveAndTypeVariables.symbols | 50 +++++++++++++++++++ .../nonPrimitiveAndTypeVariables.types | 50 +++++++++++++++++++ 4 files changed, 146 insertions(+) create mode 100644 tests/baselines/reference/nonPrimitiveAndTypeVariables.errors.txt create mode 100644 tests/baselines/reference/nonPrimitiveAndTypeVariables.js create mode 100644 tests/baselines/reference/nonPrimitiveAndTypeVariables.symbols create mode 100644 tests/baselines/reference/nonPrimitiveAndTypeVariables.types diff --git a/tests/baselines/reference/nonPrimitiveAndTypeVariables.errors.txt b/tests/baselines/reference/nonPrimitiveAndTypeVariables.errors.txt new file mode 100644 index 0000000000000..27bd17410aca9 --- /dev/null +++ b/tests/baselines/reference/nonPrimitiveAndTypeVariables.errors.txt @@ -0,0 +1,24 @@ +tests/cases/conformance/types/nonPrimitive/nonPrimitiveAndTypeVariables.ts(10,9): error TS2322: Type 'T' is not assignable to type 'object'. +tests/cases/conformance/types/nonPrimitive/nonPrimitiveAndTypeVariables.ts(11,9): error TS2322: Type 'T' is not assignable to type 'object | U'. + Type 'T' is not assignable to type 'U'. + + +==== tests/cases/conformance/types/nonPrimitive/nonPrimitiveAndTypeVariables.ts (2 errors) ==== + // Repros from #23800 + + type A = { [P in keyof T]: T[P] extends V ? 1 : 0; }; + type B = { [P in keyof T]: T[P] extends V | object ? 1 : 0; }; + + type a = A<{ a: 0 | 1 }, 0>; // { a: 0; } + type b = B<{ a: 0 | 1 }, 0>; // { a: 0; } + + function foo(x: T) { + let a: object = x; // Error + ~ +!!! error TS2322: Type 'T' is not assignable to type 'object'. + let b: U | object = x; // Error + ~ +!!! error TS2322: Type 'T' is not assignable to type 'object | U'. +!!! error TS2322: Type 'T' is not assignable to type 'U'. + } + \ No newline at end of file diff --git a/tests/baselines/reference/nonPrimitiveAndTypeVariables.js b/tests/baselines/reference/nonPrimitiveAndTypeVariables.js new file mode 100644 index 0000000000000..6260624706ce4 --- /dev/null +++ b/tests/baselines/reference/nonPrimitiveAndTypeVariables.js @@ -0,0 +1,22 @@ +//// [nonPrimitiveAndTypeVariables.ts] +// Repros from #23800 + +type A = { [P in keyof T]: T[P] extends V ? 1 : 0; }; +type B = { [P in keyof T]: T[P] extends V | object ? 1 : 0; }; + +type a = A<{ a: 0 | 1 }, 0>; // { a: 0; } +type b = B<{ a: 0 | 1 }, 0>; // { a: 0; } + +function foo(x: T) { + let a: object = x; // Error + let b: U | object = x; // Error +} + + +//// [nonPrimitiveAndTypeVariables.js] +"use strict"; +// Repros from #23800 +function foo(x) { + var a = x; // Error + var b = x; // Error +} diff --git a/tests/baselines/reference/nonPrimitiveAndTypeVariables.symbols b/tests/baselines/reference/nonPrimitiveAndTypeVariables.symbols new file mode 100644 index 0000000000000..791e47c26639f --- /dev/null +++ b/tests/baselines/reference/nonPrimitiveAndTypeVariables.symbols @@ -0,0 +1,50 @@ +=== tests/cases/conformance/types/nonPrimitive/nonPrimitiveAndTypeVariables.ts === +// Repros from #23800 + +type A = { [P in keyof T]: T[P] extends V ? 1 : 0; }; +>A : Symbol(A, Decl(nonPrimitiveAndTypeVariables.ts, 0, 0)) +>T : Symbol(T, Decl(nonPrimitiveAndTypeVariables.ts, 2, 7)) +>V : Symbol(V, Decl(nonPrimitiveAndTypeVariables.ts, 2, 9)) +>P : Symbol(P, Decl(nonPrimitiveAndTypeVariables.ts, 2, 18)) +>T : Symbol(T, Decl(nonPrimitiveAndTypeVariables.ts, 2, 7)) +>T : Symbol(T, Decl(nonPrimitiveAndTypeVariables.ts, 2, 7)) +>P : Symbol(P, Decl(nonPrimitiveAndTypeVariables.ts, 2, 18)) +>V : Symbol(V, Decl(nonPrimitiveAndTypeVariables.ts, 2, 9)) + +type B = { [P in keyof T]: T[P] extends V | object ? 1 : 0; }; +>B : Symbol(B, Decl(nonPrimitiveAndTypeVariables.ts, 2, 59)) +>T : Symbol(T, Decl(nonPrimitiveAndTypeVariables.ts, 3, 7)) +>V : Symbol(V, Decl(nonPrimitiveAndTypeVariables.ts, 3, 9)) +>P : Symbol(P, Decl(nonPrimitiveAndTypeVariables.ts, 3, 18)) +>T : Symbol(T, Decl(nonPrimitiveAndTypeVariables.ts, 3, 7)) +>T : Symbol(T, Decl(nonPrimitiveAndTypeVariables.ts, 3, 7)) +>P : Symbol(P, Decl(nonPrimitiveAndTypeVariables.ts, 3, 18)) +>V : Symbol(V, Decl(nonPrimitiveAndTypeVariables.ts, 3, 9)) + +type a = A<{ a: 0 | 1 }, 0>; // { a: 0; } +>a : Symbol(a, Decl(nonPrimitiveAndTypeVariables.ts, 3, 68)) +>A : Symbol(A, Decl(nonPrimitiveAndTypeVariables.ts, 0, 0)) +>a : Symbol(a, Decl(nonPrimitiveAndTypeVariables.ts, 5, 12)) + +type b = B<{ a: 0 | 1 }, 0>; // { a: 0; } +>b : Symbol(b, Decl(nonPrimitiveAndTypeVariables.ts, 5, 28)) +>B : Symbol(B, Decl(nonPrimitiveAndTypeVariables.ts, 2, 59)) +>a : Symbol(a, Decl(nonPrimitiveAndTypeVariables.ts, 6, 12)) + +function foo(x: T) { +>foo : Symbol(foo, Decl(nonPrimitiveAndTypeVariables.ts, 6, 28)) +>T : Symbol(T, Decl(nonPrimitiveAndTypeVariables.ts, 8, 13)) +>U : Symbol(U, Decl(nonPrimitiveAndTypeVariables.ts, 8, 15)) +>x : Symbol(x, Decl(nonPrimitiveAndTypeVariables.ts, 8, 19)) +>T : Symbol(T, Decl(nonPrimitiveAndTypeVariables.ts, 8, 13)) + + let a: object = x; // Error +>a : Symbol(a, Decl(nonPrimitiveAndTypeVariables.ts, 9, 7)) +>x : Symbol(x, Decl(nonPrimitiveAndTypeVariables.ts, 8, 19)) + + let b: U | object = x; // Error +>b : Symbol(b, Decl(nonPrimitiveAndTypeVariables.ts, 10, 7)) +>U : Symbol(U, Decl(nonPrimitiveAndTypeVariables.ts, 8, 15)) +>x : Symbol(x, Decl(nonPrimitiveAndTypeVariables.ts, 8, 19)) +} + diff --git a/tests/baselines/reference/nonPrimitiveAndTypeVariables.types b/tests/baselines/reference/nonPrimitiveAndTypeVariables.types new file mode 100644 index 0000000000000..76755f5a9a175 --- /dev/null +++ b/tests/baselines/reference/nonPrimitiveAndTypeVariables.types @@ -0,0 +1,50 @@ +=== tests/cases/conformance/types/nonPrimitive/nonPrimitiveAndTypeVariables.ts === +// Repros from #23800 + +type A = { [P in keyof T]: T[P] extends V ? 1 : 0; }; +>A : A +>T : T +>V : V +>P : P +>T : T +>T : T +>P : P +>V : V + +type B = { [P in keyof T]: T[P] extends V | object ? 1 : 0; }; +>B : B +>T : T +>V : V +>P : P +>T : T +>T : T +>P : P +>V : V + +type a = A<{ a: 0 | 1 }, 0>; // { a: 0; } +>a : A<{ a: 0 | 1; }, 0> +>A : A +>a : 0 | 1 + +type b = B<{ a: 0 | 1 }, 0>; // { a: 0; } +>b : B<{ a: 0 | 1; }, 0> +>B : B +>a : 0 | 1 + +function foo(x: T) { +>foo : (x: T) => void +>T : T +>U : U +>x : T +>T : T + + let a: object = x; // Error +>a : object +>x : T + + let b: U | object = x; // Error +>b : object | U +>U : U +>x : T +} + From 4c933aef9a5c86aecafa6c1f3bafaf960a49c02e Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Tue, 1 May 2018 13:05:49 -0700 Subject: [PATCH 4/5] Check that test cases produce expected types --- .../types/nonPrimitive/nonPrimitiveAndTypeVariables.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/cases/conformance/types/nonPrimitive/nonPrimitiveAndTypeVariables.ts b/tests/cases/conformance/types/nonPrimitive/nonPrimitiveAndTypeVariables.ts index a5b0c2e76383d..a0eeec2cdd762 100644 --- a/tests/cases/conformance/types/nonPrimitive/nonPrimitiveAndTypeVariables.ts +++ b/tests/cases/conformance/types/nonPrimitive/nonPrimitiveAndTypeVariables.ts @@ -5,8 +5,8 @@ type A = { [P in keyof T]: T[P] extends V ? 1 : 0; }; type B = { [P in keyof T]: T[P] extends V | object ? 1 : 0; }; -type a = A<{ a: 0 | 1 }, 0>; // { a: 0; } -type b = B<{ a: 0 | 1 }, 0>; // { a: 0; } +let a: A<{ a: 0 | 1 }, 0> = { a: 0 }; +let b: B<{ a: 0 | 1 }, 0> = { a: 0 }; function foo(x: T) { let a: object = x; // Error From 0066b027724a31657cddff003d3bde45d2b3014b Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Tue, 1 May 2018 13:06:19 -0700 Subject: [PATCH 5/5] Accept new baselines --- .../nonPrimitiveAndTypeVariables.errors.txt | 4 ++-- .../reference/nonPrimitiveAndTypeVariables.js | 6 ++++-- .../nonPrimitiveAndTypeVariables.symbols | 16 +++++++++------- .../reference/nonPrimitiveAndTypeVariables.types | 10 ++++++++-- 4 files changed, 23 insertions(+), 13 deletions(-) diff --git a/tests/baselines/reference/nonPrimitiveAndTypeVariables.errors.txt b/tests/baselines/reference/nonPrimitiveAndTypeVariables.errors.txt index 27bd17410aca9..83ce98f1cd625 100644 --- a/tests/baselines/reference/nonPrimitiveAndTypeVariables.errors.txt +++ b/tests/baselines/reference/nonPrimitiveAndTypeVariables.errors.txt @@ -9,8 +9,8 @@ tests/cases/conformance/types/nonPrimitive/nonPrimitiveAndTypeVariables.ts(11,9) type A = { [P in keyof T]: T[P] extends V ? 1 : 0; }; type B = { [P in keyof T]: T[P] extends V | object ? 1 : 0; }; - type a = A<{ a: 0 | 1 }, 0>; // { a: 0; } - type b = B<{ a: 0 | 1 }, 0>; // { a: 0; } + let a: A<{ a: 0 | 1 }, 0> = { a: 0 }; + let b: B<{ a: 0 | 1 }, 0> = { a: 0 }; function foo(x: T) { let a: object = x; // Error diff --git a/tests/baselines/reference/nonPrimitiveAndTypeVariables.js b/tests/baselines/reference/nonPrimitiveAndTypeVariables.js index 6260624706ce4..fda272c1fe26d 100644 --- a/tests/baselines/reference/nonPrimitiveAndTypeVariables.js +++ b/tests/baselines/reference/nonPrimitiveAndTypeVariables.js @@ -4,8 +4,8 @@ type A = { [P in keyof T]: T[P] extends V ? 1 : 0; }; type B = { [P in keyof T]: T[P] extends V | object ? 1 : 0; }; -type a = A<{ a: 0 | 1 }, 0>; // { a: 0; } -type b = B<{ a: 0 | 1 }, 0>; // { a: 0; } +let a: A<{ a: 0 | 1 }, 0> = { a: 0 }; +let b: B<{ a: 0 | 1 }, 0> = { a: 0 }; function foo(x: T) { let a: object = x; // Error @@ -16,6 +16,8 @@ function foo(x: T) { //// [nonPrimitiveAndTypeVariables.js] "use strict"; // Repros from #23800 +var a = { a: 0 }; +var b = { a: 0 }; function foo(x) { var a = x; // Error var b = x; // Error diff --git a/tests/baselines/reference/nonPrimitiveAndTypeVariables.symbols b/tests/baselines/reference/nonPrimitiveAndTypeVariables.symbols index 791e47c26639f..083c67e7fdb23 100644 --- a/tests/baselines/reference/nonPrimitiveAndTypeVariables.symbols +++ b/tests/baselines/reference/nonPrimitiveAndTypeVariables.symbols @@ -21,18 +21,20 @@ type B = { [P in keyof T]: T[P] extends V | object ? 1 : 0; }; >P : Symbol(P, Decl(nonPrimitiveAndTypeVariables.ts, 3, 18)) >V : Symbol(V, Decl(nonPrimitiveAndTypeVariables.ts, 3, 9)) -type a = A<{ a: 0 | 1 }, 0>; // { a: 0; } ->a : Symbol(a, Decl(nonPrimitiveAndTypeVariables.ts, 3, 68)) +let a: A<{ a: 0 | 1 }, 0> = { a: 0 }; +>a : Symbol(a, Decl(nonPrimitiveAndTypeVariables.ts, 5, 3)) >A : Symbol(A, Decl(nonPrimitiveAndTypeVariables.ts, 0, 0)) ->a : Symbol(a, Decl(nonPrimitiveAndTypeVariables.ts, 5, 12)) +>a : Symbol(a, Decl(nonPrimitiveAndTypeVariables.ts, 5, 10)) +>a : Symbol(a, Decl(nonPrimitiveAndTypeVariables.ts, 5, 29)) -type b = B<{ a: 0 | 1 }, 0>; // { a: 0; } ->b : Symbol(b, Decl(nonPrimitiveAndTypeVariables.ts, 5, 28)) +let b: B<{ a: 0 | 1 }, 0> = { a: 0 }; +>b : Symbol(b, Decl(nonPrimitiveAndTypeVariables.ts, 6, 3)) >B : Symbol(B, Decl(nonPrimitiveAndTypeVariables.ts, 2, 59)) ->a : Symbol(a, Decl(nonPrimitiveAndTypeVariables.ts, 6, 12)) +>a : Symbol(a, Decl(nonPrimitiveAndTypeVariables.ts, 6, 10)) +>a : Symbol(a, Decl(nonPrimitiveAndTypeVariables.ts, 6, 29)) function foo(x: T) { ->foo : Symbol(foo, Decl(nonPrimitiveAndTypeVariables.ts, 6, 28)) +>foo : Symbol(foo, Decl(nonPrimitiveAndTypeVariables.ts, 6, 37)) >T : Symbol(T, Decl(nonPrimitiveAndTypeVariables.ts, 8, 13)) >U : Symbol(U, Decl(nonPrimitiveAndTypeVariables.ts, 8, 15)) >x : Symbol(x, Decl(nonPrimitiveAndTypeVariables.ts, 8, 19)) diff --git a/tests/baselines/reference/nonPrimitiveAndTypeVariables.types b/tests/baselines/reference/nonPrimitiveAndTypeVariables.types index 76755f5a9a175..f2fba1201407f 100644 --- a/tests/baselines/reference/nonPrimitiveAndTypeVariables.types +++ b/tests/baselines/reference/nonPrimitiveAndTypeVariables.types @@ -21,15 +21,21 @@ type B = { [P in keyof T]: T[P] extends V | object ? 1 : 0; }; >P : P >V : V -type a = A<{ a: 0 | 1 }, 0>; // { a: 0; } +let a: A<{ a: 0 | 1 }, 0> = { a: 0 }; >a : A<{ a: 0 | 1; }, 0> >A : A >a : 0 | 1 +>{ a: 0 } : { a: 0; } +>a : 0 +>0 : 0 -type b = B<{ a: 0 | 1 }, 0>; // { a: 0; } +let b: B<{ a: 0 | 1 }, 0> = { a: 0 }; >b : B<{ a: 0 | 1; }, 0> >B : B >a : 0 | 1 +>{ a: 0 } : { a: 0; } +>a : 0 +>0 : 0 function foo(x: T) { >foo : (x: T) => void