Skip to content

Commit a3c379d

Browse files
committed
Improve Generator Yield Type Inference Inside Bodies demo
1 parent 20afb5d commit a3c379d

1 file changed

Lines changed: 20 additions & 10 deletions

File tree

example.php

Lines changed: 20 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -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

12161223
class 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

Comments
 (0)