fix compiler regression in internal calls and native arithmetic

master
韩天峰 10 hours ago
parent 0f1efb52a4
commit fd20616236
  1. 3
      src/Context/FunctionContext.php
  2. 4
      src/Parser/AssignOpTrait.php
  3. 15
      src/Parser/BinaryOpTrait.php
  4. 22
      src/Parser/MethodCallTrait.php

@ -68,6 +68,8 @@ class FunctionContext
*/
public array $stdContainers = [];
public array $localVars = [];
/** @var array<string, true> Locals explicitly created through std::int/float/bool. */
public array $explicitNativeTypeVars = [];
/** @var array<string, string> C++ initializers folded into function-scope local declarations. */
public array $localVarInitializers = [];
public array $staticVars = [];
@ -121,6 +123,7 @@ class FunctionContext
public function __construct()
{
$this->localVars = [];
$this->explicitNativeTypeVars = [];
$this->localVarInitializers = [];
$this->staticVars = [];
$this->arguments = [];

@ -621,11 +621,15 @@ trait AssignOpTrait
$finalVarType = $right->getAttribute('nativeType');
$this->addLocalVar($var, $finalVarType);
}
$this->context->explicitNativeTypeVars[$var] = true;
return $var . ' = ' . $valueExpr;
}
}
} elseif ($this->isVarExpr($right)) {
$rightVar = $this->parseIdentifier($right);
if (isset($this->context->explicitNativeTypeVars[$rightVar])) {
$this->context->explicitNativeTypeVars[$var] = true;
}
$this->assertStdContainerDoesNotEscapeNativeObjects($right, $rightVar);
$type = $this->isStdContainer($rightVar) ? Type::ARRAY : $this->getVarType($rightVar);
$finalVarType = $this->getNormalAssignType($type);

@ -167,6 +167,8 @@ trait BinaryOpTrait
&& $leftType === Type::INT
&& $rightType === Type::INT
&& in_array($op, ['+', '-', '*', '/'], true)
&& !$this->isExplicitNativeArithmeticExpr($left)
&& !$this->isExplicitNativeArithmeticExpr($right)
&& $this->evaluateConstantIntArithmetic($left, $right, $op) === null
) {
// Keep the potentially widening result boxed, but pass the native
@ -178,6 +180,19 @@ trait BinaryOpTrait
return '((' . $leftExpr . ') ' . $op . ' (' . $rightExpr . '))';
}
/**
* std::int/float/bool explicitly opt a value into native C++ arithmetic,
* independently of the file-wide `use native_types` declaration.
*/
protected function isExplicitNativeArithmeticExpr(NodeAbstract $expr): bool
{
if ($this->isVarExpr($expr) && is_string($expr->name)) {
return isset($this->context->explicitNativeTypeVars[$this->parseIdentifier($expr)]);
}
return $expr->getAttribute('nativeType') !== null;
}
/**
* Fold constant integer shifts to PHP semantics in non-native mode.
*

@ -312,6 +312,28 @@ trait MethodCallTrait
return null;
}
// A DynamicCall is also used for real methods inherited from an
// internal Zend class. Only attempt __call devirtualization when the
// TypePHP class hierarchy actually provides a compiled __call method;
// otherwise getNativeMethod() would continue into the internal parent
// and incorrectly diagnose the absent magic method.
$currentClass = $exactClass;
$hasCompiledMagicMethod = false;
while ($this->hasClass($currentClass)) {
$currentDef = $this->getClass($currentClass);
if ($currentDef->hasMethod('__call')) {
$hasCompiledMagicMethod = true;
break;
}
if ($currentDef->extends === '') {
break;
}
$currentClass = $currentDef->extends;
}
if (!$hasCompiledMagicMethod) {
return null;
}
$nativeFunc = $this->getNativeMethod($expr, $exactClass, '__call', false);
if ($nativeFunc === false || !$this->hasFunction($nativeFunc)) {
return null;

Loading…
Cancel
Save