Merge pull request #26 from Giandonn/fix/class-exists-trait-fold --skip-tests

fix(optimizer): class_exists() must not fold a trait name to true
master
韩天峰 9 hours ago committed by GitHub
commit a0c873261c
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 22
      phpunit/code/class-exists-class-and-enum.php
  2. 16
      phpunit/code/class-exists-trait.php
  3. 50
      phpunit/src/ClassExistsTraitFoldTest.php
  4. 5
      src/Optimizer/FuncCallOptimizer.php
  5. 8
      tests/compiler/stdlib/class_exists.phpt

@ -0,0 +1,22 @@
<?php
/**
* This file is part of TypePHP(AOT).
*
* @link https://www.swoole.com/aot/
* @contact service@swoole.com
*/
class Real
{
}
enum Suit
{
case Hearts;
}
function main(): void
{
var_dump(class_exists('Real'));
var_dump(class_exists('Suit'));
}

@ -0,0 +1,16 @@
<?php
/**
* This file is part of TypePHP(AOT).
*
* @link https://www.swoole.com/aot/
* @contact service@swoole.com
*/
trait Helper
{
}
function main(): void
{
var_dump(class_exists('Helper'));
}

@ -0,0 +1,50 @@
<?php
/**
* This file is part of TypePHP(AOT).
*
* @link https://www.swoole.com/aot/
* @contact service@swoole.com
*/
namespace TypePhp\Tests;
use PHPUnit\Framework\TestCase;
use TypePhp\CompilerTest;
/**
* @internal
* @coversNothing
*/
class ClassExistsTraitFoldTest extends TestCase
{
public function testTraitNameFoldsToFalse(): void
{
$cpp = $this->compileToCpp('class-exists-trait.php');
// The trait is known at compile time, so the call is still folded -
// just to the answer PHP gives, which is false for a trait.
self::assertStringNotContainsString('php::fn::class_exists(', $cpp);
self::assertStringContainsString('= false;', $cpp);
}
public function testClassAndEnumNamesStillFoldToTrue(): void
{
$cpp = $this->compileToCpp('class-exists-class-and-enum.php');
self::assertStringNotContainsString('php::fn::class_exists(', $cpp);
self::assertStringNotContainsString('= false;', $cpp);
}
private function compileToCpp(string $file): string
{
global $translator;
$compiler = CompilerTest::create(TYPEPHP_ROOT_PATH);
$translator = $compiler;
$source = TYPEPHP_ROOT_PATH . '/phpunit/code/' . $file;
$compiler->addFiles([$source]);
$compiler->prepareFile($source);
return file_get_contents($compiler->convertFile($source));
}
}

@ -667,6 +667,11 @@ trait FuncCallOptimizer
if (!$this->isScalarString($cn) || !$this->hasClass($cn->value)) {
return false;
}
// The class table also carries traits, but a trait is not a class to
// class_exists(): PHP answers false for it and true for an enum.
if ($this->getClassDef($cn->value)?->trait !== null) {
return 'false';
}
return $this->isNativeObjectClass($cn->value) ? 'false' : 'true';
}

@ -16,6 +16,12 @@ function main() {
var_dump(class_exists("NonexistentClass"));
var_dump(class_exists("NonexistentClass", false));
// A trait is not a class. The answer must not depend on whether the name
// is a literal the compiler can resolve at compile time.
var_dump(class_exists("MyTrait"));
$traitName = "MyTrait";
var_dump(class_exists($traitName));
// interface_exists
var_dump(interface_exists("MyInterface"));
var_dump(interface_exists("NonexistentInterface"));
@ -38,6 +44,8 @@ bool(true)
bool(true)
bool(false)
bool(false)
bool(false)
bool(false)
bool(true)
bool(false)
bool(false)

Loading…
Cancel
Save