Merge pull request #32386 from microsoft/fix32349

Instantiate contextual types for return expressions
This commit is contained in:
Anders Hejlsberg
2019-07-23 17:33:25 -07:00
committed by GitHub
5 changed files with 266 additions and 2 deletions

View File

@@ -19119,7 +19119,7 @@ namespace ts {
// If the given contextual type contains instantiable types and if a mapper representing
// return type inferences is available, instantiate those types using that mapper.
function instantiateContextualType(contextualType: Type | undefined, node: Expression, contextFlags?: ContextFlags): Type | undefined {
function instantiateContextualType(contextualType: Type | undefined, node: Node, contextFlags?: ContextFlags): Type | undefined {
if (contextualType && maybeTypeOfKind(contextualType, TypeFlags.Instantiable)) {
const inferenceContext = getInferenceContext(node);
// If no inferences have been made, nothing is gained from instantiating as type parameters
@@ -23436,7 +23436,7 @@ namespace ts {
nextType && isUnitType(nextType)) {
const contextualType = !contextualSignature ? undefined :
contextualSignature === getSignatureFromDeclaration(func) ? isGenerator ? undefined : returnType :
getReturnTypeOfSignature(contextualSignature);
instantiateContextualType(getReturnTypeOfSignature(contextualSignature), func);
if (isGenerator) {
yieldType = getWidenedLiteralLikeTypeForContextualIterationTypeIfNeeded(yieldType, contextualType, IterationTypeKind.Yield, isAsync);
returnType = getWidenedLiteralLikeTypeForContextualIterationTypeIfNeeded(returnType, contextualType, IterationTypeKind.Return, isAsync);

View File

@@ -138,6 +138,40 @@ declare function passContentsToFunc<T>(outerBox: T, consumer: BoxConsumerFromOut
declare const outerBoxOfString: OuterBox<string>;
passContentsToFunc(outerBoxOfString, box => box.value);
// Repro from #32349
type DooDad = 'SOMETHING' | 'ELSE' ;
class Interesting {
public compiles = () : Promise<DooDad> => {
return Promise.resolve().then(() => {
if (1 < 2) {
return 'SOMETHING';
}
return 'ELSE';
});
};
public doesnt = () : Promise<DooDad> => {
return Promise.resolve().then(() => {
return 'ELSE';
});
};
public slightlyDifferentErrorMessage = () : Promise<DooDad> => {
return Promise.resolve().then(() => {
if (1 < 2) {
return 'SOMETHING';
}
return 'SOMETHING';
});
};
}
// Repro from #32349
declare function invoke<T>(f: () => T): T;
let xx: 0 | 1 | 2 = invoke(() => 1);
//// [instantiateContextualTypes.js]
@@ -162,3 +196,29 @@ var N1;
createElement2(InferFunctionTypes, [(foo) => "" + foo]);
})(N1 || (N1 = {}));
passContentsToFunc(outerBoxOfString, box => box.value);
class Interesting {
constructor() {
this.compiles = () => {
return Promise.resolve().then(() => {
if (1 < 2) {
return 'SOMETHING';
}
return 'ELSE';
});
};
this.doesnt = () => {
return Promise.resolve().then(() => {
return 'ELSE';
});
};
this.slightlyDifferentErrorMessage = () => {
return Promise.resolve().then(() => {
if (1 < 2) {
return 'SOMETHING';
}
return 'SOMETHING';
});
};
}
}
let xx = invoke(() => 1);

View File

@@ -407,3 +407,77 @@ passContentsToFunc(outerBoxOfString, box => box.value);
>box : Symbol(box, Decl(instantiateContextualTypes.ts, 138, 36))
>value : Symbol(value, Decl(instantiateContextualTypes.ts, 121, 20))
// Repro from #32349
type DooDad = 'SOMETHING' | 'ELSE' ;
>DooDad : Symbol(DooDad, Decl(instantiateContextualTypes.ts, 138, 55))
class Interesting {
>Interesting : Symbol(Interesting, Decl(instantiateContextualTypes.ts, 142, 36))
public compiles = () : Promise<DooDad> => {
>compiles : Symbol(Interesting.compiles, Decl(instantiateContextualTypes.ts, 144, 19))
>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, --, --))
>DooDad : Symbol(DooDad, Decl(instantiateContextualTypes.ts, 138, 55))
return Promise.resolve().then(() => {
>Promise.resolve().then : Symbol(Promise.then, Decl(lib.es5.d.ts, --, --))
>Promise.resolve : Symbol(PromiseConstructor.resolve, 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, --, --))
>resolve : Symbol(PromiseConstructor.resolve, Decl(lib.es2015.promise.d.ts, --, --), Decl(lib.es2015.promise.d.ts, --, --))
>then : Symbol(Promise.then, Decl(lib.es5.d.ts, --, --))
if (1 < 2) {
return 'SOMETHING';
}
return 'ELSE';
});
};
public doesnt = () : Promise<DooDad> => {
>doesnt : Symbol(Interesting.doesnt, Decl(instantiateContextualTypes.ts, 152, 3))
>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, --, --))
>DooDad : Symbol(DooDad, Decl(instantiateContextualTypes.ts, 138, 55))
return Promise.resolve().then(() => {
>Promise.resolve().then : Symbol(Promise.then, Decl(lib.es5.d.ts, --, --))
>Promise.resolve : Symbol(PromiseConstructor.resolve, 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, --, --))
>resolve : Symbol(PromiseConstructor.resolve, Decl(lib.es2015.promise.d.ts, --, --), Decl(lib.es2015.promise.d.ts, --, --))
>then : Symbol(Promise.then, Decl(lib.es5.d.ts, --, --))
return 'ELSE';
});
};
public slightlyDifferentErrorMessage = () : Promise<DooDad> => {
>slightlyDifferentErrorMessage : Symbol(Interesting.slightlyDifferentErrorMessage, Decl(instantiateContextualTypes.ts, 157, 3))
>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, --, --))
>DooDad : Symbol(DooDad, Decl(instantiateContextualTypes.ts, 138, 55))
return Promise.resolve().then(() => {
>Promise.resolve().then : Symbol(Promise.then, Decl(lib.es5.d.ts, --, --))
>Promise.resolve : Symbol(PromiseConstructor.resolve, 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, --, --))
>resolve : Symbol(PromiseConstructor.resolve, Decl(lib.es2015.promise.d.ts, --, --), Decl(lib.es2015.promise.d.ts, --, --))
>then : Symbol(Promise.then, Decl(lib.es5.d.ts, --, --))
if (1 < 2) {
return 'SOMETHING';
}
return 'SOMETHING';
});
};
}
// Repro from #32349
declare function invoke<T>(f: () => T): T;
>invoke : Symbol(invoke, Decl(instantiateContextualTypes.ts, 166, 1))
>T : Symbol(T, Decl(instantiateContextualTypes.ts, 170, 24))
>f : Symbol(f, Decl(instantiateContextualTypes.ts, 170, 27))
>T : Symbol(T, Decl(instantiateContextualTypes.ts, 170, 24))
>T : Symbol(T, Decl(instantiateContextualTypes.ts, 170, 24))
let xx: 0 | 1 | 2 = invoke(() => 1);
>xx : Symbol(xx, Decl(instantiateContextualTypes.ts, 172, 3))
>invoke : Symbol(invoke, Decl(instantiateContextualTypes.ts, 166, 1))

View File

@@ -326,3 +326,99 @@ passContentsToFunc(outerBoxOfString, box => box.value);
>box : InnerBox<string>
>value : string
// Repro from #32349
type DooDad = 'SOMETHING' | 'ELSE' ;
>DooDad : DooDad
class Interesting {
>Interesting : Interesting
public compiles = () : Promise<DooDad> => {
>compiles : () => Promise<DooDad>
>() : Promise<DooDad> => { return Promise.resolve().then(() => { if (1 < 2) { return 'SOMETHING'; } return 'ELSE'; }); } : () => Promise<DooDad>
return Promise.resolve().then(() => {
>Promise.resolve().then(() => { if (1 < 2) { return 'SOMETHING'; } return 'ELSE'; }) : Promise<DooDad>
>Promise.resolve().then : <TResult1 = void, TResult2 = never>(onfulfilled?: ((value: void) => TResult1 | PromiseLike<TResult1>) | null | undefined, onrejected?: ((reason: any) => TResult2 | PromiseLike<TResult2>) | null | undefined) => Promise<TResult1 | TResult2>
>Promise.resolve() : Promise<void>
>Promise.resolve : { <T>(value: T | PromiseLike<T>): Promise<T>; (): Promise<void>; }
>Promise : PromiseConstructor
>resolve : { <T>(value: T | PromiseLike<T>): Promise<T>; (): Promise<void>; }
>then : <TResult1 = void, TResult2 = never>(onfulfilled?: ((value: void) => TResult1 | PromiseLike<TResult1>) | null | undefined, onrejected?: ((reason: any) => TResult2 | PromiseLike<TResult2>) | null | undefined) => Promise<TResult1 | TResult2>
>() => { if (1 < 2) { return 'SOMETHING'; } return 'ELSE'; } : () => "SOMETHING" | "ELSE"
if (1 < 2) {
>1 < 2 : boolean
>1 : 1
>2 : 2
return 'SOMETHING';
>'SOMETHING' : "SOMETHING"
}
return 'ELSE';
>'ELSE' : "ELSE"
});
};
public doesnt = () : Promise<DooDad> => {
>doesnt : () => Promise<DooDad>
>() : Promise<DooDad> => { return Promise.resolve().then(() => { return 'ELSE'; }); } : () => Promise<DooDad>
return Promise.resolve().then(() => {
>Promise.resolve().then(() => { return 'ELSE'; }) : Promise<DooDad>
>Promise.resolve().then : <TResult1 = void, TResult2 = never>(onfulfilled?: ((value: void) => TResult1 | PromiseLike<TResult1>) | null | undefined, onrejected?: ((reason: any) => TResult2 | PromiseLike<TResult2>) | null | undefined) => Promise<TResult1 | TResult2>
>Promise.resolve() : Promise<void>
>Promise.resolve : { <T>(value: T | PromiseLike<T>): Promise<T>; (): Promise<void>; }
>Promise : PromiseConstructor
>resolve : { <T>(value: T | PromiseLike<T>): Promise<T>; (): Promise<void>; }
>then : <TResult1 = void, TResult2 = never>(onfulfilled?: ((value: void) => TResult1 | PromiseLike<TResult1>) | null | undefined, onrejected?: ((reason: any) => TResult2 | PromiseLike<TResult2>) | null | undefined) => Promise<TResult1 | TResult2>
>() => { return 'ELSE'; } : () => "ELSE"
return 'ELSE';
>'ELSE' : "ELSE"
});
};
public slightlyDifferentErrorMessage = () : Promise<DooDad> => {
>slightlyDifferentErrorMessage : () => Promise<DooDad>
>() : Promise<DooDad> => { return Promise.resolve().then(() => { if (1 < 2) { return 'SOMETHING'; } return 'SOMETHING'; }); } : () => Promise<DooDad>
return Promise.resolve().then(() => {
>Promise.resolve().then(() => { if (1 < 2) { return 'SOMETHING'; } return 'SOMETHING'; }) : Promise<DooDad>
>Promise.resolve().then : <TResult1 = void, TResult2 = never>(onfulfilled?: ((value: void) => TResult1 | PromiseLike<TResult1>) | null | undefined, onrejected?: ((reason: any) => TResult2 | PromiseLike<TResult2>) | null | undefined) => Promise<TResult1 | TResult2>
>Promise.resolve() : Promise<void>
>Promise.resolve : { <T>(value: T | PromiseLike<T>): Promise<T>; (): Promise<void>; }
>Promise : PromiseConstructor
>resolve : { <T>(value: T | PromiseLike<T>): Promise<T>; (): Promise<void>; }
>then : <TResult1 = void, TResult2 = never>(onfulfilled?: ((value: void) => TResult1 | PromiseLike<TResult1>) | null | undefined, onrejected?: ((reason: any) => TResult2 | PromiseLike<TResult2>) | null | undefined) => Promise<TResult1 | TResult2>
>() => { if (1 < 2) { return 'SOMETHING'; } return 'SOMETHING'; } : () => "SOMETHING"
if (1 < 2) {
>1 < 2 : boolean
>1 : 1
>2 : 2
return 'SOMETHING';
>'SOMETHING' : "SOMETHING"
}
return 'SOMETHING';
>'SOMETHING' : "SOMETHING"
});
};
}
// Repro from #32349
declare function invoke<T>(f: () => T): T;
>invoke : <T>(f: () => T) => T
>f : () => T
let xx: 0 | 1 | 2 = invoke(() => 1);
>xx : 0 | 1 | 2
>invoke(() => 1) : 1
>invoke : <T>(f: () => T) => T
>() => 1 : () => 1
>1 : 1

View File

@@ -140,3 +140,37 @@ declare function passContentsToFunc<T>(outerBox: T, consumer: BoxConsumerFromOut
declare const outerBoxOfString: OuterBox<string>;
passContentsToFunc(outerBoxOfString, box => box.value);
// Repro from #32349
type DooDad = 'SOMETHING' | 'ELSE' ;
class Interesting {
public compiles = () : Promise<DooDad> => {
return Promise.resolve().then(() => {
if (1 < 2) {
return 'SOMETHING';
}
return 'ELSE';
});
};
public doesnt = () : Promise<DooDad> => {
return Promise.resolve().then(() => {
return 'ELSE';
});
};
public slightlyDifferentErrorMessage = () : Promise<DooDad> => {
return Promise.resolve().then(() => {
if (1 < 2) {
return 'SOMETHING';
}
return 'SOMETHING';
});
};
}
// Repro from #32349
declare function invoke<T>(f: () => T): T;
let xx: 0 | 1 | 2 = invoke(() => 1);