Skip to content

Commit

Permalink
Filter out non-array types when contextually typing array literal ele…
Browse files Browse the repository at this point in the history
…ments (#52589)
  • Loading branch information
Andarist authored Mar 10, 2023
1 parent a8ffab2 commit e775383
Show file tree
Hide file tree
Showing 10 changed files with 297 additions and 13 deletions.
21 changes: 8 additions & 13 deletions src/compiler/checker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19574,18 +19574,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
return result;
}
const moreThanOneRealChildren = length(validChildren) > 1;
let arrayLikeTargetParts: Type;
let nonArrayLikeTargetParts: Type;
const iterableType = getGlobalIterableType(/*reportErrors*/ false);
if (iterableType !== emptyGenericType) {
const anyIterable = createIterableType(anyType);
arrayLikeTargetParts = filterType(childrenTargetType, t => isTypeAssignableTo(t, anyIterable));
nonArrayLikeTargetParts = filterType(childrenTargetType, t => !isTypeAssignableTo(t, anyIterable));
}
else {
arrayLikeTargetParts = filterType(childrenTargetType, isArrayOrTupleLikeType);
nonArrayLikeTargetParts = filterType(childrenTargetType, t => !isArrayOrTupleLikeType(t));
}
const arrayLikeTargetParts = filterType(childrenTargetType, isAssignableToAvailableAnyIterable);
const nonArrayLikeTargetParts = filterType(childrenTargetType, t => !isAssignableToAvailableAnyIterable(t));
if (moreThanOneRealChildren) {
if (arrayLikeTargetParts !== neverType) {
const realSource = createTupleType(checkJsxChildren(containingElement, CheckMode.Normal));
Expand Down Expand Up @@ -23108,6 +23098,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
return isArrayLikeType(type) || isTupleLikeType(type);
}

function isAssignableToAvailableAnyIterable(type: Type): boolean {
const anyIterable = getGlobalIterableType(/*reportErrors*/ false) !== emptyGenericType && createIterableType(anyType);
return anyIterable ? isTypeAssignableTo(type, anyIterable) : isArrayOrTupleLikeType(type);
}

function getTupleElementType(type: Type, index: number) {
const propType = getTypeOfPropertyOfType(type, "" + index as __String);
if (propType) {
Expand Down Expand Up @@ -29067,7 +29062,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
// type of T.
function getContextualTypeForElementExpression(arrayContextualType: Type | undefined, index: number): Type | undefined {
return arrayContextualType && (
index >= 0 && getTypeOfPropertyOfContextualType(arrayContextualType, "" + index as __String) ||
index >= 0 && getTypeOfPropertyOfContextualType(filterType(arrayContextualType, t => !!getIndexTypeOfType(t, numberType) || isAssignableToAvailableAnyIterable(t)), "" + index as __String) ||
mapType(arrayContextualType, t =>
isTupleType(t) ?
getElementTypeOfSliceOfTupleType(t, 0, /*endSkipCount*/ 0, /*writing*/ false, /*noReductions*/ true) :
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
=== tests/cases/compiler/contextualSignatureInArrayElementPrefersArrayUnionMemberLibEs2015.ts ===
// repro from #52588

declare function test(
>test : Symbol(test, Decl(contextualSignatureInArrayElementPrefersArrayUnionMemberLibEs2015.ts, 0, 0))

arg: Record<string, (arg: string) => void> | Array<(arg: number) => void>
>arg : Symbol(arg, Decl(contextualSignatureInArrayElementPrefersArrayUnionMemberLibEs2015.ts, 2, 22))
>Record : Symbol(Record, Decl(lib.es5.d.ts, --, --))
>arg : Symbol(arg, Decl(contextualSignatureInArrayElementPrefersArrayUnionMemberLibEs2015.ts, 3, 23))
>Array : Symbol(Array, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.core.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.symbol.wellknown.d.ts, --, --))
>arg : Symbol(arg, Decl(contextualSignatureInArrayElementPrefersArrayUnionMemberLibEs2015.ts, 3, 54))

): void;

test([
>test : Symbol(test, Decl(contextualSignatureInArrayElementPrefersArrayUnionMemberLibEs2015.ts, 0, 0))

(arg) => {
>arg : Symbol(arg, Decl(contextualSignatureInArrayElementPrefersArrayUnionMemberLibEs2015.ts, 7, 3))

arg; // number
>arg : Symbol(arg, Decl(contextualSignatureInArrayElementPrefersArrayUnionMemberLibEs2015.ts, 7, 3))

},
]);

Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
=== tests/cases/compiler/contextualSignatureInArrayElementPrefersArrayUnionMemberLibEs2015.ts ===
// repro from #52588

declare function test(
>test : (arg: Record<string, (arg: string) => void> | ((arg: number) => void)[]) => void

arg: Record<string, (arg: string) => void> | Array<(arg: number) => void>
>arg : Record<string, (arg: string) => void> | ((arg: number) => void)[]
>arg : string
>arg : number

): void;

test([
>test([ (arg) => { arg; // number },]) : void
>test : (arg: Record<string, (arg: string) => void> | ((arg: number) => void)[]) => void
>[ (arg) => { arg; // number },] : ((arg: number) => void)[]

(arg) => {
>(arg) => { arg; // number } : (arg: number) => void
>arg : number

arg; // number
>arg : number

},
]);

Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
=== tests/cases/compiler/contextualSignatureInArrayElementPrefersArrayUnionMemberLibEs5.ts ===
// repro from #52588

declare function test(
>test : Symbol(test, Decl(contextualSignatureInArrayElementPrefersArrayUnionMemberLibEs5.ts, 0, 0))

arg: Record<string, (arg: string) => void> | Array<(arg: number) => void>
>arg : Symbol(arg, Decl(contextualSignatureInArrayElementPrefersArrayUnionMemberLibEs5.ts, 2, 22))
>Record : Symbol(Record, Decl(lib.es5.d.ts, --, --))
>arg : Symbol(arg, Decl(contextualSignatureInArrayElementPrefersArrayUnionMemberLibEs5.ts, 3, 23))
>Array : Symbol(Array, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --))
>arg : Symbol(arg, Decl(contextualSignatureInArrayElementPrefersArrayUnionMemberLibEs5.ts, 3, 54))

): void;

test([
>test : Symbol(test, Decl(contextualSignatureInArrayElementPrefersArrayUnionMemberLibEs5.ts, 0, 0))

(arg) => {
>arg : Symbol(arg, Decl(contextualSignatureInArrayElementPrefersArrayUnionMemberLibEs5.ts, 7, 3))

arg; // number
>arg : Symbol(arg, Decl(contextualSignatureInArrayElementPrefersArrayUnionMemberLibEs5.ts, 7, 3))

},
]);

Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
=== tests/cases/compiler/contextualSignatureInArrayElementPrefersArrayUnionMemberLibEs5.ts ===
// repro from #52588

declare function test(
>test : (arg: Record<string, (arg: string) => void> | ((arg: number) => void)[]) => void

arg: Record<string, (arg: string) => void> | Array<(arg: number) => void>
>arg : Record<string, (arg: string) => void> | ((arg: number) => void)[]
>arg : string
>arg : number

): void;

test([
>test([ (arg) => { arg; // number },]) : void
>test : (arg: Record<string, (arg: string) => void> | ((arg: number) => void)[]) => void
>[ (arg) => { arg; // number },] : ((arg: number) => void)[]

(arg) => {
>(arg) => { arg; // number } : (arg: number) => void
>arg : number

arg; // number
>arg : number

},
]);

67 changes: 67 additions & 0 deletions tests/baselines/reference/contextualTypeCaching.symbols
Original file line number Diff line number Diff line change
Expand Up @@ -60,3 +60,70 @@ emit('a', {
},
});

// simplified repro from 52589#issuecomment-1416180638
declare class MyCompiler {
>MyCompiler : Symbol(MyCompiler, Decl(contextualTypeCaching.ts, 21, 3))

compile(): void;
>compile : Symbol(MyCompiler.compile, Decl(contextualTypeCaching.ts, 24, 26))
}
interface WebpackPluginInstance {
>WebpackPluginInstance : Symbol(WebpackPluginInstance, Decl(contextualTypeCaching.ts, 26, 1))

apply: (compiler: MyCompiler) => void;
>apply : Symbol(WebpackPluginInstance.apply, Decl(contextualTypeCaching.ts, 27, 33))
>compiler : Symbol(compiler, Decl(contextualTypeCaching.ts, 28, 10))
>MyCompiler : Symbol(MyCompiler, Decl(contextualTypeCaching.ts, 21, 3))
}
type WebpackPluginFunction = (this: MyCompiler, compiler: MyCompiler) => void;
>WebpackPluginFunction : Symbol(WebpackPluginFunction, Decl(contextualTypeCaching.ts, 29, 1))
>this : Symbol(this, Decl(contextualTypeCaching.ts, 30, 30))
>MyCompiler : Symbol(MyCompiler, Decl(contextualTypeCaching.ts, 21, 3))
>compiler : Symbol(compiler, Decl(contextualTypeCaching.ts, 30, 47))
>MyCompiler : Symbol(MyCompiler, Decl(contextualTypeCaching.ts, 21, 3))

interface Optimization {
>Optimization : Symbol(Optimization, Decl(contextualTypeCaching.ts, 30, 78))

minimizer?: (WebpackPluginInstance | WebpackPluginFunction)[];
>minimizer : Symbol(Optimization.minimizer, Decl(contextualTypeCaching.ts, 31, 24))
>WebpackPluginInstance : Symbol(WebpackPluginInstance, Decl(contextualTypeCaching.ts, 26, 1))
>WebpackPluginFunction : Symbol(WebpackPluginFunction, Decl(contextualTypeCaching.ts, 29, 1))
}
declare const A: <T, P extends keyof T>(
>A : Symbol(A, Decl(contextualTypeCaching.ts, 34, 13))
>T : Symbol(T, Decl(contextualTypeCaching.ts, 34, 18))
>P : Symbol(P, Decl(contextualTypeCaching.ts, 34, 20))
>T : Symbol(T, Decl(contextualTypeCaching.ts, 34, 18))

obj: T,
>obj : Symbol(obj, Decl(contextualTypeCaching.ts, 34, 40))
>T : Symbol(T, Decl(contextualTypeCaching.ts, 34, 18))

prop: P,
>prop : Symbol(prop, Decl(contextualTypeCaching.ts, 35, 9))
>P : Symbol(P, Decl(contextualTypeCaching.ts, 34, 20))

factory: () => T[P]
>factory : Symbol(factory, Decl(contextualTypeCaching.ts, 36, 10))
>T : Symbol(T, Decl(contextualTypeCaching.ts, 34, 18))
>P : Symbol(P, Decl(contextualTypeCaching.ts, 34, 20))

) => void;
export const applyOptimizationDefaults = (optimization: Optimization) => {
>applyOptimizationDefaults : Symbol(applyOptimizationDefaults, Decl(contextualTypeCaching.ts, 39, 12))
>optimization : Symbol(optimization, Decl(contextualTypeCaching.ts, 39, 42))
>Optimization : Symbol(Optimization, Decl(contextualTypeCaching.ts, 30, 78))

A(optimization, "minimizer", () => [
>A : Symbol(A, Decl(contextualTypeCaching.ts, 34, 13))
>optimization : Symbol(optimization, Decl(contextualTypeCaching.ts, 39, 42))
{
apply: (compiler) => {},
>apply : Symbol(apply, Decl(contextualTypeCaching.ts, 41, 5))
>compiler : Symbol(compiler, Decl(contextualTypeCaching.ts, 42, 14))

},
]);
};

58 changes: 58 additions & 0 deletions tests/baselines/reference/contextualTypeCaching.types
Original file line number Diff line number Diff line change
Expand Up @@ -54,3 +54,61 @@ emit('a', {
},
});

// simplified repro from 52589#issuecomment-1416180638
declare class MyCompiler {
>MyCompiler : MyCompiler

compile(): void;
>compile : () => void
}
interface WebpackPluginInstance {
apply: (compiler: MyCompiler) => void;
>apply : (compiler: MyCompiler) => void
>compiler : MyCompiler
}
type WebpackPluginFunction = (this: MyCompiler, compiler: MyCompiler) => void;
>WebpackPluginFunction : (this: MyCompiler, compiler: MyCompiler) => void
>this : MyCompiler
>compiler : MyCompiler

interface Optimization {
minimizer?: (WebpackPluginInstance | WebpackPluginFunction)[];
>minimizer : (WebpackPluginInstance | WebpackPluginFunction)[] | undefined
}
declare const A: <T, P extends keyof T>(
>A : <T, P extends keyof T>(obj: T, prop: P, factory: () => T[P]) => void

obj: T,
>obj : T

prop: P,
>prop : P

factory: () => T[P]
>factory : () => T[P]

) => void;
export const applyOptimizationDefaults = (optimization: Optimization) => {
>applyOptimizationDefaults : (optimization: Optimization) => void
>(optimization: Optimization) => { A(optimization, "minimizer", () => [ { apply: (compiler) => {}, }, ]);} : (optimization: Optimization) => void
>optimization : Optimization

A(optimization, "minimizer", () => [
>A(optimization, "minimizer", () => [ { apply: (compiler) => {}, }, ]) : void
>A : <T, P extends keyof T>(obj: T, prop: P, factory: () => T[P]) => void
>optimization : Optimization
>"minimizer" : "minimizer"
>() => [ { apply: (compiler) => {}, }, ] : () => { apply: (compiler: MyCompiler) => void; }[]
>[ { apply: (compiler) => {}, }, ] : { apply: (compiler: MyCompiler) => void; }[]
{
>{ apply: (compiler) => {}, } : { apply: (compiler: MyCompiler) => void; }

apply: (compiler) => {},
>apply : (compiler: MyCompiler) => void
>(compiler) => {} : (compiler: MyCompiler) => void
>compiler : MyCompiler

},
]);
};

Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
// @strict: true
// @noEmit: true
// @lib: es2015

// repro from #52588

declare function test(
arg: Record<string, (arg: string) => void> | Array<(arg: number) => void>
): void;

test([
(arg) => {
arg; // number
},
]);
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
// @strict: true
// @noEmit: true
// @lib: es5

// repro from #52588

declare function test(
arg: Record<string, (arg: string) => void> | Array<(arg: number) => void>
): void;

test([
(arg) => {
arg; // number
},
]);
24 changes: 24 additions & 0 deletions tests/cases/compiler/contextualTypeCaching.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,3 +23,27 @@ emit('a', {
nestedCallback: (r) => {},
},
});

// simplified repro from 52589#issuecomment-1416180638
declare class MyCompiler {
compile(): void;
}
interface WebpackPluginInstance {
apply: (compiler: MyCompiler) => void;
}
type WebpackPluginFunction = (this: MyCompiler, compiler: MyCompiler) => void;
interface Optimization {
minimizer?: (WebpackPluginInstance | WebpackPluginFunction)[];
}
declare const A: <T, P extends keyof T>(
obj: T,
prop: P,
factory: () => T[P]
) => void;
export const applyOptimizationDefaults = (optimization: Optimization) => {
A(optimization, "minimizer", () => [
{
apply: (compiler) => {},
},
]);
};

0 comments on commit e775383

Please sign in to comment.