diff --git a/tsc/internal/checker/checker.go b/tsc/internal/checker/checker.go index 845f62365bb84..7fb9e41a508e8 100644 --- a/tsc/internal/checker/checker.go +++ b/tsc/internal/checker/checker.go @@ -21787,10 +21787,23 @@ func (c *Checker) getUnionOrIntersectionProperty(t *Type, name string, skipObjec return prop } -func (c *Checker) createUnionOrIntersectionProperty(containingType *Type, name string, skipObjectFunctionPropertyAugment bool) *ast.Symbol { +// unionOrIntersectionPropertyParts is what the constituents of a union or +// intersection contribute to its property of a given name. +type unionOrIntersectionPropertyParts struct { + singleProp *ast.Symbol + propSet collections.OrderedSet[*ast.Symbol] // distinct constituent properties, if more than one + indexTypes []*Type + propFlags ast.SymbolFlags + checkFlags ast.CheckFlags + optionalFlag ast.SymbolFlags + syntheticFlag ast.CheckFlags + mergedInstantiations bool +} + +func (c *Checker) collectUnionOrIntersectionPropertyParts(containingType *Type, name string, skipObjectFunctionPropertyAugment bool, parts *unionOrIntersectionPropertyParts) { propFlags := ast.SymbolFlagsNone var singleProp *ast.Symbol - var propSet collections.OrderedSet[*ast.Symbol] + propSet := &parts.propSet var indexTypes []*Type isUnion := containingType.flags&TypeFlagsUnion != 0 // Flags we want to propagate to the result if they exist in all source symbols @@ -21895,6 +21908,16 @@ func (c *Checker) createUnionOrIntersectionProperty(containingType *Type, name s } } } + parts.singleProp, parts.indexTypes, parts.mergedInstantiations = singleProp, indexTypes, mergedInstantiations + parts.propFlags, parts.checkFlags, parts.optionalFlag, parts.syntheticFlag = propFlags, checkFlags, optionalFlag, syntheticFlag +} + +func (c *Checker) createUnionOrIntersectionProperty(containingType *Type, name string, skipObjectFunctionPropertyAugment bool) *ast.Symbol { + var parts unionOrIntersectionPropertyParts + c.collectUnionOrIntersectionPropertyParts(containingType, name, skipObjectFunctionPropertyAugment, &parts) + singleProp, propSet, indexTypes := parts.singleProp, &parts.propSet, parts.indexTypes + propFlags, checkFlags, optionalFlag, syntheticFlag := parts.propFlags, parts.checkFlags, parts.optionalFlag, parts.syntheticFlag + isUnion := containingType.flags&TypeFlagsUnion != 0 if singleProp == nil { // No property was found return nil @@ -21902,7 +21925,7 @@ func (c *Checker) createUnionOrIntersectionProperty(containingType *Type, name s if isUnion && (propSet.Size() != 0 || checkFlags&ast.CheckFlagsPartial != 0) && checkFlags&(ast.CheckFlagsContainsPrivate|ast.CheckFlagsContainsProtected|ast.CheckFlagsContainsWritePrivate|ast.CheckFlagsContainsWriteProtected) != 0 && - !(propSet.Size() != 0 && c.hasCommonDeclaration(&propSet)) { + !(propSet.Size() != 0 && c.hasCommonDeclaration(propSet)) { // A property in a union has a private or protected declaration in one constituent, but is missing // or has a different declaration in another constituent. If the private or protected declaration is // for reading, we don't create a property. @@ -21918,7 +21941,7 @@ func (c *Checker) createUnionOrIntersectionProperty(containingType *Type, name s } } if propSet.Size() == 0 && checkFlags&ast.CheckFlagsReadPartial == 0 && len(indexTypes) == 0 { - if !mergedInstantiations { + if !parts.mergedInstantiations { return singleProp } // No symbol from a union/intersection should have a `.parent` set (since unions/intersections don't act as symbol parents) @@ -21975,7 +21998,7 @@ func (c *Checker) createUnionOrIntersectionProperty(containingType *Type, name s if t != firstType { checkFlags |= ast.CheckFlagsHasNonUniformType } - if isLiteralType(t) || c.isPatternLiteralType(t) { + if c.isLiteralOrPatternLiteralType(t) { checkFlags |= ast.CheckFlagsHasLiteralType } if t.flags&TypeFlagsNever != 0 && t != c.uniqueLiteralType { @@ -22189,7 +22212,7 @@ func (c *Checker) getReducedType(t *Type) *Type { case t.flags&TypeFlagsIntersection != 0: if t.objectFlags&ObjectFlagsIsNeverIntersectionComputed == 0 { t.objectFlags |= ObjectFlagsIsNeverIntersectionComputed - if core.Some(c.getPropertiesOfUnionOrIntersectionType(t), c.isNeverReducedProperty) { + if c.isNeverReducedIntersection(t) { t.objectFlags |= ObjectFlagsIsNeverIntersection } } @@ -22216,6 +22239,59 @@ func (c *Checker) isNeverReducedProperty(prop *ast.Symbol) bool { return c.isDiscriminantWithNeverType(prop) || isConflictingPrivateProperty(prop) } +// isNeverReducedIntersection returns +// core.Some(c.getPropertiesOfUnionOrIntersectionType(t), c.isNeverReducedProperty) +// without creating the combined properties that can't satisfy +// isNeverReducedProperty, which in large intersections are most of them. +func (c *Checker) isNeverReducedIntersection(t *Type) bool { + if props := t.AsUnionOrIntersectionType().resolvedProperties; props != nil { + return core.Some(props, c.isNeverReducedProperty) + } + var checked collections.Set[string] + for _, current := range t.Types() { + for _, prop := range c.getPropertiesOfType(current) { + if !checked.AddIfAbsent(prop.Name) { + continue + } + var parts unionOrIntersectionPropertyParts + c.collectUnionOrIntersectionPropertyParts(t, prop.Name, true /*skipObjectFunctionPropertyAugment*/, &parts) + var combined *ast.Symbol + switch { + case parts.propSet.Size() == 0 && !parts.mergedInstantiations: + // What createUnionOrIntersectionProperty returns. Merged instantiations + // get a copy without check flags, which can't reduce. + combined = parts.singleProp + case parts.propSet.Size() != 0 && c.mayBeNeverReducedProperty(&parts): + combined = c.getPropertyOfUnionOrIntersectionType(t, prop.Name, true /*skipObjectFunctionPropertyAugment*/) + } + if combined != nil && c.isNeverReducedProperty(combined) { + return true + } + } + } + return false +} + +// mayBeNeverReducedProperty reports whether the property combined from parts +// with more than one distinct constituent property can satisfy +// isNeverReducedProperty, which requires CheckFlagsHasLiteralType or +// CheckFlagsContainsPrivate. +func (c *Checker) mayBeNeverReducedProperty(parts *unionOrIntersectionPropertyParts) bool { + if parts.checkFlags&ast.CheckFlagsContainsPrivate != 0 { + return true + } + for prop := range parts.propSet.Values() { + if c.isLiteralOrPatternLiteralType(c.getTypeOfSymbol(prop)) { + return true + } + } + return false +} + +func (c *Checker) isLiteralOrPatternLiteralType(t *Type) bool { + return isLiteralType(t) || c.isPatternLiteralType(t) +} + func (c *Checker) getReducedApparentType(t *Type) *Type { // Since getApparentType may return a non-reduced union or intersection type, we need to perform // type reduction both before and after obtaining the apparent type. For example, given a type parameter diff --git a/tsc/testdata/baselines/reference/compiler/intersectionNeverReductionByProperty.errors.txt b/tsc/testdata/baselines/reference/compiler/intersectionNeverReductionByProperty.errors.txt new file mode 100644 index 0000000000000..1894b4ed94bd9 --- /dev/null +++ b/tsc/testdata/baselines/reference/compiler/intersectionNeverReductionByProperty.errors.txt @@ -0,0 +1,138 @@ +intersectionNeverReductionByProperty.ts(24,4): error TS2339: Property 'kind' does not exist on type 'never'. + The intersection 'A1' was reduced to 'never' because property 'kind' has conflicting types in some constituents. +intersectionNeverReductionByProperty.ts(30,4): error TS2339: Property 'flag' does not exist on type 'never'. + The intersection 'A7' was reduced to 'never' because property 'flag' has conflicting types in some constituents. +intersectionNeverReductionByProperty.ts(31,4): error TS2339: Property 'tag' does not exist on type 'never'. + The intersection 'A8' was reduced to 'never' because property 'tag' has conflicting types in some constituents. +intersectionNeverReductionByProperty.ts(58,4): error TS2339: Property 'x' does not exist on type 'never'. + The intersection 'P1 & P2' was reduced to 'never' because property 'x' exists in multiple constituents and is private in some. +intersectionNeverReductionByProperty.ts(59,4): error TS2445: Property 'x' is protected and only accessible within class 'Q1 & Q2' and its subclasses. +intersectionNeverReductionByProperty.ts(63,4): error TS2339: Property 'kind' does not exist on type 'never'. + The intersection 'Generic<"a"> & Generic<"b">' was reduced to 'never' because property 'value' has conflicting types in some constituents. +intersectionNeverReductionByProperty.ts(70,4): error TS2339: Property 'kind' does not exist on type 'never'. + The intersection 'Tagged<"b">' was reduced to 'never' because property 'kind' has conflicting types in some constituents. +intersectionNeverReductionByProperty.ts(74,7): error TS2339: Property 'kind' does not exist on type 'never'. + Property 'kind' does not exist on type 'never'. +intersectionNeverReductionByProperty.ts(90,4): error TS2339: Property 'p1' does not exist on type 'never'. + The intersection 'Many & { kind: "other"; }' was reduced to 'never' because property 'kind' has conflicting types in some constituents. + + +==== intersectionNeverReductionByProperty.ts (9 errors) ==== + // Intersections that are and aren't reduced to never because of conflicting + // discriminants or private properties. + + type A1 = { kind: "a"; x: string } & { kind: "b"; y: string }; + type A2 = { kind: "a" | "b"; x: string } & { kind: "b"; y: string }; + type A3 = { kind?: "a" } & { kind?: "b" }; + type A4 = { kind: "a" } & { kind: string }; + type A5 = { kind: `a${string}` } & { kind: `b${string}` }; + type A6 = { kind: never } & { kind: "a" }; + type A7 = { flag: true } & { flag: false }; + type A8 = { tag: 1; a: string } & { b: number } & { tag: 2; c: boolean }; + type A9 = { x: string } & { x: number }; + + declare const a1: A1; + declare const a2: A2; + declare const a3: A3; + declare const a4: A4; + declare const a5: A5; + declare const a6: A6; + declare const a7: A7; + declare const a8: A8; + declare const a9: A9; + + a1.kind; + ~~~~ +!!! error TS2339: Property 'kind' does not exist on type 'never'. +!!! error TS2339: The intersection 'A1' was reduced to 'never' because property 'kind' has conflicting types in some constituents. + a2.kind; + a3.kind; + a4.kind; + a5.kind; + a6.kind; + a7.flag; + ~~~~ +!!! error TS2339: Property 'flag' does not exist on type 'never'. +!!! error TS2339: The intersection 'A7' was reduced to 'never' because property 'flag' has conflicting types in some constituents. + a8.tag; + ~~~ +!!! error TS2339: Property 'tag' does not exist on type 'never'. +!!! error TS2339: The intersection 'A8' was reduced to 'never' because property 'tag' has conflicting types in some constituents. + a9.x; + + class P1 { + private x = 1; + } + class P2 { + private x = 1; + } + class Q1 { + protected x = 1; + } + class Q2 { + protected x = 1; + } + class Generic { + private value!: T; + kind!: T; + } + + declare const b1: P1 & P2; + declare const b2: Q1 & Q2; + declare const b3: P1 & { y: string }; + declare const b4: Generic & Generic; + declare const b5: Generic & Generic; + declare const b6: Generic<"a"> & Generic<"b">; + + b1.x; + ~ +!!! error TS2339: Property 'x' does not exist on type 'never'. +!!! error TS2339: The intersection 'P1 & P2' was reduced to 'never' because property 'x' exists in multiple constituents and is private in some. + b2.x; + ~ +!!! error TS2445: Property 'x' is protected and only accessible within class 'Q1 & Q2' and its subclasses. + b3.y; + b4.kind; + b5.kind; + b6.kind; + ~~~~ +!!! error TS2339: Property 'kind' does not exist on type 'never'. +!!! error TS2339: The intersection 'Generic<"a"> & Generic<"b">' was reduced to 'never' because property 'value' has conflicting types in some constituents. + + type Tagged = { kind: T } & { kind: "a" }; + declare const c1: Tagged<"a">; + declare const c2: Tagged<"b">; + declare const c3: Tagged; + c1.kind; + c2.kind; + ~~~~ +!!! error TS2339: Property 'kind' does not exist on type 'never'. +!!! error TS2339: The intersection 'Tagged<"b">' was reduced to 'never' because property 'kind' has conflicting types in some constituents. + c3.kind; + + function f(x: T & { kind: "c" }, y: T & { kind: "a" }) { + x.kind; + ~~~~ +!!! error TS2339: Property 'kind' does not exist on type 'never'. +!!! error TS2339: Property 'kind' does not exist on type 'never'. + y.kind; + } + + interface Many { + p1: string; + p2: number; + p3: boolean; + p4: string[]; + p5: () => void; + kind: "many"; + } + declare const d1: Many & { kind: "many"; extra: string }; + declare const d2: Many & { kind: "other" }; + declare const d3: Many & Partial & { p1: "literal" }; + d1.extra; + d2.p1; + ~~ +!!! error TS2339: Property 'p1' does not exist on type 'never'. +!!! error TS2339: The intersection 'Many & { kind: "other"; }' was reduced to 'never' because property 'kind' has conflicting types in some constituents. + d3.p1; + \ No newline at end of file diff --git a/tsc/testdata/baselines/reference/compiler/intersectionNeverReductionByProperty.symbols b/tsc/testdata/baselines/reference/compiler/intersectionNeverReductionByProperty.symbols new file mode 100644 index 0000000000000..0da725cfab748 --- /dev/null +++ b/tsc/testdata/baselines/reference/compiler/intersectionNeverReductionByProperty.symbols @@ -0,0 +1,331 @@ +//// [tests/cases/compiler/intersectionNeverReductionByProperty.ts] //// + +=== intersectionNeverReductionByProperty.ts === +// Intersections that are and aren't reduced to never because of conflicting +// discriminants or private properties. + +type A1 = { kind: "a"; x: string } & { kind: "b"; y: string }; +>A1 : Symbol(A1, Decl(intersectionNeverReductionByProperty.ts, 0, 0)) +>kind : Symbol(kind, Decl(intersectionNeverReductionByProperty.ts, 3, 11)) +>x : Symbol(x, Decl(intersectionNeverReductionByProperty.ts, 3, 22)) +>kind : Symbol(kind, Decl(intersectionNeverReductionByProperty.ts, 3, 38)) +>y : Symbol(y, Decl(intersectionNeverReductionByProperty.ts, 3, 49)) + +type A2 = { kind: "a" | "b"; x: string } & { kind: "b"; y: string }; +>A2 : Symbol(A2, Decl(intersectionNeverReductionByProperty.ts, 3, 62)) +>kind : Symbol(kind, Decl(intersectionNeverReductionByProperty.ts, 4, 11)) +>x : Symbol(x, Decl(intersectionNeverReductionByProperty.ts, 4, 28)) +>kind : Symbol(kind, Decl(intersectionNeverReductionByProperty.ts, 4, 44)) +>y : Symbol(y, Decl(intersectionNeverReductionByProperty.ts, 4, 55)) + +type A3 = { kind?: "a" } & { kind?: "b" }; +>A3 : Symbol(A3, Decl(intersectionNeverReductionByProperty.ts, 4, 68)) +>kind : Symbol(kind, Decl(intersectionNeverReductionByProperty.ts, 5, 11)) +>kind : Symbol(kind, Decl(intersectionNeverReductionByProperty.ts, 5, 28)) + +type A4 = { kind: "a" } & { kind: string }; +>A4 : Symbol(A4, Decl(intersectionNeverReductionByProperty.ts, 5, 42)) +>kind : Symbol(kind, Decl(intersectionNeverReductionByProperty.ts, 6, 11)) +>kind : Symbol(kind, Decl(intersectionNeverReductionByProperty.ts, 6, 27)) + +type A5 = { kind: `a${string}` } & { kind: `b${string}` }; +>A5 : Symbol(A5, Decl(intersectionNeverReductionByProperty.ts, 6, 43)) +>kind : Symbol(kind, Decl(intersectionNeverReductionByProperty.ts, 7, 11)) +>kind : Symbol(kind, Decl(intersectionNeverReductionByProperty.ts, 7, 36)) + +type A6 = { kind: never } & { kind: "a" }; +>A6 : Symbol(A6, Decl(intersectionNeverReductionByProperty.ts, 7, 58)) +>kind : Symbol(kind, Decl(intersectionNeverReductionByProperty.ts, 8, 11)) +>kind : Symbol(kind, Decl(intersectionNeverReductionByProperty.ts, 8, 29)) + +type A7 = { flag: true } & { flag: false }; +>A7 : Symbol(A7, Decl(intersectionNeverReductionByProperty.ts, 8, 42)) +>flag : Symbol(flag, Decl(intersectionNeverReductionByProperty.ts, 9, 11)) +>flag : Symbol(flag, Decl(intersectionNeverReductionByProperty.ts, 9, 28)) + +type A8 = { tag: 1; a: string } & { b: number } & { tag: 2; c: boolean }; +>A8 : Symbol(A8, Decl(intersectionNeverReductionByProperty.ts, 9, 43)) +>tag : Symbol(tag, Decl(intersectionNeverReductionByProperty.ts, 10, 11)) +>a : Symbol(a, Decl(intersectionNeverReductionByProperty.ts, 10, 19)) +>b : Symbol(b, Decl(intersectionNeverReductionByProperty.ts, 10, 35)) +>tag : Symbol(tag, Decl(intersectionNeverReductionByProperty.ts, 10, 51)) +>c : Symbol(c, Decl(intersectionNeverReductionByProperty.ts, 10, 59)) + +type A9 = { x: string } & { x: number }; +>A9 : Symbol(A9, Decl(intersectionNeverReductionByProperty.ts, 10, 73)) +>x : Symbol(x, Decl(intersectionNeverReductionByProperty.ts, 11, 11)) +>x : Symbol(x, Decl(intersectionNeverReductionByProperty.ts, 11, 27)) + +declare const a1: A1; +>a1 : Symbol(a1, Decl(intersectionNeverReductionByProperty.ts, 13, 13)) +>A1 : Symbol(A1, Decl(intersectionNeverReductionByProperty.ts, 0, 0)) + +declare const a2: A2; +>a2 : Symbol(a2, Decl(intersectionNeverReductionByProperty.ts, 14, 13)) +>A2 : Symbol(A2, Decl(intersectionNeverReductionByProperty.ts, 3, 62)) + +declare const a3: A3; +>a3 : Symbol(a3, Decl(intersectionNeverReductionByProperty.ts, 15, 13)) +>A3 : Symbol(A3, Decl(intersectionNeverReductionByProperty.ts, 4, 68)) + +declare const a4: A4; +>a4 : Symbol(a4, Decl(intersectionNeverReductionByProperty.ts, 16, 13)) +>A4 : Symbol(A4, Decl(intersectionNeverReductionByProperty.ts, 5, 42)) + +declare const a5: A5; +>a5 : Symbol(a5, Decl(intersectionNeverReductionByProperty.ts, 17, 13)) +>A5 : Symbol(A5, Decl(intersectionNeverReductionByProperty.ts, 6, 43)) + +declare const a6: A6; +>a6 : Symbol(a6, Decl(intersectionNeverReductionByProperty.ts, 18, 13)) +>A6 : Symbol(A6, Decl(intersectionNeverReductionByProperty.ts, 7, 58)) + +declare const a7: A7; +>a7 : Symbol(a7, Decl(intersectionNeverReductionByProperty.ts, 19, 13)) +>A7 : Symbol(A7, Decl(intersectionNeverReductionByProperty.ts, 8, 42)) + +declare const a8: A8; +>a8 : Symbol(a8, Decl(intersectionNeverReductionByProperty.ts, 20, 13)) +>A8 : Symbol(A8, Decl(intersectionNeverReductionByProperty.ts, 9, 43)) + +declare const a9: A9; +>a9 : Symbol(a9, Decl(intersectionNeverReductionByProperty.ts, 21, 13)) +>A9 : Symbol(A9, Decl(intersectionNeverReductionByProperty.ts, 10, 73)) + +a1.kind; +>a1 : Symbol(a1, Decl(intersectionNeverReductionByProperty.ts, 13, 13)) + +a2.kind; +>a2.kind : Symbol(kind, Decl(intersectionNeverReductionByProperty.ts, 4, 11), Decl(intersectionNeverReductionByProperty.ts, 4, 44)) +>a2 : Symbol(a2, Decl(intersectionNeverReductionByProperty.ts, 14, 13)) +>kind : Symbol(kind, Decl(intersectionNeverReductionByProperty.ts, 4, 11), Decl(intersectionNeverReductionByProperty.ts, 4, 44)) + +a3.kind; +>a3.kind : Symbol(kind, Decl(intersectionNeverReductionByProperty.ts, 5, 11), Decl(intersectionNeverReductionByProperty.ts, 5, 28)) +>a3 : Symbol(a3, Decl(intersectionNeverReductionByProperty.ts, 15, 13)) +>kind : Symbol(kind, Decl(intersectionNeverReductionByProperty.ts, 5, 11), Decl(intersectionNeverReductionByProperty.ts, 5, 28)) + +a4.kind; +>a4.kind : Symbol(kind, Decl(intersectionNeverReductionByProperty.ts, 6, 11), Decl(intersectionNeverReductionByProperty.ts, 6, 27)) +>a4 : Symbol(a4, Decl(intersectionNeverReductionByProperty.ts, 16, 13)) +>kind : Symbol(kind, Decl(intersectionNeverReductionByProperty.ts, 6, 11), Decl(intersectionNeverReductionByProperty.ts, 6, 27)) + +a5.kind; +>a5.kind : Symbol(kind, Decl(intersectionNeverReductionByProperty.ts, 7, 11), Decl(intersectionNeverReductionByProperty.ts, 7, 36)) +>a5 : Symbol(a5, Decl(intersectionNeverReductionByProperty.ts, 17, 13)) +>kind : Symbol(kind, Decl(intersectionNeverReductionByProperty.ts, 7, 11), Decl(intersectionNeverReductionByProperty.ts, 7, 36)) + +a6.kind; +>a6.kind : Symbol(kind, Decl(intersectionNeverReductionByProperty.ts, 8, 11), Decl(intersectionNeverReductionByProperty.ts, 8, 29)) +>a6 : Symbol(a6, Decl(intersectionNeverReductionByProperty.ts, 18, 13)) +>kind : Symbol(kind, Decl(intersectionNeverReductionByProperty.ts, 8, 11), Decl(intersectionNeverReductionByProperty.ts, 8, 29)) + +a7.flag; +>a7 : Symbol(a7, Decl(intersectionNeverReductionByProperty.ts, 19, 13)) + +a8.tag; +>a8 : Symbol(a8, Decl(intersectionNeverReductionByProperty.ts, 20, 13)) + +a9.x; +>a9.x : Symbol(x, Decl(intersectionNeverReductionByProperty.ts, 11, 11), Decl(intersectionNeverReductionByProperty.ts, 11, 27)) +>a9 : Symbol(a9, Decl(intersectionNeverReductionByProperty.ts, 21, 13)) +>x : Symbol(x, Decl(intersectionNeverReductionByProperty.ts, 11, 11), Decl(intersectionNeverReductionByProperty.ts, 11, 27)) + +class P1 { +>P1 : Symbol(P1, Decl(intersectionNeverReductionByProperty.ts, 31, 5)) + + private x = 1; +>x : Symbol(P1.x, Decl(intersectionNeverReductionByProperty.ts, 33, 10)) +} +class P2 { +>P2 : Symbol(P2, Decl(intersectionNeverReductionByProperty.ts, 35, 1)) + + private x = 1; +>x : Symbol(P2.x, Decl(intersectionNeverReductionByProperty.ts, 36, 10)) +} +class Q1 { +>Q1 : Symbol(Q1, Decl(intersectionNeverReductionByProperty.ts, 38, 1)) + + protected x = 1; +>x : Symbol(Q1.x, Decl(intersectionNeverReductionByProperty.ts, 39, 10)) +} +class Q2 { +>Q2 : Symbol(Q2, Decl(intersectionNeverReductionByProperty.ts, 41, 1)) + + protected x = 1; +>x : Symbol(Q2.x, Decl(intersectionNeverReductionByProperty.ts, 42, 10)) +} +class Generic { +>Generic : Symbol(Generic, Decl(intersectionNeverReductionByProperty.ts, 44, 1)) +>T : Symbol(T, Decl(intersectionNeverReductionByProperty.ts, 45, 14)) + + private value!: T; +>value : Symbol(Generic.value, Decl(intersectionNeverReductionByProperty.ts, 45, 18)) +>T : Symbol(T, Decl(intersectionNeverReductionByProperty.ts, 45, 14)) + + kind!: T; +>kind : Symbol(Generic.kind, Decl(intersectionNeverReductionByProperty.ts, 46, 22)) +>T : Symbol(T, Decl(intersectionNeverReductionByProperty.ts, 45, 14)) +} + +declare const b1: P1 & P2; +>b1 : Symbol(b1, Decl(intersectionNeverReductionByProperty.ts, 50, 13)) +>P1 : Symbol(P1, Decl(intersectionNeverReductionByProperty.ts, 31, 5)) +>P2 : Symbol(P2, Decl(intersectionNeverReductionByProperty.ts, 35, 1)) + +declare const b2: Q1 & Q2; +>b2 : Symbol(b2, Decl(intersectionNeverReductionByProperty.ts, 51, 13)) +>Q1 : Symbol(Q1, Decl(intersectionNeverReductionByProperty.ts, 38, 1)) +>Q2 : Symbol(Q2, Decl(intersectionNeverReductionByProperty.ts, 41, 1)) + +declare const b3: P1 & { y: string }; +>b3 : Symbol(b3, Decl(intersectionNeverReductionByProperty.ts, 52, 13)) +>P1 : Symbol(P1, Decl(intersectionNeverReductionByProperty.ts, 31, 5)) +>y : Symbol(y, Decl(intersectionNeverReductionByProperty.ts, 52, 24)) + +declare const b4: Generic & Generic; +>b4 : Symbol(b4, Decl(intersectionNeverReductionByProperty.ts, 53, 13)) +>Generic : Symbol(Generic, Decl(intersectionNeverReductionByProperty.ts, 44, 1)) +>Generic : Symbol(Generic, Decl(intersectionNeverReductionByProperty.ts, 44, 1)) + +declare const b5: Generic & Generic; +>b5 : Symbol(b5, Decl(intersectionNeverReductionByProperty.ts, 54, 13)) +>Generic : Symbol(Generic, Decl(intersectionNeverReductionByProperty.ts, 44, 1)) +>Generic : Symbol(Generic, Decl(intersectionNeverReductionByProperty.ts, 44, 1)) + +declare const b6: Generic<"a"> & Generic<"b">; +>b6 : Symbol(b6, Decl(intersectionNeverReductionByProperty.ts, 55, 13)) +>Generic : Symbol(Generic, Decl(intersectionNeverReductionByProperty.ts, 44, 1)) +>Generic : Symbol(Generic, Decl(intersectionNeverReductionByProperty.ts, 44, 1)) + +b1.x; +>b1 : Symbol(b1, Decl(intersectionNeverReductionByProperty.ts, 50, 13)) + +b2.x; +>b2.x : Symbol(x, Decl(intersectionNeverReductionByProperty.ts, 39, 10), Decl(intersectionNeverReductionByProperty.ts, 42, 10)) +>b2 : Symbol(b2, Decl(intersectionNeverReductionByProperty.ts, 51, 13)) +>x : Symbol(x, Decl(intersectionNeverReductionByProperty.ts, 39, 10), Decl(intersectionNeverReductionByProperty.ts, 42, 10)) + +b3.y; +>b3.y : Symbol(y, Decl(intersectionNeverReductionByProperty.ts, 52, 24)) +>b3 : Symbol(b3, Decl(intersectionNeverReductionByProperty.ts, 52, 13)) +>y : Symbol(y, Decl(intersectionNeverReductionByProperty.ts, 52, 24)) + +b4.kind; +>b4.kind : Symbol(Generic.kind, Decl(intersectionNeverReductionByProperty.ts, 46, 22)) +>b4 : Symbol(b4, Decl(intersectionNeverReductionByProperty.ts, 53, 13)) +>kind : Symbol(Generic.kind, Decl(intersectionNeverReductionByProperty.ts, 46, 22)) + +b5.kind; +>b5.kind : Symbol(Generic.kind, Decl(intersectionNeverReductionByProperty.ts, 46, 22)) +>b5 : Symbol(b5, Decl(intersectionNeverReductionByProperty.ts, 54, 13)) +>kind : Symbol(Generic.kind, Decl(intersectionNeverReductionByProperty.ts, 46, 22)) + +b6.kind; +>b6 : Symbol(b6, Decl(intersectionNeverReductionByProperty.ts, 55, 13)) + +type Tagged = { kind: T } & { kind: "a" }; +>Tagged : Symbol(Tagged, Decl(intersectionNeverReductionByProperty.ts, 62, 8)) +>T : Symbol(T, Decl(intersectionNeverReductionByProperty.ts, 64, 12)) +>kind : Symbol(kind, Decl(intersectionNeverReductionByProperty.ts, 64, 18)) +>T : Symbol(T, Decl(intersectionNeverReductionByProperty.ts, 64, 12)) +>kind : Symbol(kind, Decl(intersectionNeverReductionByProperty.ts, 64, 32)) + +declare const c1: Tagged<"a">; +>c1 : Symbol(c1, Decl(intersectionNeverReductionByProperty.ts, 65, 13)) +>Tagged : Symbol(Tagged, Decl(intersectionNeverReductionByProperty.ts, 62, 8)) + +declare const c2: Tagged<"b">; +>c2 : Symbol(c2, Decl(intersectionNeverReductionByProperty.ts, 66, 13)) +>Tagged : Symbol(Tagged, Decl(intersectionNeverReductionByProperty.ts, 62, 8)) + +declare const c3: Tagged; +>c3 : Symbol(c3, Decl(intersectionNeverReductionByProperty.ts, 67, 13)) +>Tagged : Symbol(Tagged, Decl(intersectionNeverReductionByProperty.ts, 62, 8)) + +c1.kind; +>c1.kind : Symbol(kind, Decl(intersectionNeverReductionByProperty.ts, 64, 18), Decl(intersectionNeverReductionByProperty.ts, 64, 32)) +>c1 : Symbol(c1, Decl(intersectionNeverReductionByProperty.ts, 65, 13)) +>kind : Symbol(kind, Decl(intersectionNeverReductionByProperty.ts, 64, 18), Decl(intersectionNeverReductionByProperty.ts, 64, 32)) + +c2.kind; +>c2 : Symbol(c2, Decl(intersectionNeverReductionByProperty.ts, 66, 13)) + +c3.kind; +>c3.kind : Symbol(kind, Decl(intersectionNeverReductionByProperty.ts, 64, 18), Decl(intersectionNeverReductionByProperty.ts, 64, 32)) +>c3 : Symbol(c3, Decl(intersectionNeverReductionByProperty.ts, 67, 13)) +>kind : Symbol(kind, Decl(intersectionNeverReductionByProperty.ts, 64, 18), Decl(intersectionNeverReductionByProperty.ts, 64, 32)) + +function f(x: T & { kind: "c" }, y: T & { kind: "a" }) { +>f : Symbol(f, Decl(intersectionNeverReductionByProperty.ts, 70, 8)) +>T : Symbol(T, Decl(intersectionNeverReductionByProperty.ts, 72, 11)) +>kind : Symbol(kind, Decl(intersectionNeverReductionByProperty.ts, 72, 22)) +>kind : Symbol(kind, Decl(intersectionNeverReductionByProperty.ts, 72, 38)) +>x : Symbol(x, Decl(intersectionNeverReductionByProperty.ts, 72, 52)) +>T : Symbol(T, Decl(intersectionNeverReductionByProperty.ts, 72, 11)) +>kind : Symbol(kind, Decl(intersectionNeverReductionByProperty.ts, 72, 60)) +>y : Symbol(y, Decl(intersectionNeverReductionByProperty.ts, 72, 73)) +>T : Symbol(T, Decl(intersectionNeverReductionByProperty.ts, 72, 11)) +>kind : Symbol(kind, Decl(intersectionNeverReductionByProperty.ts, 72, 82)) + + x.kind; +>x : Symbol(x, Decl(intersectionNeverReductionByProperty.ts, 72, 52)) + + y.kind; +>y.kind : Symbol(kind, Decl(intersectionNeverReductionByProperty.ts, 72, 22), Decl(intersectionNeverReductionByProperty.ts, 72, 82)) +>y : Symbol(y, Decl(intersectionNeverReductionByProperty.ts, 72, 73)) +>kind : Symbol(kind, Decl(intersectionNeverReductionByProperty.ts, 72, 22), Decl(intersectionNeverReductionByProperty.ts, 72, 82)) +} + +interface Many { +>Many : Symbol(Many, Decl(intersectionNeverReductionByProperty.ts, 75, 1)) + + p1: string; +>p1 : Symbol(Many.p1, Decl(intersectionNeverReductionByProperty.ts, 77, 16)) + + p2: number; +>p2 : Symbol(Many.p2, Decl(intersectionNeverReductionByProperty.ts, 78, 15)) + + p3: boolean; +>p3 : Symbol(Many.p3, Decl(intersectionNeverReductionByProperty.ts, 79, 15)) + + p4: string[]; +>p4 : Symbol(Many.p4, Decl(intersectionNeverReductionByProperty.ts, 80, 16)) + + p5: () => void; +>p5 : Symbol(Many.p5, Decl(intersectionNeverReductionByProperty.ts, 81, 17)) + + kind: "many"; +>kind : Symbol(Many.kind, Decl(intersectionNeverReductionByProperty.ts, 82, 19)) +} +declare const d1: Many & { kind: "many"; extra: string }; +>d1 : Symbol(d1, Decl(intersectionNeverReductionByProperty.ts, 85, 13)) +>Many : Symbol(Many, Decl(intersectionNeverReductionByProperty.ts, 75, 1)) +>kind : Symbol(kind, Decl(intersectionNeverReductionByProperty.ts, 85, 26)) +>extra : Symbol(extra, Decl(intersectionNeverReductionByProperty.ts, 85, 40)) + +declare const d2: Many & { kind: "other" }; +>d2 : Symbol(d2, Decl(intersectionNeverReductionByProperty.ts, 86, 13)) +>Many : Symbol(Many, Decl(intersectionNeverReductionByProperty.ts, 75, 1)) +>kind : Symbol(kind, Decl(intersectionNeverReductionByProperty.ts, 86, 26)) + +declare const d3: Many & Partial & { p1: "literal" }; +>d3 : Symbol(d3, Decl(intersectionNeverReductionByProperty.ts, 87, 13)) +>Many : Symbol(Many, Decl(intersectionNeverReductionByProperty.ts, 75, 1)) +>Partial : Symbol(Partial, Decl(lib.es5.d.ts, --, --)) +>Many : Symbol(Many, Decl(intersectionNeverReductionByProperty.ts, 75, 1)) +>p1 : Symbol(p1, Decl(intersectionNeverReductionByProperty.ts, 87, 42)) + +d1.extra; +>d1.extra : Symbol(extra, Decl(intersectionNeverReductionByProperty.ts, 85, 40)) +>d1 : Symbol(d1, Decl(intersectionNeverReductionByProperty.ts, 85, 13)) +>extra : Symbol(extra, Decl(intersectionNeverReductionByProperty.ts, 85, 40)) + +d2.p1; +>d2 : Symbol(d2, Decl(intersectionNeverReductionByProperty.ts, 86, 13)) + +d3.p1; +>d3.p1 : Symbol(p1, Decl(intersectionNeverReductionByProperty.ts, 77, 16), Decl(intersectionNeverReductionByProperty.ts, 87, 42)) +>d3 : Symbol(d3, Decl(intersectionNeverReductionByProperty.ts, 87, 13)) +>p1 : Symbol(p1, Decl(intersectionNeverReductionByProperty.ts, 77, 16), Decl(intersectionNeverReductionByProperty.ts, 87, 42)) + diff --git a/tsc/testdata/baselines/reference/compiler/intersectionNeverReductionByProperty.types b/tsc/testdata/baselines/reference/compiler/intersectionNeverReductionByProperty.types new file mode 100644 index 0000000000000..962507c1efa68 --- /dev/null +++ b/tsc/testdata/baselines/reference/compiler/intersectionNeverReductionByProperty.types @@ -0,0 +1,315 @@ +//// [tests/cases/compiler/intersectionNeverReductionByProperty.ts] //// + +=== intersectionNeverReductionByProperty.ts === +// Intersections that are and aren't reduced to never because of conflicting +// discriminants or private properties. + +type A1 = { kind: "a"; x: string } & { kind: "b"; y: string }; +>A1 : never +>kind : "a" +>x : string +>kind : "b" +>y : string + +type A2 = { kind: "a" | "b"; x: string } & { kind: "b"; y: string }; +>A2 : A2 +>kind : "a" | "b" +>x : string +>kind : "b" +>y : string + +type A3 = { kind?: "a" } & { kind?: "b" }; +>A3 : A3 +>kind : "a" | undefined +>kind : "b" | undefined + +type A4 = { kind: "a" } & { kind: string }; +>A4 : A4 +>kind : "a" +>kind : string + +type A5 = { kind: `a${string}` } & { kind: `b${string}` }; +>A5 : A5 +>kind : `a${string}` +>kind : `b${string}` + +type A6 = { kind: never } & { kind: "a" }; +>A6 : A6 +>kind : never +>kind : "a" + +type A7 = { flag: true } & { flag: false }; +>A7 : never +>flag : true +>true : true +>flag : false +>false : false + +type A8 = { tag: 1; a: string } & { b: number } & { tag: 2; c: boolean }; +>A8 : never +>tag : 1 +>a : string +>b : number +>tag : 2 +>c : boolean + +type A9 = { x: string } & { x: number }; +>A9 : A9 +>x : string +>x : number + +declare const a1: A1; +>a1 : never + +declare const a2: A2; +>a2 : A2 + +declare const a3: A3; +>a3 : A3 + +declare const a4: A4; +>a4 : A4 + +declare const a5: A5; +>a5 : A5 + +declare const a6: A6; +>a6 : A6 + +declare const a7: A7; +>a7 : never + +declare const a8: A8; +>a8 : never + +declare const a9: A9; +>a9 : A9 + +a1.kind; +>a1.kind : any +>a1 : never +>kind : any + +a2.kind; +>a2.kind : "b" +>a2 : A2 +>kind : "b" + +a3.kind; +>a3.kind : undefined +>a3 : A3 +>kind : undefined + +a4.kind; +>a4.kind : "a" +>a4 : A4 +>kind : "a" + +a5.kind; +>a5.kind : `a${string}` & `b${string}` +>a5 : A5 +>kind : `a${string}` & `b${string}` + +a6.kind; +>a6.kind : never +>a6 : A6 +>kind : never + +a7.flag; +>a7.flag : any +>a7 : never +>flag : any + +a8.tag; +>a8.tag : any +>a8 : never +>tag : any + +a9.x; +>a9.x : never +>a9 : A9 +>x : never + +class P1 { +>P1 : P1 + + private x = 1; +>x : number +>1 : 1 +} +class P2 { +>P2 : P2 + + private x = 1; +>x : number +>1 : 1 +} +class Q1 { +>Q1 : Q1 + + protected x = 1; +>x : number +>1 : 1 +} +class Q2 { +>Q2 : Q2 + + protected x = 1; +>x : number +>1 : 1 +} +class Generic { +>Generic : Generic + + private value!: T; +>value : T + + kind!: T; +>kind : T +} + +declare const b1: P1 & P2; +>b1 : never + +declare const b2: Q1 & Q2; +>b2 : Q1 & Q2 + +declare const b3: P1 & { y: string }; +>b3 : P1 & { y: string; } +>y : string + +declare const b4: Generic & Generic; +>b4 : Generic + +declare const b5: Generic & Generic; +>b5 : Generic & Generic + +declare const b6: Generic<"a"> & Generic<"b">; +>b6 : never + +b1.x; +>b1.x : any +>b1 : never +>x : any + +b2.x; +>b2.x : number +>b2 : Q1 & Q2 +>x : number + +b3.y; +>b3.y : string +>b3 : P1 & { y: string; } +>y : string + +b4.kind; +>b4.kind : string +>b4 : Generic +>kind : string + +b5.kind; +>b5.kind : never +>b5 : Generic & Generic +>kind : never + +b6.kind; +>b6.kind : any +>b6 : never +>kind : any + +type Tagged = { kind: T } & { kind: "a" }; +>Tagged : Tagged +>kind : T +>kind : "a" + +declare const c1: Tagged<"a">; +>c1 : Tagged<"a"> + +declare const c2: Tagged<"b">; +>c2 : never + +declare const c3: Tagged; +>c3 : Tagged + +c1.kind; +>c1.kind : "a" +>c1 : Tagged<"a"> +>kind : "a" + +c2.kind; +>c2.kind : any +>c2 : never +>kind : any + +c3.kind; +>c3.kind : "a" +>c3 : Tagged +>kind : "a" + +function f(x: T & { kind: "c" }, y: T & { kind: "a" }) { +>f : (x: T & { kind: "c"; }, y: T & { kind: "a"; }) => void +>kind : "a" +>kind : "b" +>x : never +>kind : "c" +>y : T & { kind: "a"; } +>kind : "a" + + x.kind; +>x.kind : any +>x : never +>kind : any + + y.kind; +>y.kind : "a" +>y : { kind: "a"; } & { kind: "a"; } +>kind : "a" +} + +interface Many { + p1: string; +>p1 : string + + p2: number; +>p2 : number + + p3: boolean; +>p3 : boolean + + p4: string[]; +>p4 : string[] + + p5: () => void; +>p5 : () => void + + kind: "many"; +>kind : "many" +} +declare const d1: Many & { kind: "many"; extra: string }; +>d1 : Many & { kind: "many"; extra: string; } +>kind : "many" +>extra : string + +declare const d2: Many & { kind: "other" }; +>d2 : never +>kind : "other" + +declare const d3: Many & Partial & { p1: "literal" }; +>d3 : Many & Partial & { p1: "literal"; } +>p1 : "literal" + +d1.extra; +>d1.extra : string +>d1 : Many & { kind: "many"; extra: string; } +>extra : string + +d2.p1; +>d2.p1 : any +>d2 : never +>p1 : any + +d3.p1; +>d3.p1 : "literal" +>d3 : Many & Partial & { p1: "literal"; } +>p1 : "literal" + diff --git a/tsc/testdata/tests/cases/compiler/intersectionNeverReductionByProperty.ts b/tsc/testdata/tests/cases/compiler/intersectionNeverReductionByProperty.ts new file mode 100644 index 0000000000000..05455cc49799d --- /dev/null +++ b/tsc/testdata/tests/cases/compiler/intersectionNeverReductionByProperty.ts @@ -0,0 +1,95 @@ +// @strict: true +// @target: esnext +// @noEmit: true + +// Intersections that are and aren't reduced to never because of conflicting +// discriminants or private properties. + +type A1 = { kind: "a"; x: string } & { kind: "b"; y: string }; +type A2 = { kind: "a" | "b"; x: string } & { kind: "b"; y: string }; +type A3 = { kind?: "a" } & { kind?: "b" }; +type A4 = { kind: "a" } & { kind: string }; +type A5 = { kind: `a${string}` } & { kind: `b${string}` }; +type A6 = { kind: never } & { kind: "a" }; +type A7 = { flag: true } & { flag: false }; +type A8 = { tag: 1; a: string } & { b: number } & { tag: 2; c: boolean }; +type A9 = { x: string } & { x: number }; + +declare const a1: A1; +declare const a2: A2; +declare const a3: A3; +declare const a4: A4; +declare const a5: A5; +declare const a6: A6; +declare const a7: A7; +declare const a8: A8; +declare const a9: A9; + +a1.kind; +a2.kind; +a3.kind; +a4.kind; +a5.kind; +a6.kind; +a7.flag; +a8.tag; +a9.x; + +class P1 { + private x = 1; +} +class P2 { + private x = 1; +} +class Q1 { + protected x = 1; +} +class Q2 { + protected x = 1; +} +class Generic { + private value!: T; + kind!: T; +} + +declare const b1: P1 & P2; +declare const b2: Q1 & Q2; +declare const b3: P1 & { y: string }; +declare const b4: Generic & Generic; +declare const b5: Generic & Generic; +declare const b6: Generic<"a"> & Generic<"b">; + +b1.x; +b2.x; +b3.y; +b4.kind; +b5.kind; +b6.kind; + +type Tagged = { kind: T } & { kind: "a" }; +declare const c1: Tagged<"a">; +declare const c2: Tagged<"b">; +declare const c3: Tagged; +c1.kind; +c2.kind; +c3.kind; + +function f(x: T & { kind: "c" }, y: T & { kind: "a" }) { + x.kind; + y.kind; +} + +interface Many { + p1: string; + p2: number; + p3: boolean; + p4: string[]; + p5: () => void; + kind: "many"; +} +declare const d1: Many & { kind: "many"; extra: string }; +declare const d2: Many & { kind: "other" }; +declare const d3: Many & Partial & { p1: "literal" }; +d1.extra; +d2.p1; +d3.p1;