Resolve function imports before dispatch and policy checks (#108)
* fix(compiler): resolve function imports before dispatch and policy checks * test: close PHP section in function import PHPT * fix(compiler): resolve first-class function aliasesmaster
parent
df6c0dfd99
commit
ce4c712b0c
5 changed files with 124 additions and 0 deletions
@ -0,0 +1,3 @@ |
||||
<?php |
||||
use function exec as SAFE; |
||||
function importedPolicyCall(): void { safe('not-executed'); } |
||||
@ -0,0 +1,27 @@ |
||||
<?php |
||||
namespace { |
||||
function route(): string { return 'global'; } |
||||
function size(string $value): int { return 99; } |
||||
} |
||||
namespace AliasLibrary { |
||||
function route(): string { return 'import'; } |
||||
function callback_target(): string { return 'import-callback'; } |
||||
} |
||||
namespace AliasConsumer { |
||||
use function AliasLibrary\route as ROUTE; |
||||
use function AliasLibrary\route as GET_CALLED_CLASS; |
||||
use function strlen as SIZE; |
||||
use function AliasLibrary\route as extract; |
||||
use function AliasLibrary\{route as GROUPED}; |
||||
use function AliasLibrary\callback_target as CALLBACK_TARGET; |
||||
|
||||
function exercise(): void { |
||||
echo route(), ':', RoUtE(), ':', get_called_class(), ':', sIzE('abc'), ':', grouped(), ':', extract(), ':', \route(), "\n"; |
||||
$size = sIzE(...); |
||||
$callback = cAlLbAcK_tArGeT(...); |
||||
$route = rOuTe(...); |
||||
$dynamic = $size; |
||||
echo $size('abcd'), ':', $callback(), ':', $route(), ':', $dynamic('abc'), "\n"; |
||||
} |
||||
} |
||||
namespace { function main(): void { \AliasConsumer\exercise(); } } |
||||
@ -0,0 +1,32 @@ |
||||
<?php |
||||
|
||||
use TypePhp\CompilerTest; |
||||
|
||||
final class FunctionImportResolutionTest extends BaseTest |
||||
{ |
||||
public function testImportedFunctionsTakePrecedenceRegardlessOfAliasCase(): void |
||||
{ |
||||
global $translator; |
||||
$compiler = CompilerTest::create(TYPEPHP_ROOT_PATH); |
||||
$translator = $compiler; |
||||
$source = TYPEPHP_ROOT_PATH . '/phpunit/code/function-import-resolution.php'; |
||||
$compiler->addFiles([$source]); |
||||
$compiler->prepareFile($source); |
||||
$code = file_get_contents($compiler->convertFile($source)); |
||||
preg_match('/void php_aliasconsumer__exercise\(\) \{(.*?)\n\}/s', $code, $match); |
||||
self::assertCount(2, $match); |
||||
self::assertSame(5, substr_count($match[1], 'php_aliaslibrary__route(')); |
||||
self::assertSame(1, substr_count($match[1], 'php_route(')); |
||||
// The three first-class callables are materialized through |
||||
// Closure::fromCallable(); ordinary aliases above must stay direct. |
||||
self::assertSame(3, substr_count($match[1], 'php::call(')); |
||||
self::assertStringNotContainsString('ZEND_STRL("sIzE")', $match[1]); |
||||
self::assertStringNotContainsString('ZEND_STRL("cAlLbAcK_tArGeT")', $match[1]); |
||||
|
||||
$literalStrings = (new \ReflectionProperty($compiler, 'literalStrings'))->getValue($compiler); |
||||
self::assertArrayHasKey('strlen', $literalStrings); |
||||
self::assertArrayHasKey('AliasLibrary\\callback_target', $literalStrings); |
||||
self::assertArrayNotHasKey('sIzE', $literalStrings); |
||||
self::assertArrayNotHasKey('cAlLbAcK_tArGeT', $literalStrings); |
||||
} |
||||
} |
||||
@ -0,0 +1,34 @@ |
||||
--TEST-- |
||||
Function imports are case-insensitive and take precedence over global functions |
||||
--FILE-- |
||||
<?php |
||||
namespace { |
||||
function route(): string { return 'global'; } |
||||
function size(string $value): int { return 99; } |
||||
} |
||||
namespace AliasLibrary { |
||||
function route(): string { return 'import'; } |
||||
function callback_target(): string { return 'import-callback'; } |
||||
} |
||||
namespace AliasConsumer { |
||||
use function AliasLibrary\route as ROUTE; |
||||
use function AliasLibrary\route as GET_CALLED_CLASS; |
||||
use function strlen as SIZE; |
||||
use function AliasLibrary\route as extract; |
||||
use function AliasLibrary\{route as GROUPED}; |
||||
use function AliasLibrary\callback_target as CALLBACK_TARGET; |
||||
|
||||
function exercise(): void { |
||||
echo route(), ':', RoUtE(), ':', get_called_class(), ':', sIzE('abc'), ':', grouped(), ':', extract(), ':', \route(), "\n"; |
||||
$size = sIzE(...); |
||||
$callback = cAlLbAcK_tArGeT(...); |
||||
$route = rOuTe(...); |
||||
$dynamic = $size; |
||||
echo $size('abcd'), ':', $callback(), ':', $route(), ':', $dynamic('abc'), "\n"; |
||||
} |
||||
} |
||||
namespace { function main(): void { \AliasConsumer\exercise(); } } |
||||
?> |
||||
--EXPECT-- |
||||
import:import:import:3:import:import:global |
||||
4:import-callback:import:3 |
||||
Loading…
Reference in new issue