Skip to content
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.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
67 changes: 42 additions & 25 deletions src/compiler/checker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,10 +42,10 @@ namespace ts {
iterableCacheKey: "iterationTypesOfAsyncIterable" | "iterationTypesOfIterable";
iteratorCacheKey: "iterationTypesOfAsyncIterator" | "iterationTypesOfIterator";
iteratorSymbolName: "asyncIterator" | "iterator";
getGlobalIteratorType: (reportErrors: boolean) => Type;
getGlobalIterableType: (reportErrors: boolean) => Type;
getGlobalIterableIteratorType: (reportErrors: boolean) => Type;
getGlobalGeneratorType: (reportErrors: boolean) => Type;
getGlobalIteratorType: (reportErrors: boolean) => GenericType;
getGlobalIterableType: (reportErrors: boolean) => GenericType;
getGlobalIterableIteratorType: (reportErrors: boolean) => GenericType;
getGlobalGeneratorType: (reportErrors: boolean) => GenericType;
resolveIterationType: (type: Type, errorNode: Node | undefined) => Type | undefined;
mustHaveANextMethodDiagnostic: DiagnosticMessage;
mustBeAMethodDiagnostic: DiagnosticMessage;
Expand Down Expand Up @@ -9495,24 +9495,10 @@ namespace ts {
return createTypeFromGenericGlobalType(getGlobalTypedPropertyDescriptorType(), [propertyType]);
}

function createAsyncGeneratorType(yieldType: Type, returnType: Type, nextType: Type) {
const globalAsyncGeneratorType = getGlobalAsyncGeneratorType(/*reportErrors*/ true);
if (globalAsyncGeneratorType !== emptyGenericType) {
yieldType = getAwaitedType(yieldType) || unknownType;
returnType = getAwaitedType(returnType) || unknownType;
nextType = getAwaitedType(nextType) || unknownType;
}
return createTypeFromGenericGlobalType(globalAsyncGeneratorType, [yieldType, returnType, nextType]);
}

function createIterableType(iteratedType: Type): Type {
return createTypeFromGenericGlobalType(getGlobalIterableType(/*reportErrors*/ true), [iteratedType]);
}

function createGeneratorType(yieldType: Type, returnType: Type, nextType: Type) {
return createTypeFromGenericGlobalType(getGlobalGeneratorType(/*reportErrors*/ true), [yieldType, returnType, nextType]);
}

function createArrayType(elementType: Type, readonly?: boolean): ObjectType {
return createTypeFromGenericGlobalType(readonly ? globalReadonlyArrayType : globalArrayType, [elementType]);
}
Expand Down Expand Up @@ -23317,9 +23303,36 @@ namespace ts {
}

function createGeneratorReturnType(yieldType: Type, returnType: Type, nextType: Type, isAsyncGenerator: boolean) {
return isAsyncGenerator
? createAsyncGeneratorType(yieldType, returnType, nextType)
: createGeneratorType(yieldType, returnType, nextType);
const resolver = isAsyncGenerator ? asyncIterationTypesResolver : syncIterationTypesResolver;
const globalGeneratorType = resolver.getGlobalGeneratorType(/*reportErrors*/ false);
yieldType = resolver.resolveIterationType(yieldType, /*errorNode*/ undefined) || unknownType;
returnType = resolver.resolveIterationType(returnType, /*errorNode*/ undefined) || unknownType;
nextType = resolver.resolveIterationType(nextType, /*errorNode*/ undefined) || unknownType;
if (globalGeneratorType === emptyGenericType) {
// Fall back to the global IterableIterator if returnType is assignable to the expected return iteration
// type of IterableIterator, and the expected next iteration type of IterableIterator is assignable to
// nextType.
const globalType = resolver.getGlobalIterableIteratorType(/*reportErrors*/ false);
const iterationTypes = globalType !== emptyGenericType ? getIterationTypesOfGlobalIterableType(globalType, resolver) : undefined;
const iterableIteratorReturnType = iterationTypes ? iterationTypes.returnType : anyType;
const iterableIteratorNextType = iterationTypes ? iterationTypes.nextType : undefinedType;
if (isTypeAssignableTo(returnType, iterableIteratorReturnType) &&
isTypeAssignableTo(iterableIteratorNextType, nextType)) {
if (globalType !== emptyGenericType) {
return createTypeFromGenericGlobalType(globalType, [yieldType]);
}

// The global IterableIterator type doesn't exist, so report an error
resolver.getGlobalIterableIteratorType(/*reportErrors*/ true);
return emptyObjectType;
}

// The global Generator type doesn't exist, so report an error
resolver.getGlobalGeneratorType(/*reportErrors*/ true);
return emptyObjectType;
}

return createTypeFromGenericGlobalType(globalGeneratorType, [yieldType, returnType, nextType]);
}

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

function getIterationTypesOfGlobalIterableType(globalType: Type, resolver: IterationTypesResolver) {
const globalIterationTypes =
getIterationTypesOfIterableCached(globalType, resolver) ||
getIterationTypesOfIterableSlow(globalType, resolver, /*errorNode*/ undefined);
return globalIterationTypes === noIterationTypes ? defaultIterationTypes : globalIterationTypes;
}

/**
* Gets the *yield*, *return*, and *next* types of an `Iterable`-like or `AsyncIterable`-like
* type from from common heuristics.
Expand All @@ -28132,10 +28152,7 @@ namespace ts {
// iteration types of their `[Symbol.iterator]()` method. The same is true for their async cousins.
// While we define these as `any` and `undefined` in our libs by default, a custom lib *could* use
// different definitions.
const globalIterationTypes =
getIterationTypesOfIterableCached(globalType, resolver) ||
getIterationTypesOfIterableSlow(globalType, resolver, /*errorNode*/ undefined);
const { returnType, nextType } = globalIterationTypes === noIterationTypes ? defaultIterationTypes : globalIterationTypes;
const { returnType, nextType } = getIterationTypesOfGlobalIterableType(globalType, resolver);
return (type as IterableOrIteratorType)[resolver.iterableCacheKey] = createIterationTypes(yieldType, returnType, nextType);
}

Expand Down
4 changes: 2 additions & 2 deletions tests/baselines/reference/castOfYield.errors.txt
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
error TS2318: Cannot find global type 'Generator'.
error TS2318: Cannot find global type 'IterableIterator'.
tests/cases/compiler/castOfYield.ts(4,14): error TS1109: Expression expected.


!!! error TS2318: Cannot find global type 'Generator'.
!!! error TS2318: Cannot find global type 'IterableIterator'.
==== tests/cases/compiler/castOfYield.ts (1 errors) ====
function* f() {
<number> (yield 0);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
=== tests/cases/conformance/generators/generatorReturnTypeFallback.1.ts ===
// Allow generators to fallback to IterableIterator if they do not need a type for the sent value while in strictNullChecks mode.
function* f() {
>f : Symbol(f, Decl(generatorReturnTypeFallback.1.ts, 0, 0))

yield 1;
}
9 changes: 9 additions & 0 deletions tests/baselines/reference/generatorReturnTypeFallback.1.types
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
=== tests/cases/conformance/generators/generatorReturnTypeFallback.1.ts ===
// Allow generators to fallback to IterableIterator if they do not need a type for the sent value while in strictNullChecks mode.
function* f() {
>f : () => IterableIterator<number>

yield 1;
>yield 1 : any
>1 : 1
}
10 changes: 10 additions & 0 deletions tests/baselines/reference/generatorReturnTypeFallback.2.errors.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
error TS2318: Cannot find global type 'IterableIterator'.


!!! error TS2318: Cannot find global type 'IterableIterator'.
==== tests/cases/conformance/generators/generatorReturnTypeFallback.2.ts (0 errors) ====
// Allow generators to fallback to IterableIterator if they do not need a type for the sent value while in strictNullChecks mode.
// Report an error if IterableIterator cannot be found.
function* f() {
yield 1;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
=== tests/cases/conformance/generators/generatorReturnTypeFallback.2.ts ===
// Allow generators to fallback to IterableIterator if they do not need a type for the sent value while in strictNullChecks mode.
// Report an error if IterableIterator cannot be found.
function* f() {
>f : Symbol(f, Decl(generatorReturnTypeFallback.2.ts, 0, 0))

yield 1;
}
10 changes: 10 additions & 0 deletions tests/baselines/reference/generatorReturnTypeFallback.2.types
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
=== tests/cases/conformance/generators/generatorReturnTypeFallback.2.ts ===
// Allow generators to fallback to IterableIterator if they do not need a type for the sent value while in strictNullChecks mode.
// Report an error if IterableIterator cannot be found.
function* f() {
>f : () => {}

yield 1;
>yield 1 : any
>1 : 1
}
10 changes: 10 additions & 0 deletions tests/baselines/reference/generatorReturnTypeFallback.3.errors.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
error TS2318: Cannot find global type 'Generator'.


!!! error TS2318: Cannot find global type 'Generator'.
==== tests/cases/conformance/generators/generatorReturnTypeFallback.3.ts (0 errors) ====
// Do not allow generators to fallback to IterableIterator while in strictNullChecks mode if they need a type for the sent value.
// NOTE: In non-strictNullChecks mode, `undefined` (the default sent value) is assignable to everything.
function* f() {
const x: string = yield 1;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
=== tests/cases/conformance/generators/generatorReturnTypeFallback.3.ts ===
// Do not allow generators to fallback to IterableIterator while in strictNullChecks mode if they need a type for the sent value.
// NOTE: In non-strictNullChecks mode, `undefined` (the default sent value) is assignable to everything.
function* f() {
>f : Symbol(f, Decl(generatorReturnTypeFallback.3.ts, 0, 0))

const x: string = yield 1;
>x : Symbol(x, Decl(generatorReturnTypeFallback.3.ts, 3, 9))
}
11 changes: 11 additions & 0 deletions tests/baselines/reference/generatorReturnTypeFallback.3.types
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
=== tests/cases/conformance/generators/generatorReturnTypeFallback.3.ts ===
// Do not allow generators to fallback to IterableIterator while in strictNullChecks mode if they need a type for the sent value.
// NOTE: In non-strictNullChecks mode, `undefined` (the default sent value) is assignable to everything.
function* f() {
>f : () => {}

const x: string = yield 1;
>x : string
>yield 1 : any
>1 : 1
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
=== tests/cases/conformance/generators/generatorReturnTypeFallback.4.ts ===
// Allow generators to fallback to IterableIterator if they are not in strictNullChecks mode
// NOTE: In non-strictNullChecks mode, `undefined` (the default sent value) is assignable to everything.
function* f() {
>f : Symbol(f, Decl(generatorReturnTypeFallback.4.ts, 0, 0))

const x: string = yield 1;
>x : Symbol(x, Decl(generatorReturnTypeFallback.4.ts, 3, 9))
}
11 changes: 11 additions & 0 deletions tests/baselines/reference/generatorReturnTypeFallback.4.types
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
=== tests/cases/conformance/generators/generatorReturnTypeFallback.4.ts ===
// Allow generators to fallback to IterableIterator if they are not in strictNullChecks mode
// NOTE: In non-strictNullChecks mode, `undefined` (the default sent value) is assignable to everything.
function* f() {
>f : () => IterableIterator<number>

const x: string = yield 1;
>x : string
>yield 1 : any
>1 : 1
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
=== tests/cases/conformance/generators/generatorReturnTypeFallback.5.ts ===
// Allow generators to fallback to IterableIterator if they do not need a type for the sent value while in strictNullChecks mode.
function* f(): IterableIterator<number> {
>f : Symbol(f, Decl(generatorReturnTypeFallback.5.ts, 0, 0))
>IterableIterator : Symbol(IterableIterator, Decl(lib.es2015.iterable.d.ts, --, --))

yield 1;
}
9 changes: 9 additions & 0 deletions tests/baselines/reference/generatorReturnTypeFallback.5.types
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
=== tests/cases/conformance/generators/generatorReturnTypeFallback.5.ts ===
// Allow generators to fallback to IterableIterator if they do not need a type for the sent value while in strictNullChecks mode.
function* f(): IterableIterator<number> {
>f : () => IterableIterator<number>

yield 1;
>yield 1 : undefined
>1 : 1
}
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
error TS2318: Cannot find global type 'Generator'.
error TS2318: Cannot find global type 'IterableIterator'.
tests/cases/compiler/spreadOfParamsFromGeneratorMakesRequiredParams.ts(6,1): error TS2554: Expected 2 arguments, but got 1.


!!! error TS2318: Cannot find global type 'Generator'.
!!! error TS2318: Cannot find global type 'IterableIterator'.
==== tests/cases/compiler/spreadOfParamsFromGeneratorMakesRequiredParams.ts (1 errors) ====
declare function call<Fn extends (...args: any[]) => any>(
fn: Fn,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
error TS2318: Cannot find global type 'Generator'.
error TS2318: Cannot find global type 'IterableIterator'.
tests/cases/conformance/es6/templates/templateStringWithEmbeddedYieldKeyword.ts(1,15): error TS1005: '(' expected.


!!! error TS2318: Cannot find global type 'Generator'.
!!! error TS2318: Cannot find global type 'IterableIterator'.
==== tests/cases/conformance/es6/templates/templateStringWithEmbeddedYieldKeyword.ts (1 errors) ====
function* gen {
~
Expand Down
4 changes: 2 additions & 2 deletions tests/baselines/reference/types.forAwait.es2018.3.errors.txt
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
error TS2318: Cannot find global type 'AsyncGenerator'.
error TS2318: Cannot find global type 'AsyncIterableIterator'.
tests/cases/conformance/types/forAwait/types.forAwait.es2018.3.ts(3,27): error TS2504: Type '{}' must have a '[Symbol.asyncIterator]()' method that returns an async iterator.
tests/cases/conformance/types/forAwait/types.forAwait.es2018.3.ts(5,21): error TS2504: Type '{}' must have a '[Symbol.asyncIterator]()' method that returns an async iterator.
tests/cases/conformance/types/forAwait/types.forAwait.es2018.3.ts(10,27): error TS2504: Type '{}' must have a '[Symbol.asyncIterator]()' method that returns an async iterator.
tests/cases/conformance/types/forAwait/types.forAwait.es2018.3.ts(12,21): error TS2504: Type '{}' must have a '[Symbol.asyncIterator]()' method that returns an async iterator.


!!! error TS2318: Cannot find global type 'AsyncGenerator'.
!!! error TS2318: Cannot find global type 'AsyncIterableIterator'.
==== tests/cases/conformance/types/forAwait/types.forAwait.es2018.3.ts (4 errors) ====
async function f1() {
let y: number;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
// @target: esnext
// @lib: es5,es2015.iterable
// @noemit: true
// @strict: true

// Allow generators to fallback to IterableIterator if they do not need a type for the sent value while in strictNullChecks mode.
function* f() {
yield 1;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
// @target: esnext
// @lib: es5
// @noemit: true
// @strict: true

// Allow generators to fallback to IterableIterator if they do not need a type for the sent value while in strictNullChecks mode.
// Report an error if IterableIterator cannot be found.
function* f() {
yield 1;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
// @target: esnext
// @lib: es5,es2015.iterable
// @noemit: true
// @strict: true

// Do not allow generators to fallback to IterableIterator while in strictNullChecks mode if they need a type for the sent value.
// NOTE: In non-strictNullChecks mode, `undefined` (the default sent value) is assignable to everything.
function* f() {
const x: string = yield 1;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
// @target: esnext
// @lib: es5,es2015.iterable
// @noemit: true
// @strict: false

// Allow generators to fallback to IterableIterator if they are not in strictNullChecks mode
// NOTE: In non-strictNullChecks mode, `undefined` (the default sent value) is assignable to everything.
function* f() {
const x: string = yield 1;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
// @target: esnext
// @lib: es5,es2015.iterable
// @noemit: true
// @strict: true

// Allow generators to fallback to IterableIterator if they do not need a type for the sent value while in strictNullChecks mode.
function* f(): IterableIterator<number> {
yield 1;
}