Skip to content

Commit c17a2af

Browse files
ZzzenBobobUnicorn
authored andcommitted
support contextual return type of iife (microsoft#45007)
1 parent edad4a1 commit c17a2af

16 files changed

+254
-104
lines changed

src/compiler/checker.ts

+4
Original file line numberDiff line numberDiff line change
@@ -25352,6 +25352,10 @@ namespace ts {
2535225352
if (signature && !isResolvingReturnTypeOfSignature(signature)) {
2535325353
return getReturnTypeOfSignature(signature);
2535425354
}
25355+
const iife = getImmediatelyInvokedFunctionExpression(functionDecl);
25356+
if (iife) {
25357+
return getContextualType(iife);
25358+
}
2535525359
return undefined;
2535625360
}
2535725361

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
//// [contextualReturnTypeOfIIFE.ts]
2+
const test1: Promise<[one: number, two: string]> = (async () => {
3+
return [1, 'two'];
4+
})();
5+
6+
const test2: Promise<[one: number, two: string]> = new Promise(
7+
(resolve) => resolve([1, 'two']),
8+
);
9+
10+
const obj: { foo: [one: number, two: string] } = {
11+
foo: (() => [1, 'two'])()
12+
};
13+
14+
15+
//// [contextualReturnTypeOfIIFE.js]
16+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
17+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
18+
return new (P || (P = Promise))(function (resolve, reject) {
19+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
20+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
21+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
22+
step((generator = generator.apply(thisArg, _arguments || [])).next());
23+
});
24+
};
25+
var __generator = (this && this.__generator) || function (thisArg, body) {
26+
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
27+
return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
28+
function verb(n) { return function (v) { return step([n, v]); }; }
29+
function step(op) {
30+
if (f) throw new TypeError("Generator is already executing.");
31+
while (_) try {
32+
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
33+
if (y = 0, t) op = [op[0] & 2, t.value];
34+
switch (op[0]) {
35+
case 0: case 1: t = op; break;
36+
case 4: _.label++; return { value: op[1], done: false };
37+
case 5: _.label++; y = op[1]; op = [0]; continue;
38+
case 7: op = _.ops.pop(); _.trys.pop(); continue;
39+
default:
40+
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
41+
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
42+
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
43+
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
44+
if (t[2]) _.ops.pop();
45+
_.trys.pop(); continue;
46+
}
47+
op = body.call(thisArg, _);
48+
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
49+
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
50+
}
51+
};
52+
var _this = this;
53+
var test1 = (function () { return __awaiter(_this, void 0, void 0, function () {
54+
return __generator(this, function (_a) {
55+
return [2 /*return*/, [1, 'two']];
56+
});
57+
}); })();
58+
var test2 = new Promise(function (resolve) { return resolve([1, 'two']); });
59+
var obj = {
60+
foo: (function () { return [1, 'two']; })()
61+
};
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
=== tests/cases/compiler/contextualReturnTypeOfIIFE.ts ===
2+
const test1: Promise<[one: number, two: string]> = (async () => {
3+
>test1 : Symbol(test1, Decl(contextualReturnTypeOfIIFE.ts, 0, 5))
4+
>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, --, --))
5+
6+
return [1, 'two'];
7+
})();
8+
9+
const test2: Promise<[one: number, two: string]> = new Promise(
10+
>test2 : Symbol(test2, Decl(contextualReturnTypeOfIIFE.ts, 4, 5))
11+
>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, --, --))
12+
>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, --, --))
13+
14+
(resolve) => resolve([1, 'two']),
15+
>resolve : Symbol(resolve, Decl(contextualReturnTypeOfIIFE.ts, 5, 5))
16+
>resolve : Symbol(resolve, Decl(contextualReturnTypeOfIIFE.ts, 5, 5))
17+
18+
);
19+
20+
const obj: { foo: [one: number, two: string] } = {
21+
>obj : Symbol(obj, Decl(contextualReturnTypeOfIIFE.ts, 8, 5))
22+
>foo : Symbol(foo, Decl(contextualReturnTypeOfIIFE.ts, 8, 12))
23+
24+
foo: (() => [1, 'two'])()
25+
>foo : Symbol(foo, Decl(contextualReturnTypeOfIIFE.ts, 8, 50))
26+
27+
};
28+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
=== tests/cases/compiler/contextualReturnTypeOfIIFE.ts ===
2+
const test1: Promise<[one: number, two: string]> = (async () => {
3+
>test1 : Promise<[one: number, two: string]>
4+
>(async () => { return [1, 'two'];})() : Promise<[number, string]>
5+
>(async () => { return [1, 'two'];}) : () => Promise<[number, string]>
6+
>async () => { return [1, 'two'];} : () => Promise<[number, string]>
7+
8+
return [1, 'two'];
9+
>[1, 'two'] : [number, string]
10+
>1 : 1
11+
>'two' : "two"
12+
13+
})();
14+
15+
const test2: Promise<[one: number, two: string]> = new Promise(
16+
>test2 : Promise<[one: number, two: string]>
17+
>new Promise( (resolve) => resolve([1, 'two']),) : Promise<[one: number, two: string]>
18+
>Promise : PromiseConstructor
19+
20+
(resolve) => resolve([1, 'two']),
21+
>(resolve) => resolve([1, 'two']) : (resolve: (value: [one: number, two: string] | PromiseLike<[one: number, two: string]>) => void) => void
22+
>resolve : (value: [one: number, two: string] | PromiseLike<[one: number, two: string]>) => void
23+
>resolve([1, 'two']) : void
24+
>resolve : (value: [one: number, two: string] | PromiseLike<[one: number, two: string]>) => void
25+
>[1, 'two'] : [number, string]
26+
>1 : 1
27+
>'two' : "two"
28+
29+
);
30+
31+
const obj: { foo: [one: number, two: string] } = {
32+
>obj : { foo: [one: number, two: string]; }
33+
>foo : [one: number, two: string]
34+
>{ foo: (() => [1, 'two'])()} : { foo: [number, string]; }
35+
36+
foo: (() => [1, 'two'])()
37+
>foo : [number, string]
38+
>(() => [1, 'two'])() : [number, string]
39+
>(() => [1, 'two']) : () => [number, string]
40+
>() => [1, 'two'] : () => [number, string]
41+
>[1, 'two'] : [number, string]
42+
>1 : 1
43+
>'two' : "two"
44+
45+
};
46+

tests/baselines/reference/generatorTypeCheck27.symbols

+2
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,9 @@ function* g(): IterableIterator<(x: string) => number> {
77
yield * function* () {
88
yield x => x.length;
99
>x : Symbol(x, Decl(generatorTypeCheck27.ts, 2, 13))
10+
>x.length : Symbol(String.length, Decl(lib.es5.d.ts, --, --))
1011
>x : Symbol(x, Decl(generatorTypeCheck27.ts, 2, 13))
12+
>length : Symbol(String.length, Decl(lib.es5.d.ts, --, --))
1113

1214
} ();
1315
}

tests/baselines/reference/generatorTypeCheck27.types

+8-8
Original file line numberDiff line numberDiff line change
@@ -5,16 +5,16 @@ function* g(): IterableIterator<(x: string) => number> {
55

66
yield * function* () {
77
>yield * function* () { yield x => x.length; } () : void
8-
>function* () { yield x => x.length; } () : Generator<(x: any) => any, void, unknown>
9-
>function* () { yield x => x.length; } : () => Generator<(x: any) => any, void, unknown>
8+
>function* () { yield x => x.length; } () : Generator<(x: string) => number, void, undefined>
9+
>function* () { yield x => x.length; } : () => Generator<(x: string) => number, void, undefined>
1010

1111
yield x => x.length;
12-
>yield x => x.length : any
13-
>x => x.length : (x: any) => any
14-
>x : any
15-
>x.length : any
16-
>x : any
17-
>length : any
12+
>yield x => x.length : undefined
13+
>x => x.length : (x: string) => number
14+
>x : string
15+
>x.length : number
16+
>x : string
17+
>length : number
1818

1919
} ();
2020
}

tests/baselines/reference/generatorTypeCheck29.symbols

+2
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,9 @@ function* g2(): Iterator<Iterable<(x: string) => number>> {
88
yield function* () {
99
yield x => x.length;
1010
>x : Symbol(x, Decl(generatorTypeCheck29.ts, 2, 13))
11+
>x.length : Symbol(String.length, Decl(lib.es5.d.ts, --, --))
1112
>x : Symbol(x, Decl(generatorTypeCheck29.ts, 2, 13))
13+
>length : Symbol(String.length, Decl(lib.es5.d.ts, --, --))
1214

1315
} ()
1416
}

tests/baselines/reference/generatorTypeCheck29.types

+8-8
Original file line numberDiff line numberDiff line change
@@ -5,16 +5,16 @@ function* g2(): Iterator<Iterable<(x: string) => number>> {
55

66
yield function* () {
77
>yield function* () { yield x => x.length; } () : undefined
8-
>function* () { yield x => x.length; } () : Generator<(x: any) => any, void, unknown>
9-
>function* () { yield x => x.length; } : () => Generator<(x: any) => any, void, unknown>
8+
>function* () { yield x => x.length; } () : Generator<(x: string) => number, void, undefined>
9+
>function* () { yield x => x.length; } : () => Generator<(x: string) => number, void, undefined>
1010

1111
yield x => x.length;
12-
>yield x => x.length : any
13-
>x => x.length : (x: any) => any
14-
>x : any
15-
>x.length : any
16-
>x : any
17-
>length : any
12+
>yield x => x.length : undefined
13+
>x => x.length : (x: string) => number
14+
>x : string
15+
>x.length : number
16+
>x : string
17+
>length : number
1818

1919
} ()
2020
}

tests/baselines/reference/generatorTypeCheck30.symbols

+2
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,9 @@ function* g2(): Iterator<Iterable<(x: string) => number>> {
88
yield function* () {
99
yield x => x.length;
1010
>x : Symbol(x, Decl(generatorTypeCheck30.ts, 2, 13))
11+
>x.length : Symbol(String.length, Decl(lib.es5.d.ts, --, --))
1112
>x : Symbol(x, Decl(generatorTypeCheck30.ts, 2, 13))
13+
>length : Symbol(String.length, Decl(lib.es5.d.ts, --, --))
1214

1315
} ()
1416
}

tests/baselines/reference/generatorTypeCheck30.types

+8-8
Original file line numberDiff line numberDiff line change
@@ -5,16 +5,16 @@ function* g2(): Iterator<Iterable<(x: string) => number>> {
55

66
yield function* () {
77
>yield function* () { yield x => x.length; } () : undefined
8-
>function* () { yield x => x.length; } () : Generator<(x: any) => any, void, unknown>
9-
>function* () { yield x => x.length; } : () => Generator<(x: any) => any, void, unknown>
8+
>function* () { yield x => x.length; } () : Generator<(x: string) => number, void, undefined>
9+
>function* () { yield x => x.length; } : () => Generator<(x: string) => number, void, undefined>
1010

1111
yield x => x.length;
12-
>yield x => x.length : any
13-
>x => x.length : (x: any) => any
14-
>x : any
15-
>x.length : any
16-
>x : any
17-
>length : any
12+
>yield x => x.length : undefined
13+
>x => x.length : (x: string) => number
14+
>x : string
15+
>x.length : number
16+
>x : string
17+
>length : number
1818

1919
} ()
2020
}
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
tests/cases/conformance/es6/yieldExpressions/generatorTypeCheck31.ts(2,11): error TS2322: Type 'Generator<(x: any) => any, void, unknown>' is not assignable to type '() => Iterable<(x: string) => number>'.
2-
Type 'Generator<(x: any) => any, void, unknown>' provides no match for the signature '(): Iterable<(x: string) => number>'.
1+
tests/cases/conformance/es6/yieldExpressions/generatorTypeCheck31.ts(2,11): error TS2322: Type 'Generator<(x: any) => any, void, any>' is not assignable to type '() => Iterable<(x: string) => number>'.
2+
Type 'Generator<(x: any) => any, void, any>' provides no match for the signature '(): Iterable<(x: string) => number>'.
33

44

55
==== tests/cases/conformance/es6/yieldExpressions/generatorTypeCheck31.ts (1 errors) ====
@@ -10,6 +10,6 @@ tests/cases/conformance/es6/yieldExpressions/generatorTypeCheck31.ts(2,11): erro
1010
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1111
} ()
1212
~~~~~~~~
13-
!!! error TS2322: Type 'Generator<(x: any) => any, void, unknown>' is not assignable to type '() => Iterable<(x: string) => number>'.
14-
!!! error TS2322: Type 'Generator<(x: any) => any, void, unknown>' provides no match for the signature '(): Iterable<(x: string) => number>'.
13+
!!! error TS2322: Type 'Generator<(x: any) => any, void, any>' is not assignable to type '() => Iterable<(x: string) => number>'.
14+
!!! error TS2322: Type 'Generator<(x: any) => any, void, any>' provides no match for the signature '(): Iterable<(x: string) => number>'.
1515
}

tests/baselines/reference/generatorTypeCheck31.types

+2-2
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@ function* g2(): Iterator<() => Iterable<(x: string) => number>> {
55

66
yield function* () {
77
>yield function* () { yield x => x.length; } () : undefined
8-
>function* () { yield x => x.length; } () : Generator<(x: any) => any, void, unknown>
9-
>function* () { yield x => x.length; } : () => Generator<(x: any) => any, void, unknown>
8+
>function* () { yield x => x.length; } () : Generator<(x: any) => any, void, any>
9+
>function* () { yield x => x.length; } : () => Generator<(x: any) => any, void, any>
1010

1111
yield x => x.length;
1212
>yield x => x.length : any

tests/baselines/reference/types.asyncGenerators.es2018.1.types

+27-27
Original file line numberDiff line numberDiff line change
@@ -122,14 +122,14 @@ const assignability4: () => AsyncIterableIterator<number> = async function * ()
122122
};
123123
const assignability5: () => AsyncIterableIterator<number> = async function * () {
124124
>assignability5 : () => AsyncIterableIterator<number>
125-
>async function * () { yield* (async function * () { yield 1; })();} : () => AsyncGenerator<number, void, unknown>
125+
>async function * () { yield* (async function * () { yield 1; })();} : () => AsyncGenerator<number, void, undefined>
126126

127127
yield* (async function * () { yield 1; })();
128128
>yield* (async function * () { yield 1; })() : void
129-
>(async function * () { yield 1; })() : AsyncGenerator<number, void, unknown>
130-
>(async function * () { yield 1; }) : () => AsyncGenerator<number, void, unknown>
131-
>async function * () { yield 1; } : () => AsyncGenerator<number, void, unknown>
132-
>yield 1 : any
129+
>(async function * () { yield 1; })() : AsyncGenerator<number, void, undefined>
130+
>(async function * () { yield 1; }) : () => AsyncGenerator<number, void, undefined>
131+
>async function * () { yield 1; } : () => AsyncGenerator<number, void, undefined>
132+
>yield 1 : undefined
133133
>1 : 1
134134

135135
};
@@ -182,14 +182,14 @@ const assignability9: () => AsyncIterable<number> = async function * () {
182182
};
183183
const assignability10: () => AsyncIterable<number> = async function * () {
184184
>assignability10 : () => AsyncIterable<number>
185-
>async function * () { yield* (async function * () { yield 1; })();} : () => AsyncGenerator<number, void, unknown>
185+
>async function * () { yield* (async function * () { yield 1; })();} : () => AsyncGenerator<number, void, undefined>
186186

187187
yield* (async function * () { yield 1; })();
188188
>yield* (async function * () { yield 1; })() : void
189-
>(async function * () { yield 1; })() : AsyncGenerator<number, void, unknown>
190-
>(async function * () { yield 1; }) : () => AsyncGenerator<number, void, unknown>
191-
>async function * () { yield 1; } : () => AsyncGenerator<number, void, unknown>
192-
>yield 1 : any
189+
>(async function * () { yield 1; })() : AsyncGenerator<number, void, undefined>
190+
>(async function * () { yield 1; }) : () => AsyncGenerator<number, void, undefined>
191+
>async function * () { yield 1; } : () => AsyncGenerator<number, void, undefined>
192+
>yield 1 : undefined
193193
>1 : 1
194194

195195
};
@@ -242,14 +242,14 @@ const assignability14: () => AsyncIterator<number> = async function * () {
242242
};
243243
const assignability15: () => AsyncIterator<number> = async function * () {
244244
>assignability15 : () => AsyncIterator<number>
245-
>async function * () { yield* (async function * () { yield 1; })();} : () => AsyncGenerator<number, void, unknown>
245+
>async function * () { yield* (async function * () { yield 1; })();} : () => AsyncGenerator<number, void, undefined>
246246

247247
yield* (async function * () { yield 1; })();
248248
>yield* (async function * () { yield 1; })() : void
249-
>(async function * () { yield 1; })() : AsyncGenerator<number, void, unknown>
250-
>(async function * () { yield 1; }) : () => AsyncGenerator<number, void, unknown>
251-
>async function * () { yield 1; } : () => AsyncGenerator<number, void, unknown>
252-
>yield 1 : any
249+
>(async function * () { yield 1; })() : AsyncGenerator<number, void, undefined>
250+
>(async function * () { yield 1; }) : () => AsyncGenerator<number, void, undefined>
251+
>async function * () { yield 1; } : () => AsyncGenerator<number, void, undefined>
252+
>yield 1 : undefined
253253
>1 : 1
254254

255255
};
@@ -297,10 +297,10 @@ async function * explicitReturnType5(): AsyncIterableIterator<number> {
297297

298298
yield* (async function * () { yield 1; })();
299299
>yield* (async function * () { yield 1; })() : void
300-
>(async function * () { yield 1; })() : AsyncGenerator<number, void, unknown>
301-
>(async function * () { yield 1; }) : () => AsyncGenerator<number, void, unknown>
302-
>async function * () { yield 1; } : () => AsyncGenerator<number, void, unknown>
303-
>yield 1 : any
300+
>(async function * () { yield 1; })() : AsyncGenerator<number, void, undefined>
301+
>(async function * () { yield 1; }) : () => AsyncGenerator<number, void, undefined>
302+
>async function * () { yield 1; } : () => AsyncGenerator<number, void, undefined>
303+
>yield 1 : undefined
304304
>1 : 1
305305
}
306306
async function * explicitReturnType6(): AsyncIterable<number> {
@@ -347,10 +347,10 @@ async function * explicitReturnType10(): AsyncIterable<number> {
347347

348348
yield* (async function * () { yield 1; })();
349349
>yield* (async function * () { yield 1; })() : void
350-
>(async function * () { yield 1; })() : AsyncGenerator<number, void, unknown>
351-
>(async function * () { yield 1; }) : () => AsyncGenerator<number, void, unknown>
352-
>async function * () { yield 1; } : () => AsyncGenerator<number, void, unknown>
353-
>yield 1 : any
350+
>(async function * () { yield 1; })() : AsyncGenerator<number, void, undefined>
351+
>(async function * () { yield 1; }) : () => AsyncGenerator<number, void, undefined>
352+
>async function * () { yield 1; } : () => AsyncGenerator<number, void, undefined>
353+
>yield 1 : undefined
354354
>1 : 1
355355
}
356356
async function * explicitReturnType11(): AsyncIterator<number> {
@@ -397,10 +397,10 @@ async function * explicitReturnType15(): AsyncIterator<number> {
397397

398398
yield* (async function * () { yield 1; })();
399399
>yield* (async function * () { yield 1; })() : void
400-
>(async function * () { yield 1; })() : AsyncGenerator<number, void, unknown>
401-
>(async function * () { yield 1; }) : () => AsyncGenerator<number, void, unknown>
402-
>async function * () { yield 1; } : () => AsyncGenerator<number, void, unknown>
403-
>yield 1 : any
400+
>(async function * () { yield 1; })() : AsyncGenerator<number, void, undefined>
401+
>(async function * () { yield 1; }) : () => AsyncGenerator<number, void, undefined>
402+
>async function * () { yield 1; } : () => AsyncGenerator<number, void, undefined>
403+
>yield 1 : undefined
404404
>1 : 1
405405
}
406406
async function * explicitReturnType16(): {} {

0 commit comments

Comments
 (0)