Cherry-pick of upstream 84ad3a5. The generator return type covariance change is built on yurun's Translator.php, which diverged from origin/master, so the files are materialized from the upstream commit directly (they already include the cc25d71 FiberGenerator change). - isReturnTypeOverrideCompatible now performs full covariance: every value the child can return must be acceptable under the parent's declared return type (nullable/union narrowing allowed). - Add getReturnAcceptedTypes/isReturnTypeSubtype/isReturnTypeCoveredBy/ isReturnTypeEntryCompatible helpers; generators use their source-level declared return type so interface/abstract covariance checks hold. - FunctionDef gains declaredReturnType/declaredReturnClass/declaredReturnTypeCheck. Regression tests: interface-return-type.phpt, interface-return-type-variants.phpt.pull/31/head
parent
c0556882ab
commit
cdf4e5f789
5 changed files with 323 additions and 32 deletions
@ -0,0 +1,82 @@ |
||||
--TEST-- |
||||
generator methods implementing interfaces with iterable, nullable and union return types |
||||
--FILE-- |
||||
<?php |
||||
interface GenInterface |
||||
{ |
||||
public function gen(array $array): \Generator; |
||||
} |
||||
|
||||
interface IterableInterface |
||||
{ |
||||
public function it(array $array): iterable; |
||||
} |
||||
|
||||
interface NullableInterface |
||||
{ |
||||
public function nullable(array $array): ?\Generator; |
||||
} |
||||
|
||||
interface UnionInterface |
||||
{ |
||||
public function union(array $array): \Generator|\Iterator; |
||||
} |
||||
|
||||
class Box implements GenInterface, IterableInterface, NullableInterface, UnionInterface |
||||
{ |
||||
public function gen(array $array): \Generator |
||||
{ |
||||
foreach ($array as $value) { |
||||
yield $value * 2; |
||||
} |
||||
} |
||||
|
||||
public function it(array $array): iterable |
||||
{ |
||||
foreach ($array as $value) { |
||||
yield $value; |
||||
} |
||||
} |
||||
|
||||
public function nullable(array $array): ?\Generator |
||||
{ |
||||
foreach ($array as $value) { |
||||
yield $value; |
||||
} |
||||
} |
||||
|
||||
public function union(array $array): \Generator|\Iterator |
||||
{ |
||||
foreach ($array as $value) { |
||||
yield $value; |
||||
} |
||||
} |
||||
} |
||||
|
||||
function main() |
||||
{ |
||||
$box = new Box(); |
||||
foreach ($box->gen([1, 2, 3]) as $v) { |
||||
var_dump($v); |
||||
} |
||||
foreach ($box->it([4, 5]) as $v) { |
||||
var_dump($v); |
||||
} |
||||
foreach ($box->nullable([6, 7]) as $v) { |
||||
var_dump($v); |
||||
} |
||||
foreach ($box->union([8, 9]) as $v) { |
||||
var_dump($v); |
||||
} |
||||
} |
||||
?> |
||||
--EXPECT-- |
||||
int(2) |
||||
int(4) |
||||
int(6) |
||||
int(4) |
||||
int(5) |
||||
int(6) |
||||
int(7) |
||||
int(8) |
||||
int(9) |
||||
@ -0,0 +1,38 @@ |
||||
--TEST-- |
||||
generator method implementing an interface that declares \Generator return type |
||||
--FILE-- |
||||
<?php |
||||
interface T |
||||
{ |
||||
public function test(array $array): \Generator; |
||||
} |
||||
|
||||
class TestClass implements T |
||||
{ |
||||
public function test(array $array): \Generator |
||||
{ |
||||
foreach ($array as $value) { |
||||
yield $value; |
||||
} |
||||
} |
||||
} |
||||
|
||||
function main() |
||||
{ |
||||
$test = new TestClass; |
||||
$g = $test->test([1, 2, 3]); |
||||
// TypePHP generators return a \FiberGenerator which implements Iterator |
||||
// but is NOT the Zend \Generator class. |
||||
var_dump($g instanceof \Generator); |
||||
var_dump($g instanceof \Iterator); |
||||
foreach ($g as $value) { |
||||
var_dump($value); |
||||
} |
||||
} |
||||
?> |
||||
--EXPECT-- |
||||
bool(false) |
||||
bool(true) |
||||
int(1) |
||||
int(2) |
||||
int(3) |
||||
Loading…
Reference in new issue