Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Basic support for generators as iterators #3031

Merged
merged 46 commits into from
May 30, 2015
Merged

Basic support for generators as iterators #3031

merged 46 commits into from
May 30, 2015

Conversation

JsonFreeman
Copy link
Contributor

This covers part of the proposal in #2873. Namely, it handles checking types in a generator function, and inferring the return type of a generator function.

Specifically, here is what is implemented (copied from the proposal, with strikethroughs marking the differences):

Type annotation on a generator

A generator function can have a return type annotation, just like a function. The annotation represents the type of the generator returned by the function. Here is an example:

function *g(): Iterable<string> {
    for (var i = 0; i < 100; i++) {
        yield ""; // string is assignable to string
    }
    yield * otherStringGenerator(); // otherStringGenerator must be iterable and element type assignable to string
}

Here are the rules:

  • IterableIterator<any> must be assignable to the type annotation.
    • An element type T is structurally retrieved from the type denoted by the type annotation, considering the type annotation as an IterableIterator. It is an error if IterableIterator<T> for this T is not assignable to the type denoted by the type annotation.
  • The operand of every yield expression (if present) must be assignable to the element type of the generator (string in this case)
  • The operand of every yield * expression must be assignable to Iterable<any>
  • The element type of the operand of every yield * expression must be assignable to the element type of the generator. (string is assignable to string)
  • The operand of a yield (if present) expression is contextually typed by the element type of the generator (string)
  • The operand of a yield * expression is contextually typed by the type of the generator (Iterable<string>)
  • A yield expression has type any.
  • A yield * expression has type any.
  • The generator cannot have return expressions.
    • The generator is allowed to have return expressions as well, but they are ignored for the purposes of type checking the generator type.

Inferring the type of a generator

A generator function with no type annotation can have the type annotation inferred. So in the following case, the type will be inferred from the yield statements:

function *g() {
    for (var i = 0; i < 100; i++) {
        yield ""; // infer string
    }
    yield * otherStringGenerator(); // infer element type of otherStringGenerator
}
  • Rather than inferring Iterable, we will infer IterableIterator, with some element type. The reason is that someone can call next directly on the generator without first getting its iterator. A generator is in fact an iterator as well as an iterable.
  • The element type is the common supertype of all the yield operands and the element types of all the yield * operands.
  • It is an error if there is no common supertype.
  • As before, the operand of every yield * expression must be assignable to Iterable<any>
  • yield and yield * expressions again have type any
  • If the generator is contextually typed, the operands of yield expressions are contextually typed by the element type of the contextual type
  • If the generator is contextually typed, the operands of yield * expressions are contextually typed by the contextual type.
  • Again, return expressions are allowed, but not used for inferring the element type.~~ Return expressions are not allowed. Consider relaxing this later, particularly if there is no type annotation.~~
  • If there are no yield operands and no yield* expressions, the element type is an implicit any, which errors in noImplicitAny mode.

… generators

Conflicts:
	src/compiler/diagnosticInformationMap.generated.ts
	src/compiler/diagnosticMessages.json
error(node.type, Diagnostics.A_generator_cannot_have_a_void_type_annotation);
}
else {
let generatorElementType = getElementTypeFromIterableIterator(returnType) || anyType;
Copy link
Member

Choose a reason for hiding this comment

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

I think it's kind of weird that getTypeFromTypeNode returns unknownType when failing whereas getElementTypeFromIterableIterator returns undefined.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

getElementTypeFromIterableIterator is used for computing a contextual type, and everything that is used for getting a contextual type has to return undefined if it has nothing to contribute.

@DanielRosenwasser
Copy link
Member

We'll need to do work on quick info and highlighting spans later on

@JsonFreeman
Copy link
Contributor Author

What is there to do for quick info? Highlighting spans will require work yes.

@DanielRosenwasser
Copy link
Member

Just to confirm what quick info looks like for a function type.

By the way, can you default-export a generator?

@JsonFreeman
Copy link
Contributor Author

Yes, you can default-export a generator.

… generators

Conflicts:
	src/compiler/diagnosticInformationMap.generated.ts
	src/compiler/diagnosticMessages.json
	tests/baselines/reference/emitArrowFunctionWhenUsingArguments14_ES6.symbols
	tests/baselines/reference/emitArrowFunctionWhenUsingArguments15_ES6.symbols
	tests/baselines/reference/emitArrowFunctionWhenUsingArguments16_ES6.symbols
	tests/baselines/reference/emitArrowFunctionWhenUsingArguments17_ES6.symbols
	tests/baselines/reference/emitArrowFunctionWhenUsingArguments18_ES6.symbols
	tests/baselines/reference/for-of37.symbols
	tests/baselines/reference/for-of38.symbols
	tests/baselines/reference/for-of40.symbols
	tests/baselines/reference/for-of45.symbols
	tests/baselines/reference/for-of50.symbols
	tests/baselines/reference/iterableArrayPattern30.symbols
	tests/baselines/reference/promiseVoidErrorCallback.symbols
	tests/baselines/reference/typedArrays.symbols
JsonFreeman added a commit that referenced this pull request May 30, 2015
Basic support for generators as iterators
@JsonFreeman JsonFreeman merged commit 675679a into master May 30, 2015
@JsonFreeman JsonFreeman deleted the generators branch May 30, 2015 00:48
@ghost ghost mentioned this pull request Mar 2, 2018
@microsoft microsoft locked and limited conversation to collaborators Jun 18, 2018
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

5 participants