|
| 1 | +--TEST-- |
| 2 | +Reification: the opcache DFA optimizer monomorphizes non-turbofish generic calls from each argument's SSA-inferred type; reassignment binds the actual type, not the declared one, and unknown types stay generic |
| 3 | +--EXTENSIONS-- |
| 4 | +opcache |
| 5 | +--INI-- |
| 6 | +opcache.enable=1 |
| 7 | +opcache.enable_cli=1 |
| 8 | +opcache.optimization_level=-1 |
| 9 | +--FILE-- |
| 10 | +<?php |
| 11 | +declare(strict_types=1); |
| 12 | + |
| 13 | +function retStr<T : int|float|string>(T $x): T { return "s"; } |
| 14 | +function retInt<T : int|float|string>(T $x): T { return 7; } |
| 15 | + |
| 16 | +function from_int(int $i) { return retStr($i); } |
| 17 | +function from_float(float $f) { return retStr($f); } |
| 18 | +function local_literal() { $v = 1.5; return retStr($v); } |
| 19 | + |
| 20 | +// Reassignment must bind T from the SSA type (string), not the declared int. |
| 21 | +function reassigned(int $val) { $val = 'x'; return retInt($val); } |
| 22 | + |
| 23 | +function from_unknown(array $a) { $v = $a[0]; return retInt($v); } |
| 24 | + |
| 25 | +function check(string $name, callable $fn): void { |
| 26 | + try { |
| 27 | + $r = $fn(); |
| 28 | + echo "$name: ", var_export($r, true), "\n"; |
| 29 | + } catch (TypeError $e) { |
| 30 | + echo "$name: TypeError\n"; |
| 31 | + } |
| 32 | +} |
| 33 | + |
| 34 | +check('from_int', fn() => from_int(1)); |
| 35 | +check('from_float', fn() => from_float(1.5)); |
| 36 | +check('local_literal', fn() => local_literal()); |
| 37 | +check('reassigned', fn() => reassigned(1)); |
| 38 | +check('from_unknown', fn() => from_unknown([42])); |
| 39 | +?> |
| 40 | +--EXPECT-- |
| 41 | +from_int: TypeError |
| 42 | +from_float: TypeError |
| 43 | +local_literal: TypeError |
| 44 | +reassigned: TypeError |
| 45 | +from_unknown: 7 |
0 commit comments