- Preserve PHP's concat-assignment operation for statically typed strings using in-place append - Add parseInPlaceStringConcatAssign method to handle string concatenation assignments efficiently - Prevent O(n^2) work when rebuilding target = concat(target, rhs) operations - Keep compound RHS evaluated completely before target changes in concat assignments - Optimize native scalar binary operand handling to avoid unnecessary Variant boxing - Add native scalar call results remain unboxed when ordered in native-types mode - Create string concatenation assignment tests with proper PHP value and COW semantics - Update version number from 1109 to 1110master
parent
65d3710a61
commit
7418b6247e
10 changed files with 177 additions and 10 deletions
@ -0,0 +1,8 @@ |
||||
<?php |
||||
|
||||
function recursivePhpInt(int $value): int |
||||
{ |
||||
return $value < 2 |
||||
? 1 |
||||
: recursivePhpInt($value - 2) + recursivePhpInt($value - 1); |
||||
} |
||||
@ -0,0 +1,10 @@ |
||||
<?php |
||||
|
||||
use native_types; |
||||
|
||||
function recursiveNativeInt(int $value): int |
||||
{ |
||||
return $value < 2 |
||||
? 1 |
||||
: recursiveNativeInt($value - 2) + recursiveNativeInt($value - 1); |
||||
} |
||||
@ -0,0 +1,10 @@ |
||||
<?php |
||||
|
||||
function stringConcatAssignCodegen(string $suffix): string |
||||
{ |
||||
$value = ''; |
||||
$value .= 'hello'; |
||||
$value .= ', ' . $suffix; |
||||
$result = ($value .= $value); |
||||
return $result; |
||||
} |
||||
@ -0,0 +1,40 @@ |
||||
<?php |
||||
|
||||
use TypePhp\CompilerTest; |
||||
|
||||
final class NativeScalarBinaryOperandTest extends \BaseTest |
||||
{ |
||||
public function testNativeScalarCallResultsRemainUnboxedWhenOrdered(): void |
||||
{ |
||||
global $translator; |
||||
|
||||
$compiler = CompilerTest::create(ROOT_PATH); |
||||
$translator = $compiler; |
||||
$source = ROOT_PATH . '/phpunit/code/native-scalar-binary-operands.php'; |
||||
$compiler->addFiles([$source]); |
||||
$compiler->prepareFile($source); |
||||
$generated = $compiler->convertFile($source); |
||||
$code = file_get_contents($generated); |
||||
|
||||
self::assertIsString($code); |
||||
self::assertStringContainsString('php::Int php_recursivenativeint(php::Int value)', $code); |
||||
self::assertStringNotContainsString('php::Var tmp_var_', $code); |
||||
} |
||||
|
||||
public function testPhpCompatibleScalarCallResultsRemainBoxedWhenOrdered(): void |
||||
{ |
||||
global $translator; |
||||
|
||||
$compiler = CompilerTest::create(ROOT_PATH); |
||||
$translator = $compiler; |
||||
$source = ROOT_PATH . '/phpunit/code/dynamic-scalar-binary-operands.php'; |
||||
$compiler->addFiles([$source]); |
||||
$compiler->prepareFile($source); |
||||
$generated = $compiler->convertFile($source); |
||||
$code = file_get_contents($generated); |
||||
|
||||
self::assertIsString($code); |
||||
self::assertStringContainsString('php::Int php_recursivephpint(php::Int value)', $code); |
||||
self::assertStringContainsString('php::Var tmp_var_', $code); |
||||
} |
||||
} |
||||
@ -0,0 +1,24 @@ |
||||
<?php |
||||
|
||||
use TypePhp\CompilerTest; |
||||
|
||||
final class StringConcatAssignTest extends \BaseTest |
||||
{ |
||||
public function testTypedStringConcatAssignmentUsesInPlaceAppend(): void |
||||
{ |
||||
global $translator; |
||||
|
||||
$compiler = CompilerTest::create(ROOT_PATH); |
||||
$translator = $compiler; |
||||
$source = ROOT_PATH . '/phpunit/code/string-concat-assign.php'; |
||||
$compiler->addFiles([$source]); |
||||
$compiler->prepareFile($source); |
||||
$generated = $compiler->convertFile($source); |
||||
$code = file_get_contents($generated); |
||||
|
||||
self::assertIsString($code); |
||||
self::assertGreaterThanOrEqual(3, substr_count($code, 'value.append(')); |
||||
self::assertStringContainsString('value.append(php::concat({', $code); |
||||
self::assertStringNotContainsString('value = php::concat({value,', $code); |
||||
} |
||||
} |
||||
@ -0,0 +1,40 @@ |
||||
--TEST-- |
||||
String concat assignment preserves PHP value, COW and expression semantics |
||||
--FILE-- |
||||
<?php |
||||
declare(strict_types=1); |
||||
|
||||
final class ConcatAssignStringable |
||||
{ |
||||
public function __toString(): string |
||||
{ |
||||
echo "convert\n"; |
||||
return 'object'; |
||||
} |
||||
} |
||||
|
||||
function main(): void |
||||
{ |
||||
$value = 'start'; |
||||
$copy = $value; |
||||
$suffix = 'tail'; |
||||
|
||||
$value .= ':'; |
||||
$value .= $suffix . ':' . new ConcatAssignStringable(); |
||||
var_dump($value, $copy); |
||||
|
||||
$self = 'ab'; |
||||
$self .= $self; |
||||
var_dump($self); |
||||
|
||||
$result = ($value .= '!'); |
||||
var_dump($value, $result); |
||||
} |
||||
?> |
||||
--EXPECT-- |
||||
convert |
||||
string(17) "start:tail:object" |
||||
string(5) "start" |
||||
string(4) "abab" |
||||
string(18) "start:tail:object!" |
||||
string(18) "start:tail:object!" |
||||
@ -1 +1 @@ |
||||
1109 |
||||
1110 |
||||
Loading…
Reference in new issue