修复三元表达式 issue

pull/45/head
韩天峰 3 weeks ago
parent c3614aa6d3
commit cee9ee6e1b
  1. 18
      src/Parser/SelectionExpressionTrait.php
  2. 29
      tests/compiler/ternary-typed-arg.phpt

@ -46,7 +46,11 @@ trait SelectionExpressionTrait
$else = 'php::Var(' . $else . ')'; $else = 'php::Var(' . $else . ')';
} }
if ($hasBranchStmts) { if ($hasBranchStmts) {
$code = '[&]() -> ' . Type::VAR . '{'; // The materialized temporary (see getOrderedOperandTmpType) is
// declared with the ternary's static type, so the lambda return
// type must match it instead of always being php::Var.
$ternaryType = $this->detectTypeOfExpr($expr);
$code = '[&]() -> ' . $ternaryType . '{';
$code .= $this->formatCapturedStmtLines($condBeforeStmts); $code .= $this->formatCapturedStmtLines($condBeforeStmts);
if ($condAfterStmts) { if ($condAfterStmts) {
$condTmpVar = $this->addTmpVar(Type::VAR); $condTmpVar = $this->addTmpVar(Type::VAR);
@ -56,9 +60,9 @@ trait SelectionExpressionTrait
} }
$cond = $this->convertConditionExpr($expr->cond, $cond); $cond = $this->convertConditionExpr($expr->cond, $cond);
$code .= $this->getIndent() . 'if (' . $cond . ') {'; $code .= $this->getIndent() . 'if (' . $cond . ') {';
$code .= $this->formatTernaryReturn($if, $ifBeforeStmts, $ifAfterStmts); $code .= $this->formatTernaryReturn($if, $ifBeforeStmts, $ifAfterStmts, $ternaryType);
$code .= $this->getIndent() . '} else {'; $code .= $this->getIndent() . '} else {';
$code .= $this->formatTernaryReturn($else, $elseBeforeStmts, $elseAfterStmts); $code .= $this->formatTernaryReturn($else, $elseBeforeStmts, $elseAfterStmts, $ternaryType);
$code .= $this->getIndent() . '}'; $code .= $this->getIndent() . '}';
$code .= $this->getIndent() . '}()'; $code .= $this->getIndent() . '}()';
return $code; return $code;
@ -67,16 +71,18 @@ trait SelectionExpressionTrait
return '(' . $cond . ') ? (' . $if . ') : (' . $else . ')'; return '(' . $cond . ') ? (' . $if . ') : (' . $else . ')';
} }
protected function formatTernaryReturn(string $value, array $beforeStmts, array $afterStmts): string protected function formatTernaryReturn(string $value, array $beforeStmts, array $afterStmts, string $returnType): string
{ {
$code = $this->formatCapturedStmtLines($beforeStmts); $code = $this->formatCapturedStmtLines($beforeStmts);
if ($afterStmts) { if ($afterStmts) {
$tmpVar = $this->addTmpVar(Type::VAR); $tmpVar = $this->addTmpVar($returnType);
$code .= $this->getIndent() . "{$tmpVar} = {$value};"; $code .= $this->getIndent() . "{$tmpVar} = {$value};";
$code .= $this->formatCapturedStmtLines($afterStmts); $code .= $this->formatCapturedStmtLines($afterStmts);
$code .= $this->getIndent() . 'return ' . $tmpVar . ';'; $code .= $this->getIndent() . 'return ' . $tmpVar . ';';
} else { } else {
$code .= $this->getIndent() . 'return php::Var(' . $value . ');'; $code .= $returnType === Type::VAR
? $this->getIndent() . 'return php::Var(' . $value . ');'
: $this->getIndent() . 'return ' . $value . ';';
} }
return $code; return $code;
} }

@ -0,0 +1,29 @@
--TEST--
Ternary with captured statements keeps its static type for typed arguments
--FILE--
<?php
declare(strict_types=1);
class TernaryBoolArg
{
public function takeBool(bool $flag): bool
{
return $flag;
}
}
function main(): void
{
$range = [1, 2, 3];
$obj = new TernaryBoolArg();
// The condition contains a function call, which forces the ternary into a
// captured-statement lambda. The lambda must still yield php::Bool so it
// can feed the typed parameter.
var_dump($obj->takeBool(count($range) > 1 ? true : false));
var_dump($obj->takeBool(count($range) > 5 ? true : false));
}
?>
--EXPECT--
bool(true)
bool(false)
Loading…
Cancel
Save