Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 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
24 changes: 18 additions & 6 deletions src/compiler/checker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26638,12 +26638,17 @@ namespace ts {
if (contextualReturnType) {
const functionFlags = getFunctionFlags(func);
if (functionFlags & FunctionFlags.Generator) { // Generator or AsyncGenerator function
const use = functionFlags & FunctionFlags.Async ? IterationUse.AsyncGeneratorReturnType : IterationUse.GeneratorReturnType;
const iterationTypes = getIterationTypesOfIterable(contextualReturnType, use, /*errorNode*/ undefined);
if (!iterationTypes) {
if (contextualReturnType.flags & TypeFlags.Union) {
contextualReturnType = filterType(contextualReturnType, type => {
const generator = createGeneratorReturnType(anyType, anyType, anyType, (functionFlags & FunctionFlags.Async) !== 0);
Copy link
Member

Choose a reason for hiding this comment

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

Maybe this should be hoisted out to a createTypeChecker singleton anyGenerator? (Maybe lazily initialized though)

return checkTypeAssignableTo(generator, type, /*errorNode*/ undefined);
Copy link
Contributor

Choose a reason for hiding this comment

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

getIterationTypeOfGeneratorFunctionReturnType will do this work for you (returning undefined if its not generator-like), would this work instead?

const isAsyncGenerator = (functionFlags & functionFlags.Async) !== 0;
const iterationReturnType = mapType(contextualReturnType,
    type => getIterationTypeOfGeneratorFunctionReturnType(IterationTypeKind.Return, type, isAsyncGenerator));
if (iterationReturnType) {
    return undefined;
}

mapType will remove undefined results, and will return undefined if all results were undefined, so it can also act as a filter.

Copy link
Member Author

Choose a reason for hiding this comment

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

The problem is that getIterationTypeOfGeneratorFunctionReturnType returns, e.g., any for type number, which is why I went for removing the useless union components in the first place. Should I somehow change the behavior of getIterationTypeOfGeneratorFunctionReturnType instead? That seemed more tricky.

Copy link
Contributor

@rbuckton rbuckton Jul 27, 2022

Choose a reason for hiding this comment

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

It returns any if the type passed is a number type? It's only supposed to return any if the type passed in is any. For anything else that isn't iterable it's supposed to return undefined.

Most of the relevant functions used by getIterationTypeOfX have something like the following at the top of the function:

if (isTypeAny(type)) {
    return anyIterationTypes;
}

Copy link
Member Author

Choose a reason for hiding this comment

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

Yes, it returns any. What happens is: we call getIterationTypeOfGeneratorFunctionReturnType with type number. This calls getIterationTypesOfGeneratorFunctionReturnType, which then returns getIterationTypesOfIterable(number, use, /*errorNode*/ undefined) || getIterationTypesOfIterator(number, resolver, /*errorNode*/ undefined).

getIterationTypesOfIterable(number, use, /*errorNode*/ undefined) returns undefined, so we return getIterationTypesOfIterator(number, resolver, /*errorNode*/ undefined).

getIterationTypesOfIterator(number, resolver, /*errorNode*/ undefined) eventually just tries to get the types of properties next, return, throw, which are all any for type number. So it returns something like IteratorType { next = any, throw = any, return = any }, from which we conclude that the generator return type of type number is any.
So yeah, in short, getIterationTypeOfGeneratorFunctionReturnType returns any for a non-iterable/iterator type like number, it doesn't return undefined.

I don't understand all the subtleties involved, so that's why I went with filtering the union by checking generator type assignability, but maybe I could be filtering using some of the other getIterationTypesX functions?

I think filtering by calling getIterationTypesOfIterable and seeing if it's undefined could maybe work at first, but the fact that when it returns undefined we also call getIterationTypesOfIterator seemed to suggest to me that getIterationTypesOfIterable didn't cover all of the cases of iterator/iterable types.

Let me know what you think.

Copy link
Contributor

Choose a reason for hiding this comment

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

It seems getIterationTypesOfIteratorSlow may be doing the wrong thing here. It should be returning noIterationTypes for number:

function getIterationTypesOfIteratorSlow(type: Type, resolver: IterationTypesResolver, errorNode: Node | undefined) {
    const iterationTypes = combineIterationTypes([
        getIterationTypesOfMethod(type, resolver, "next", errorNode),
        getIterationTypesOfMethod(type, resolver, "return", errorNode),
        getIterationTypesOfMethod(type, resolver, "throw", errorNode),
    ]);
    return setCachedIterationTypes(type, resolver.iteratorCacheKey, iterationTypes);
}
  • getIterationTypesOfMethod(number, resolver, "next", errorNode) - This is probably the culprit, as it should return undefined for type number, but instead returns anyIterationTypes due to this logic:
    // Both async and non-async iterators *must* have a `next` method.
    const methodSignatures = methodType ? getSignaturesOfType(methodType, SignatureKind.Call) : emptyArray;
    if (methodSignatures.length === 0) {
        if (errorNode) {
            const diagnostic = methodName === "next"
                ? resolver.mustHaveANextMethodDiagnostic
                : resolver.mustBeAMethodDiagnostic;
            error(errorNode, diagnostic, methodName);
        }
        return methodName === "next" ? anyIterationTypes : undefined;
     // ^- should probably just be `return undefined;`
    }
  • getIterationTypesOfMethod(number, resolver, "return", errorNode) - This looks like it returns undefined for type number, which is correct.
  • getIterationTypesOfMethod(number, resolver, "throw", errorNode) - This looks like it returns undefined for type number, which is correct.

The results of those three methods are passed to combineIterationTypes, which would then return noIterationTypes once the iteration types for the "next" method are corrected.

Copy link
Contributor

Choose a reason for hiding this comment

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

I need to look into this a bit further, as changing this results in some other additional diagnostics that we may not want.

Copy link
Contributor

Choose a reason for hiding this comment

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

The return value for getIterationTypesOfIteratorSlow should be fixed by #50146.

Copy link
Member Author

Choose a reason for hiding this comment

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

I ended up not using mapType in the way you suggested, because in the previous version of the code, when we call getIterationTypeOfGeneratorFunctionReturnType on a union, although it maps the workers to each component type in the union, the way it combines the resulting iterationTypes is specific, so I don't think we'd get the same result if we just called mapType, which just unions the resulting mapped types.

Copy link
Contributor

Choose a reason for hiding this comment

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

I think it should have produced the same type for IterationTypeKind.Return, since the logic in getIterationTypesOfIterable related to union types just appends the resulting types and unions them for yield and return, with a bit more in the way of caching and error reporting. The only case that would differ would be for IterationTypeKind.Next, since the next types are intersected rather than unioned.

});
}
const iterationReturnType = getIterationTypeOfGeneratorFunctionReturnType(IterationTypeKind.Return, contextualReturnType, (functionFlags & FunctionFlags.Async) !== 0);
if (!iterationReturnType) {
return undefined;
}
contextualReturnType = iterationTypes.returnType;
contextualReturnType = iterationReturnType;
// falls through to unwrap Promise for AsyncGenerators
}

Expand Down Expand Up @@ -26672,11 +26677,18 @@ namespace ts {
const func = getContainingFunction(node);
if (func) {
const functionFlags = getFunctionFlags(func);
const contextualReturnType = getContextualReturnType(func);
let contextualReturnType = getContextualReturnType(func);
if (contextualReturnType) {
const isAsyncGenerator = (functionFlags & FunctionFlags.Async) !== 0;
if (!node.asteriskToken && contextualReturnType.flags & TypeFlags.Union) {
contextualReturnType = filterType(contextualReturnType, type => {
const generator = createGeneratorReturnType(anyType, anyType, anyType, isAsyncGenerator);
return checkTypeAssignableTo(generator, type, /*errorNode*/ undefined);
Copy link
Contributor

Choose a reason for hiding this comment

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

The same idea applies here as above.

});
}
return node.asteriskToken
? contextualReturnType
: getIterationTypeOfGeneratorFunctionReturnType(IterationTypeKind.Yield, contextualReturnType, (functionFlags & FunctionFlags.Async) !== 0);
: getIterationTypeOfGeneratorFunctionReturnType(IterationTypeKind.Yield, contextualReturnType, isAsyncGenerator);
}
}

Expand Down
12 changes: 12 additions & 0 deletions tests/baselines/reference/contextualTypeOnYield1.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
//// [contextualTypeOnYield1.ts]
type FuncOrGeneratorFunc = () => (number | Generator<(arg: number) => void, any, void>)

const f: FuncOrGeneratorFunc = function*() {
yield (num) => console.log(num); // `num` should be inferred to have type `number`.
}

//// [contextualTypeOnYield1.js]
"use strict";
const f = function* () {
yield (num) => console.log(num); // `num` should be inferred to have type `number`.
};
17 changes: 17 additions & 0 deletions tests/baselines/reference/contextualTypeOnYield1.symbols
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
=== tests/cases/compiler/contextualTypeOnYield1.ts ===
type FuncOrGeneratorFunc = () => (number | Generator<(arg: number) => void, any, void>)
>FuncOrGeneratorFunc : Symbol(FuncOrGeneratorFunc, Decl(contextualTypeOnYield1.ts, 0, 0))
>Generator : Symbol(Generator, Decl(lib.es2015.generator.d.ts, --, --))
>arg : Symbol(arg, Decl(contextualTypeOnYield1.ts, 0, 54))

const f: FuncOrGeneratorFunc = function*() {
>f : Symbol(f, Decl(contextualTypeOnYield1.ts, 2, 5))
>FuncOrGeneratorFunc : Symbol(FuncOrGeneratorFunc, Decl(contextualTypeOnYield1.ts, 0, 0))

yield (num) => console.log(num); // `num` should be inferred to have type `number`.
>num : Symbol(num, Decl(contextualTypeOnYield1.ts, 3, 9))
>console.log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --))
>console : Symbol(console, Decl(lib.dom.d.ts, --, --))
>log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --))
>num : Symbol(num, Decl(contextualTypeOnYield1.ts, 3, 9))
}
19 changes: 19 additions & 0 deletions tests/baselines/reference/contextualTypeOnYield1.types
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
=== tests/cases/compiler/contextualTypeOnYield1.ts ===
type FuncOrGeneratorFunc = () => (number | Generator<(arg: number) => void, any, void>)
>FuncOrGeneratorFunc : () => number | Generator<(arg: number) => void, any, void>
>arg : number

const f: FuncOrGeneratorFunc = function*() {
>f : FuncOrGeneratorFunc
>function*() { yield (num) => console.log(num); // `num` should be inferred to have type `number`.} : () => Generator<(num: number) => void, void, any>

yield (num) => console.log(num); // `num` should be inferred to have type `number`.
>yield (num) => console.log(num) : any
>(num) => console.log(num) : (num: number) => void
>num : number
>console.log(num) : void
>console.log : (...data: any[]) => void
>console : Console
>log : (...data: any[]) => void
>num : number
}
11 changes: 11 additions & 0 deletions tests/baselines/reference/contextualTypeOnYield2.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
//// [contextualTypeOnYield2.ts]
type OrGen = () => (number | Generator<string, (arg: number) => void, undefined>);
const g: OrGen = function* () {
return (num) => console.log(num);
}

//// [contextualTypeOnYield2.js]
"use strict";
const g = function* () {
return (num) => console.log(num);
};
17 changes: 17 additions & 0 deletions tests/baselines/reference/contextualTypeOnYield2.symbols
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
=== tests/cases/compiler/contextualTypeOnYield2.ts ===
type OrGen = () => (number | Generator<string, (arg: number) => void, undefined>);
>OrGen : Symbol(OrGen, Decl(contextualTypeOnYield2.ts, 0, 0))
>Generator : Symbol(Generator, Decl(lib.es2015.generator.d.ts, --, --))
>arg : Symbol(arg, Decl(contextualTypeOnYield2.ts, 0, 48))

const g: OrGen = function* () {
>g : Symbol(g, Decl(contextualTypeOnYield2.ts, 1, 5))
>OrGen : Symbol(OrGen, Decl(contextualTypeOnYield2.ts, 0, 0))

return (num) => console.log(num);
>num : Symbol(num, Decl(contextualTypeOnYield2.ts, 2, 12))
>console.log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --))
>console : Symbol(console, Decl(lib.dom.d.ts, --, --))
>log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --))
>num : Symbol(num, Decl(contextualTypeOnYield2.ts, 2, 12))
}
18 changes: 18 additions & 0 deletions tests/baselines/reference/contextualTypeOnYield2.types
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
=== tests/cases/compiler/contextualTypeOnYield2.ts ===
type OrGen = () => (number | Generator<string, (arg: number) => void, undefined>);
>OrGen : () => number | Generator<string, (arg: number) => void, undefined>
>arg : number

const g: OrGen = function* () {
>g : OrGen
>function* () { return (num) => console.log(num);} : () => Generator<never, (num: number) => void, any>

return (num) => console.log(num);
>(num) => console.log(num) : (num: number) => void
>num : number
>console.log(num) : void
>console.log : (...data: any[]) => void
>console : Console
>log : (...data: any[]) => void
>num : number
}
28 changes: 26 additions & 2 deletions tests/baselines/reference/generatorReturnContextualType.errors.txt
Original file line number Diff line number Diff line change
@@ -1,29 +1,53 @@
tests/cases/conformance/generators/generatorReturnContextualType.ts(17,3): error TS2322: Type '{ x: string; }' is not assignable to type '{ x: "x"; }'.
tests/cases/conformance/generators/generatorReturnContextualType.ts(29,3): error TS2322: Type '{ x: string; }' is not assignable to type '{ x: "x"; }'.
Types of property 'x' are incompatible.
Type 'string' is not assignable to type '"x"'.
tests/cases/conformance/generators/generatorReturnContextualType.ts(34,3): error TS2322: Type '{ x: string; }' is not assignable to type '{ x: "x"; }'.
Types of property 'x' are incompatible.
Type 'string' is not assignable to type '"x"'.


==== tests/cases/conformance/generators/generatorReturnContextualType.ts (1 errors) ====
==== tests/cases/conformance/generators/generatorReturnContextualType.ts (2 errors) ====
// #35995

function* f1(): Generator<any, { x: 'x' }, any> {
return { x: 'x' };
}

function* g1(): Iterator<any, { x: 'x' }, any> {
return { x: 'x' };
}

async function* f2(): AsyncGenerator<any, { x: 'x' }, any> {
return { x: 'x' };
}

async function* g2(): AsyncIterator<any, { x: 'x' }, any> {
return { x: 'x' };
}

async function* f3(): AsyncGenerator<any, { x: 'x' }, any> {
return Promise.resolve({ x: 'x' });
}

async function* g3(): AsyncIterator<any, { x: 'x' }, any> {
return Promise.resolve({ x: 'x' });
}

async function* f4(): AsyncGenerator<any, { x: 'x' }, any> {
const ret = { x: 'x' };
return Promise.resolve(ret); // Error
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
!!! error TS2322: Type '{ x: string; }' is not assignable to type '{ x: "x"; }'.
!!! error TS2322: Types of property 'x' are incompatible.
!!! error TS2322: Type 'string' is not assignable to type '"x"'.
}

async function* g4(): AsyncIterator<any, { x: 'x' }, any> {
const ret = { x: 'x' };
return Promise.resolve(ret); // Error
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
!!! error TS2322: Type '{ x: string; }' is not assignable to type '{ x: "x"; }'.
!!! error TS2322: Types of property 'x' are incompatible.
!!! error TS2322: Type 'string' is not assignable to type '"x"'.
}

30 changes: 30 additions & 0 deletions tests/baselines/reference/generatorReturnContextualType.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,18 +5,35 @@ function* f1(): Generator<any, { x: 'x' }, any> {
return { x: 'x' };
}

function* g1(): Iterator<any, { x: 'x' }, any> {
return { x: 'x' };
}

async function* f2(): AsyncGenerator<any, { x: 'x' }, any> {
return { x: 'x' };
}

async function* g2(): AsyncIterator<any, { x: 'x' }, any> {
return { x: 'x' };
}

async function* f3(): AsyncGenerator<any, { x: 'x' }, any> {
return Promise.resolve({ x: 'x' });
}

async function* g3(): AsyncIterator<any, { x: 'x' }, any> {
return Promise.resolve({ x: 'x' });
}

async function* f4(): AsyncGenerator<any, { x: 'x' }, any> {
const ret = { x: 'x' };
return Promise.resolve(ret); // Error
}

async function* g4(): AsyncIterator<any, { x: 'x' }, any> {
const ret = { x: 'x' };
return Promise.resolve(ret); // Error
}


//// [generatorReturnContextualType.js]
Expand All @@ -25,13 +42,26 @@ async function* f4(): AsyncGenerator<any, { x: 'x' }, any> {
function* f1() {
return { x: 'x' };
}
function* g1() {
return { x: 'x' };
}
async function* f2() {
return { x: 'x' };
}
async function* g2() {
return { x: 'x' };
}
async function* f3() {
return Promise.resolve({ x: 'x' });
}
async function* g3() {
return Promise.resolve({ x: 'x' });
}
async function* f4() {
const ret = { x: 'x' };
return Promise.resolve(ret); // Error
}
async function* g4() {
const ret = { x: 'x' };
return Promise.resolve(ret); // Error
}
68 changes: 57 additions & 11 deletions tests/baselines/reference/generatorReturnContextualType.symbols
Original file line number Diff line number Diff line change
Expand Up @@ -10,40 +10,86 @@ function* f1(): Generator<any, { x: 'x' }, any> {
>x : Symbol(x, Decl(generatorReturnContextualType.ts, 3, 10))
}

function* g1(): Iterator<any, { x: 'x' }, any> {
>g1 : Symbol(g1, Decl(generatorReturnContextualType.ts, 4, 1))
>Iterator : Symbol(Iterator, Decl(lib.es2015.iterable.d.ts, --, --))
>x : Symbol(x, Decl(generatorReturnContextualType.ts, 6, 31))

return { x: 'x' };
>x : Symbol(x, Decl(generatorReturnContextualType.ts, 7, 10))
}

async function* f2(): AsyncGenerator<any, { x: 'x' }, any> {
>f2 : Symbol(f2, Decl(generatorReturnContextualType.ts, 4, 1))
>f2 : Symbol(f2, Decl(generatorReturnContextualType.ts, 8, 1))
>AsyncGenerator : Symbol(AsyncGenerator, Decl(lib.es2018.asyncgenerator.d.ts, --, --))
>x : Symbol(x, Decl(generatorReturnContextualType.ts, 6, 43))
>x : Symbol(x, Decl(generatorReturnContextualType.ts, 10, 43))

return { x: 'x' };
>x : Symbol(x, Decl(generatorReturnContextualType.ts, 7, 10))
>x : Symbol(x, Decl(generatorReturnContextualType.ts, 11, 10))
}

async function* g2(): AsyncIterator<any, { x: 'x' }, any> {
>g2 : Symbol(g2, Decl(generatorReturnContextualType.ts, 12, 1))
>AsyncIterator : Symbol(AsyncIterator, Decl(lib.es2018.asynciterable.d.ts, --, --))
>x : Symbol(x, Decl(generatorReturnContextualType.ts, 14, 42))

return { x: 'x' };
>x : Symbol(x, Decl(generatorReturnContextualType.ts, 15, 10))
}

async function* f3(): AsyncGenerator<any, { x: 'x' }, any> {
>f3 : Symbol(f3, Decl(generatorReturnContextualType.ts, 8, 1))
>f3 : Symbol(f3, Decl(generatorReturnContextualType.ts, 16, 1))
>AsyncGenerator : Symbol(AsyncGenerator, Decl(lib.es2018.asyncgenerator.d.ts, --, --))
>x : Symbol(x, Decl(generatorReturnContextualType.ts, 10, 43))
>x : Symbol(x, Decl(generatorReturnContextualType.ts, 18, 43))

return Promise.resolve({ x: 'x' });
>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, --, --), Decl(lib.es2018.promise.d.ts, --, --))
>resolve : Symbol(PromiseConstructor.resolve, Decl(lib.es2015.promise.d.ts, --, --), Decl(lib.es2015.promise.d.ts, --, --))
>x : Symbol(x, Decl(generatorReturnContextualType.ts, 19, 26))
}

async function* g3(): AsyncIterator<any, { x: 'x' }, any> {
>g3 : Symbol(g3, Decl(generatorReturnContextualType.ts, 20, 1))
>AsyncIterator : Symbol(AsyncIterator, Decl(lib.es2018.asynciterable.d.ts, --, --))
>x : Symbol(x, Decl(generatorReturnContextualType.ts, 22, 42))

return Promise.resolve({ x: 'x' });
>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, --, --), Decl(lib.es2018.promise.d.ts, --, --))
>resolve : Symbol(PromiseConstructor.resolve, Decl(lib.es2015.promise.d.ts, --, --), Decl(lib.es2015.promise.d.ts, --, --))
>x : Symbol(x, Decl(generatorReturnContextualType.ts, 11, 26))
>x : Symbol(x, Decl(generatorReturnContextualType.ts, 23, 26))
}

async function* f4(): AsyncGenerator<any, { x: 'x' }, any> {
>f4 : Symbol(f4, Decl(generatorReturnContextualType.ts, 12, 1))
>f4 : Symbol(f4, Decl(generatorReturnContextualType.ts, 24, 1))
>AsyncGenerator : Symbol(AsyncGenerator, Decl(lib.es2018.asyncgenerator.d.ts, --, --))
>x : Symbol(x, Decl(generatorReturnContextualType.ts, 14, 43))
>x : Symbol(x, Decl(generatorReturnContextualType.ts, 26, 43))

const ret = { x: 'x' };
>ret : Symbol(ret, Decl(generatorReturnContextualType.ts, 27, 7))
>x : Symbol(x, Decl(generatorReturnContextualType.ts, 27, 15))

return Promise.resolve(ret); // Error
>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, --, --), Decl(lib.es2018.promise.d.ts, --, --))
>resolve : Symbol(PromiseConstructor.resolve, Decl(lib.es2015.promise.d.ts, --, --), Decl(lib.es2015.promise.d.ts, --, --))
>ret : Symbol(ret, Decl(generatorReturnContextualType.ts, 27, 7))
}

async function* g4(): AsyncIterator<any, { x: 'x' }, any> {
>g4 : Symbol(g4, Decl(generatorReturnContextualType.ts, 29, 1))
>AsyncIterator : Symbol(AsyncIterator, Decl(lib.es2018.asynciterable.d.ts, --, --))
>x : Symbol(x, Decl(generatorReturnContextualType.ts, 31, 42))

const ret = { x: 'x' };
>ret : Symbol(ret, Decl(generatorReturnContextualType.ts, 15, 7))
>x : Symbol(x, Decl(generatorReturnContextualType.ts, 15, 15))
>ret : Symbol(ret, Decl(generatorReturnContextualType.ts, 32, 7))
>x : Symbol(x, Decl(generatorReturnContextualType.ts, 32, 15))

return Promise.resolve(ret); // Error
>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, --, --), Decl(lib.es2018.promise.d.ts, --, --))
>resolve : Symbol(PromiseConstructor.resolve, Decl(lib.es2015.promise.d.ts, --, --), Decl(lib.es2015.promise.d.ts, --, --))
>ret : Symbol(ret, Decl(generatorReturnContextualType.ts, 15, 7))
>ret : Symbol(ret, Decl(generatorReturnContextualType.ts, 32, 7))
}

Loading