@@ -1212,18 +1212,24 @@ public function foreachGeneratorParam(\Generator $pencils): void
12121212
12131213
12141214// ── Generator Yield Type Inference Inside Bodies ────────────────────────────
1215+ //
1216+ // Generator<TKey, TValue, TSend, TReturn>
1217+ //
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
12151222
12161223class GeneratorYieldDemo
12171224{
12181225 /** @return \Generator<int, Pen> */
12191226 public function findAll (): \Generator
12201227 {
1221- // yield $var — the LSP infers $pen as Pen from @return Generator<int, Pen>
1222- $ pen = new Pen ( ' blue ' );
1228+ // Reverse yield inference: $pen has no assignment, so the LSP
1229+ // infers it as Pen from @return Generator<int, Pen> (TValue)
12231230 yield $ pen ;
12241231 $ pen ->write (); // resolves to Pen
12251232
1226- $ anotherPen = new Pen ('red ' );
12271233 yield 0 => $ anotherPen ;
12281234 $ anotherPen ->color (); // key => value yields also work
12291235 }
@@ -1232,9 +1238,9 @@ public function findAll(): \Generator
12321238 public function yieldInsideControlFlow (): \Generator
12331239 {
12341240 if (true ) {
1235- $ pen = new Pen ( ' green ' );
1241+ // Reverse inference works inside control flow blocks too
12361242 yield $ pen ;
1237- $ pen ->write (); // resolves inside control flow blocks
1243+ $ pen ->write (); // resolves to Pen
12381244 }
12391245 }
12401246
@@ -1249,7 +1255,9 @@ public function chainingThroughYieldInferred(): \Generator
12491255 /** @return \Generator<int, string, Pencil, void> */
12501256 public function coroutine (): \Generator
12511257 {
1252- // TSend inference: $var = yield assigns the 3rd type param
1258+ // TSend inference: $var = yield gets the 3rd Generator type param.
1259+ // yield produces 'ready' (TValue = string) to the consumer;
1260+ // the yield expression evaluates to whatever was ->send()'d (TSend = Pencil)
12531261 $ pencil = yield 'ready ' ;
12541262 $ pencil ->sketch (); // resolves to Pencil (TSend)
12551263 }
@@ -3939,15 +3947,17 @@ function runDemoAssertions(): void
39393947 }
39403948
39413949 // ── Generator yield inference (GeneratorYieldDemo) ───────────────────
3950+ // findAll() uses reverse yield inference (unassigned vars) so it yields
3951+ // null at runtime. Only chainingThroughYieldInferred() yields real Pens.
39423952 $ yieldDemo = new GeneratorYieldDemo ();
3943- foreach ($ yieldDemo ->findAll () as $ yieldedPen ) {
3944- assert ($ yieldedPen instanceof Pen, 'GeneratorYieldDemo::findAll() must yield Pen ' );
3945- break ;
3946- }
39473953 foreach ($ yieldDemo ->chainingThroughYieldInferred () as $ chainPen ) {
39483954 assert ($ chainPen instanceof Pen, 'chainingThroughYieldInferred() must yield Pen ' );
39493955 break ;
39503956 }
3957+ $ coroutineGen = $ yieldDemo ->coroutine ();
3958+ $ yielded = $ coroutineGen ->current ();
3959+ assert ($ yielded === 'ready ' , 'coroutine() must yield string (TValue) ' );
3960+ $ coroutineGen ->send (new Pencil ());
39513961
39523962 // ── GenericContext: Box<Gift> and TypedCollection<int, Gift> ─────────
39533963 $ gcSrc = new ScaffoldingGenericContext ();
0 commit comments