Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Port #30857 #30968

Merged
merged 1 commit into from Apr 16, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
27 changes: 21 additions & 6 deletions src/compiler/checker.ts
Expand Up @@ -14709,15 +14709,30 @@ namespace ts {
inferFromTypes(source, (<ConditionalType>target).falseType);
}
else if (target.flags & TypeFlags.UnionOrIntersection) {
// We infer from types that are not naked type variables first so that inferences we
// make from nested naked type variables and given slightly higher priority by virtue
// of being first in the candidates array.
let typeVariableCount = 0;
for (const t of (<UnionOrIntersectionType>target).types) {
const savePriority = priority;
// Inferences directly to naked type variables are given lower priority as they are
// less specific. For example, when inferring from Promise<string> to T | Promise<T>,
// we want to infer string for T, not Promise<string> | string.
if (getInferenceInfoForType(t)) {
priority |= InferencePriority.NakedTypeVariable;
typeVariableCount++;
}
else {
inferFromTypes(source, t);
}
}
// Inferences directly to naked type variables are given lower priority as they are
// less specific. For example, when inferring from Promise<string> to T | Promise<T>,
// we want to infer string for T, not Promise<string> | string. For intersection types
// we only infer to single naked type variables.
if (target.flags & TypeFlags.Union ? typeVariableCount !== 0 : typeVariableCount === 1) {
const savePriority = priority;
priority |= InferencePriority.NakedTypeVariable;
for (const t of (<UnionOrIntersectionType>target).types) {
if (getInferenceInfoForType(t)) {
inferFromTypes(source, t);
}
}
inferFromTypes(source, t);
priority = savePriority;
}
}
Expand Down
16 changes: 8 additions & 8 deletions tests/baselines/reference/conditionalTypeDoesntSpinForever.types
Expand Up @@ -120,9 +120,9 @@ export enum PubSubRecordIsStoredInRedisAsA {

buildPubSubRecordType(Object.assign({}, soFar, {storedAs: PubSubRecordIsStoredInRedisAsA.jsonEncodedRedisString})) as
>buildPubSubRecordType(Object.assign({}, soFar, {storedAs: PubSubRecordIsStoredInRedisAsA.jsonEncodedRedisString})) as BuildPubSubRecordType<SO_FAR & {storedAs: PubSubRecordIsStoredInRedisAsA.jsonEncodedRedisString}> : BuildPubSubRecordType<SO_FAR & { storedAs: PubSubRecordIsStoredInRedisAsA.jsonEncodedRedisString; }>
>buildPubSubRecordType(Object.assign({}, soFar, {storedAs: PubSubRecordIsStoredInRedisAsA.jsonEncodedRedisString})) : BuildPubSubRecordType<SO_FAR & { storedAs: PubSubRecordIsStoredInRedisAsA.jsonEncodedRedisString; }>
>buildPubSubRecordType(Object.assign({}, soFar, {storedAs: PubSubRecordIsStoredInRedisAsA.jsonEncodedRedisString})) : BuildPubSubRecordType<SO_FAR & { storedAs: PubSubRecordIsStoredInRedisAsA; }>
>buildPubSubRecordType : <SO_FAR>(soFar: SO_FAR) => BuildPubSubRecordType<SO_FAR>
>Object.assign({}, soFar, {storedAs: PubSubRecordIsStoredInRedisAsA.jsonEncodedRedisString}) : SO_FAR & { storedAs: PubSubRecordIsStoredInRedisAsA.jsonEncodedRedisString; }
>Object.assign({}, soFar, {storedAs: PubSubRecordIsStoredInRedisAsA.jsonEncodedRedisString}) : SO_FAR & { storedAs: PubSubRecordIsStoredInRedisAsA; }
>Object.assign : { <T, U>(target: T, source: U): T & U; <T, U, V>(target: T, source1: U, source2: V): T & U & V; <T, U, V, W>(target: T, source1: U, source2: V, source3: W): T & U & V & W; (target: object, ...sources: any[]): any; }
>Object : ObjectConstructor
>assign : { <T, U>(target: T, source: U): T & U; <T, U, V>(target: T, source1: U, source2: V): T & U & V; <T, U, V, W>(target: T, source1: U, source2: V, source3: W): T & U & V & W; (target: object, ...sources: any[]): any; }
Expand All @@ -144,9 +144,9 @@ export enum PubSubRecordIsStoredInRedisAsA {

buildPubSubRecordType(Object.assign({}, soFar, {storedAs: PubSubRecordIsStoredInRedisAsA.redisHash})) as
>buildPubSubRecordType(Object.assign({}, soFar, {storedAs: PubSubRecordIsStoredInRedisAsA.redisHash})) as BuildPubSubRecordType<SO_FAR & {storedAs: PubSubRecordIsStoredInRedisAsA.redisHash}> : BuildPubSubRecordType<SO_FAR & { storedAs: PubSubRecordIsStoredInRedisAsA.redisHash; }>
>buildPubSubRecordType(Object.assign({}, soFar, {storedAs: PubSubRecordIsStoredInRedisAsA.redisHash})) : BuildPubSubRecordType<SO_FAR & { storedAs: PubSubRecordIsStoredInRedisAsA.redisHash; }>
>buildPubSubRecordType(Object.assign({}, soFar, {storedAs: PubSubRecordIsStoredInRedisAsA.redisHash})) : BuildPubSubRecordType<SO_FAR & { storedAs: PubSubRecordIsStoredInRedisAsA; }>
>buildPubSubRecordType : <SO_FAR>(soFar: SO_FAR) => BuildPubSubRecordType<SO_FAR>
>Object.assign({}, soFar, {storedAs: PubSubRecordIsStoredInRedisAsA.redisHash}) : SO_FAR & { storedAs: PubSubRecordIsStoredInRedisAsA.redisHash; }
>Object.assign({}, soFar, {storedAs: PubSubRecordIsStoredInRedisAsA.redisHash}) : SO_FAR & { storedAs: PubSubRecordIsStoredInRedisAsA; }
>Object.assign : { <T, U>(target: T, source: U): T & U; <T, U, V>(target: T, source1: U, source2: V): T & U & V; <T, U, V, W>(target: T, source1: U, source2: V, source3: W): T & U & V & W; (target: object, ...sources: any[]): any; }
>Object : ObjectConstructor
>assign : { <T, U>(target: T, source: U): T & U; <T, U, V>(target: T, source1: U, source2: V): T & U & V; <T, U, V, W>(target: T, source1: U, source2: V, source3: W): T & U & V & W; (target: object, ...sources: any[]): any; }
Expand Down Expand Up @@ -337,16 +337,16 @@ export enum PubSubRecordIsStoredInRedisAsA {

buildPubSubRecordType(Object.assign({}, soFar, {maxMsToWaitBeforePublishing: 0})) as BuildPubSubRecordType<SO_FAR & {maxMsToWaitBeforePublishing: 0}>,
>buildPubSubRecordType(Object.assign({}, soFar, {maxMsToWaitBeforePublishing: 0})) as BuildPubSubRecordType<SO_FAR & {maxMsToWaitBeforePublishing: 0}> : BuildPubSubRecordType<SO_FAR & { maxMsToWaitBeforePublishing: 0; }>
>buildPubSubRecordType(Object.assign({}, soFar, {maxMsToWaitBeforePublishing: 0})) : BuildPubSubRecordType<SO_FAR & { maxMsToWaitBeforePublishing: 0; }>
>buildPubSubRecordType(Object.assign({}, soFar, {maxMsToWaitBeforePublishing: 0})) : BuildPubSubRecordType<SO_FAR & { maxMsToWaitBeforePublishing: number; }>
>buildPubSubRecordType : <SO_FAR>(soFar: SO_FAR) => BuildPubSubRecordType<SO_FAR>
>Object.assign({}, soFar, {maxMsToWaitBeforePublishing: 0}) : SO_FAR & { maxMsToWaitBeforePublishing: 0; }
>Object.assign({}, soFar, {maxMsToWaitBeforePublishing: 0}) : SO_FAR & { maxMsToWaitBeforePublishing: number; }
>Object.assign : { <T, U>(target: T, source: U): T & U; <T, U, V>(target: T, source1: U, source2: V): T & U & V; <T, U, V, W>(target: T, source1: U, source2: V, source3: W): T & U & V & W; (target: object, ...sources: any[]): any; }
>Object : ObjectConstructor
>assign : { <T, U>(target: T, source: U): T & U; <T, U, V>(target: T, source1: U, source2: V): T & U & V; <T, U, V, W>(target: T, source1: U, source2: V, source3: W): T & U & V & W; (target: object, ...sources: any[]): any; }
>{} : {}
>soFar : SO_FAR
>{maxMsToWaitBeforePublishing: 0} : { maxMsToWaitBeforePublishing: 0; }
>maxMsToWaitBeforePublishing : 0
>{maxMsToWaitBeforePublishing: 0} : { maxMsToWaitBeforePublishing: number; }
>maxMsToWaitBeforePublishing : number
>0 : 0
>maxMsToWaitBeforePublishing : 0
}
Expand Down
2 changes: 1 addition & 1 deletion tests/baselines/reference/objectSpread.types
Expand Up @@ -602,7 +602,7 @@ let exclusive: { id: string, a: number, b: string, c: string, d: boolean } =
>d : boolean

f({ a: 1, b: 'yes' }, { c: 'no', d: false })
>f({ a: 1, b: 'yes' }, { c: 'no', d: false }) : { a: number; b: string; } & { c: string; d: false; } & { id: string; }
>f({ a: 1, b: 'yes' }, { c: 'no', d: false }) : { a: number; b: string; } & { c: string; d: boolean; } & { id: string; }
>f : <T, U>(t: T, u: U) => T & U & { id: string; }
>{ a: 1, b: 'yes' } : { a: number; b: string; }
>a : number
Expand Down
16 changes: 13 additions & 3 deletions tests/baselines/reference/unionAndIntersectionInference1.js
Expand Up @@ -85,10 +85,16 @@ const createTest = (): ITest => {
}

declare function f1<T, U>(x: T | U): T | U;
declare function f2<T, U>(x: T & U): T & U;
declare function f2<T, U>(x: T, y: U): T | U;

let x1: string = f1('a');
let x2: string = f2('a');
let x2: string = f2('a', 'b');

// Repro from #30442

const func = <T>() => {};
const assign = <T, U>(a: T, b: U) => Object.assign(a, b);
const res: (() => void) & { func: any } = assign(() => {}, { func });


//// [unionAndIntersectionInference1.js]
Expand Down Expand Up @@ -134,4 +140,8 @@ const createTest = () => {
return { name: 'test' };
};
let x1 = f1('a');
let x2 = f2('a');
let x2 = f2('a', 'b');
// Repro from #30442
const func = () => { };
const assign = (a, b) => Object.assign(a, b);
const res = assign(() => { }, { func });
31 changes: 29 additions & 2 deletions tests/baselines/reference/unionAndIntersectionInference1.symbols
Expand Up @@ -239,12 +239,13 @@ declare function f1<T, U>(x: T | U): T | U;
>T : Symbol(T, Decl(unionAndIntersectionInference1.ts, 85, 20))
>U : Symbol(U, Decl(unionAndIntersectionInference1.ts, 85, 22))

declare function f2<T, U>(x: T & U): T & U;
declare function f2<T, U>(x: T, y: U): T | U;
>f2 : Symbol(f2, Decl(unionAndIntersectionInference1.ts, 85, 43))
>T : Symbol(T, Decl(unionAndIntersectionInference1.ts, 86, 20))
>U : Symbol(U, Decl(unionAndIntersectionInference1.ts, 86, 22))
>x : Symbol(x, Decl(unionAndIntersectionInference1.ts, 86, 26))
>T : Symbol(T, Decl(unionAndIntersectionInference1.ts, 86, 20))
>y : Symbol(y, Decl(unionAndIntersectionInference1.ts, 86, 31))
>U : Symbol(U, Decl(unionAndIntersectionInference1.ts, 86, 22))
>T : Symbol(T, Decl(unionAndIntersectionInference1.ts, 86, 20))
>U : Symbol(U, Decl(unionAndIntersectionInference1.ts, 86, 22))
Expand All @@ -253,7 +254,33 @@ let x1: string = f1('a');
>x1 : Symbol(x1, Decl(unionAndIntersectionInference1.ts, 88, 3))
>f1 : Symbol(f1, Decl(unionAndIntersectionInference1.ts, 83, 1))

let x2: string = f2('a');
let x2: string = f2('a', 'b');
>x2 : Symbol(x2, Decl(unionAndIntersectionInference1.ts, 89, 3))
>f2 : Symbol(f2, Decl(unionAndIntersectionInference1.ts, 85, 43))

// Repro from #30442

const func = <T>() => {};
>func : Symbol(func, Decl(unionAndIntersectionInference1.ts, 93, 5))
>T : Symbol(T, Decl(unionAndIntersectionInference1.ts, 93, 14))

const assign = <T, U>(a: T, b: U) => Object.assign(a, b);
>assign : Symbol(assign, Decl(unionAndIntersectionInference1.ts, 94, 5))
>T : Symbol(T, Decl(unionAndIntersectionInference1.ts, 94, 16))
>U : Symbol(U, Decl(unionAndIntersectionInference1.ts, 94, 18))
>a : Symbol(a, Decl(unionAndIntersectionInference1.ts, 94, 22))
>T : Symbol(T, Decl(unionAndIntersectionInference1.ts, 94, 16))
>b : Symbol(b, Decl(unionAndIntersectionInference1.ts, 94, 27))
>U : Symbol(U, Decl(unionAndIntersectionInference1.ts, 94, 18))
>Object.assign : Symbol(ObjectConstructor.assign, Decl(lib.es2015.core.d.ts, --, --), Decl(lib.es2015.core.d.ts, --, --), Decl(lib.es2015.core.d.ts, --, --), Decl(lib.es2015.core.d.ts, --, --))
>Object : Symbol(Object, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --))
>assign : Symbol(ObjectConstructor.assign, Decl(lib.es2015.core.d.ts, --, --), Decl(lib.es2015.core.d.ts, --, --), Decl(lib.es2015.core.d.ts, --, --), Decl(lib.es2015.core.d.ts, --, --))
>a : Symbol(a, Decl(unionAndIntersectionInference1.ts, 94, 22))
>b : Symbol(b, Decl(unionAndIntersectionInference1.ts, 94, 27))

const res: (() => void) & { func: any } = assign(() => {}, { func });
>res : Symbol(res, Decl(unionAndIntersectionInference1.ts, 95, 5))
>func : Symbol(func, Decl(unionAndIntersectionInference1.ts, 95, 27))
>assign : Symbol(assign, Decl(unionAndIntersectionInference1.ts, 94, 5))
>func : Symbol(func, Decl(unionAndIntersectionInference1.ts, 95, 60))

41 changes: 35 additions & 6 deletions tests/baselines/reference/unionAndIntersectionInference1.types
Expand Up @@ -216,19 +216,48 @@ declare function f1<T, U>(x: T | U): T | U;
>f1 : <T, U>(x: T | U) => T | U
>x : T | U

declare function f2<T, U>(x: T & U): T & U;
>f2 : <T, U>(x: T & U) => T & U
>x : T & U
declare function f2<T, U>(x: T, y: U): T | U;
>f2 : <T, U>(x: T, y: U) => T | U
>x : T
>y : U

let x1: string = f1('a');
>x1 : string
>f1('a') : "a"
>f1 : <T, U>(x: T | U) => T | U
>'a' : "a"

let x2: string = f2('a');
let x2: string = f2('a', 'b');
>x2 : string
>f2('a') : "a"
>f2 : <T, U>(x: T & U) => T & U
>f2('a', 'b') : "a" | "b"
>f2 : <T, U>(x: T, y: U) => T | U
>'a' : "a"
>'b' : "b"

// Repro from #30442

const func = <T>() => {};
>func : <T>() => void
><T>() => {} : <T>() => void

const assign = <T, U>(a: T, b: U) => Object.assign(a, b);
>assign : <T, U>(a: T, b: U) => T & U
><T, U>(a: T, b: U) => Object.assign(a, b) : <T, U>(a: T, b: U) => T & U
>a : T
>b : U
>Object.assign(a, b) : T & U
>Object.assign : { <T, U>(target: T, source: U): T & U; <T, U, V>(target: T, source1: U, source2: V): T & U & V; <T, U, V, W>(target: T, source1: U, source2: V, source3: W): T & U & V & W; (target: object, ...sources: any[]): any; }
>Object : ObjectConstructor
>assign : { <T, U>(target: T, source: U): T & U; <T, U, V>(target: T, source1: U, source2: V): T & U & V; <T, U, V, W>(target: T, source1: U, source2: V, source3: W): T & U & V & W; (target: object, ...sources: any[]): any; }
>a : T
>b : U

const res: (() => void) & { func: any } = assign(() => {}, { func });
>res : (() => void) & { func: any; }
>func : any
>assign(() => {}, { func }) : (() => void) & { func: <T>() => void; }
>assign : <T, U>(a: T, b: U) => T & U
>() => {} : () => void
>{ func } : { func: <T>() => void; }
>func : <T>() => void

Expand Up @@ -86,7 +86,13 @@ const createTest = (): ITest => {
}

declare function f1<T, U>(x: T | U): T | U;
declare function f2<T, U>(x: T & U): T & U;
declare function f2<T, U>(x: T, y: U): T | U;

let x1: string = f1('a');
let x2: string = f2('a');
let x2: string = f2('a', 'b');

// Repro from #30442

const func = <T>() => {};
const assign = <T, U>(a: T, b: U) => Object.assign(a, b);
const res: (() => void) & { func: any } = assign(() => {}, { func });