diff --git a/phpunit/code/polymorphic-dispatch.php b/phpunit/code/polymorphic-dispatch.php new file mode 100644 index 00000000..be4b9a1a --- /dev/null +++ b/phpunit/code/polymorphic-dispatch.php @@ -0,0 +1,46 @@ +addFiles([$source]); + $compiler->prepareFile($source); + $code = file_get_contents($compiler->convertFile($source)); + + self::assertIsString($code); + + // Exact new object definition get_class() folds to compile-time literal string + self::assertMatchesRegularExpression( + '/php_getexactclass\(\) \{.*?tmp_var_\d+ = \(get_str\(\d+\)\);/s', + $code, + ); + + // Polymorphic get_class() must NOT fold to BaseAnimal; it must invoke runtime get_class + self::assertMatchesRegularExpression( + '/php_getpolymorphicclass\(\) \{.*?tmp_var_\d+ = \(php::fn::get_class\(animal\)\);/s', + $code, + ); + + // Exact new object definition static call devirtualizes to cached call + self::assertMatchesRegularExpression( + '/php_callexactstatic\(\) \{.*?typephp_call_cached\(get_str\(\d+\)/s', + $code, + ); + + // Polymorphic static call must NOT statically bind to BaseAnimal; it must dispatch dynamically + self::assertMatchesRegularExpression( + '/php_callpolymorphicstatic\(\) \{.*?php::callStaticMethod\([^)]+\)/s', + $code, + ); + } +} diff --git a/src/Optimizer/FuncCallOptimizer.php b/src/Optimizer/FuncCallOptimizer.php index 2a28700a..46c1eaa2 100644 --- a/src/Optimizer/FuncCallOptimizer.php +++ b/src/Optimizer/FuncCallOptimizer.php @@ -1118,8 +1118,8 @@ protected function genGetClassOptimized(string $n, Node\Expr\FuncCall $e, array 'Native classes do not support runtime class introspection; use `NativeClass::class`', ); } - if ($this->isVarExpr($obj) && $this->isStableObject($obj->name)) { - return $this->getLiteralString($this->getObjectType($obj->name)); + if ($this->isVarExpr($obj) && isset($this->context->exactObjects[$obj->name])) { + return $this->getLiteralString($this->context->exactObjects[$obj->name]); } return 'php::fn::get_class(' . $this->parseIdentifier($obj) . ')'; } diff --git a/src/Parser/MethodCallTrait.php b/src/Parser/MethodCallTrait.php index f1fe3ae3..a8c6960c 100644 --- a/src/Parser/MethodCallTrait.php +++ b/src/Parser/MethodCallTrait.php @@ -1103,10 +1103,10 @@ protected function parseStaticCall(Expr\StaticCall $expr): string if (!$this->isNameExpr($expr->class)) { if ($this->isVarExpr($expr->class) - && $this->isStableObject($class) + && isset($this->context->exactObjects[$class]) && $this->isIdExpr($expr->name) ) { - $class = $this->getObjectType($class); + $class = $this->context->exactObjects[$class]; goto _do_call; } $classTarget = $this->materializeDynamicStaticCallTarget($expr->class);