From 5b0bcecfae0d7b3dc8f5f0a00e48847610767d79 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Thu, 2 Nov 2017 16:58:41 -0700 Subject: [PATCH 1/4] Properly handle intersection types in getUnmatchedProperty --- src/compiler/checker.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 09354d957a3..840a6351a2f 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -10792,7 +10792,7 @@ namespace ts { } function getUnmatchedProperty(source: Type, target: Type, requireOptionalProperties: boolean) { - const properties = getPropertiesOfObjectType(target); + const properties = target.flags & TypeFlags.Intersection ? getPropertiesOfUnionOrIntersectionType(target) : getPropertiesOfObjectType(target); for (const targetProp of properties) { if (requireOptionalProperties || !(targetProp.flags & SymbolFlags.Optional)) { const sourceProp = getPropertyOfType(source, targetProp.escapedName); From 2191b75fc70ea5ae6b4bde1d61228980f9e7bca5 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Thu, 2 Nov 2017 17:07:31 -0700 Subject: [PATCH 2/4] Accept new baselines --- ...ssFunctionComponentsWithTypeArguments4.errors.txt | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/tests/baselines/reference/tsxStatelessFunctionComponentsWithTypeArguments4.errors.txt b/tests/baselines/reference/tsxStatelessFunctionComponentsWithTypeArguments4.errors.txt index 2feed16ac0a..d692364d264 100644 --- a/tests/baselines/reference/tsxStatelessFunctionComponentsWithTypeArguments4.errors.txt +++ b/tests/baselines/reference/tsxStatelessFunctionComponentsWithTypeArguments4.errors.txt @@ -1,9 +1,9 @@ tests/cases/conformance/jsx/file.tsx(9,33): error TS2322: Type '{ a: number; }' is not assignable to type 'IntrinsicAttributes & { b: {}; a: number; }'. Type '{ a: number; }' is not assignable to type '{ b: {}; a: number; }'. Property 'b' is missing in type '{ a: number; }'. -tests/cases/conformance/jsx/file.tsx(10,33): error TS2322: Type 'T' is not assignable to type 'IntrinsicAttributes & { b: number; a: {}; }'. - Type '{ b: number; }' is not assignable to type 'IntrinsicAttributes & { b: number; a: {}; }'. - Type '{ b: number; }' is not assignable to type '{ b: number; a: {}; }'. +tests/cases/conformance/jsx/file.tsx(10,33): error TS2322: Type 'T' is not assignable to type 'IntrinsicAttributes & { b: {}; a: {}; }'. + Type '{ b: number; }' is not assignable to type 'IntrinsicAttributes & { b: {}; a: {}; }'. + Type '{ b: number; }' is not assignable to type '{ b: {}; a: {}; }'. Property 'a' is missing in type '{ b: number; }'. Type 'T' is not assignable to type 'IntrinsicAttributes'. Type '{ b: number; }' has no properties in common with type 'IntrinsicAttributes'. @@ -25,9 +25,9 @@ tests/cases/conformance/jsx/file.tsx(10,33): error TS2322: Type 'T' is not assig !!! error TS2322: Property 'b' is missing in type '{ a: number; }'. let a2 = // missing a ~~~~~~~~~~~~~~~~~~~~~ -!!! error TS2322: Type 'T' is not assignable to type 'IntrinsicAttributes & { b: number; a: {}; }'. -!!! error TS2322: Type '{ b: number; }' is not assignable to type 'IntrinsicAttributes & { b: number; a: {}; }'. -!!! error TS2322: Type '{ b: number; }' is not assignable to type '{ b: number; a: {}; }'. +!!! error TS2322: Type 'T' is not assignable to type 'IntrinsicAttributes & { b: {}; a: {}; }'. +!!! error TS2322: Type '{ b: number; }' is not assignable to type 'IntrinsicAttributes & { b: {}; a: {}; }'. +!!! error TS2322: Type '{ b: number; }' is not assignable to type '{ b: {}; a: {}; }'. !!! error TS2322: Property 'a' is missing in type '{ b: number; }'. !!! error TS2322: Type 'T' is not assignable to type 'IntrinsicAttributes'. !!! error TS2322: Type '{ b: number; }' has no properties in common with type 'IntrinsicAttributes'. From 63f7029b9a8751f96acf72ff3ae29fcf196c32e5 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Thu, 2 Nov 2017 17:31:17 -0700 Subject: [PATCH 3/4] Add regression tests --- .../reference/intersectionTypeInference3.js | 25 ++++++++ .../intersectionTypeInference3.symbols | 57 +++++++++++++++++ .../intersectionTypeInference3.types | 61 +++++++++++++++++++ .../intersectionTypeInference3.ts | 20 ++++++ 4 files changed, 163 insertions(+) create mode 100644 tests/baselines/reference/intersectionTypeInference3.js create mode 100644 tests/baselines/reference/intersectionTypeInference3.symbols create mode 100644 tests/baselines/reference/intersectionTypeInference3.types create mode 100644 tests/cases/conformance/types/intersection/intersectionTypeInference3.ts diff --git a/tests/baselines/reference/intersectionTypeInference3.js b/tests/baselines/reference/intersectionTypeInference3.js new file mode 100644 index 00000000000..8a7db286ca2 --- /dev/null +++ b/tests/baselines/reference/intersectionTypeInference3.js @@ -0,0 +1,25 @@ +//// [intersectionTypeInference3.ts] +// Repro from #19682 + +type Nominal = Type & { + [Symbol.species]: Kind; +}; + +type A = Nominal<'A', string>; + +declare const a: Set; +declare const b: Set; + +const c1 = Array.from(a).concat(Array.from(b)); + +// Simpler repro + +declare function from(): T[]; +const c2: ReadonlyArray = from(); + + +//// [intersectionTypeInference3.js] +"use strict"; +// Repro from #19682 +const c1 = Array.from(a).concat(Array.from(b)); +const c2 = from(); diff --git a/tests/baselines/reference/intersectionTypeInference3.symbols b/tests/baselines/reference/intersectionTypeInference3.symbols new file mode 100644 index 00000000000..5b717508319 --- /dev/null +++ b/tests/baselines/reference/intersectionTypeInference3.symbols @@ -0,0 +1,57 @@ +=== tests/cases/conformance/types/intersection/intersectionTypeInference3.ts === +// Repro from #19682 + +type Nominal = Type & { +>Nominal : Symbol(Nominal, Decl(intersectionTypeInference3.ts, 0, 0)) +>Kind : Symbol(Kind, Decl(intersectionTypeInference3.ts, 2, 13)) +>Type : Symbol(Type, Decl(intersectionTypeInference3.ts, 2, 33)) +>Type : Symbol(Type, Decl(intersectionTypeInference3.ts, 2, 33)) + + [Symbol.species]: Kind; +>Symbol.species : Symbol(SymbolConstructor.species, Decl(lib.es2015.symbol.wellknown.d.ts, --, --)) +>Symbol : Symbol(Symbol, Decl(lib.es2015.symbol.wellknown.d.ts, --, --), Decl(lib.es2015.symbol.d.ts, --, --), Decl(lib.es2015.symbol.d.ts, --, --)) +>species : Symbol(SymbolConstructor.species, Decl(lib.es2015.symbol.wellknown.d.ts, --, --)) +>Kind : Symbol(Kind, Decl(intersectionTypeInference3.ts, 2, 13)) + +}; + +type A = Nominal<'A', string>; +>A : Symbol(A, Decl(intersectionTypeInference3.ts, 4, 2)) +>Nominal : Symbol(Nominal, Decl(intersectionTypeInference3.ts, 0, 0)) + +declare const a: Set; +>a : Symbol(a, Decl(intersectionTypeInference3.ts, 8, 13)) +>Set : Symbol(Set, Decl(lib.es2015.symbol.wellknown.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.collection.d.ts, --, --), Decl(lib.es2015.collection.d.ts, --, --)) +>A : Symbol(A, Decl(intersectionTypeInference3.ts, 4, 2)) + +declare const b: Set; +>b : Symbol(b, Decl(intersectionTypeInference3.ts, 9, 13)) +>Set : Symbol(Set, Decl(lib.es2015.symbol.wellknown.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.collection.d.ts, --, --), Decl(lib.es2015.collection.d.ts, --, --)) +>A : Symbol(A, Decl(intersectionTypeInference3.ts, 4, 2)) + +const c1 = Array.from(a).concat(Array.from(b)); +>c1 : Symbol(c1, Decl(intersectionTypeInference3.ts, 11, 5)) +>Array.from(a).concat : Symbol(Array.concat, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --)) +>Array.from : Symbol(ArrayConstructor.from, Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.core.d.ts, --, --)) +>Array : Symbol(Array, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.symbol.wellknown.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.core.d.ts, --, --)) +>from : Symbol(ArrayConstructor.from, Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.core.d.ts, --, --)) +>a : Symbol(a, Decl(intersectionTypeInference3.ts, 8, 13)) +>concat : Symbol(Array.concat, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --)) +>Array.from : Symbol(ArrayConstructor.from, Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.core.d.ts, --, --)) +>Array : Symbol(Array, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.symbol.wellknown.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.core.d.ts, --, --)) +>from : Symbol(ArrayConstructor.from, Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.core.d.ts, --, --)) +>b : Symbol(b, Decl(intersectionTypeInference3.ts, 9, 13)) + +// Simpler repro + +declare function from(): T[]; +>from : Symbol(from, Decl(intersectionTypeInference3.ts, 11, 47)) +>T : Symbol(T, Decl(intersectionTypeInference3.ts, 15, 22)) +>T : Symbol(T, Decl(intersectionTypeInference3.ts, 15, 22)) + +const c2: ReadonlyArray = from(); +>c2 : Symbol(c2, Decl(intersectionTypeInference3.ts, 16, 5)) +>ReadonlyArray : Symbol(ReadonlyArray, Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.core.d.ts, --, --)) +>A : Symbol(A, Decl(intersectionTypeInference3.ts, 4, 2)) +>from : Symbol(from, Decl(intersectionTypeInference3.ts, 11, 47)) + diff --git a/tests/baselines/reference/intersectionTypeInference3.types b/tests/baselines/reference/intersectionTypeInference3.types new file mode 100644 index 00000000000..4d474c84d54 --- /dev/null +++ b/tests/baselines/reference/intersectionTypeInference3.types @@ -0,0 +1,61 @@ +=== tests/cases/conformance/types/intersection/intersectionTypeInference3.ts === +// Repro from #19682 + +type Nominal = Type & { +>Nominal : Nominal +>Kind : Kind +>Type : Type +>Type : Type + + [Symbol.species]: Kind; +>Symbol.species : symbol +>Symbol : SymbolConstructor +>species : symbol +>Kind : Kind + +}; + +type A = Nominal<'A', string>; +>A : Nominal<"A", string> +>Nominal : Nominal + +declare const a: Set; +>a : Set> +>Set : Set +>A : Nominal<"A", string> + +declare const b: Set; +>b : Set> +>Set : Set +>A : Nominal<"A", string> + +const c1 = Array.from(a).concat(Array.from(b)); +>c1 : Nominal<"A", string>[] +>Array.from(a).concat(Array.from(b)) : Nominal<"A", string>[] +>Array.from(a).concat : { (...items: ReadonlyArray>[]): Nominal<"A", string>[]; (...items: (Nominal<"A", string> | ReadonlyArray>)[]): Nominal<"A", string>[]; } +>Array.from(a) : Nominal<"A", string>[] +>Array.from : { (iterable: Iterable, mapfn?: ((v: T, k: number) => U) | undefined, thisArg?: any): U[]; (arrayLike: ArrayLike, mapfn?: ((v: T, k: number) => U) | undefined, thisArg?: any): U[]; } +>Array : ArrayConstructor +>from : { (iterable: Iterable, mapfn?: ((v: T, k: number) => U) | undefined, thisArg?: any): U[]; (arrayLike: ArrayLike, mapfn?: ((v: T, k: number) => U) | undefined, thisArg?: any): U[]; } +>a : Set> +>concat : { (...items: ReadonlyArray>[]): Nominal<"A", string>[]; (...items: (Nominal<"A", string> | ReadonlyArray>)[]): Nominal<"A", string>[]; } +>Array.from(b) : Nominal<"A", string>[] +>Array.from : { (iterable: Iterable, mapfn?: ((v: T, k: number) => U) | undefined, thisArg?: any): U[]; (arrayLike: ArrayLike, mapfn?: ((v: T, k: number) => U) | undefined, thisArg?: any): U[]; } +>Array : ArrayConstructor +>from : { (iterable: Iterable, mapfn?: ((v: T, k: number) => U) | undefined, thisArg?: any): U[]; (arrayLike: ArrayLike, mapfn?: ((v: T, k: number) => U) | undefined, thisArg?: any): U[]; } +>b : Set> + +// Simpler repro + +declare function from(): T[]; +>from : () => T[] +>T : T +>T : T + +const c2: ReadonlyArray = from(); +>c2 : ReadonlyArray> +>ReadonlyArray : ReadonlyArray +>A : Nominal<"A", string> +>from() : Nominal<"A", string>[] +>from : () => T[] + diff --git a/tests/cases/conformance/types/intersection/intersectionTypeInference3.ts b/tests/cases/conformance/types/intersection/intersectionTypeInference3.ts new file mode 100644 index 00000000000..ceaff10f7f1 --- /dev/null +++ b/tests/cases/conformance/types/intersection/intersectionTypeInference3.ts @@ -0,0 +1,20 @@ +// @strict: true +// @target: es2015 + +// Repro from #19682 + +type Nominal = Type & { + [Symbol.species]: Kind; +}; + +type A = Nominal<'A', string>; + +declare const a: Set; +declare const b: Set; + +const c1 = Array.from(a).concat(Array.from(b)); + +// Simpler repro + +declare function from(): T[]; +const c2: ReadonlyArray = from(); From 9bb6a527712022c5d0237eedac875cae4f9603e3 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Thu, 2 Nov 2017 20:13:25 -0700 Subject: [PATCH 4/4] Accept new baselines --- .../reference/intersectionTypeInference3.symbols | 8 ++++---- .../baselines/reference/intersectionTypeInference3.types | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/tests/baselines/reference/intersectionTypeInference3.symbols b/tests/baselines/reference/intersectionTypeInference3.symbols index 5b717508319..3945cf64fb6 100644 --- a/tests/baselines/reference/intersectionTypeInference3.symbols +++ b/tests/baselines/reference/intersectionTypeInference3.symbols @@ -32,14 +32,14 @@ declare const b: Set; const c1 = Array.from(a).concat(Array.from(b)); >c1 : Symbol(c1, Decl(intersectionTypeInference3.ts, 11, 5)) >Array.from(a).concat : Symbol(Array.concat, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --)) ->Array.from : Symbol(ArrayConstructor.from, Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.core.d.ts, --, --)) +>Array.from : Symbol(ArrayConstructor.from, Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.core.d.ts, --, --), Decl(lib.es2015.core.d.ts, --, --)) >Array : Symbol(Array, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.symbol.wellknown.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.core.d.ts, --, --)) ->from : Symbol(ArrayConstructor.from, Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.core.d.ts, --, --)) +>from : Symbol(ArrayConstructor.from, Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.core.d.ts, --, --), Decl(lib.es2015.core.d.ts, --, --)) >a : Symbol(a, Decl(intersectionTypeInference3.ts, 8, 13)) >concat : Symbol(Array.concat, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --)) ->Array.from : Symbol(ArrayConstructor.from, Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.core.d.ts, --, --)) +>Array.from : Symbol(ArrayConstructor.from, Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.core.d.ts, --, --), Decl(lib.es2015.core.d.ts, --, --)) >Array : Symbol(Array, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.symbol.wellknown.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.core.d.ts, --, --)) ->from : Symbol(ArrayConstructor.from, Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.core.d.ts, --, --)) +>from : Symbol(ArrayConstructor.from, Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.core.d.ts, --, --), Decl(lib.es2015.core.d.ts, --, --)) >b : Symbol(b, Decl(intersectionTypeInference3.ts, 9, 13)) // Simpler repro diff --git a/tests/baselines/reference/intersectionTypeInference3.types b/tests/baselines/reference/intersectionTypeInference3.types index 4d474c84d54..9fca37af8c1 100644 --- a/tests/baselines/reference/intersectionTypeInference3.types +++ b/tests/baselines/reference/intersectionTypeInference3.types @@ -34,15 +34,15 @@ const c1 = Array.from(a).concat(Array.from(b)); >Array.from(a).concat(Array.from(b)) : Nominal<"A", string>[] >Array.from(a).concat : { (...items: ReadonlyArray>[]): Nominal<"A", string>[]; (...items: (Nominal<"A", string> | ReadonlyArray>)[]): Nominal<"A", string>[]; } >Array.from(a) : Nominal<"A", string>[] ->Array.from : { (iterable: Iterable, mapfn?: ((v: T, k: number) => U) | undefined, thisArg?: any): U[]; (arrayLike: ArrayLike, mapfn?: ((v: T, k: number) => U) | undefined, thisArg?: any): U[]; } +>Array.from : { (iterable: Iterable): T[]; (iterable: Iterable, mapfn: (v: T, k: number) => U, thisArg?: any): U[]; (arrayLike: ArrayLike): T[]; (arrayLike: ArrayLike, mapfn: (v: T, k: number) => U, thisArg?: any): U[]; } >Array : ArrayConstructor ->from : { (iterable: Iterable, mapfn?: ((v: T, k: number) => U) | undefined, thisArg?: any): U[]; (arrayLike: ArrayLike, mapfn?: ((v: T, k: number) => U) | undefined, thisArg?: any): U[]; } +>from : { (iterable: Iterable): T[]; (iterable: Iterable, mapfn: (v: T, k: number) => U, thisArg?: any): U[]; (arrayLike: ArrayLike): T[]; (arrayLike: ArrayLike, mapfn: (v: T, k: number) => U, thisArg?: any): U[]; } >a : Set> >concat : { (...items: ReadonlyArray>[]): Nominal<"A", string>[]; (...items: (Nominal<"A", string> | ReadonlyArray>)[]): Nominal<"A", string>[]; } >Array.from(b) : Nominal<"A", string>[] ->Array.from : { (iterable: Iterable, mapfn?: ((v: T, k: number) => U) | undefined, thisArg?: any): U[]; (arrayLike: ArrayLike, mapfn?: ((v: T, k: number) => U) | undefined, thisArg?: any): U[]; } +>Array.from : { (iterable: Iterable): T[]; (iterable: Iterable, mapfn: (v: T, k: number) => U, thisArg?: any): U[]; (arrayLike: ArrayLike): T[]; (arrayLike: ArrayLike, mapfn: (v: T, k: number) => U, thisArg?: any): U[]; } >Array : ArrayConstructor ->from : { (iterable: Iterable, mapfn?: ((v: T, k: number) => U) | undefined, thisArg?: any): U[]; (arrayLike: ArrayLike, mapfn?: ((v: T, k: number) => U) | undefined, thisArg?: any): U[]; } +>from : { (iterable: Iterable): T[]; (iterable: Iterable, mapfn: (v: T, k: number) => U, thisArg?: any): U[]; (arrayLike: ArrayLike): T[]; (arrayLike: ArrayLike, mapfn: (v: T, k: number) => U, thisArg?: any): U[]; } >b : Set> // Simpler repro