@@ -1215,21 +1215,23 @@ public function foreachGeneratorParam(\Generator $pencils): void
12151215//
12161216// Generator<TKey, TValue, TSend, TReturn>
12171217//
1218- // - `yield $expr` produces TValue to the consumer
1219- // - `$var = yield $expr` assigns TSend (the sent value) to $var
1220- // - Reverse yield inference: when ` yield $var` appears and $var has no
1221- // prior assignment, PHPantom infers $var as TValue from the @return type
1218+ // - `yield $expr` produces TValue to the consumer. The yielded variable
1219+ // keeps its own type (from its assignment), not the Generator annotation.
1220+ // - `$var = yield $expr` assigns TSend (the sent value) to $var. The yield
1221+ // expression evaluates to whatever was passed via ->send().
12221222
12231223class GeneratorYieldDemo
12241224{
12251225 /** @return \Generator<int, Pen> */
12261226 public function findAll (): \Generator
12271227 {
1228- // Reverse yield inference: $pen has no assignment, so the LSP
1229- // infers it as Pen from @return Generator<int, Pen> (TValue)
1228+ // The type of $pen comes from `new Pen(...)`, not from the @return.
1229+ // Completion on $pen-> works because the assignment is known.
1230+ $ pen = new Pen ('blue ' );
12301231 yield $ pen ;
12311232 $ pen ->write (); // resolves to Pen
12321233
1234+ $ anotherPen = new Pen ('red ' );
12331235 yield 0 => $ anotherPen ;
12341236 $ anotherPen ->color (); // key => value yields also work
12351237 }
@@ -1238,9 +1240,9 @@ public function findAll(): \Generator
12381240 public function yieldInsideControlFlow (): \Generator
12391241 {
12401242 if (true ) {
1241- // Reverse inference works inside control flow blocks too
1243+ $ pen = new Pen ( ' green ' );
12421244 yield $ pen ;
1243- $ pen ->write (); // resolves to Pen
1245+ $ pen ->write (); // resolves inside control flow blocks
12441246 }
12451247 }
12461248
@@ -1249,15 +1251,15 @@ public function chainingThroughYieldInferred(): \Generator
12491251 {
12501252 $ pen = new Pen ('black ' );
12511253 yield $ pen ;
1252- $ pen ->rename ('Bold ' )->color (); // chains through inferred type
1254+ $ pen ->rename ('Bold ' )->color (); // chains through yielded variable
12531255 }
12541256
12551257 /** @return \Generator<int, string, Pencil, void> */
12561258 public function coroutine (): \Generator
12571259 {
12581260 // TSend inference: $var = yield gets the 3rd Generator type param.
12591261 // yield produces 'ready' (TValue = string) to the consumer;
1260- // the yield expression evaluates to whatever was ->send()'d (TSend = Pencil)
1262+ // the yield expression evaluates to whatever was ->send()'d (TSend = Pencil).
12611263 $ pencil = yield 'ready ' ;
12621264 $ pencil ->sketch (); // resolves to Pencil (TSend)
12631265 }
@@ -4034,9 +4036,11 @@ function runDemoAssertions(): void
40344036 }
40354037
40364038 // ── Generator yield inference (GeneratorYieldDemo) ───────────────────
4037- // findAll() uses reverse yield inference (unassigned vars) so it yields
4038- // null at runtime. Only chainingThroughYieldInferred() yields real Pens.
40394039 $ yieldDemo = new GeneratorYieldDemo ();
4040+ foreach ($ yieldDemo ->findAll () as $ yieldedPen ) {
4041+ assert ($ yieldedPen instanceof Pen, 'GeneratorYieldDemo::findAll() must yield Pen ' );
4042+ break ;
4043+ }
40404044 foreach ($ yieldDemo ->chainingThroughYieldInferred () as $ chainPen ) {
40414045 assert ($ chainPen instanceof Pen, 'chainingThroughYieldInferred() must yield Pen ' );
40424046 break ;
0 commit comments