From fb717df6bf85318c3d1e833a1dde6789d394cdb2 Mon Sep 17 00:00:00 2001 From: Daniel Rosenwasser Date: Wed, 24 Aug 2022 11:39:00 -0700 Subject: [PATCH] Discard union types before considering weak type checks on unit-like types (#50423) * Only check isUnitType when dealing with non-unions. * Add test case. * Accepted baselines. --- src/compiler/checker.ts | 2 +- .../reference/weakTypesAndLiterals01.js | 67 ++++++++++++ .../reference/weakTypesAndLiterals01.symbols | 95 ++++++++++++++++ .../reference/weakTypesAndLiterals01.types | 101 ++++++++++++++++++ .../comparable/weakTypesAndLiterals01.ts | 51 +++++++++ 5 files changed, 315 insertions(+), 1 deletion(-) create mode 100644 tests/baselines/reference/weakTypesAndLiterals01.js create mode 100644 tests/baselines/reference/weakTypesAndLiterals01.symbols create mode 100644 tests/baselines/reference/weakTypesAndLiterals01.types create mode 100644 tests/cases/conformance/types/typeRelationships/comparable/weakTypesAndLiterals01.ts diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 8472c8b38e7e5..eb0cda34736c1 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -18901,7 +18901,7 @@ namespace ts { } } - const isPerformingCommonPropertyChecks = (relation !== comparableRelation || relation === comparableRelation && isLiteralType(source)) && + const isPerformingCommonPropertyChecks = (relation !== comparableRelation || !(source.flags & TypeFlags.Union) && isLiteralType(source)) && !(intersectionState & IntersectionState.Target) && source.flags & (TypeFlags.Primitive | TypeFlags.Object | TypeFlags.Intersection) && source !== globalObjectType && target.flags & (TypeFlags.Object | TypeFlags.Intersection) && isWeakType(target) && diff --git a/tests/baselines/reference/weakTypesAndLiterals01.js b/tests/baselines/reference/weakTypesAndLiterals01.js new file mode 100644 index 0000000000000..1034ed6fd1888 --- /dev/null +++ b/tests/baselines/reference/weakTypesAndLiterals01.js @@ -0,0 +1,67 @@ +//// [weakTypesAndLiterals01.ts] +type WeakTypes = + | { optional?: true; } + | { toLowerCase?(): string } + | { toUpperCase?(): string, otherOptionalProp?: number }; + +type LiteralsOrWeakTypes = + | "A" + | "B" + | WeakTypes; + +declare let aOrB: "A" | "B"; + +const f = (arg: LiteralsOrWeakTypes) => { + if (arg === "A") { + return arg; + } + else { + return arg; + } +} + +const g = (arg: WeakTypes) => { + if (arg === "A") { + return arg; + } + else { + return arg; + } +} + +const h = (arg: LiteralsOrWeakTypes) => { + if (arg === aOrB) { + return arg; + } + else { + return arg; + } +} + +const i = (arg: WeakTypes) => { + if (arg === aOrB) { + return arg; + } + else { + return arg; + } +} + + + + +//// [weakTypesAndLiterals01.d.ts] +type WeakTypes = { + optional?: true; +} | { + toLowerCase?(): string; +} | { + toUpperCase?(): string; + otherOptionalProp?: number; +}; +type LiteralsOrWeakTypes = "A" | "B" | WeakTypes; +declare let aOrB: "A" | "B"; +declare const f: (arg: LiteralsOrWeakTypes) => WeakTypes | "A" | "B"; +declare const g: (arg: WeakTypes) => WeakTypes; +declare const h: (arg: LiteralsOrWeakTypes) => LiteralsOrWeakTypes; +declare const i: (arg: WeakTypes) => WeakTypes; diff --git a/tests/baselines/reference/weakTypesAndLiterals01.symbols b/tests/baselines/reference/weakTypesAndLiterals01.symbols new file mode 100644 index 0000000000000..7a3abe9c9c702 --- /dev/null +++ b/tests/baselines/reference/weakTypesAndLiterals01.symbols @@ -0,0 +1,95 @@ +=== tests/cases/conformance/types/typeRelationships/comparable/weakTypesAndLiterals01.ts === +type WeakTypes = +>WeakTypes : Symbol(WeakTypes, Decl(weakTypesAndLiterals01.ts, 0, 0)) + + | { optional?: true; } +>optional : Symbol(optional, Decl(weakTypesAndLiterals01.ts, 1, 7)) + + | { toLowerCase?(): string } +>toLowerCase : Symbol(toLowerCase, Decl(weakTypesAndLiterals01.ts, 2, 7)) + + | { toUpperCase?(): string, otherOptionalProp?: number }; +>toUpperCase : Symbol(toUpperCase, Decl(weakTypesAndLiterals01.ts, 3, 7)) +>otherOptionalProp : Symbol(otherOptionalProp, Decl(weakTypesAndLiterals01.ts, 3, 31)) + +type LiteralsOrWeakTypes = +>LiteralsOrWeakTypes : Symbol(LiteralsOrWeakTypes, Decl(weakTypesAndLiterals01.ts, 3, 61)) + + | "A" + | "B" + | WeakTypes; +>WeakTypes : Symbol(WeakTypes, Decl(weakTypesAndLiterals01.ts, 0, 0)) + +declare let aOrB: "A" | "B"; +>aOrB : Symbol(aOrB, Decl(weakTypesAndLiterals01.ts, 10, 11)) + +const f = (arg: LiteralsOrWeakTypes) => { +>f : Symbol(f, Decl(weakTypesAndLiterals01.ts, 12, 5)) +>arg : Symbol(arg, Decl(weakTypesAndLiterals01.ts, 12, 11)) +>LiteralsOrWeakTypes : Symbol(LiteralsOrWeakTypes, Decl(weakTypesAndLiterals01.ts, 3, 61)) + + if (arg === "A") { +>arg : Symbol(arg, Decl(weakTypesAndLiterals01.ts, 12, 11)) + + return arg; +>arg : Symbol(arg, Decl(weakTypesAndLiterals01.ts, 12, 11)) + } + else { + return arg; +>arg : Symbol(arg, Decl(weakTypesAndLiterals01.ts, 12, 11)) + } +} + +const g = (arg: WeakTypes) => { +>g : Symbol(g, Decl(weakTypesAndLiterals01.ts, 21, 5)) +>arg : Symbol(arg, Decl(weakTypesAndLiterals01.ts, 21, 11)) +>WeakTypes : Symbol(WeakTypes, Decl(weakTypesAndLiterals01.ts, 0, 0)) + + if (arg === "A") { +>arg : Symbol(arg, Decl(weakTypesAndLiterals01.ts, 21, 11)) + + return arg; +>arg : Symbol(arg, Decl(weakTypesAndLiterals01.ts, 21, 11)) + } + else { + return arg; +>arg : Symbol(arg, Decl(weakTypesAndLiterals01.ts, 21, 11)) + } +} + +const h = (arg: LiteralsOrWeakTypes) => { +>h : Symbol(h, Decl(weakTypesAndLiterals01.ts, 30, 5)) +>arg : Symbol(arg, Decl(weakTypesAndLiterals01.ts, 30, 11)) +>LiteralsOrWeakTypes : Symbol(LiteralsOrWeakTypes, Decl(weakTypesAndLiterals01.ts, 3, 61)) + + if (arg === aOrB) { +>arg : Symbol(arg, Decl(weakTypesAndLiterals01.ts, 30, 11)) +>aOrB : Symbol(aOrB, Decl(weakTypesAndLiterals01.ts, 10, 11)) + + return arg; +>arg : Symbol(arg, Decl(weakTypesAndLiterals01.ts, 30, 11)) + } + else { + return arg; +>arg : Symbol(arg, Decl(weakTypesAndLiterals01.ts, 30, 11)) + } +} + +const i = (arg: WeakTypes) => { +>i : Symbol(i, Decl(weakTypesAndLiterals01.ts, 39, 5)) +>arg : Symbol(arg, Decl(weakTypesAndLiterals01.ts, 39, 11)) +>WeakTypes : Symbol(WeakTypes, Decl(weakTypesAndLiterals01.ts, 0, 0)) + + if (arg === aOrB) { +>arg : Symbol(arg, Decl(weakTypesAndLiterals01.ts, 39, 11)) +>aOrB : Symbol(aOrB, Decl(weakTypesAndLiterals01.ts, 10, 11)) + + return arg; +>arg : Symbol(arg, Decl(weakTypesAndLiterals01.ts, 39, 11)) + } + else { + return arg; +>arg : Symbol(arg, Decl(weakTypesAndLiterals01.ts, 39, 11)) + } +} + diff --git a/tests/baselines/reference/weakTypesAndLiterals01.types b/tests/baselines/reference/weakTypesAndLiterals01.types new file mode 100644 index 0000000000000..e2d928ccbf58b --- /dev/null +++ b/tests/baselines/reference/weakTypesAndLiterals01.types @@ -0,0 +1,101 @@ +=== tests/cases/conformance/types/typeRelationships/comparable/weakTypesAndLiterals01.ts === +type WeakTypes = +>WeakTypes : { optional?: true | undefined; } | { toLowerCase?(): string; } | { toUpperCase?(): string; otherOptionalProp?: number | undefined; } + + | { optional?: true; } +>optional : true | undefined +>true : true + + | { toLowerCase?(): string } +>toLowerCase : (() => string) | undefined + + | { toUpperCase?(): string, otherOptionalProp?: number }; +>toUpperCase : (() => string) | undefined +>otherOptionalProp : number | undefined + +type LiteralsOrWeakTypes = +>LiteralsOrWeakTypes : WeakTypes | "A" | "B" + + | "A" + | "B" + | WeakTypes; + +declare let aOrB: "A" | "B"; +>aOrB : "A" | "B" + +const f = (arg: LiteralsOrWeakTypes) => { +>f : (arg: LiteralsOrWeakTypes) => WeakTypes | "A" | "B" +>(arg: LiteralsOrWeakTypes) => { if (arg === "A") { return arg; } else { return arg; }} : (arg: LiteralsOrWeakTypes) => WeakTypes | "A" | "B" +>arg : LiteralsOrWeakTypes + + if (arg === "A") { +>arg === "A" : boolean +>arg : LiteralsOrWeakTypes +>"A" : "A" + + return arg; +>arg : { toLowerCase?(): string; } | { toUpperCase?(): string; otherOptionalProp?: number | undefined; } | "A" + } + else { + return arg; +>arg : WeakTypes | "B" + } +} + +const g = (arg: WeakTypes) => { +>g : (arg: WeakTypes) => WeakTypes +>(arg: WeakTypes) => { if (arg === "A") { return arg; } else { return arg; }} : (arg: WeakTypes) => WeakTypes +>arg : WeakTypes + + if (arg === "A") { +>arg === "A" : boolean +>arg : WeakTypes +>"A" : "A" + + return arg; +>arg : { toLowerCase?(): string; } | { toUpperCase?(): string; otherOptionalProp?: number | undefined; } + } + else { + return arg; +>arg : WeakTypes + } +} + +const h = (arg: LiteralsOrWeakTypes) => { +>h : (arg: LiteralsOrWeakTypes) => LiteralsOrWeakTypes +>(arg: LiteralsOrWeakTypes) => { if (arg === aOrB) { return arg; } else { return arg; }} : (arg: LiteralsOrWeakTypes) => LiteralsOrWeakTypes +>arg : LiteralsOrWeakTypes + + if (arg === aOrB) { +>arg === aOrB : boolean +>arg : LiteralsOrWeakTypes +>aOrB : "A" | "B" + + return arg; +>arg : { toLowerCase?(): string; } | { toUpperCase?(): string; otherOptionalProp?: number | undefined; } | "A" | "B" + } + else { + return arg; +>arg : LiteralsOrWeakTypes + } +} + +const i = (arg: WeakTypes) => { +>i : (arg: WeakTypes) => WeakTypes +>(arg: WeakTypes) => { if (arg === aOrB) { return arg; } else { return arg; }} : (arg: WeakTypes) => WeakTypes +>arg : WeakTypes + + if (arg === aOrB) { +>arg === aOrB : boolean +>arg : WeakTypes +>aOrB : "A" | "B" + + return arg; +>arg : { toLowerCase?(): string; } | { toUpperCase?(): string; otherOptionalProp?: number | undefined; } + } + else { + return arg; +>arg : WeakTypes + } +} + diff --git a/tests/cases/conformance/types/typeRelationships/comparable/weakTypesAndLiterals01.ts b/tests/cases/conformance/types/typeRelationships/comparable/weakTypesAndLiterals01.ts new file mode 100644 index 0000000000000..003a56a5c655d --- /dev/null +++ b/tests/cases/conformance/types/typeRelationships/comparable/weakTypesAndLiterals01.ts @@ -0,0 +1,51 @@ +// @strict: true +// @declaration: true +// @emitDeclarationOnly: true + +type WeakTypes = + | { optional?: true; } + | { toLowerCase?(): string } + | { toUpperCase?(): string, otherOptionalProp?: number }; + +type LiteralsOrWeakTypes = + | "A" + | "B" + | WeakTypes; + +declare let aOrB: "A" | "B"; + +const f = (arg: LiteralsOrWeakTypes) => { + if (arg === "A") { + return arg; + } + else { + return arg; + } +} + +const g = (arg: WeakTypes) => { + if (arg === "A") { + return arg; + } + else { + return arg; + } +} + +const h = (arg: LiteralsOrWeakTypes) => { + if (arg === aOrB) { + return arg; + } + else { + return arg; + } +} + +const i = (arg: WeakTypes) => { + if (arg === aOrB) { + return arg; + } + else { + return arg; + } +}