diff --git a/src/main/php/lang/ast/emit/PHP.class.php b/src/main/php/lang/ast/emit/PHP.class.php index 7f5d0a46..c0971156 100755 --- a/src/main/php/lang/ast/emit/PHP.class.php +++ b/src/main/php/lang/ast/emit/PHP.class.php @@ -14,7 +14,7 @@ UnpackExpression, Variable }; -use lang\ast\types\{IsUnion, IsFunction, IsArray, IsMap}; +use lang\ast\types\{IsUnion, IsFunction, IsArray, IsMap, IsNullable}; use lang\ast\{Emitter, Node, Type}; abstract class PHP extends Emitter { @@ -234,17 +234,26 @@ protected function emitVariable($result, $variable) { protected function emitCast($result, $cast) { static $native= ['string' => true, 'int' => true, 'float' => true, 'bool' => true, 'array' => true, 'object' => true]; - $name= $cast->type->name(); - if ('?' === $name[0]) { - $result->out->write('cast('); - $this->emitOne($result, $cast->expression); - $result->out->write(',\''.$name.'\', false)'); - } else if (isset($native[$name])) { - $result->out->write('('.$cast->type->literal().')'); + // Inline nullable checks using ternaries + if ($cast->type instanceof IsNullable) { + $t= $result->temp(); + $result->out->write('null===('.$t.'='); $this->emitOne($result, $cast->expression); + $result->out->write(')?null:'); + + $name= $cast->type->element->name(); + $expression= new Variable(substr($t, 1)); + } else { + $name= $cast->type->name(); + $expression= $cast->expression; + } + + if (isset($native[$name])) { + $result->out->write('('.$name.')'); + $this->emitOne($result, $expression); } else { $result->out->write('cast('); - $this->emitOne($result, $cast->expression); + $this->emitOne($result, $expression); $result->out->write(',\''.$name.'\')'); } } diff --git a/src/test/php/lang/ast/unittest/emit/CastingTest.class.php b/src/test/php/lang/ast/unittest/emit/CastingTest.class.php index 48676097..d7e0a70b 100755 --- a/src/test/php/lang/ast/unittest/emit/CastingTest.class.php +++ b/src/test/php/lang/ast/unittest/emit/CastingTest.class.php @@ -89,6 +89,19 @@ public function run($value) { )); } + #[Test, Values([null, 'test'])] + public function nullable_string_cast_of_expression_returning($value) { + Assert::equals($value, $this->run( + 'class { + public function run($value) { + $values= [$value]; + return (?string)array_pop($values); + } + }', + $value + )); + } + #[Test] public function cast_braced() { Assert::equals(['test'], $this->run(