Semantic Diff

#8981 Declare the variance of iterator, generator and tagged template types

1 commit

9e2f371482f529406d70df0565784aa8df3554e9..pr-8981

85cf497a8 · Christoph Knittel with Claude Opus 5.5 · Oct 23, 2026

Declare the variance of iterator, generator and tagged template types

Why

The iterator family's type parameters were invariant, so a generator of [#A] could not be coerced to one of [#A | #B], and values of library types built on Generator.t were not generalised under the relaxed value restriction. Yields and return values only flow out of an iterator and resume values only flow in. Needed for generators (#8934).

modifiedTyping coercion

let g: Generator.t<[#A], int, [#X | #Y]> = gen()let h = (g :> Generator.t<[#A | #B], int, [#X]>)
rule
Before
t<y, r, n> ≤ t<y', r', n'> only if y = y', r = r', n = n'
After
y ≤ y'r ≤ r'n' ≤ n
t<y, r, n> ≤ t<y', r', n'>
(Iterator variance)
t ∈ {Iterator, AsyncIterator, Generator, AsyncGenerator, IterableIterator, AsyncIterableIterator, IteratorObject}
rawResult<+y, +r>arrayLike<+a>taggedTemplate<-param, +output>

Review

  • Is +'return sound when Generator.returnValue takes a 'return? Only up to a contrived case: a generator shared under two types, resumed through returnValue while a finally block yields, hands the wider value to the narrower reference. TypeScript's Generator has the same hole.