Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 16 additions & 12 deletions src/compiler/checker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20714,20 +20714,24 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
instantiateAnonymousType(target, newMapper, newAliasSymbol, newAliasTypeArguments);
target.instantiations.set(id, result); // Set cached result early in case we recursively invoke instantiation while eagerly computing type variable visibility below
const resultObjectFlags = getObjectFlags(result);
if (result.flags & TypeFlags.ObjectFlagsType && !(resultObjectFlags & ObjectFlags.CouldContainTypeVariablesComputed)) {
const resultCouldContainTypeVariables = some(typeArguments, couldContainTypeVariables); // one of the input type arguments might be or contain the result
if (!(getObjectFlags(result) & ObjectFlags.CouldContainTypeVariablesComputed)) {
// if `result` is one of the object types we tried to make (it may not be, due to how `instantiateMappedType` works), we can carry forward the type variable containment check from the input type arguments
if (resultObjectFlags & (ObjectFlags.Mapped | ObjectFlags.Anonymous | ObjectFlags.Reference)) {
(result as ObjectFlagsType).objectFlags |= ObjectFlags.CouldContainTypeVariablesComputed | (resultCouldContainTypeVariables ? ObjectFlags.CouldContainTypeVariables : 0);
}
// If none of the type arguments for the outer type parameters contain type variables, it follows
// that the instantiated type doesn't reference type variables.
// Intrinsics have `CouldContainTypeVariablesComputed` pre-set, so this should only cover unions and intersections resulting from `instantiateMappedType`
else {
(result as ObjectFlagsType).objectFlags |= !resultCouldContainTypeVariables ? ObjectFlags.CouldContainTypeVariablesComputed : 0;
if (result.flags & TypeFlags.ObjectFlagsType) {
let propagatingFlags = getPropagatingFlagsOfTypes(typeArguments);
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Propagating from typeArguments is the core of the fix, the rest is just adjusted indentation.

You can also find some prior related discussion here: #49887 (comment)

if (!(resultObjectFlags & ObjectFlags.CouldContainTypeVariablesComputed)) {
const resultCouldContainTypeVariables = some(typeArguments, couldContainTypeVariables); // one of the input type arguments might be or contain the result
if (!(getObjectFlags(result) & ObjectFlags.CouldContainTypeVariablesComputed)) {
// if `result` is one of the object types we tried to make (it may not be, due to how `instantiateMappedType` works), we can carry forward the type variable containment check from the input type arguments
if (resultObjectFlags & (ObjectFlags.Mapped | ObjectFlags.Anonymous | ObjectFlags.Reference)) {
propagatingFlags |= ObjectFlags.CouldContainTypeVariablesComputed | (resultCouldContainTypeVariables ? ObjectFlags.CouldContainTypeVariables : 0);
}
// If none of the type arguments for the outer type parameters contain type variables, it follows
// that the instantiated type doesn't reference type variables.
// Intrinsics have `CouldContainTypeVariablesComputed` pre-set, so this should only cover unions and intersections resulting from `instantiateMappedType`
else {
propagatingFlags |= !resultCouldContainTypeVariables ? ObjectFlags.CouldContainTypeVariablesComputed : 0;
}
}
}
(result as ObjectFlagsType).objectFlags |= propagatingFlags;
}
}
return result;
Expand Down
92 changes: 92 additions & 0 deletions tests/baselines/reference/nonInferrableTypePropagation4.errors.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
nonInferrableTypePropagation4.ts(15,22): error TS2345: Argument of type '() => P<unknown>' is not assignable to parameter of type '() => P<{ default: unknown; }>'.
Type 'P<unknown>' is not assignable to type 'P<{ default: unknown; }>'.
Type 'unknown' is not assignable to type '{ default: unknown; }'.
nonInferrableTypePropagation4.ts(25,22): error TS2345: Argument of type '() => P<unknown>' is not assignable to parameter of type '() => P<WithDefault<unknown>>'.
Type 'P<unknown>' is not assignable to type 'P<WithDefault<unknown>>'.
Type 'unknown' is not assignable to type 'WithDefault<unknown>'.
nonInferrableTypePropagation4.ts(33,22): error TS2345: Argument of type '() => P<unknown>' is not assignable to parameter of type '() => P<[unknown]>'.
Type 'P<unknown>' is not assignable to type 'P<[unknown]>'.
Type 'unknown' is not assignable to type '[unknown]'.
nonInferrableTypePropagation4.ts(41,22): error TS2345: Argument of type '() => P<unknown>' is not assignable to parameter of type '() => P<{ default: { prop: unknown; }; }>'.
Type 'P<unknown>' is not assignable to type 'P<{ default: { prop: unknown; }; }>'.
Type 'unknown' is not assignable to type '{ default: { prop: unknown; }; }'.
nonInferrableTypePropagation4.ts(49,22): error TS2345: Argument of type '() => P<unknown>' is not assignable to parameter of type '() => P<{ default: [unknown]; }>'.
Type 'P<unknown>' is not assignable to type 'P<{ default: [unknown]; }>'.
Type 'unknown' is not assignable to type '{ default: [unknown]; }'.


==== nonInferrableTypePropagation4.ts (5 errors) ====
// https://github.com/microsoft/TypeScript/issues/62345

interface P<T> {
then: (onfulfilled: (value: T) => unknown) => unknown;
}

interface PConstructor {
new <T>(executor: (resolve: (value: T) => void) => void): P<T>;
}

declare var P: PConstructor;

declare function foo1<T>(x: () => P<{ default: T }>): T;

const result1 = foo1(() => {
~~~~~~~
!!! error TS2345: Argument of type '() => P<unknown>' is not assignable to parameter of type '() => P<{ default: unknown; }>'.
!!! error TS2345: Type 'P<unknown>' is not assignable to type 'P<{ default: unknown; }>'.
!!! error TS2345: Type 'unknown' is not assignable to type '{ default: unknown; }'.
return new P((resolve) => {
resolve;
});
});

type WithDefault<T> = { default: T };

declare function foo2<T>(x: () => P<WithDefault<T>>): T;

const result2 = foo2(() => {
~~~~~~~
!!! error TS2345: Argument of type '() => P<unknown>' is not assignable to parameter of type '() => P<WithDefault<unknown>>'.
!!! error TS2345: Type 'P<unknown>' is not assignable to type 'P<WithDefault<unknown>>'.
!!! error TS2345: Type 'unknown' is not assignable to type 'WithDefault<unknown>'.
return new P((resolve) => {
resolve;
});
});

declare function foo3<T>(x: () => P<[T]>): T;

const result3 = foo3(() => {
~~~~~~~
!!! error TS2345: Argument of type '() => P<unknown>' is not assignable to parameter of type '() => P<[unknown]>'.
!!! error TS2345: Type 'P<unknown>' is not assignable to type 'P<[unknown]>'.
!!! error TS2345: Type 'unknown' is not assignable to type '[unknown]'.
return new P((resolve) => {
resolve;
});
});

declare function foo4<T>(x: () => P<{ default: { prop: T } }>): T;

const result4 = foo4(() => {
~~~~~~~
!!! error TS2345: Argument of type '() => P<unknown>' is not assignable to parameter of type '() => P<{ default: { prop: unknown; }; }>'.
!!! error TS2345: Type 'P<unknown>' is not assignable to type 'P<{ default: { prop: unknown; }; }>'.
!!! error TS2345: Type 'unknown' is not assignable to type '{ default: { prop: unknown; }; }'.
return new P((resolve) => {
resolve;
});
});

declare function foo5<T>(x: () => P<{ default: [T] }>): T;

const result5 = foo5(() => {
~~~~~~~
!!! error TS2345: Argument of type '() => P<unknown>' is not assignable to parameter of type '() => P<{ default: [unknown]; }>'.
!!! error TS2345: Type 'P<unknown>' is not assignable to type 'P<{ default: [unknown]; }>'.
!!! error TS2345: Type 'unknown' is not assignable to type '{ default: [unknown]; }'.
return new P((resolve) => {
resolve;
});
});

154 changes: 154 additions & 0 deletions tests/baselines/reference/nonInferrableTypePropagation4.symbols
Original file line number Diff line number Diff line change
@@ -0,0 +1,154 @@
//// [tests/cases/compiler/nonInferrableTypePropagation4.ts] ////

=== nonInferrableTypePropagation4.ts ===
// https://github.com/microsoft/TypeScript/issues/62345

interface P<T> {
>P : Symbol(P, Decl(nonInferrableTypePropagation4.ts, 0, 0), Decl(nonInferrableTypePropagation4.ts, 10, 11))
>T : Symbol(T, Decl(nonInferrableTypePropagation4.ts, 2, 12))

then: (onfulfilled: (value: T) => unknown) => unknown;
>then : Symbol(P.then, Decl(nonInferrableTypePropagation4.ts, 2, 16))
>onfulfilled : Symbol(onfulfilled, Decl(nonInferrableTypePropagation4.ts, 3, 9))
>value : Symbol(value, Decl(nonInferrableTypePropagation4.ts, 3, 23))
>T : Symbol(T, Decl(nonInferrableTypePropagation4.ts, 2, 12))
}

interface PConstructor {
>PConstructor : Symbol(PConstructor, Decl(nonInferrableTypePropagation4.ts, 4, 1))

new <T>(executor: (resolve: (value: T) => void) => void): P<T>;
>T : Symbol(T, Decl(nonInferrableTypePropagation4.ts, 7, 7))
>executor : Symbol(executor, Decl(nonInferrableTypePropagation4.ts, 7, 10))
>resolve : Symbol(resolve, Decl(nonInferrableTypePropagation4.ts, 7, 21))
>value : Symbol(value, Decl(nonInferrableTypePropagation4.ts, 7, 31))
>T : Symbol(T, Decl(nonInferrableTypePropagation4.ts, 7, 7))
>P : Symbol(P, Decl(nonInferrableTypePropagation4.ts, 0, 0), Decl(nonInferrableTypePropagation4.ts, 10, 11))
>T : Symbol(T, Decl(nonInferrableTypePropagation4.ts, 7, 7))
}

declare var P: PConstructor;
>P : Symbol(P, Decl(nonInferrableTypePropagation4.ts, 0, 0), Decl(nonInferrableTypePropagation4.ts, 10, 11))
>PConstructor : Symbol(PConstructor, Decl(nonInferrableTypePropagation4.ts, 4, 1))

declare function foo1<T>(x: () => P<{ default: T }>): T;
>foo1 : Symbol(foo1, Decl(nonInferrableTypePropagation4.ts, 10, 28))
>T : Symbol(T, Decl(nonInferrableTypePropagation4.ts, 12, 22))
>x : Symbol(x, Decl(nonInferrableTypePropagation4.ts, 12, 25))
>P : Symbol(P, Decl(nonInferrableTypePropagation4.ts, 0, 0), Decl(nonInferrableTypePropagation4.ts, 10, 11))
>default : Symbol(default, Decl(nonInferrableTypePropagation4.ts, 12, 37))
>T : Symbol(T, Decl(nonInferrableTypePropagation4.ts, 12, 22))
>T : Symbol(T, Decl(nonInferrableTypePropagation4.ts, 12, 22))

const result1 = foo1(() => {
>result1 : Symbol(result1, Decl(nonInferrableTypePropagation4.ts, 14, 5))
>foo1 : Symbol(foo1, Decl(nonInferrableTypePropagation4.ts, 10, 28))

return new P((resolve) => {
>P : Symbol(P, Decl(nonInferrableTypePropagation4.ts, 0, 0), Decl(nonInferrableTypePropagation4.ts, 10, 11))
>resolve : Symbol(resolve, Decl(nonInferrableTypePropagation4.ts, 15, 16))

resolve;
>resolve : Symbol(resolve, Decl(nonInferrableTypePropagation4.ts, 15, 16))

});
});

type WithDefault<T> = { default: T };
>WithDefault : Symbol(WithDefault, Decl(nonInferrableTypePropagation4.ts, 18, 3))
>T : Symbol(T, Decl(nonInferrableTypePropagation4.ts, 20, 17))
>default : Symbol(default, Decl(nonInferrableTypePropagation4.ts, 20, 23))
>T : Symbol(T, Decl(nonInferrableTypePropagation4.ts, 20, 17))

declare function foo2<T>(x: () => P<WithDefault<T>>): T;
>foo2 : Symbol(foo2, Decl(nonInferrableTypePropagation4.ts, 20, 37))
>T : Symbol(T, Decl(nonInferrableTypePropagation4.ts, 22, 22))
>x : Symbol(x, Decl(nonInferrableTypePropagation4.ts, 22, 25))
>P : Symbol(P, Decl(nonInferrableTypePropagation4.ts, 0, 0), Decl(nonInferrableTypePropagation4.ts, 10, 11))
>WithDefault : Symbol(WithDefault, Decl(nonInferrableTypePropagation4.ts, 18, 3))
>T : Symbol(T, Decl(nonInferrableTypePropagation4.ts, 22, 22))
>T : Symbol(T, Decl(nonInferrableTypePropagation4.ts, 22, 22))

const result2 = foo2(() => {
>result2 : Symbol(result2, Decl(nonInferrableTypePropagation4.ts, 24, 5))
>foo2 : Symbol(foo2, Decl(nonInferrableTypePropagation4.ts, 20, 37))

return new P((resolve) => {
>P : Symbol(P, Decl(nonInferrableTypePropagation4.ts, 0, 0), Decl(nonInferrableTypePropagation4.ts, 10, 11))
>resolve : Symbol(resolve, Decl(nonInferrableTypePropagation4.ts, 25, 16))

resolve;
>resolve : Symbol(resolve, Decl(nonInferrableTypePropagation4.ts, 25, 16))

});
});

declare function foo3<T>(x: () => P<[T]>): T;
>foo3 : Symbol(foo3, Decl(nonInferrableTypePropagation4.ts, 28, 3))
>T : Symbol(T, Decl(nonInferrableTypePropagation4.ts, 30, 22))
>x : Symbol(x, Decl(nonInferrableTypePropagation4.ts, 30, 25))
>P : Symbol(P, Decl(nonInferrableTypePropagation4.ts, 0, 0), Decl(nonInferrableTypePropagation4.ts, 10, 11))
>T : Symbol(T, Decl(nonInferrableTypePropagation4.ts, 30, 22))
>T : Symbol(T, Decl(nonInferrableTypePropagation4.ts, 30, 22))

const result3 = foo3(() => {
>result3 : Symbol(result3, Decl(nonInferrableTypePropagation4.ts, 32, 5))
>foo3 : Symbol(foo3, Decl(nonInferrableTypePropagation4.ts, 28, 3))

return new P((resolve) => {
>P : Symbol(P, Decl(nonInferrableTypePropagation4.ts, 0, 0), Decl(nonInferrableTypePropagation4.ts, 10, 11))
>resolve : Symbol(resolve, Decl(nonInferrableTypePropagation4.ts, 33, 16))

resolve;
>resolve : Symbol(resolve, Decl(nonInferrableTypePropagation4.ts, 33, 16))

});
});

declare function foo4<T>(x: () => P<{ default: { prop: T } }>): T;
>foo4 : Symbol(foo4, Decl(nonInferrableTypePropagation4.ts, 36, 3))
>T : Symbol(T, Decl(nonInferrableTypePropagation4.ts, 38, 22))
>x : Symbol(x, Decl(nonInferrableTypePropagation4.ts, 38, 25))
>P : Symbol(P, Decl(nonInferrableTypePropagation4.ts, 0, 0), Decl(nonInferrableTypePropagation4.ts, 10, 11))
>default : Symbol(default, Decl(nonInferrableTypePropagation4.ts, 38, 37))
>prop : Symbol(prop, Decl(nonInferrableTypePropagation4.ts, 38, 48))
>T : Symbol(T, Decl(nonInferrableTypePropagation4.ts, 38, 22))
>T : Symbol(T, Decl(nonInferrableTypePropagation4.ts, 38, 22))

const result4 = foo4(() => {
>result4 : Symbol(result4, Decl(nonInferrableTypePropagation4.ts, 40, 5))
>foo4 : Symbol(foo4, Decl(nonInferrableTypePropagation4.ts, 36, 3))

return new P((resolve) => {
>P : Symbol(P, Decl(nonInferrableTypePropagation4.ts, 0, 0), Decl(nonInferrableTypePropagation4.ts, 10, 11))
>resolve : Symbol(resolve, Decl(nonInferrableTypePropagation4.ts, 41, 16))

resolve;
>resolve : Symbol(resolve, Decl(nonInferrableTypePropagation4.ts, 41, 16))

});
});

declare function foo5<T>(x: () => P<{ default: [T] }>): T;
>foo5 : Symbol(foo5, Decl(nonInferrableTypePropagation4.ts, 44, 3))
>T : Symbol(T, Decl(nonInferrableTypePropagation4.ts, 46, 22))
>x : Symbol(x, Decl(nonInferrableTypePropagation4.ts, 46, 25))
>P : Symbol(P, Decl(nonInferrableTypePropagation4.ts, 0, 0), Decl(nonInferrableTypePropagation4.ts, 10, 11))
>default : Symbol(default, Decl(nonInferrableTypePropagation4.ts, 46, 37))
>T : Symbol(T, Decl(nonInferrableTypePropagation4.ts, 46, 22))
>T : Symbol(T, Decl(nonInferrableTypePropagation4.ts, 46, 22))

const result5 = foo5(() => {
>result5 : Symbol(result5, Decl(nonInferrableTypePropagation4.ts, 48, 5))
>foo5 : Symbol(foo5, Decl(nonInferrableTypePropagation4.ts, 44, 3))

return new P((resolve) => {
>P : Symbol(P, Decl(nonInferrableTypePropagation4.ts, 0, 0), Decl(nonInferrableTypePropagation4.ts, 10, 11))
>resolve : Symbol(resolve, Decl(nonInferrableTypePropagation4.ts, 49, 16))

resolve;
>resolve : Symbol(resolve, Decl(nonInferrableTypePropagation4.ts, 49, 16))

});
});

Loading
Loading