Exclude comparable relation from literal type relation optimization (#53419)

This commit is contained in:
Anders Hejlsberg 2023-03-23 07:04:16 -07:00 committed by GitHub
parent 25550bd3d6
commit 37bafa539c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 187 additions and 2 deletions

View File

@ -20899,14 +20899,15 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
if (containsType(targetTypes, source)) {
return Ternary.True;
}
if (getObjectFlags(target) & ObjectFlags.PrimitiveUnion && !(source.flags & TypeFlags.EnumLiteral) && (
if (relation !== comparableRelation && getObjectFlags(target) & ObjectFlags.PrimitiveUnion && !(source.flags & TypeFlags.EnumLiteral) && (
source.flags & (TypeFlags.StringLiteral | TypeFlags.BooleanLiteral | TypeFlags.BigIntLiteral) ||
(relation === subtypeRelation || relation === strictSubtypeRelation) && source.flags & TypeFlags.NumberLiteral)) {
// When relating a literal type to a union of primitive types, we know the relation is false unless
// the union contains the base primitive type or the literal type in one of its fresh/regular forms.
// We exclude numeric literals for non-subtype relations because numeric literals are assignable to
// numeric enum literals with the same value. Similarly, we exclude enum literal types because
// identically named enum types are related (see isEmumTypeRelatedTo).
// identically named enum types are related (see isEnumTypeRelatedTo). We exclude the comparable
// relation in entirety because it needs to be checked in both directions.
const alternateForm = source === (source as StringLiteralType).regularType ? (source as StringLiteralType).freshType : (source as StringLiteralType).regularType;
const primitive = source.flags & TypeFlags.StringLiteral ? stringType :
source.flags & TypeFlags.NumberLiteral ? numberType :

View File

@ -0,0 +1,75 @@
=== tests/cases/compiler/comparableRelationBidirectional.ts ===
enum AutomationMode {
>AutomationMode : Symbol(AutomationMode, Decl(comparableRelationBidirectional.ts, 0, 0))
NONE = "",
>NONE : Symbol(AutomationMode.NONE, Decl(comparableRelationBidirectional.ts, 0, 21))
TIME = "time",
>TIME : Symbol(AutomationMode.TIME, Decl(comparableRelationBidirectional.ts, 1, 14))
SYSTEM = "system",
>SYSTEM : Symbol(AutomationMode.SYSTEM, Decl(comparableRelationBidirectional.ts, 2, 18))
LOCATION = "location",
>LOCATION : Symbol(AutomationMode.LOCATION, Decl(comparableRelationBidirectional.ts, 3, 22))
}
interface ThemePreset {
>ThemePreset : Symbol(ThemePreset, Decl(comparableRelationBidirectional.ts, 5, 1))
id: string;
>id : Symbol(ThemePreset.id, Decl(comparableRelationBidirectional.ts, 7, 23))
}
interface Automation {
>Automation : Symbol(Automation, Decl(comparableRelationBidirectional.ts, 9, 1))
mode: AutomationMode;
>mode : Symbol(Automation.mode, Decl(comparableRelationBidirectional.ts, 11, 22))
>AutomationMode : Symbol(AutomationMode, Decl(comparableRelationBidirectional.ts, 0, 0))
}
interface UserSettings {
>UserSettings : Symbol(UserSettings, Decl(comparableRelationBidirectional.ts, 13, 1))
presets: ThemePreset[];
>presets : Symbol(UserSettings.presets, Decl(comparableRelationBidirectional.ts, 15, 24))
>ThemePreset : Symbol(ThemePreset, Decl(comparableRelationBidirectional.ts, 5, 1))
automation: Automation;
>automation : Symbol(UserSettings.automation, Decl(comparableRelationBidirectional.ts, 16, 27))
>Automation : Symbol(Automation, Decl(comparableRelationBidirectional.ts, 9, 1))
}
interface ExtensionData {
>ExtensionData : Symbol(ExtensionData, Decl(comparableRelationBidirectional.ts, 18, 1))
settings: UserSettings;
>settings : Symbol(ExtensionData.settings, Decl(comparableRelationBidirectional.ts, 20, 25))
>UserSettings : Symbol(UserSettings, Decl(comparableRelationBidirectional.ts, 13, 1))
}
export function getMockData(): ExtensionData {
>getMockData : Symbol(getMockData, Decl(comparableRelationBidirectional.ts, 22, 1))
>ExtensionData : Symbol(ExtensionData, Decl(comparableRelationBidirectional.ts, 18, 1))
return {
settings: {
>settings : Symbol(settings, Decl(comparableRelationBidirectional.ts, 25, 12))
presets: [],
>presets : Symbol(presets, Decl(comparableRelationBidirectional.ts, 26, 19))
automation: {
>automation : Symbol(automation, Decl(comparableRelationBidirectional.ts, 27, 24))
mode: "",
>mode : Symbol(mode, Decl(comparableRelationBidirectional.ts, 28, 25))
},
} as UserSettings,
>UserSettings : Symbol(UserSettings, Decl(comparableRelationBidirectional.ts, 13, 1))
}
}

View File

@ -0,0 +1,72 @@
=== tests/cases/compiler/comparableRelationBidirectional.ts ===
enum AutomationMode {
>AutomationMode : AutomationMode
NONE = "",
>NONE : AutomationMode.NONE
>"" : ""
TIME = "time",
>TIME : AutomationMode.TIME
>"time" : "time"
SYSTEM = "system",
>SYSTEM : AutomationMode.SYSTEM
>"system" : "system"
LOCATION = "location",
>LOCATION : AutomationMode.LOCATION
>"location" : "location"
}
interface ThemePreset {
id: string;
>id : string
}
interface Automation {
mode: AutomationMode;
>mode : AutomationMode
}
interface UserSettings {
presets: ThemePreset[];
>presets : ThemePreset[]
automation: Automation;
>automation : Automation
}
interface ExtensionData {
settings: UserSettings;
>settings : UserSettings
}
export function getMockData(): ExtensionData {
>getMockData : () => ExtensionData
return {
>{ settings: { presets: [], automation: { mode: "", }, } as UserSettings, } : { settings: UserSettings; }
settings: {
>settings : UserSettings
>{ presets: [], automation: { mode: "", }, } as UserSettings : UserSettings
>{ presets: [], automation: { mode: "", }, } : { presets: never[]; automation: { mode: ""; }; }
presets: [],
>presets : never[]
>[] : never[]
automation: {
>automation : { mode: ""; }
>{ mode: "", } : { mode: ""; }
mode: "",
>mode : ""
>"" : ""
},
} as UserSettings,
}
}

View File

@ -0,0 +1,37 @@
// @strict: true
// @noEmit: true
enum AutomationMode {
NONE = "",
TIME = "time",
SYSTEM = "system",
LOCATION = "location",
}
interface ThemePreset {
id: string;
}
interface Automation {
mode: AutomationMode;
}
interface UserSettings {
presets: ThemePreset[];
automation: Automation;
}
interface ExtensionData {
settings: UserSettings;
}
export function getMockData(): ExtensionData {
return {
settings: {
presets: [],
automation: {
mode: "",
},
} as UserSettings,
}
}