Skip to content

Commit d045eab

Browse files
committed
Fall back to (Async)IterableIterator if (Async)Generator not found
1 parent fb50920 commit d045eab

22 files changed

+209
-33
lines changed

src/compiler/checker.ts

Lines changed: 42 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -42,10 +42,10 @@ namespace ts {
4242
iterableCacheKey: "iterationTypesOfAsyncIterable" | "iterationTypesOfIterable";
4343
iteratorCacheKey: "iterationTypesOfAsyncIterator" | "iterationTypesOfIterator";
4444
iteratorSymbolName: "asyncIterator" | "iterator";
45-
getGlobalIteratorType: (reportErrors: boolean) => Type;
46-
getGlobalIterableType: (reportErrors: boolean) => Type;
47-
getGlobalIterableIteratorType: (reportErrors: boolean) => Type;
48-
getGlobalGeneratorType: (reportErrors: boolean) => Type;
45+
getGlobalIteratorType: (reportErrors: boolean) => GenericType;
46+
getGlobalIterableType: (reportErrors: boolean) => GenericType;
47+
getGlobalIterableIteratorType: (reportErrors: boolean) => GenericType;
48+
getGlobalGeneratorType: (reportErrors: boolean) => GenericType;
4949
resolveIterationType: (type: Type, errorNode: Node | undefined) => Type | undefined;
5050
mustHaveANextMethodDiagnostic: DiagnosticMessage;
5151
mustBeAMethodDiagnostic: DiagnosticMessage;
@@ -9495,24 +9495,10 @@ namespace ts {
94959495
return createTypeFromGenericGlobalType(getGlobalTypedPropertyDescriptorType(), [propertyType]);
94969496
}
94979497

9498-
function createAsyncGeneratorType(yieldType: Type, returnType: Type, nextType: Type) {
9499-
const globalAsyncGeneratorType = getGlobalAsyncGeneratorType(/*reportErrors*/ true);
9500-
if (globalAsyncGeneratorType !== emptyGenericType) {
9501-
yieldType = getAwaitedType(yieldType) || unknownType;
9502-
returnType = getAwaitedType(returnType) || unknownType;
9503-
nextType = getAwaitedType(nextType) || unknownType;
9504-
}
9505-
return createTypeFromGenericGlobalType(globalAsyncGeneratorType, [yieldType, returnType, nextType]);
9506-
}
9507-
95089498
function createIterableType(iteratedType: Type): Type {
95099499
return createTypeFromGenericGlobalType(getGlobalIterableType(/*reportErrors*/ true), [iteratedType]);
95109500
}
95119501

9512-
function createGeneratorType(yieldType: Type, returnType: Type, nextType: Type) {
9513-
return createTypeFromGenericGlobalType(getGlobalGeneratorType(/*reportErrors*/ true), [yieldType, returnType, nextType]);
9514-
}
9515-
95169502
function createArrayType(elementType: Type, readonly?: boolean): ObjectType {
95179503
return createTypeFromGenericGlobalType(readonly ? globalReadonlyArrayType : globalArrayType, [elementType]);
95189504
}
@@ -23317,9 +23303,36 @@ namespace ts {
2331723303
}
2331823304

2331923305
function createGeneratorReturnType(yieldType: Type, returnType: Type, nextType: Type, isAsyncGenerator: boolean) {
23320-
return isAsyncGenerator
23321-
? createAsyncGeneratorType(yieldType, returnType, nextType)
23322-
: createGeneratorType(yieldType, returnType, nextType);
23306+
const resolver = isAsyncGenerator ? asyncIterationTypesResolver : syncIterationTypesResolver;
23307+
const globalGeneratorType = resolver.getGlobalGeneratorType(/*reportErrors*/ false);
23308+
yieldType = resolver.resolveIterationType(yieldType, /*errorNode*/ undefined) || unknownType;
23309+
returnType = resolver.resolveIterationType(returnType, /*errorNode*/ undefined) || unknownType;
23310+
nextType = resolver.resolveIterationType(nextType, /*errorNode*/ undefined) || unknownType;
23311+
if (globalGeneratorType === emptyGenericType) {
23312+
// Fall back to the global IterableIterator if returnType is assignable to the expected return iteration
23313+
// type of IterableIterator, and the expected next iteration type of IterableIterator is assignable to
23314+
// nextType.
23315+
const globalType = resolver.getGlobalIterableIteratorType(/*reportErrors*/ false);
23316+
const iterationTypes = globalType !== emptyGenericType ? getIterationTypesOfGlobalIterableType(globalType, resolver) : undefined;
23317+
const iterableIteratorReturnType = iterationTypes ? iterationTypes.returnType : anyType;
23318+
const iterableIteratorNextType = iterationTypes ? iterationTypes.nextType : undefinedType;
23319+
if (isTypeAssignableTo(returnType, iterableIteratorReturnType) &&
23320+
isTypeAssignableTo(iterableIteratorNextType, nextType)) {
23321+
if (globalType !== emptyGenericType) {
23322+
return createTypeFromGenericGlobalType(globalType, [yieldType]);
23323+
}
23324+
23325+
// The global IterableIterator type doesn't exist, so report an error
23326+
resolver.getGlobalIterableIteratorType(/*reportErrors*/ true);
23327+
return emptyObjectType;
23328+
}
23329+
23330+
// The global Generator type doesn't exist, so report an error
23331+
resolver.getGlobalGeneratorType(/*reportErrors*/ true);
23332+
return emptyObjectType;
23333+
}
23334+
23335+
return createTypeFromGenericGlobalType(globalGeneratorType, [yieldType, returnType, nextType]);
2332323336
}
2332423337

2332523338
function checkAndAggregateYieldOperandTypes(func: FunctionLikeDeclaration, checkMode: CheckMode | undefined) {
@@ -28107,6 +28120,13 @@ namespace ts {
2810728120
return (type as IterableOrIteratorType)[resolver.iterableCacheKey];
2810828121
}
2810928122

28123+
function getIterationTypesOfGlobalIterableType(globalType: Type, resolver: IterationTypesResolver) {
28124+
const globalIterationTypes =
28125+
getIterationTypesOfIterableCached(globalType, resolver) ||
28126+
getIterationTypesOfIterableSlow(globalType, resolver, /*errorNode*/ undefined);
28127+
return globalIterationTypes === noIterationTypes ? defaultIterationTypes : globalIterationTypes;
28128+
}
28129+
2811028130
/**
2811128131
* Gets the *yield*, *return*, and *next* types of an `Iterable`-like or `AsyncIterable`-like
2811228132
* type from from common heuristics.
@@ -28132,10 +28152,7 @@ namespace ts {
2813228152
// iteration types of their `[Symbol.iterator]()` method. The same is true for their async cousins.
2813328153
// While we define these as `any` and `undefined` in our libs by default, a custom lib *could* use
2813428154
// different definitions.
28135-
const globalIterationTypes =
28136-
getIterationTypesOfIterableCached(globalType, resolver) ||
28137-
getIterationTypesOfIterableSlow(globalType, resolver, /*errorNode*/ undefined);
28138-
const { returnType, nextType } = globalIterationTypes === noIterationTypes ? defaultIterationTypes : globalIterationTypes;
28155+
const { returnType, nextType } = getIterationTypesOfGlobalIterableType(globalType, resolver);
2813928156
return (type as IterableOrIteratorType)[resolver.iterableCacheKey] = createIterationTypes(yieldType, returnType, nextType);
2814028157
}
2814128158

tests/baselines/reference/castOfYield.errors.txt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1-
error TS2318: Cannot find global type 'Generator'.
1+
error TS2318: Cannot find global type 'IterableIterator'.
22
tests/cases/compiler/castOfYield.ts(4,14): error TS1109: Expression expected.
33

44

5-
!!! error TS2318: Cannot find global type 'Generator'.
5+
!!! error TS2318: Cannot find global type 'IterableIterator'.
66
==== tests/cases/compiler/castOfYield.ts (1 errors) ====
77
function* f() {
88
<number> (yield 0);
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
=== tests/cases/conformance/generators/generatorReturnTypeFallback.1.ts ===
2+
// Allow generators to fallback to IterableIterator if they do not need a type for the sent value while in strictNullChecks mode.
3+
function* f() {
4+
>f : Symbol(f, Decl(generatorReturnTypeFallback.1.ts, 0, 0))
5+
6+
yield 1;
7+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
=== tests/cases/conformance/generators/generatorReturnTypeFallback.1.ts ===
2+
// Allow generators to fallback to IterableIterator if they do not need a type for the sent value while in strictNullChecks mode.
3+
function* f() {
4+
>f : () => IterableIterator<number>
5+
6+
yield 1;
7+
>yield 1 : any
8+
>1 : 1
9+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
error TS2318: Cannot find global type 'IterableIterator'.
2+
3+
4+
!!! error TS2318: Cannot find global type 'IterableIterator'.
5+
==== tests/cases/conformance/generators/generatorReturnTypeFallback.2.ts (0 errors) ====
6+
// Allow generators to fallback to IterableIterator if they do not need a type for the sent value while in strictNullChecks mode.
7+
// Report an error if IterableIterator cannot be found.
8+
function* f() {
9+
yield 1;
10+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
=== tests/cases/conformance/generators/generatorReturnTypeFallback.2.ts ===
2+
// Allow generators to fallback to IterableIterator if they do not need a type for the sent value while in strictNullChecks mode.
3+
// Report an error if IterableIterator cannot be found.
4+
function* f() {
5+
>f : Symbol(f, Decl(generatorReturnTypeFallback.2.ts, 0, 0))
6+
7+
yield 1;
8+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
=== tests/cases/conformance/generators/generatorReturnTypeFallback.2.ts ===
2+
// Allow generators to fallback to IterableIterator if they do not need a type for the sent value while in strictNullChecks mode.
3+
// Report an error if IterableIterator cannot be found.
4+
function* f() {
5+
>f : () => {}
6+
7+
yield 1;
8+
>yield 1 : any
9+
>1 : 1
10+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
error TS2318: Cannot find global type 'Generator'.
2+
3+
4+
!!! error TS2318: Cannot find global type 'Generator'.
5+
==== tests/cases/conformance/generators/generatorReturnTypeFallback.3.ts (0 errors) ====
6+
// Do not allow generators to fallback to IterableIterator while in strictNullChecks mode if they need a type for the sent value.
7+
// NOTE: In non-strictNullChecks mode, `undefined` (the default sent value) is assignable to everything.
8+
function* f() {
9+
const x: string = yield 1;
10+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
=== tests/cases/conformance/generators/generatorReturnTypeFallback.3.ts ===
2+
// Do not allow generators to fallback to IterableIterator while in strictNullChecks mode if they need a type for the sent value.
3+
// NOTE: In non-strictNullChecks mode, `undefined` (the default sent value) is assignable to everything.
4+
function* f() {
5+
>f : Symbol(f, Decl(generatorReturnTypeFallback.3.ts, 0, 0))
6+
7+
const x: string = yield 1;
8+
>x : Symbol(x, Decl(generatorReturnTypeFallback.3.ts, 3, 9))
9+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
=== tests/cases/conformance/generators/generatorReturnTypeFallback.3.ts ===
2+
// Do not allow generators to fallback to IterableIterator while in strictNullChecks mode if they need a type for the sent value.
3+
// NOTE: In non-strictNullChecks mode, `undefined` (the default sent value) is assignable to everything.
4+
function* f() {
5+
>f : () => {}
6+
7+
const x: string = yield 1;
8+
>x : string
9+
>yield 1 : any
10+
>1 : 1
11+
}

0 commit comments

Comments
 (0)