mirror of
https://github.com/microsoft/TypeScript.git
synced 2025-11-18 17:21:48 +00:00
Fixed accidental propagation of caching-related objectFlags (#52546)
This commit is contained in:
@@ -16270,7 +16270,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
|
||||
}
|
||||
|
||||
// This function assumes the constituent type list is sorted and deduplicated.
|
||||
function getUnionTypeFromSortedList(types: Type[], objectFlags: ObjectFlags, aliasSymbol?: Symbol, aliasTypeArguments?: readonly Type[], origin?: Type): Type {
|
||||
function getUnionTypeFromSortedList(types: Type[], precomputedObjectFlags: ObjectFlags, aliasSymbol?: Symbol, aliasTypeArguments?: readonly Type[], origin?: Type): Type {
|
||||
if (types.length === 0) {
|
||||
return neverType;
|
||||
}
|
||||
@@ -16285,7 +16285,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
|
||||
let type = unionTypes.get(id);
|
||||
if (!type) {
|
||||
type = createType(TypeFlags.Union) as UnionType;
|
||||
type.objectFlags = objectFlags | getPropagatingFlagsOfTypes(types, /*excludeKinds*/ TypeFlags.Nullable);
|
||||
type.objectFlags = precomputedObjectFlags | getPropagatingFlagsOfTypes(types, /*excludeKinds*/ TypeFlags.Nullable);
|
||||
type.types = types;
|
||||
type.origin = origin;
|
||||
type.aliasSymbol = aliasSymbol;
|
||||
@@ -25649,7 +25649,9 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
|
||||
newOrigin = createOriginUnionOrIntersectionType(TypeFlags.Union, originFiltered);
|
||||
}
|
||||
}
|
||||
return getUnionTypeFromSortedList(filtered, (type as UnionType).objectFlags, /*aliasSymbol*/ undefined, /*aliasTypeArguments*/ undefined, newOrigin);
|
||||
// filtering could remove intersections so `ContainsIntersections` might be forwarded "incorrectly"
|
||||
// it is purely an optimization hint so there is no harm in accidentally forwarding it
|
||||
return getUnionTypeFromSortedList(filtered, (type as UnionType).objectFlags & (ObjectFlags.PrimitiveUnion | ObjectFlags.ContainsIntersections), /*aliasSymbol*/ undefined, /*aliasTypeArguments*/ undefined, newOrigin);
|
||||
}
|
||||
return type.flags & TypeFlags.Never || f(type) ? type : neverType;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
=== tests/cases/compiler/unknownLikeUnionObjectFlagsNotPropagated.ts ===
|
||||
// repro from #52475#issuecomment-1411215277
|
||||
|
||||
type MyType = {} | null | undefined;
|
||||
>MyType : Symbol(MyType, Decl(unknownLikeUnionObjectFlagsNotPropagated.ts, 0, 0))
|
||||
|
||||
const myVar: MyType = null as MyType;
|
||||
>myVar : Symbol(myVar, Decl(unknownLikeUnionObjectFlagsNotPropagated.ts, 4, 5))
|
||||
>MyType : Symbol(MyType, Decl(unknownLikeUnionObjectFlagsNotPropagated.ts, 0, 0))
|
||||
>MyType : Symbol(MyType, Decl(unknownLikeUnionObjectFlagsNotPropagated.ts, 0, 0))
|
||||
|
||||
myVar?.toLocaleString;
|
||||
>myVar?.toLocaleString : Symbol(Object.toLocaleString, Decl(lib.es5.d.ts, --, --))
|
||||
>myVar : Symbol(myVar, Decl(unknownLikeUnionObjectFlagsNotPropagated.ts, 4, 5))
|
||||
>toLocaleString : Symbol(Object.toLocaleString, Decl(lib.es5.d.ts, --, --))
|
||||
|
||||
myVar;
|
||||
>myVar : Symbol(myVar, Decl(unknownLikeUnionObjectFlagsNotPropagated.ts, 4, 5))
|
||||
|
||||
async function myUnusedFunction() {
|
||||
>myUnusedFunction : Symbol(myUnusedFunction, Decl(unknownLikeUnionObjectFlagsNotPropagated.ts, 7, 6))
|
||||
|
||||
const fetch1 = Promise.resolve(['hello', 'world']);
|
||||
>fetch1 : Symbol(fetch1, Decl(unknownLikeUnionObjectFlagsNotPropagated.ts, 10, 9))
|
||||
>Promise.resolve : Symbol(PromiseConstructor.resolve, Decl(lib.es2015.promise.d.ts, --, --), Decl(lib.es2015.promise.d.ts, --, --), Decl(lib.es2015.promise.d.ts, --, --))
|
||||
>Promise : Symbol(Promise, Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.promise.d.ts, --, --), Decl(lib.es2015.symbol.wellknown.d.ts, --, --), Decl(lib.es2018.promise.d.ts, --, --))
|
||||
>resolve : Symbol(PromiseConstructor.resolve, Decl(lib.es2015.promise.d.ts, --, --), Decl(lib.es2015.promise.d.ts, --, --), Decl(lib.es2015.promise.d.ts, --, --))
|
||||
|
||||
const [data1] = await Promise.all([fetch1]);
|
||||
>data1 : Symbol(data1, Decl(unknownLikeUnionObjectFlagsNotPropagated.ts, 11, 11))
|
||||
>Promise.all : Symbol(PromiseConstructor.all, Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.promise.d.ts, --, --))
|
||||
>Promise : Symbol(Promise, Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.promise.d.ts, --, --), Decl(lib.es2015.symbol.wellknown.d.ts, --, --), Decl(lib.es2018.promise.d.ts, --, --))
|
||||
>all : Symbol(PromiseConstructor.all, Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.promise.d.ts, --, --))
|
||||
>fetch1 : Symbol(fetch1, Decl(unknownLikeUnionObjectFlagsNotPropagated.ts, 10, 9))
|
||||
|
||||
data1.length;
|
||||
>data1.length : Symbol(Array.length, Decl(lib.es5.d.ts, --, --))
|
||||
>data1 : Symbol(data1, Decl(unknownLikeUnionObjectFlagsNotPropagated.ts, 11, 11))
|
||||
>length : Symbol(Array.length, Decl(lib.es5.d.ts, --, --))
|
||||
}
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
=== tests/cases/compiler/unknownLikeUnionObjectFlagsNotPropagated.ts ===
|
||||
// repro from #52475#issuecomment-1411215277
|
||||
|
||||
type MyType = {} | null | undefined;
|
||||
>MyType : {} | null | undefined
|
||||
>null : null
|
||||
|
||||
const myVar: MyType = null as MyType;
|
||||
>myVar : MyType
|
||||
>null as MyType : MyType
|
||||
>null : null
|
||||
|
||||
myVar?.toLocaleString;
|
||||
>myVar?.toLocaleString : (() => string) | undefined
|
||||
>myVar : MyType
|
||||
>toLocaleString : (() => string) | undefined
|
||||
|
||||
myVar;
|
||||
>myVar : MyType
|
||||
|
||||
async function myUnusedFunction() {
|
||||
>myUnusedFunction : () => Promise<void>
|
||||
|
||||
const fetch1 = Promise.resolve(['hello', 'world']);
|
||||
>fetch1 : Promise<string[]>
|
||||
>Promise.resolve(['hello', 'world']) : Promise<string[]>
|
||||
>Promise.resolve : { (): Promise<void>; <T>(value: T): Promise<Awaited<T>>; <T>(value: T | PromiseLike<T>): Promise<Awaited<T>>; }
|
||||
>Promise : PromiseConstructor
|
||||
>resolve : { (): Promise<void>; <T>(value: T): Promise<Awaited<T>>; <T>(value: T | PromiseLike<T>): Promise<Awaited<T>>; }
|
||||
>['hello', 'world'] : string[]
|
||||
>'hello' : "hello"
|
||||
>'world' : "world"
|
||||
|
||||
const [data1] = await Promise.all([fetch1]);
|
||||
>data1 : string[]
|
||||
>await Promise.all([fetch1]) : [string[]]
|
||||
>Promise.all([fetch1]) : Promise<[string[]]>
|
||||
>Promise.all : { <T>(values: Iterable<T | PromiseLike<T>>): Promise<Awaited<T>[]>; <T extends readonly unknown[] | []>(values: T): Promise<{ -readonly [P in keyof T]: Awaited<T[P]>; }>; }
|
||||
>Promise : PromiseConstructor
|
||||
>all : { <T>(values: Iterable<T | PromiseLike<T>>): Promise<Awaited<T>[]>; <T extends readonly unknown[] | []>(values: T): Promise<{ -readonly [P in keyof T]: Awaited<T[P]>; }>; }
|
||||
>[fetch1] : [Promise<string[]>]
|
||||
>fetch1 : Promise<string[]>
|
||||
|
||||
data1.length;
|
||||
>data1.length : number
|
||||
>data1 : string[]
|
||||
>length : number
|
||||
}
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
// @strict: true
|
||||
// @noEmit: true
|
||||
// @lib: esnext
|
||||
|
||||
// repro from #52475#issuecomment-1411215277
|
||||
|
||||
type MyType = {} | null | undefined;
|
||||
|
||||
const myVar: MyType = null as MyType;
|
||||
|
||||
myVar?.toLocaleString;
|
||||
myVar;
|
||||
|
||||
async function myUnusedFunction() {
|
||||
const fetch1 = Promise.resolve(['hello', 'world']);
|
||||
const [data1] = await Promise.all([fetch1]);
|
||||
data1.length;
|
||||
}
|
||||
Reference in New Issue
Block a user