diff --git a/CHANGELOG.md b/CHANGELOG.md index 6ffd834d..c80e4722 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,39 @@ ## 0.8.0 +### Breaking: native scalar storage is now the default + +`use native_types` has been removed. Inferred `int`, `float`, and `bool` +locals now use `php::Int`, `php::Float`, and `php::Bool` by default. Their +storage type is fixed and the compiler never promotes one of these locals to +`php::Var` merely because a later operation needs dynamic PHP semantics. + +Two explicit escape hatches remain: + +- `use varint_types` is a file-level mode that stores inferred integer values + in `php::Var`, preserving PHP's overflow-to-float, non-integral division, + and other Zend integer arithmetic behavior. It does not box `float` or + `bool` locals. +- `std::any($value)` erases the static type of that individual expression, so + a variable initialized from it uses `php::Var` and may participate in PHP + reference or dynamic-value operations. + +For example, `$i = 100` is now permanently an integer local. Reusing `$i` as a +`foreach` key is rejected because PHP keys have type `int|string`; write +`$i = std::any(100)` or select `use varint_types` if this reuse is intentional. +Projects must remove `use native_types` and add the new compatibility mode only +to files that genuinely depend on Zend integer widening semantics. + +Fixed-storage locals can no longer be converted to PHP references. This rule +applies to native scalars, strings, arrays, objects, streams, high-precision +values, and `std` containers. Zend references are untyped, so allowing one to +alias fixed C++ storage could corrupt the variable's type. Use `std::any()` +before reference operations and explicitly convert the result back afterward. + +TypePHP is always strict. Project sources no longer need +`declare(strict_types=1)`; the directive remains accepted as a redundant PHP +compatibility declaration, while `strict_types=0` is rejected. + ### Breaking: compile-time API namespace cleanup TypePHP compile-time APIs now occupy only two global class symbols: @@ -45,6 +78,32 @@ should review the change log and run their full test suite before upgrading. ## 0.8.0(中文) +### 破坏性变更:默认使用原生标量存储 + +`use native_types` 已移除。推断出的 `int`、`float`、`bool` 局部变量现在默认分别 +使用 `php::Int`、`php::Float`、`php::Bool`。这些变量的存储类型一旦确定便不会因为 +后续操作需要 PHP 动态语义而被编译器自动提升为 `php::Var`。 + +只保留两个显式出口: + +- `use varint_types` 是文件级模式,使推断出的整数使用 `php::Var`,保留 PHP 的 + 整数溢出转浮点、整数除法产生非整数结果等 Zend 算术语义;它不会装箱 `float` + 或 `bool`。 +- `std::any($value)` 只擦除该表达式的静态类型。以它初始化的变量使用 `php::Var`, + 可参与引用或其他动态值操作。 + +例如 `$i = 100` 现在固定为整数局部变量。由于 PHP 的 foreach key 类型为 +`int|string`,之后复用 `$i` 作为 key 会在编译期报错;确需复用时,应写成 +`$i = std::any(100)` 或在文件中声明 `use varint_types`。升级项目必须删除 +`use native_types`,并且只为真正依赖 Zend 整数扩展语义的文件添加新兼容模式。 + +固定存储的局部变量不再允许转换为 PHP 引用,包括原生标量、字符串、数组、对象、 +stream、高精度值和 `std` 容器。Zend 引用没有类型约束,若允许其指向固定 C++ 存储, +可能破坏变量类型。需要引用操作时先使用 `std::any()`,操作完成后再显式转换回目标类型。 + +TypePHP 始终使用严格类型,项目源码不再需要 `declare(strict_types=1)`。该声明仍作为 +冗余的 PHP 兼容语法被接受,而 `strict_types=0` 会被拒绝。 + ### 破坏性变更:整理编译期 API 命名空间 TypePHP 编译期 API 现在只占用两个全局类符号: diff --git a/README-CN.md b/README-CN.md index 0f4595b2..9885e614 100644 --- a/README-CN.md +++ b/README-CN.md @@ -109,8 +109,11 @@ AST,待全部项目符号就绪后再在 convert 阶段解析。这一两阶 - **原生进程入口。** 二进制模式直接启动原生可执行文件,不需要 PHP CLI 或独立的 解释器进程。可执行文件仍会嵌入或链接 PHPX、`libphp` 及项目配置的原生库,部署包 中必须提供这些运行时依赖。 -- **渐进式类型,真正带来收益。** 只在性能关键处添加 `use native_types`、`std::` - 容器和类型声明,其余保持普通 PHP。 +- **默认使用强标量类型。** 推断出的 `int`、`float`、`bool` 局部变量直接使用 + C++ 原生存储。单个动态值使用 `std::any()`;只有文件确实依赖 PHP 整数扩展语义时, + 才使用 `use varint_types`。 +- **始终严格调用。** TypePHP 不启用 PHP 的弱标量类型转换,无需声明 + `declare(strict_types=1)`。 - **Zend 生态互通。** 扩展模式以标准 PHP 扩展形式加载,项目可以调用受支持的 内置函数,并显式声明依赖的其他 Zend 扩展。 @@ -299,7 +302,9 @@ TypePHP 会在适合 AOT 编译的范围内保持 PHP 语法和运行行为, - 全局作用域只允许声明,可执行语句必须位于函数或方法内; - 二进制模式对 `main()` 使用严格签名; -- `use native_types` 会让标量声明使用固定原生存储,之后不能改为不兼容类型; +- 推断出的 `int`、`float`、`bool` 默认使用固定原生存储,之后不能改为不兼容类型; +- `use varint_types` 使推断出的整数存入 `php::Var`,保留 PHP 的整数溢出和除法语义; + `std::any()` 则只擦除单个表达式的静态类型; - 静态可确定的调用和属性会直接编译,受支持的动态操作则通过 PHPX/Zend runtime fallback 执行; - `.stub.php` 用于声明 C++ 或外部库 API,函数体必须为空,stub 文件禁止声明 @@ -367,7 +372,6 @@ function main(): void ```php **Tip**: Like all native_types, the Big* types can only be used in AOT compile mode and cannot run in the normal PHP interpreter. The AOT compiler performs compile-time evaluation of functions such as `std::bigInt()` and directly generates C++ code. +> **Tip**: Big* types can only be used in AOT compile mode and cannot run in +> the normal PHP interpreter. The compiler recognizes functions such as +> `std::bigInt()` and directly generates C++ code. --- @@ -133,11 +132,9 @@ $g = std::bigFloat("3.14159265358979323846"); // from string (exact) ### 4.2 Type Annotation -Under `use native_types`, Big* type variables automatically get native C++ storage types: +Big* constructors always produce their dedicated boxed C++ storage type: ```php -use native_types; - // The compiler automatically infers the type as php::BigInt / php::Decimal / php::BigFloat $a = std::bigInt(100); // → C++: php::Variant(new BigInt(100)) $b = std::decimal("100.50"); // → C++: php::Variant(new Decimal("100.50")) @@ -586,9 +583,11 @@ This restriction also applies to comparison operations. Before comparing, both s Big* types are a proprietary feature of the AOT compiler, relying on compile-time code generation and C++ underlying libraries. The source code cannot be directly interpreted and executed by the `php` command. -### 12.8 Enabling `use native_types` +### 12.8 No file-level opt-in required -Forgetting to add `use native_types` causes Big* variables to be treated as Var (generic type), losing most of the performance advantages of native types. +Big* constructors determine their result type directly. No file-level native +type declaration is required. `use varint_types` affects only inferred ordinary +integers and does not change BigInt, Decimal, or BigFloat storage. --- @@ -598,8 +597,6 @@ Forgetting to add `use native_types` causes Big* variables to be treated as Var ```php prop)` and assigning `null` on fixed-va ```php **Note**: native-type variables **do not change their own type** during operations. For example, `Int += Float` executes `int64_t += double` in C++, and the result is truncated to int64_t, which differs from PHP behavior (in PHP the variable becomes float). This is intentional semantics of `use native_types`. +> **Note**: native variables **do not change storage type** during operations. +> For example, `Int += Float` remains Int. This fixed-type behavior is now the +> default; choose `use varint_types` or `std::any()` when dynamic integer +> widening is required. ### Rule 3: Safe Promotion of High-Precision Types @@ -560,15 +574,15 @@ When the operands include `BigInt`, `Decimal`, or `BigFloat`, only explicit and Compound assignment operators such as `+=`, `-=`, `*=`, `/=`, `%=` follow the same type promotion rules, but the RHS is converted to the type of the LHS variable. If the LHS is Var, the RHS keeps its original type (Var's `operator+=` takes over); if the LHS is a native type, the RHS is explicitly converted to that type. ```php -$a = 10; // Var +use varint_types; +$a = 10; // Var because this file selected varint_types $a += 2.5; // Var::operator+=(float) → ZendVM → $a becomes float(12.5) -use native_types; -$b = 10; // php::Int +$b = std::int(10); // Explicit php::Int inside a varint_types file $b += 2.5; // int64_t += double → C++ implicit truncation → $b = 12 (Int) ``` --- -**Last updated**: May 26, 2026 -**Applicable version**: PHP AOT Compiler v1.x +**Last updated**: September 6, 2026 +**Applicable version**: TypePHP 0.8+ diff --git a/docs/en/PHP_INCOMPATIBILITY_CLASSIFICATION.md b/docs/en/PHP_INCOMPATIBILITY_CLASSIFICATION.md index 0f6145a2..62aba3b0 100644 --- a/docs/en/PHP_INCOMPATIBILITY_CLASSIFICATION.md +++ b/docs/en/PHP_INCOMPATIBILITY_CLASSIFICATION.md @@ -66,7 +66,7 @@ These items should be documented with the exact boundary. | Binary mode requires global `main()` | Intentional Rule | This defines the binary entry ABI. | | `main()` only accepts no parameters or `(int $argc, array $argv)` | Intentional Rule | Keeps the entry ABI explicit and stable. | | `main()` must return `void` | Intentional Rule | An integer exit-code convention could be added later, but current TypePHP rules reject return values. | -| `declare(strict_types=...)` only supports `strict_types=1` | Intentional Rule | Supporting mixed strict/weak typing is possible, but TypePHP keeps strict behavior predictable. | +| TypePHP is always strict; `strict_types=0` is rejected | Intentional Rule | Per-file weak typing conflicts with TypePHP's fixed storage and static type guarantees. `strict_types=1` remains accepted as a redundant compatibility directive. | | Default parameter before required parameter | Intentional Rule | PHP allows this legacy pattern but ignores the default. TypePHP rejects it to avoid misleading declarations. | | Child class overriding parent private property | Intentional Rule / Pending if dynamicized | PHP stores private properties by declaring class. TypePHP native/fixed layouts make this expensive. Rejecting it keeps property layout predictable. | | `__construct()` return value | Intentional Rule | PHP constructors should not return values. TypePHP rejects this explicitly. | diff --git a/docs/en/STD_CONTAINERS.md b/docs/en/STD_CONTAINERS.md index 146ff9f5..8438918a 100644 --- a/docs/en/STD_CONTAINERS.md +++ b/docs/en/STD_CONTAINERS.md @@ -511,8 +511,6 @@ sec: 67.638107061386108 ### std::array Test code: ```php -use native_types; - function main(int $argc, array $argv): void { $u = (int)$argv[2]; diff --git a/docs/en/UNIVERSAL_METHODS.md b/docs/en/UNIVERSAL_METHODS.md index f75290cb..ebb74210 100644 --- a/docs/en/UNIVERSAL_METHODS.md +++ b/docs/en/UNIVERSAL_METHODS.md @@ -917,8 +917,6 @@ Format: `{type_prefix}_{snake_case_method_name}` ```php Hello World! \n"; @@ -998,8 +994,6 @@ function main(): void { ```php **提示**:和所有 native_types 一样,Big* 类型只能在 AOT 编译模式下使用,不能在普通 PHP 解释器中运行。AOT 编译器会对 `std::bigInt()` 等函数进行编译期求值,直接生成 C++ 代码。 +> **提示**:Big* 类型只能在 AOT 编译模式下使用,不能在普通 PHP 解释器中运行。 +> 编译器会识别 `std::bigInt()` 等函数并直接生成 C++ 代码。 --- @@ -133,11 +131,9 @@ $g = std::bigFloat("3.14159265358979323846"); // 从字符串(精 ### 4.2 类型标注 -在 `use native_types` 下,Big* 类型变量自动获得原生 C++ 存储类型: +Big* 构造函数始终产生对应的专用 C++ 装箱存储类型: ```php -use native_types; - // 编译器自动推断类型为 php::BigInt / php::Decimal / php::BigFloat $a = std::bigInt(100); // → C++: php::Variant(new BigInt(100)) $b = std::decimal("100.50"); // → C++: php::Variant(new Decimal("100.50")) @@ -586,9 +582,10 @@ $c = $a + std::bigFloat($b->toString()); // ✅ Big* 类型是 AOT 编译器的专有特性,依赖编译期代码生成和 C++ 底层库。源码不能被 `php` 命令直接解释执行。 -### 12.8 启用 `use native_types` +### 12.8 无需文件级开关 -忘记添加 `use native_types` 会导致 Big* 变量被当作 Var(通用类型),失去原生类型的大部分性能优势。 +Big* 构造函数会直接确定结果类型,不需要文件级原生类型声明。`use varint_types` +只影响推断出的普通整数,不改变 BigInt、Decimal 或 BigFloat 的存储。 --- @@ -598,8 +595,6 @@ Big* 类型是 AOT 编译器的专有特性,依赖编译期代码生成和 C++ ```php **注意**:原生类型变量在运算中**不会改变自身类型**。如 `Int += Float` 在 C++ 中执行 `int64_t += double`,结果截断为 int64_t,与 PHP 行为不同(PHP 中变量会变为 float)。这是 `use native_types` 有意为之的语义。 +> **注意**:原生变量在运算中**不会改变存储类型**。例如 `Int += Float` 的结果仍是 +> Int。这种固定类型行为现在是默认规则;需要动态整数扩展时应显式选择 +> `use varint_types` 或 `std::any()`。 ### 规则三:高精度类型的安全提升 @@ -560,15 +570,15 @@ $f = $d + $e; // Int + Int → int64_t 加法 `+=`、`-=`、`*=`、`/=`、`%=` 等复合赋值运算符遵循相同的类型提升规则,但 RHS 会被转换为 LHS 变量的类型。若 LHS 为 Var,RHS 保持原类型(Var 的 `operator+=` 接管);若 LHS 为原生类型,RHS 显式转换为该类型。 ```php -$a = 10; // Var +use varint_types; +$a = 10; // 该文件启用 varint_types,因此为 Var $a += 2.5; // Var::operator+=(float) → ZendVM → $a 变为 float(12.5) -use native_types; -$b = 10; // php::Int +$b = std::int(10); // varint_types 文件中显式声明 php::Int $b += 2.5; // int64_t += double → C++ 隐式截断 → $b = 12 (Int) ``` --- -**最后更新**: 2026 年 5 月 26 日 -**适用版本**: PHP AOT Compiler v1.x +**最后更新**: 2026 年 9 月 6 日 +**适用版本**: TypePHP 0.8+ diff --git a/docs/zh-cn/STD_CONTAINERS.md b/docs/zh-cn/STD_CONTAINERS.md index 50fd3592..75303383 100644 --- a/docs/zh-cn/STD_CONTAINERS.md +++ b/docs/zh-cn/STD_CONTAINERS.md @@ -510,8 +510,6 @@ sec: 67.638107061386108 ### std::array 测试代码: ```php -use native_types; - function main(int $argc, array $argv): void { $u = (int)$argv[2]; diff --git a/docs/zh-cn/UNIVERSAL_METHODS.md b/docs/zh-cn/UNIVERSAL_METHODS.md index 34ce4814..cc368c01 100644 --- a/docs/zh-cn/UNIVERSAL_METHODS.md +++ b/docs/zh-cn/UNIVERSAL_METHODS.md @@ -917,8 +917,6 @@ echo $x->contains("test"); ```php Hello World! \n"; @@ -998,8 +994,6 @@ function main(): void { ```php toArray(); +} diff --git a/phpunit/code/fixed-reference-generic-object.php b/phpunit/code/fixed-reference-generic-object.php new file mode 100644 index 00000000..dfc3769d --- /dev/null +++ b/phpunit/code/fixed-reference-generic-object.php @@ -0,0 +1,13 @@ +toRef()); +} diff --git a/phpunit/code/override_byref_return_added.php b/phpunit/code/override_byref_return_added.php index dc0c5883..1cd5b659 100644 --- a/phpunit/code/override_byref_return_added.php +++ b/phpunit/code/override_byref_return_added.php @@ -11,7 +11,8 @@ class B extends A { public function &f(): array { - static $a = []; + static $a; + $a ??= []; return $a; } } diff --git a/phpunit/code/override_byref_return_dropped.php b/phpunit/code/override_byref_return_dropped.php index b2acb90e..00b6c020 100644 --- a/phpunit/code/override_byref_return_dropped.php +++ b/phpunit/code/override_byref_return_dropped.php @@ -3,7 +3,8 @@ class A { public function &f(): array { - static $a = []; + static $a; + $a ??= []; return $a; } } diff --git a/phpunit/code/preprocessor/namespace_ending_comment_unbracketed.php b/phpunit/code/preprocessor/namespace_ending_comment_unbracketed.php index 7ad8b333..13a3233c 100644 --- a/phpunit/code/preprocessor/namespace_ending_comment_unbracketed.php +++ b/phpunit/code/preprocessor/namespace_ending_comment_unbracketed.php @@ -1,6 +1,5 @@ exec("declare(strict_types=0) is not allowed, only strict_types=1 is supported", 'declare-strict-types-zero.php'); + $this->exec("TypePHP always uses strict types; declare(strict_types=0) is not allowed", 'declare-strict-types-zero.php'); } /** @dataProvider nativeScalarArrayDimWriteProvider */ diff --git a/phpunit/src/ExitCodeTest.php b/phpunit/src/ExitCodeTest.php index cd54fec1..7d5dfbfd 100644 --- a/phpunit/src/ExitCodeTest.php +++ b/phpunit/src/ExitCodeTest.php @@ -35,7 +35,6 @@ class ExitCodeTest extends TestCase $exitCode = $this->buildAndRun(<<<'PHP' buildAndRun(<<<'PHP' buildAndRun(<<<'PHP' buildAndRun(<<<'PHP' expectException(TestError::class); + $this->expectExceptionMessage('of fixed type ' . $type . '; initialize it with std::any()'); + + $this->compileFixture($fixture); + } + + public static function fixedStorageProvider(): iterable + { + yield 'string' => ['fixed-reference-string.php', 'php::Str']; + yield 'array' => ['fixed-reference-array.php', 'php::Array']; + yield 'object' => ['fixed-reference-generic-object.php', 'php::Object']; + yield 'typed object' => ['fixed-reference-object.php', 'php::Object']; + yield 'stream' => ['fixed-reference-stream.php', 'php::Stream']; + yield 'std container' => ['fixed-reference-std-container.php', 'php::StdVector']; + } + + public function testFixedStorageCannotBePassedToKnownReferenceParameter(): void + { + $this->expectException(TestError::class); + $this->expectExceptionMessage('variable $value of fixed type php::Str'); + + $this->compileFixture('fixed-reference-argument.php'); + } + + public function testFixedStorageCannotBeUsedAsReferenceAssignmentSource(): void + { + $this->expectException(TestError::class); + $this->expectExceptionMessage('variable $value of fixed type php::Array'); + + $this->compileFixture('fixed-reference-assignment.php'); + } + + public function testFixedStorageCannotBeReturnedByReference(): void + { + $this->expectException(TestError::class); + $this->expectExceptionMessage('variable $value of fixed type php::Str'); + + $this->compileFixture('fixed-reference-return.php'); + } + + public function testFixedStaticStorageCannotBeCapturedByReference(): void + { + $this->expectException(TestError::class); + $this->expectExceptionMessage('variable $value of fixed type php::Str'); + + $this->compileFixture('fixed-reference-static.php'); + } + + public function testFixedStorageCannotUseToRefKeyword(): void + { + $this->expectException(TestError::class); + $this->expectExceptionMessage('variable $value of fixed type php::Array'); + + $this->compileFixture('fixed-reference-to-ref.php'); + } + + public function testExplicitAnyCanUseReferenceStorage(): void + { + $code = $this->compileFixture('fixed-reference-explicit-any.php'); + + self::assertStringContainsString('php::Var value', $code); + self::assertStringContainsString('value.toReference()', $code); + } + + private function compileFixture(string $fixture): string + { + global $translator; + $compiler = CompilerTest::create(TYPEPHP_ROOT_PATH); + $translator = $compiler; + $source = TYPEPHP_ROOT_PATH . '/phpunit/code/' . $fixture; + $compiler->addFiles([$source]); + $compiler->prepareFile($source); + $generated = $compiler->convertFile($source); + $code = file_get_contents($generated); + self::assertIsString($code); + return $code; + } +} diff --git a/phpunit/src/NativeSlotZeroDivisorTest.php b/phpunit/src/NativeSlotZeroDivisorTest.php index a4a7adee..2dd5a5a2 100644 --- a/phpunit/src/NativeSlotZeroDivisorTest.php +++ b/phpunit/src/NativeSlotZeroDivisorTest.php @@ -3,7 +3,7 @@ /** * std::int()/std::float() opt into native C++ arithmetic, so a proven zero * divisor cannot be silently rerouted to PHP semantics; it keeps the - * compile-time rejection that native_types mode uses. + * compile-time rejection used by native scalar storage. */ class NativeSlotZeroDivisorTest extends BaseTest { diff --git a/phpunit/src/NegativeCompatibilityTest.php b/phpunit/src/NegativeCompatibilityTest.php index 0c4f5f00..6c93e789 100644 --- a/phpunit/src/NegativeCompatibilityTest.php +++ b/phpunit/src/NegativeCompatibilityTest.php @@ -405,7 +405,7 @@ PHP, yield 'disabled strict types declare' => [ 'convert', - 'declare(strict_types=0) is not allowed, only strict_types=1 is supported', + 'TypePHP always uses strict types; declare(strict_types=0) is not allowed', <<<'PHP' expectException(TestError::class); $this->expectExceptionMessage( - 'Cannot create a reference to native variable of type php::Bool; initialize it with std::any()', + 'Cannot create a reference to variable $changed of fixed type php::Bool; initialize it with std::any()', ); $this->compileSource( diff --git a/src/CompilerBase.php b/src/CompilerBase.php index 13830967..1527879c 100644 --- a/src/CompilerBase.php +++ b/src/CompilerBase.php @@ -2391,21 +2391,7 @@ class CompilerBase implements PropertyAccessContext if (!$this->hasVar($name)) { $this->errorUndefinedVariable($v->expr); } - if ($this->hasLocalVar($name) && $this->getVarType($name) !== Type::VAR && $this->getVarType($name) !== Type::REF) { - $isParameter = false; - foreach ($this->functionDef->argInfoList as $argInfo) { - if ($argInfo->name === $name) { - $isParameter = true; - break; - } - } - if ($isParameter) { - $this->fatalError($v, 'A function returning by reference cannot return a native typed parameter'); - } - // The declaration is emitted after parsing the body, so a local can - // be promoted to Variant before C++ is generated. - $this->context->localVars[$name] = Type::VAR; - } + $this->assertVariableReferenceStorage($v->expr, $v, $name); return 'return ' . $name . '.toReference();'; } if ($this->isPropertyFetch($v->expr)) { @@ -4398,6 +4384,7 @@ class CompilerBase implements PropertyAccessContext if ($op === self::OP_REFVAL) { $this->assertNativeArrayAccessReferenceForbidden($node); $this->assertNativeObjectReferenceForbidden($node, $node); + $this->assertVariableReferenceStorage($node, $node); } if ($node instanceof Expr\ArrayDimFetch && $this->isNativeObjectClass($this->detectClassOfExpr($node->var)) diff --git a/src/Generator/CallArgumentGenerator.php b/src/Generator/CallArgumentGenerator.php index 16476ae4..bfd14f6e 100644 --- a/src/Generator/CallArgumentGenerator.php +++ b/src/Generator/CallArgumentGenerator.php @@ -847,10 +847,7 @@ trait CallArgumentGenerator } elseif ($this->getVarType($name) === Type::REF) { return '&' . $name; } else { - // A local variable of native type is converted to a plain variable - if ($this->hasLocalVar($name) and $this->isNativeType($this->getVarType($name))) { - $this->context->localVars[$name] = Type::VAR; - } + $this->assertVariableReferenceStorage($arg->value, $arg, $name); // For a by-reference parameter, use a temporary variable as the reference // and replace the actual argument with it $tmpVar = $this->genTmpVarName(); diff --git a/src/Generator/ParameterCountCheckGenerator.php b/src/Generator/ParameterCountCheckGenerator.php index ea1c926c..7305cb17 100644 --- a/src/Generator/ParameterCountCheckGenerator.php +++ b/src/Generator/ParameterCountCheckGenerator.php @@ -1,5 +1,4 @@ parseAssignToList($item->value, $itemExpr) . PHP_EOL; } else { + // Destructuring is an indirect write form. It must not + // inherit the direct-assignment initialization exception + // for readonly properties. + $writeTarget = $item->value; + while ($writeTarget instanceof Expr\ArrayDimFetch) { + $writeTarget = $writeTarget->var; + } + if ($writeTarget instanceof Expr\PropertyFetch) { + $this->preparePropertyWriteTarget($writeTarget, false); + } // Route every destructuring target through the normal // assignment pipeline. Existing native locals remain // native and receive the usual scalar conversion, while @@ -1527,7 +1537,7 @@ trait AssignOpTrait $rightExpr = ''; if ($this->isVarExpr($expr->expr)) { - $rightExpr = $tmpVar . ' = ' . $this->parseIdentifier($expr->expr) . '.toReference()'; + $rightExpr = $tmpVar . ' = ' . $this->convertToRef($expr->expr); } elseif ($expr->expr instanceof Expr\FuncCall && $this->isNameExpr($expr->expr->name)) { $name = $this->parseIdentifier($expr->expr->name); $function = $this->findNativeFunction($name); diff --git a/src/Parser/BinaryOpTrait.php b/src/Parser/BinaryOpTrait.php index 89a6aca0..ab735c59 100644 --- a/src/Parser/BinaryOpTrait.php +++ b/src/Parser/BinaryOpTrait.php @@ -734,8 +734,8 @@ trait BinaryOpTrait || $this->usesNativeScalarStorage($type) ) { // Calls and nested binary operands are materialized to preserve - // PHP's left-to-right evaluation order. In native-types mode - // their scalar result has a fixed C++ representation, so + // PHP's left-to-right evaluation order. A statically native + // scalar result has a fixed C++ representation, so // boxing it in a Variant would add dynamic arithmetic and zval // lifetime work to otherwise native expressions. return $type; @@ -781,8 +781,8 @@ trait BinaryOpTrait // around a side effect is materialized for evaluation order, but its // lowered C++ form can still be dynamic — `-strlen($s)` on an // unqualified namespaced call lowers to `-(php::call(...))`, a - // Variant. Outside native-types mode the temporary must stay dynamic, - // matching the call and binary-op policy above. + // Variant. When its type is not statically fixed the temporary must + // stay dynamic, matching the call and binary-op policy above. return Type::VAR; } diff --git a/src/Parser/ForeachTrait.php b/src/Parser/ForeachTrait.php index a52d2ecc..be2a22f1 100644 --- a/src/Parser/ForeachTrait.php +++ b/src/Parser/ForeachTrait.php @@ -265,9 +265,4 @@ trait ForeachTrait return $code; } - /** - * For backward compatibility, native types are not used by default; integers and floats are treated as php variables. - * Native int/float/bool types do not support automatic conversion. For example, an int computation that exceeds its maximum value is promoted to float, and a division that does not divide evenly becomes float. - * In some cases high-performance computation may need native types; use `$a = std::int(0)` to explicitly opt into native types. - */ } diff --git a/src/Parser/TypeConversionTrait.php b/src/Parser/TypeConversionTrait.php index f61d2d0d..ce597f77 100644 --- a/src/Parser/TypeConversionTrait.php +++ b/src/Parser/TypeConversionTrait.php @@ -290,14 +290,43 @@ trait TypeConversionTrait return $this->emitStaticPropertyFetchRef($expr, $expr); } $var = $this->parseIdentifier($expr); - if ($this->isVarExpr($expr) and $this->isNativeTypeVar($var)) { - $this->fatalError( - $expr, - 'Cannot create a reference to native variable of type ' . $this->getVarType($var) - . '; initialize it with std::any() when reference semantics are required', - ); - } + $this->assertVariableReferenceStorage($expr, $expr, $var); return $var . '.toReference()'; } + /** + * PHP references are untyped zval aliases. Exposing fixed C++ storage as + * one would let dynamic code replace the value with an incompatible type. + * Only php::Var (or an existing php::Ref) has storage that can safely + * participate in Zend reference semantics. + */ + protected function assertVariableReferenceStorage( + NodeAbstract $expr, + NodeAbstract $errorNode, + ?string $name = null, + ): void { + if (!$this->isVarExpr($expr)) { + return; + } + + $name ??= $this->parseIdentifier($expr); + if (!$this->hasVar($name)) { + return; + } + + $type = $this->hasStaticVar($name) + ? $this->context->staticVars[$name] + : $this->getVarType($name); + if ($type === Type::VAR || $type === Type::REF) { + return; + } + + $this->fatalError( + $errorNode, + 'Cannot create a reference to variable $' . $this->unescapeVarName($name) + . ' of fixed type ' . $type + . '; initialize it with std::any() when reference semantics are required', + ); + } + } diff --git a/src/Testing/TestCoverageAnalyzer.php b/src/Testing/TestCoverageAnalyzer.php index fb896d63..27240b94 100644 --- a/src/Testing/TestCoverageAnalyzer.php +++ b/src/Testing/TestCoverageAnalyzer.php @@ -6,7 +6,6 @@ * @contact service@swoole.com */ -declare(strict_types=1); namespace TypePhp\Testing; diff --git a/src/Translator.php b/src/Translator.php index 53df8acc..e05e63e4 100644 --- a/src/Translator.php +++ b/src/Translator.php @@ -3260,7 +3260,7 @@ CODE; } } elseif ($key === 'strict_types') { if (!($declare->value instanceof Node\Scalar\Int_) or $declare->value->value !== 1) { - $this->fatalError($v, 'declare(strict_types=0) is not allowed, only strict_types=1 is supported'); + $this->fatalError($v, 'TypePHP always uses strict types; declare(strict_types=0) is not allowed'); } } else { $this->fatalError($v, 'declare(' . $key . '=' . $value . ') is not supported'); diff --git a/src/TypeSystem/NativeTypeCompatibilityTrait.php b/src/TypeSystem/NativeTypeCompatibilityTrait.php index 2ad17387..06f5b95e 100644 --- a/src/TypeSystem/NativeTypeCompatibilityTrait.php +++ b/src/TypeSystem/NativeTypeCompatibilityTrait.php @@ -265,7 +265,7 @@ trait NativeTypeCompatibilityTrait if (($type === Type::VAR || $type === Type::REF) && $this->isStrictScalarType($argInfo->type)) { // A native scalar ABI value has already lost its zval type. Preserve - // the dynamic value until strict_types validation has completed. + // the dynamic value until TypePHP's strict validation has completed. // The PHPX helper evaluates the expression exactly once and returns // the final native ABI type without an immediately-invoked closure. $this->checkVarAssignExpr($arg, $argInfo->type, $type); diff --git a/src/gen_stub.php b/src/gen_stub.php index 4b16bb10..ed2cda44 100755 --- a/src/gen_stub.php +++ b/src/gen_stub.php @@ -1,5 +1,4 @@ 2, "row2" => 1, "row3" => 1); - $ar2 = array("row1" => 2, "row2" => "aa", "row3" => "1"); + $ar1 = std::any(array("row1" => 2, "row2" => 1, "row3" => 1)); + $ar2 = std::any(array("row1" => 2, "row2" => "aa", "row3" => "1")); echo "\n-- Testing array_multisort() function with all normal arguments --\n"; var_dump(array_multisort($ar1, SORT_ASC, SORT_REGULAR, $ar2, SORT_DESC, SORT_STRING) ); @@ -29,4 +29,4 @@ array(3) { string(1) "1" ["row1"]=> int(2) -} \ No newline at end of file +} diff --git a/tests/compiler/array/array-push-empty-unpack.phpt b/tests/compiler/array/array-push-empty-unpack.phpt index 670c2441..a2106a7f 100644 --- a/tests/compiler/array/array-push-empty-unpack.phpt +++ b/tests/compiler/array/array-push-empty-unpack.phpt @@ -6,7 +6,7 @@ array_push retains its required array argument when an unpacked list is empty function main(): void { // Keep the required by-reference argument before an empty unpack. - $values = []; + $values = std::any([]); array_push($values, ...[]); var_dump($values); diff --git a/tests/compiler/array/complex_array_operations.phpt b/tests/compiler/array/complex_array_operations.phpt index f6958186..2185dde7 100644 --- a/tests/compiler/array/complex_array_operations.phpt +++ b/tests/compiler/array/complex_array_operations.phpt @@ -114,7 +114,7 @@ function main() { var_dump($assoc['first']); // 110 // Test with array references - $original = ['value' => 50]; + $original = std::any(['value' => 50]); $xref =& $original; $xref['value'] += 25; var_dump($original['value']); // 75 diff --git a/tests/compiler/array/compound-offset-evaluated-once.phpt b/tests/compiler/array/compound-offset-evaluated-once.phpt index d2039286..1d3e0a99 100644 --- a/tests/compiler/array/compound-offset-evaluated-once.phpt +++ b/tests/compiler/array/compound-offset-evaluated-once.phpt @@ -2,7 +2,6 @@ Array compound assignment evaluates a side-effecting offset once --FILE-- 10, 'b0' => 20]; $interpolatedResult = ($interpolatedValues["{$offsetPart}0"] += changeCompoundOffsetPart($offsetPart)); diff --git a/tests/compiler/array/compound-overflow.phpt b/tests/compiler/array/compound-overflow.phpt index 70c41575..57e3e7a6 100644 --- a/tests/compiler/array/compound-overflow.phpt +++ b/tests/compiler/array/compound-overflow.phpt @@ -2,7 +2,6 @@ Array element compound arithmetic promotes overflowing integers to float --FILE-- property}"])); // A by-reference item binds the source variable instead of reading it. - $ref = 1; + $ref = std::any(1); var_dump(count([&$ref])); // A defined class constant is still evaluated, not discarded. diff --git a/tests/compiler/array/multi-return-forward-args.phpt b/tests/compiler/array/multi-return-forward-args.phpt index b62d2645..7ed8080b 100644 --- a/tests/compiler/array/multi-return-forward-args.phpt +++ b/tests/compiler/array/multi-return-forward-args.phpt @@ -26,7 +26,7 @@ function multi_return_forward_defaults( function main(): void { $object = (object) ['name' => 'direct']; - $directReference = 'before'; + $directReference = std::any('before'); [$value, $text, $items, $directObject, $count, $returnedReference, $rest] = multi_return_forward_args('value', 'text', [1], $object, 2, $directReference, 'x'); var_dump( @@ -40,7 +40,7 @@ function main(): void $rest, ); - $arrayReference = 'before'; + $arrayReference = std::any('before'); $array = multi_return_forward_args('array', 'adapter', [3], $object, 4, $arrayReference, 'y', 'z'); var_dump($arrayReference, $array[0], $array[1], $array[2], $array[3]->name, $array[4], $array[5], $array[6]); diff --git a/tests/compiler/array/multi-return-move-production.phpt b/tests/compiler/array/multi-return-move-production.phpt index 09190ffb..c129e5c5 100644 --- a/tests/compiler/array/multi-return-move-production.phpt +++ b/tests/compiler/array/multi-return-move-production.phpt @@ -48,7 +48,7 @@ function main(): void $first[] = 'changed'; var_dump($first, $second, $tail); - $source = 'reference'; + $source = std::any('reference'); [$referenceFirst, $referenceSecond] = multi_return_reference_value($source); $referenceFirst = 'changed'; var_dump($source, $referenceFirst, $referenceSecond); diff --git a/tests/compiler/array_method/method.phpt b/tests/compiler/array_method/method.phpt index a39b38a6..b3bb1917 100644 --- a/tests/compiler/array_method/method.phpt +++ b/tests/compiler/array_method/method.phpt @@ -140,35 +140,35 @@ function main() Assert::true($array->isEmpty()); $fruits1 = array("lemon", "orange", "banana", "apple"); - $fruits2 = array("lemon", "orange", "banana", "apple"); + $fruits2 = std::any(array("lemon", "orange", "banana", "apple")); sort($fruits2); Assert::eq($fruits1->sort(), $fruits2); Assert::eq($fruits1, $fruits2); - $stack = array("orange", "banana", "apple", "raspberry"); + $stack = std::any(array("orange", "banana", "apple", "raspberry")); Assert::eq($stack->pop(), 'raspberry'); Assert::eq(array_pop($stack), 'apple'); - $array = array("red","green"); - $array->push("blue"); - Assert::eq($array, ["red","green", "blue"]); - array_push($array, "yellow"); - Assert::eq($array, ["red","green", "blue", "yellow"]); + $mutableArray = std::any(array("red","green")); + $mutableArray->push("blue"); + Assert::eq($mutableArray, ["red","green", "blue"]); + array_push($mutableArray, "yellow"); + Assert::eq($mutableArray, ["red","green", "blue", "yellow"]); - $stack = array("orange", "banana", "apple", "raspberry"); + $stack = std::any(array("orange", "banana", "apple", "raspberry")); Assert::eq($stack->shift(), 'orange'); Assert::eq(array_shift($stack), 'banana'); - $queue = ["orange", "banana"]; + $queue = std::any(["orange", "banana"]); $queue->unshift("orange"); Assert::eq($queue, ["orange", "orange", "banana"]); array_unshift($queue, "orange"); Assert::eq($queue, ["orange", "orange", "orange", "banana"]); $array1 = array("red", "green", "blue", "yellow"); - $array2 = array("red", "green", "blue", "yellow"); - Assert::eq($array1->splice(2), array_splice($array2, 2)); - Assert::eq($array1, $array2); + $spliceArray = std::any(array("red", "green", "blue", "yellow")); + Assert::eq($array1->splice(2), array_splice($spliceArray, 2)); + Assert::eq($array1, $spliceArray); $find = array("Hello","world"); $replace = array("B"); diff --git a/tests/compiler/attribute/immutable.phpt b/tests/compiler/attribute/immutable.phpt index c0476655..e20f564d 100644 --- a/tests/compiler/attribute/immutable.phpt +++ b/tests/compiler/attribute/immutable.phpt @@ -118,7 +118,8 @@ function main(): void echo $user->traitName(), PHP_EOL; echo sumImmutable([2, 3]), PHP_EOL; echo cloneImmutable($user), PHP_EOL; - echo inspectImmutableReference($user), PHP_EOL; + $referenceUser = std::any($user); + echo inspectImmutableReference($referenceUser), PHP_EOL; echo deliberatelyEscapeImmutableCheck($user), PHP_EOL; echo (new ImmutableHookedValue())->read(), PHP_EOL; echo closureImmutableParameter($user), PHP_EOL; diff --git a/tests/compiler/basic/clone-with-references.phpt b/tests/compiler/basic/clone-with-references.phpt index ca54d127..62ef4417 100644 --- a/tests/compiler/basic/clone-with-references.phpt +++ b/tests/compiler/basic/clone-with-references.phpt @@ -12,7 +12,7 @@ if (PHP_VERSION_ID < 80500) { function main(): void { $source = new stdClass(); - $value = 'reference'; + $value = std::any('reference'); $updates = ['value' => &$value]; try { diff --git a/tests/compiler/basic/json-exception-boundary.phpt b/tests/compiler/basic/json-exception-boundary.phpt index 9e56b43b..93902ee8 100644 --- a/tests/compiler/basic/json-exception-boundary.phpt +++ b/tests/compiler/basic/json-exception-boundary.phpt @@ -12,7 +12,7 @@ function main(): void echo "decode-caught\n"; } - $recursive = []; + $recursive = std::any([]); $recursive['self'] = &$recursive; try { json_encode($recursive, JSON_THROW_ON_ERROR); diff --git a/tests/compiler/basic/std_builtin.phpt b/tests/compiler/basic/std_builtin.phpt index a07a1483..9dcc33cf 100644 --- a/tests/compiler/basic/std_builtin.phpt +++ b/tests/compiler/basic/std_builtin.phpt @@ -2,7 +2,6 @@ std::bigInt() and std::decimal() builtin functions --FILE-- >, <<=, >>=, bitShiftLeft, bitShiftRight) --FILE-- toString(); diff --git a/tests/compiler/bigint/math_func_opt.phpt b/tests/compiler/bigint/math_func_opt.phpt index 6663433e..5b7ddedd 100644 --- a/tests/compiler/bigint/math_func_opt.phpt +++ b/tests/compiler/bigint/math_func_opt.phpt @@ -2,7 +2,6 @@ Big* types: math function optimization (abs/pow/sqrt/floor/ceil/round) --FILE-- toString(), "\n"; diff --git a/tests/compiler/bigint/powmod.phpt b/tests/compiler/bigint/powmod.phpt index 4ea681b6..84fd1898 100644 --- a/tests/compiler/bigint/powmod.phpt +++ b/tests/compiler/bigint/powmod.phpt @@ -2,7 +2,6 @@ BigInt: powmod --FILE-- sqrt()->toString(); echo "\n"; diff --git a/tests/compiler/bigint/toInt_toFloat.phpt b/tests/compiler/bigint/toInt_toFloat.phpt index 4827ed68..58e10ec8 100644 --- a/tests/compiler/bigint/toInt_toFloat.phpt +++ b/tests/compiler/bigint/toInt_toFloat.phpt @@ -2,7 +2,6 @@ BigInt: toInt / toFloat --FILE-- toInt()); diff --git a/tests/compiler/bigint/toString_cast.phpt b/tests/compiler/bigint/toString_cast.phpt index a835c398..b646c83a 100644 --- a/tests/compiler/bigint/toString_cast.phpt +++ b/tests/compiler/bigint/toString_cast.phpt @@ -2,7 +2,6 @@ Big* types: (string) cast, strval() and echo → toString() --FILE-- , <=, >=, ==, !=, <=>) --FILE-- , <=, >=, ==, !=, <=>) --FILE-- toString(), "\n"; diff --git a/tests/compiler/callable/misc.phpt b/tests/compiler/callable/misc.phpt index 4aaa361f..0f04678e 100644 --- a/tests/compiler/callable/misc.phpt +++ b/tests/compiler/callable/misc.phpt @@ -48,7 +48,7 @@ function main() { var_dump($squared); // Test callable with usort - $unsorted = [5, 2, 8, 1, 9]; + $unsorted = std::any([5, 2, 8, 1, 9]); usort($unsorted, fn($a, $b) => $a <=> $b); var_dump($unsorted); } diff --git a/tests/compiler/class/abstract-method-byref-defined-var.phpt b/tests/compiler/class/abstract-method-byref-defined-var.phpt index c753ffda..d6dfc332 100644 --- a/tests/compiler/class/abstract-method-byref-defined-var.phpt +++ b/tests/compiler/class/abstract-method-byref-defined-var.phpt @@ -9,7 +9,7 @@ namespace { public function run() { - $v = 0; + $v = std::any(0); $this->abc($v); var_dump($v); } diff --git a/tests/compiler/class/abstract-method-byref-multi-param.phpt b/tests/compiler/class/abstract-method-byref-multi-param.phpt index 9023cc2d..c513bf11 100644 --- a/tests/compiler/class/abstract-method-byref-multi-param.phpt +++ b/tests/compiler/class/abstract-method-byref-multi-param.phpt @@ -9,7 +9,7 @@ namespace { public function run() { - $x = 5; + $x = std::any(5); // $x 已定义;$y 未定义,按引用传参后由实现类赋值 $this->abc($x, $y); var_dump($x, $y); diff --git a/tests/compiler/class/get-called-class.phpt b/tests/compiler/class/get-called-class.phpt index 0665b9b3..9388df39 100644 --- a/tests/compiler/class/get-called-class.phpt +++ b/tests/compiler/class/get-called-class.phpt @@ -2,7 +2,6 @@ static::class uses the runtime called scope --FILE-- ++$value; - $number = 40; + $number = std::any(40); var_dump($arrow(std::ref($number)), $number); $typed = static function (int &$value): void { diff --git a/tests/compiler/closure/closure-002.phpt b/tests/compiler/closure/closure-002.phpt index a934cf0b..6612f8bd 100644 --- a/tests/compiler/closure/closure-002.phpt +++ b/tests/compiler/closure/closure-002.phpt @@ -5,7 +5,7 @@ closure 001 function main() { $a = 100; - $b = [1, 2, 3]; + $b = std::any([1, 2, 3]); $fn = function ($x) use ($a, &$b) { var_dump($a); var_dump($b); @@ -35,4 +35,3 @@ array(3) { [2]=> int(6) } - diff --git a/tests/compiler/closure/closure-use-ref-composed.phpt b/tests/compiler/closure/closure-use-ref-composed.phpt index ba7bd4dd..24776e0c 100644 --- a/tests/compiler/closure/closure-use-ref-composed.phpt +++ b/tests/compiler/closure/closure-use-ref-composed.phpt @@ -4,8 +4,8 @@ closure use by reference should work with nested control flow data); diff --git a/tests/compiler/coalesce/assign-coalesce-compound-rhs-side-effect.phpt b/tests/compiler/coalesce/assign-coalesce-compound-rhs-side-effect.phpt index cce33885..16a7e74a 100644 --- a/tests/compiler/coalesce/assign-coalesce-compound-rhs-side-effect.phpt +++ b/tests/compiler/coalesce/assign-coalesce-compound-rhs-side-effect.phpt @@ -2,7 +2,6 @@ ??= does not evaluate a compound side-effecting RHS when the target is set --FILE-- ceil()->toString()); diff --git a/tests/compiler/decimal/compare.phpt b/tests/compiler/decimal/compare.phpt index d92bfc20..f03514e4 100644 --- a/tests/compiler/decimal/compare.phpt +++ b/tests/compiler/decimal/compare.phpt @@ -2,7 +2,6 @@ Decimal comparison and conversions --FILE-- floor()->toString()); diff --git a/tests/compiler/decimal/operator.phpt b/tests/compiler/decimal/operator.phpt index 364a190e..c3981409 100644 --- a/tests/compiler/decimal/operator.phpt +++ b/tests/compiler/decimal/operator.phpt @@ -2,7 +2,6 @@ Decimal operator overloading (+, -, *, /, %) and comparisons --FILE-- pow(std::decimal("3"))->toString()); diff --git a/tests/compiler/decimal/powmod.phpt b/tests/compiler/decimal/powmod.phpt index 8316b9c1..4fbb145c 100644 --- a/tests/compiler/decimal/powmod.phpt +++ b/tests/compiler/decimal/powmod.phpt @@ -2,7 +2,6 @@ Decimal: powmod --FILE-- toString(), "\n"; diff --git a/tests/compiler/decimal/round.phpt b/tests/compiler/decimal/round.phpt index 902b0618..09b1dcf9 100644 --- a/tests/compiler/decimal/round.phpt +++ b/tests/compiler/decimal/round.phpt @@ -2,7 +2,6 @@ Decimal: round --FILE-- sqrt()->toString()); diff --git a/tests/compiler/decimal/toFloat.phpt b/tests/compiler/decimal/toFloat.phpt index 54462bd4..7af3ffae 100644 --- a/tests/compiler/decimal/toFloat.phpt +++ b/tests/compiler/decimal/toFloat.phpt @@ -2,7 +2,6 @@ Decimal: toFloat --FILE-- toFloat()); diff --git a/tests/compiler/decimal/unary_minus.phpt b/tests/compiler/decimal/unary_minus.phpt index a5ab7151..603b37f1 100644 --- a/tests/compiler/decimal/unary_minus.phpt +++ b/tests/compiler/decimal/unary_minus.phpt @@ -2,7 +2,6 @@ Decimal unary minus operator --FILE-- id(), "\n"; var_dump($assigned === $original); @@ -67,7 +67,7 @@ function main(): void // control for the no-argument path fixed by this regression. echo ($withArgument = $original)->append('-arg'), "\n"; - $calls = 0; + $calls = std::any(0); echo ($created = makeAssignmentReceiver($calls, 'factory'))->id(), "\n"; var_dump($calls); echo $created->id(), "\n"; diff --git a/tests/compiler/dynamic_call/call-cache-arguments.phpt b/tests/compiler/dynamic_call/call-cache-arguments.phpt index 9db6dcb9..49f5a512 100644 --- a/tests/compiler/dynamic_call/call-cache-arguments.phpt +++ b/tests/compiler/dynamic_call/call-cache-arguments.phpt @@ -38,7 +38,7 @@ function main(): void var_dump($sum(...$arguments)); $increment = 'cached_increment'; - $value = 10; + $value = std::any(10); var_dump($increment(std::ref($value))); var_dump($value); diff --git a/tests/compiler/dynamic_call/call-magic-direct-safe.phpt b/tests/compiler/dynamic_call/call-magic-direct-safe.phpt index 6af2f38b..300a85aa 100644 --- a/tests/compiler/dynamic_call/call-magic-direct-safe.phpt +++ b/tests/compiler/dynamic_call/call-magic-direct-safe.phpt @@ -51,7 +51,7 @@ function main(): void // Zend constructs __call()'s argument array by value. A source reference // must not leak into that array, including on the direct compiled path. - $source = 'original'; + $source = std::any('original'); $reference = &$source; $mutating = new MutatingMagic(); var_dump($mutating->missing($reference)); diff --git a/tests/compiler/dynamic_call/call-parent-return-override-no-native-types.phpt b/tests/compiler/dynamic_call/call-parent-return-override-no-native-types.phpt index 423d0014..292e83b5 100644 --- a/tests/compiler/dynamic_call/call-parent-return-override-no-native-types.phpt +++ b/tests/compiler/dynamic_call/call-parent-return-override-no-native-types.phpt @@ -1,5 +1,5 @@ --TEST-- -call overridden method through parent parameter type without native_types +call overridden method through parent parameter type with default scalar types --FILE-- int(99) -} \ No newline at end of file +} diff --git a/tests/compiler/float_edge/decimal-literal-classification.phpt b/tests/compiler/float_edge/decimal-literal-classification.phpt index 41ecb2e5..93751666 100644 --- a/tests/compiler/float_edge/decimal-literal-classification.phpt +++ b/tests/compiler/float_edge/decimal-literal-classification.phpt @@ -2,7 +2,6 @@ Auto-Decimal literal classification: significant digits, hex, float mixing --FILE-- 'object']; $result = wrapper_argument_move('mixed', 'text', [10], $object, 5, $reference, 'x', 'y'); var_dump($reference, $result); diff --git a/tests/compiler/generator/closure-generator.phpt b/tests/compiler/generator/closure-generator.phpt index d4cb94a8..f4c92e1a 100644 --- a/tests/compiler/generator/closure-generator.phpt +++ b/tests/compiler/generator/closure-generator.phpt @@ -17,7 +17,7 @@ class GeneratorClosureBox function main(): void { - $state = 1; + $state = std::any(1); $factory = function (int $add) use (&$state): iterable { ++$state; $sent = yield 'closure' => $state + $add; diff --git a/tests/compiler/include_require/001.phpt b/tests/compiler/include_require/001.phpt index d30c8c2d..e6445b75 100644 --- a/tests/compiler/include_require/001.phpt +++ b/tests/compiler/include_require/001.phpt @@ -5,7 +5,6 @@ PHPRC=tests/compiler/include_require/no-leak.ini PHP_INI_SCAN_DIR={PWD}/empty-ini-dir --FILE-- toAny() / $b->toAny()); - $name = 'php '; + $name = std::any('php '); append_text($name->toRef(), 'keyword'); var_dump($name); @@ -38,11 +38,11 @@ function main(): void var_dump($obj->prop); $fn = 'set_value'; - $dynamic = 'old'; + $dynamic = std::any('old'); $fn($dynamic->toRef(), 'dynamic'); var_dump($dynamic); - $named = 'old'; + $named = std::any('old'); $fn = 'set_named'; $fn(label: 'named', value: $named->toRef()); var_dump($named); diff --git a/tests/compiler/loop/foreach-array-edge-cases.phpt b/tests/compiler/loop/foreach-array-edge-cases.phpt index 5344ff41..feec4e7e 100644 --- a/tests/compiler/loop/foreach-array-edge-cases.phpt +++ b/tests/compiler/loop/foreach-array-edge-cases.phpt @@ -38,7 +38,7 @@ function main(): void echo "unreachable\n"; } - $inner = 1; + $inner = std::any(1); $references = [&$inner]; foreach ($references as $value) { $value = 9; diff --git a/tests/compiler/loop/foreach-direct-array-targets.phpt b/tests/compiler/loop/foreach-direct-array-targets.phpt index d7382292..77f974c5 100644 --- a/tests/compiler/loop/foreach-direct-array-targets.phpt +++ b/tests/compiler/loop/foreach-direct-array-targets.phpt @@ -35,7 +35,7 @@ function main(): void var_dump(valuesOnly([10, 20])); var_dump(sameTarget([7 => 'last-value'])); - $source = 10; + $source = std::any(10); $values = [&$source]; foreach ($values as $value) { $value = 99; diff --git a/tests/compiler/magic_methods/indirect-update.phpt b/tests/compiler/magic_methods/indirect-update.phpt index 5c96bab9..eab7ce2c 100644 --- a/tests/compiler/magic_methods/indirect-update.phpt +++ b/tests/compiler/magic_methods/indirect-update.phpt @@ -2,7 +2,6 @@ Magic Methods - indirect property update uses __get by reference --FILE-- getCalls); // A parenthesized receiver is cacheable, but is still evaluated once. - $calls = 0; + $calls = std::any(0); namedPropertyReceiver($first, $calls)->value = 50; var_dump($calls, namedPropertyReceiver($first, $calls)->value, $calls); } diff --git a/tests/compiler/magic_methods/read-skips-isset.phpt b/tests/compiler/magic_methods/read-skips-isset.phpt index 7dba37ee..1d6a2472 100644 --- a/tests/compiler/magic_methods/read-skips-isset.phpt +++ b/tests/compiler/magic_methods/read-skips-isset.phpt @@ -2,7 +2,6 @@ Magic Methods - a plain property read invokes __get, never __isset --FILE-- child->value, 'direct argument'); var_dump($childReference); - $source = 'assigned reference'; + $source = std::any('assigned reference'); $object->value =& $source; $source = 'source changed'; var_dump($object->value); diff --git a/tests/compiler/nullsafe/nullsafe-chain-typed-return.phpt b/tests/compiler/nullsafe/nullsafe-chain-typed-return.phpt index 6c990e8a..2896884b 100644 --- a/tests/compiler/nullsafe/nullsafe-chain-typed-return.phpt +++ b/tests/compiler/nullsafe/nullsafe-chain-typed-return.phpt @@ -2,7 +2,6 @@ Nullsafe chain preserves typed method returns and member names --FILE-- write($name, 17); var_dump($writer->value()); - $calls = 0; + $calls = std::any(0); $writer->writeComputed($name, $calls); var_dump($writer->value(), $calls); - $source = 42; + $source = std::any(42); $writer->writeFromReference($name, $source); $source = 43; var_dump($writer->value(), $source); diff --git a/tests/compiler/object_property/int-property-compound-assignment.phpt b/tests/compiler/object_property/int-property-compound-assignment.phpt index aba96679..815e4d4b 100644 --- a/tests/compiler/object_property/int-property-compound-assignment.phpt +++ b/tests/compiler/object_property/int-property-compound-assignment.phpt @@ -2,7 +2,6 @@ Typed int property compound assignments use PHP arithmetic and checked writes --FILE-- value = 7; $result = nativeTypesIntCompoundReceiver($box, $receiverCalls)->value diff --git a/tests/compiler/object_property/property-array-write-composed-expr.phpt b/tests/compiler/object_property/property-array-write-composed-expr.phpt index 3f12b0b0..43faf2b1 100644 --- a/tests/compiler/object_property/property-array-write-composed-expr.phpt +++ b/tests/compiler/object_property/property-array-write-composed-expr.phpt @@ -25,7 +25,7 @@ function next_value(&$counter) { function main() { $box = new PropertyArrayWriteComposedBox(); - $counter = 0; + $counter = std::any(0); $a = ($box->node->items[] = next_value($counter)); $b = true ? ($box->node->items['k'] = next_value($counter)) : 99; diff --git a/tests/compiler/object_property/property-known-string-names.phpt b/tests/compiler/object_property/property-known-string-names.phpt index 339ddb4f..81f8b1a1 100644 --- a/tests/compiler/object_property/property-known-string-names.phpt +++ b/tests/compiler/object_property/property-known-string-names.phpt @@ -42,10 +42,10 @@ function main(): void var_dump($object->values()); $reflection = new ReflectionClass(KnownStringProperties::class); - $names = array_map( + $names = std::any(array_map( static fn (ReflectionProperty $property): string => $property->getName(), $reflection->getProperties(), - ); + )); sort($names); var_dump($names); } diff --git a/tests/compiler/operator/array-statement-write-optimized.phpt b/tests/compiler/operator/array-statement-write-optimized.phpt index ce8177b6..5a3fbd8b 100644 --- a/tests/compiler/operator/array-statement-write-optimized.phpt +++ b/tests/compiler/operator/array-statement-write-optimized.phpt @@ -2,7 +2,6 @@ Known array statement writes preserve references, keys and expression results --FILE-- 0 diff --git a/tests/compiler/operator/ternary-typed-arg.phpt b/tests/compiler/operator/ternary-typed-arg.phpt index efc0d508..3ceed3b4 100644 --- a/tests/compiler/operator/ternary-typed-arg.phpt +++ b/tests/compiler/operator/ternary-typed-arg.phpt @@ -2,7 +2,6 @@ Ternary with captured statements keeps its static type for typed arguments --FILE-- 1, '12' => 'numeric key', diff --git a/tests/compiler/place-holder/globals-null-arithmetic.phpt b/tests/compiler/place-holder/globals-null-arithmetic.phpt index de2ae550..a1b0db89 100644 --- a/tests/compiler/place-holder/globals-null-arithmetic.phpt +++ b/tests/compiler/place-holder/globals-null-arithmetic.phpt @@ -2,7 +2,6 @@ NULL globals in arithmetic should treat NULL as 0 --FILE-- int(5) -} \ No newline at end of file +} diff --git a/tests/compiler/ref/003.phpt b/tests/compiler/ref/003.phpt index c0bb7903..4eafa96e 100644 --- a/tests/compiler/ref/003.phpt +++ b/tests/compiler/ref/003.phpt @@ -4,7 +4,7 @@ ref 003 int(5) -} \ No newline at end of file +} diff --git a/tests/compiler/ref/004.phpt b/tests/compiler/ref/004.phpt index 37f6896c..413416de 100644 --- a/tests/compiler/ref/004.phpt +++ b/tests/compiler/ref/004.phpt @@ -5,7 +5,7 @@ ref 004 function main() { $a = [1, 2, 3]; - $b = [4, 5]; + $b = std::any([4, 5]); $a[] = &$b; var_dump($a); @@ -36,4 +36,4 @@ array(3) { int(5) [2]=> int(10) -} \ No newline at end of file +} diff --git a/tests/compiler/ref/007.phpt b/tests/compiler/ref/007.phpt index bc8f182c..0191e482 100644 --- a/tests/compiler/ref/007.phpt +++ b/tests/compiler/ref/007.phpt @@ -9,7 +9,7 @@ class WorkerA } public function baz(string $name) { - $value = ''; + $value = std::any(''); $this->foo($name, $value); return $value; } @@ -18,7 +18,7 @@ class WorkerA class WorkerB extends WorkerA { public function bar(string $name) { - $value = ''; + $value = std::any(''); $this->foo($name, $value); return $value; } @@ -35,4 +35,4 @@ function main() ?> --EXPECT-- string(9) "hello php" -string(12) "hello swoole" \ No newline at end of file +string(12) "hello swoole" diff --git a/tests/compiler/ref/008.phpt b/tests/compiler/ref/008.phpt index 4135787c..48de904e 100644 --- a/tests/compiler/ref/008.phpt +++ b/tests/compiler/ref/008.phpt @@ -5,7 +5,7 @@ class const 001 class WorkerA { public function foo(): array { - $list = [377, 64, 688, 2]; + $list = std::any([377, 64, 688, 2]); $ref = &$list; $this->sort($ref); return $list; @@ -32,4 +32,4 @@ array(4) { int(377) [3]=> int(688) -} \ No newline at end of file +} diff --git a/tests/compiler/ref/009.phpt b/tests/compiler/ref/009.phpt index 2b2ff674..c376688d 100644 --- a/tests/compiler/ref/009.phpt +++ b/tests/compiler/ref/009.phpt @@ -19,7 +19,7 @@ class WorkerA class WorkerB extends WorkerA { public function foo(): array { - $list = [377, 64, 688, 2]; + $list = std::any([377, 64, 688, 2]); $ref = &$list; $this->sort($ref); return $list; @@ -42,4 +42,4 @@ array(4) { int(377) [3]=> int(688) -} \ No newline at end of file +} diff --git a/tests/compiler/ref/array-ref-assign-002.phpt b/tests/compiler/ref/array-ref-assign-002.phpt index ac441ca0..5d8ca7b3 100644 --- a/tests/compiler/ref/array-ref-assign-002.phpt +++ b/tests/compiler/ref/array-ref-assign-002.phpt @@ -10,8 +10,8 @@ class RefSource function main() { - $x = 10; - $y = 20; + $x = std::any(10); + $y = std::any(20); $arr = [1, 2, 3]; $arr[0] = &$x; // 覆盖已有元素为引用 $arr[5] = &$y; // 新建元素为引用 @@ -25,7 +25,7 @@ function main() var_dump($x, $y); // 111, 222 // 嵌套:引用赋值到多维数组元素 - $z = 7; + $z = std::any(7); $m = [[1], [2]]; $m[0][0] = &$z; $z = 77; diff --git a/tests/compiler/ref/array-ref-assign-003.phpt b/tests/compiler/ref/array-ref-assign-003.phpt index 6e9f8ca4..0e42078f 100644 --- a/tests/compiler/ref/array-ref-assign-003.phpt +++ b/tests/compiler/ref/array-ref-assign-003.phpt @@ -14,13 +14,13 @@ function writeReferencedContainer(mixed &$container, mixed $value): void function main() { - $referenced = 10; + $referenced = std::any(10); $array = [&$referenced]; writeElement($array, 0, 123); var_dump($referenced, $array[0]); - $referencedAgain = 20; - $arrayByReference = [&$referencedAgain]; + $referencedAgain = std::any(20); + $arrayByReference = std::any([&$referencedAgain]); writeReferencedContainer($arrayByReference, 234); var_dump($referencedAgain, $arrayByReference[0]); diff --git a/tests/compiler/ref/array-value-write-dereferences-source.phpt b/tests/compiler/ref/array-value-write-dereferences-source.phpt index aa7669b2..229b3eef 100644 --- a/tests/compiler/ref/array-value-write-dereferences-source.phpt +++ b/tests/compiler/ref/array-value-write-dereferences-source.phpt @@ -5,7 +5,7 @@ ordinary array writes copy referenced sources while explicit references stay lin function main() { - $source = 1; + $source = std::any(1); $reference =& $source; $appended = []; @@ -21,9 +21,9 @@ function main() $reference = 2; var_dump($appended, $keyed, $literal, $mixedLiteral, $explicitReference); - $target = 10; + $target = std::any(10); $targetArray = [&$target]; - $other = 20; + $other = std::any(20); $otherReference =& $other; $targetArray[0] = $otherReference; $otherReference = 30; diff --git a/tests/compiler/ref/basic.phpt b/tests/compiler/ref/basic.phpt index 32457804..05c5f20f 100644 --- a/tests/compiler/ref/basic.phpt +++ b/tests/compiler/ref/basic.phpt @@ -6,7 +6,7 @@ function main() { require __DIR__ . '/../../../src/Assert.php'; - $a = [1, 2, 3]; + $a = std::any([1, 2, 3]); $b = &$a; $b[] = 5; @@ -17,7 +17,7 @@ function main() Assert::eq(count($b), 5); Assert::eq(count($c), 5); - $array = [1, 2, 3]; + $array = std::any([1, 2, 3]); $ref = &$array; $ref[1] = 2026; diff --git a/tests/compiler/ref/dynamic-return-reference-argument.phpt b/tests/compiler/ref/dynamic-return-reference-argument.phpt index aede4d2a..d69ead11 100644 --- a/tests/compiler/ref/dynamic-return-reference-argument.phpt +++ b/tests/compiler/ref/dynamic-return-reference-argument.phpt @@ -27,7 +27,8 @@ function &test1() function &test2() { - static $value = 0; + static $value; + $value ??= 0; ++$value; return $value; } @@ -40,7 +41,8 @@ function value_order(string $label): string function &ref_order(string $label) { - static $value = 42; + static $value; + $value ??= 42; echo "$label\n"; return $value; } diff --git a/tests/compiler/ref/dynamic-return-reference-chain.phpt b/tests/compiler/ref/dynamic-return-reference-chain.phpt index 60015aae..fabcb257 100644 --- a/tests/compiler/ref/dynamic-return-reference-chain.phpt +++ b/tests/compiler/ref/dynamic-return-reference-chain.phpt @@ -4,7 +4,8 @@ Reference-returning functions can forward dynamic and chained calls 42]; + }; + $replaceWithArray(); + $arrayValue = $stringValue->toArray(); + var_dump($arrayValue); + + $arraySource = std::any(['old']); + $replaceWithString = static function () use (&$arraySource): void { + $arraySource = 'done'; + }; + $replaceWithString(); + $finalString = $arraySource->toString(); + var_dump($finalString); +} +?> +--EXPECT-- +array(1) { + ["value"]=> + int(42) +} +string(4) "done" diff --git a/tests/compiler/ref/function-return-reference.phpt b/tests/compiler/ref/function-return-reference.phpt index 3836d2fa..d792d999 100644 --- a/tests/compiler/ref/function-return-reference.phpt +++ b/tests/compiler/ref/function-return-reference.phpt @@ -15,7 +15,7 @@ function value_copy() function main() { global $value; - $value = 1; + $value = std::any(1); $alias =& value_ref(); $alias = 42; var_dump(value_ref()); @@ -45,7 +45,7 @@ function main() function &local_ref() { - $value = 1; + $value = std::any(1); return $value; } ?> diff --git a/tests/compiler/ref/nested-reference-return.phpt b/tests/compiler/ref/nested-reference-return.phpt index f9985fd2..edcb44a8 100644 --- a/tests/compiler/ref/nested-reference-return.phpt +++ b/tests/compiler/ref/nested-reference-return.phpt @@ -25,10 +25,10 @@ function &object_property_ref(NestedReferenceBox $box): mixed function main(): void { - $values = [ + $values = std::any([ 'item' => 'before', 'outer' => ['inner' => 'nested-before'], - ]; + ]); $item =& array_element_ref($values); $item = 'after'; diff --git a/tests/compiler/ref/property-reference-rebind.phpt b/tests/compiler/ref/property-reference-rebind.phpt index 4308f434..27934301 100644 --- a/tests/compiler/ref/property-reference-rebind.phpt +++ b/tests/compiler/ref/property-reference-rebind.phpt @@ -2,7 +2,6 @@ Object property reference assignment preserves aliases and typed-property sources --FILE-- 1]; + $source = std::any(['initial' => 1]); $holder->value = &$source; $source['source'] = 2; $holder->value['property'] = 3; var_dump($source); $dynamicHolder = new PropertyReferenceHolder(); - $dynamicSource = []; + $dynamicSource = std::any([]); bindObjectProperty($dynamicHolder, $dynamicSource); $dynamicSource['dynamic'] = true; var_dump($dynamicHolder->value); - $wrong = 'invalid'; + $wrong = std::any('invalid'); try { bindObjectProperty($dynamicHolder, $wrong); echo "missing initial TypeError\n"; @@ -95,7 +94,7 @@ function main(): void $dynamicSource['preserved'] = true; var_dump($dynamicHolder->value); - $replacement = ['replacement' => true]; + $replacement = std::any(['replacement' => true]); $holder->value = &$replacement; replaceReference($source, 'detached'); var_dump($source); @@ -107,14 +106,14 @@ function main(): void } var_dump($holder->value); - $privateSource = []; + $privateSource = std::any([]); $privateHolder = new PrivatePropertyReferenceHolder(); $privateHolder->bind($privateSource); $privateSource['private'] = true; var_dump($privateHolder->value()); - $events = []; - $orderedSource = []; + $events = std::any([]); + $orderedSource = std::any([]); $orderedHolder = new PropertyReferenceHolder(); propertyReferenceTarget($events, $orderedHolder)->{propertyReferenceName($events)} = &propertyReferenceSource($events, $orderedSource); diff --git a/tests/compiler/ref/ref-closure-param.phpt b/tests/compiler/ref/ref-closure-param.phpt index 0e37e70f..b3668cd2 100644 --- a/tests/compiler/ref/ref-closure-param.phpt +++ b/tests/compiler/ref/ref-closure-param.phpt @@ -8,7 +8,7 @@ function main() $data .= " (_)"; }; $sweet = array('a' => 'apple', 'b' => 'banana'); - $fruits = array('sweet' => $sweet, 'sour' => 'lemon'); + $fruits = std::any(array('sweet' => $sweet, 'sour' => 'lemon')); array_walk_recursive($fruits, $testFn); var_dump($fruits); diff --git a/tests/compiler/ref/ref-func-param.phpt b/tests/compiler/ref/ref-func-param.phpt index a30aefa8..64cf7275 100644 --- a/tests/compiler/ref/ref-func-param.phpt +++ b/tests/compiler/ref/ref-func-param.phpt @@ -9,7 +9,7 @@ function test_fn(&$data) function main() { - $s = "foo"; + $s = std::any("foo"); test_fn($s); var_dump($s); } diff --git a/tests/compiler/ref/ref-object.phpt b/tests/compiler/ref/ref-object.phpt index a12b8fde..b576e36c 100644 --- a/tests/compiler/ref/ref-object.phpt +++ b/tests/compiler/ref/ref-object.phpt @@ -32,13 +32,13 @@ function test2(&$test) function main() { - $test = new Test(); + $test = std::any(new Test()); $testOrigin = $test; test1($test); var_dump($test !== $testOrigin); var_dump($testOrigin->value, $test->value); - $test = new Test(); + $test = std::any(new Test()); $testOrigin = $test; test2($test); var_dump($test !== $testOrigin); diff --git a/tests/compiler/ref/ref.phpt b/tests/compiler/ref/ref.phpt index 5b6714cd..bf0cd41c 100644 --- a/tests/compiler/ref/ref.phpt +++ b/tests/compiler/ref/ref.phpt @@ -4,7 +4,7 @@ object link operator mutate($value); diff --git a/tests/compiler/ref/std-any-ref.phpt b/tests/compiler/ref/std-any-ref.phpt index f712e2fd..4361f0ee 100644 --- a/tests/compiler/ref/std-any-ref.phpt +++ b/tests/compiler/ref/std-any-ref.phpt @@ -17,7 +17,7 @@ function main(): void $value = 'changed'; }; - $value = 'variable'; + $value = std::any('variable'); $replace(StD::ReF($value)); echo $value, "\n"; diff --git a/tests/compiler/ref/std-ref-static-method.phpt b/tests/compiler/ref/std-ref-static-method.phpt index bf14a556..3c7a1f48 100644 --- a/tests/compiler/ref/std-ref-static-method.phpt +++ b/tests/compiler/ref/std-ref-static-method.phpt @@ -7,7 +7,7 @@ function reference_test(&$name) { } function main() { - $name = 'php '; + $name = std::any('php '); reference_test(std::ref($name)); echo $name; } diff --git a/tests/compiler/ref/std-ref-variable.phpt b/tests/compiler/ref/std-ref-variable.phpt index 7a69792a..b48b2f05 100644 --- a/tests/compiler/ref/std-ref-variable.phpt +++ b/tests/compiler/ref/std-ref-variable.phpt @@ -6,7 +6,7 @@ function main() { eval('function reference_test(&$name) { $name .= "std::ref test"; }'); - $name = 'php '; + $name = std::any('php '); reference_test(std::ref($name)); echo $name; } diff --git a/tests/compiler/ref/unset.phpt b/tests/compiler/ref/unset.phpt index 6e27517f..3f8282b2 100644 --- a/tests/compiler/ref/unset.phpt +++ b/tests/compiler/ref/unset.phpt @@ -4,7 +4,7 @@ object link operator strict)); - $events = []; + $events = std::any([]); var_dump(array_keys( arrayKeysDynamicValues($events), arrayKeysDynamicFilter($events), diff --git a/tests/compiler/stdlib/array-slice-reverse-preserve-keys.phpt b/tests/compiler/stdlib/array-slice-reverse-preserve-keys.phpt index 2a536108..ece87b10 100644 --- a/tests/compiler/stdlib/array-slice-reverse-preserve-keys.phpt +++ b/tests/compiler/stdlib/array-slice-reverse-preserve-keys.phpt @@ -5,7 +5,7 @@ array_search keys with array_slice and array_reverse preserving keys function select_version_flags(array $flagsByVersions, int $minVersion, ?int $maxVersion): array { - ksort($flagsByVersions); + $flagsByVersions->keySort(); $index = array_search($minVersion, array_keys($flagsByVersions)); if ($index === false) { diff --git a/tests/compiler/stdlib/docblock-param-regex.phpt b/tests/compiler/stdlib/docblock-param-regex.phpt index 9b8e8fba..26aa2993 100644 --- a/tests/compiler/stdlib/docblock-param-regex.phpt +++ b/tests/compiler/stdlib/docblock-param-regex.phpt @@ -5,7 +5,6 @@ docblock param regex with recursive named groups function parse_doc_param_name(string $value): array { - $matches = []; preg_match('/^\s*(?[\w\|\\\\]+(?\((?(?:(?&parens)|[^(){}[\]<>]*+))++\)|\{(?&inparens)\}|\[(?&inparens)\]|<(?&inparens)>)*+(?::(?&type))?)\s*(\.\.\.)?\$(?\w+).*$/', $value, $matches); return [ diff --git a/tests/compiler/stdlib/null_optional_arg.phpt b/tests/compiler/stdlib/null_optional_arg.phpt index a007d2c0..ceea3866 100644 --- a/tests/compiler/stdlib/null_optional_arg.phpt +++ b/tests/compiler/stdlib/null_optional_arg.phpt @@ -2,7 +2,6 @@ Nullable and non-nullable builtin parameters preserve strict null semantics --FILE-- = 80400'])); var_dump(handle_preprocessor_conditions($conds, ['#else'])); var_dump(handle_preprocessor_conditions($conds, ['#endif', '#endif'])); diff --git a/tests/compiler/stdlib/repeatable-argv-parser.phpt b/tests/compiler/stdlib/repeatable-argv-parser.phpt index 17a93c12..fbe81660 100644 --- a/tests/compiler/stdlib/repeatable-argv-parser.phpt +++ b/tests/compiler/stdlib/repeatable-argv-parser.phpt @@ -16,7 +16,7 @@ function is_long_flag_with_equals(string $arg, array $flags, array &$values): bo function parse_repeatable_argv(array $argv, array $flags): array { - $values = []; + $values = std::any([]); for ($i = 1; $i < count($argv); $i++) { if (in_array($argv[$i], $flags, true) && isset($argv[$i + 1]) && $argv[$i + 1] !== '' && $argv[$i + 1][0] !== '-') { $values[] = $argv[$i + 1]; diff --git a/tests/compiler/stdlib/strict-builtin-typed-arguments.phpt b/tests/compiler/stdlib/strict-builtin-typed-arguments.phpt index f8e902f2..d80bbcdf 100644 --- a/tests/compiler/stdlib/strict-builtin-typed-arguments.phpt +++ b/tests/compiler/stdlib/strict-builtin-typed-arguments.phpt @@ -2,7 +2,6 @@ Optimized builtins preserve strict typed parameter validation --FILE-- update($value); var_dump($value); diff --git a/tests/compiler/type_decl/001.phpt b/tests/compiler/type_decl/001.phpt index f7279222..a29068df 100644 --- a/tests/compiler/type_decl/001.phpt +++ b/tests/compiler/type_decl/001.phpt @@ -2,7 +2,6 @@ Type Declarations - Strict and weak typing modes --FILE-- 'one', 'nested' => ['b' => 'two']]; - $second = 'three'; + $first = std::any(['a' => 'one', 'nested' => ['b' => 'two']]); + $second = std::any('three'); var_dump(convert_values('!', $first, $second)); var_dump($first, $second); - $invalid = ['ok', 42]; + $invalid = std::any(['ok', 42]); var_dump(convert_values('?', $invalid)); var_dump($invalid); } diff --git a/tests/compiler/variadic/by-reference-dynamic-explicit.phpt b/tests/compiler/variadic/by-reference-dynamic-explicit.phpt index 3413de9a..0c177ff9 100644 --- a/tests/compiler/variadic/by-reference-dynamic-explicit.phpt +++ b/tests/compiler/variadic/by-reference-dynamic-explicit.phpt @@ -25,14 +25,14 @@ class DynamicReferenceMutator function main(): void { $function = 'dynamic_increment'; - $number = 40; + $number = std::any(40); $function(std::ref($number)); var_dump($number); $mutator = new DynamicReferenceMutator(); $method = [$mutator, 'suffix']; - $first = 'one'; - $second = 'two'; + $first = std::any('one'); + $second = std::any('two'); $method('!', std::ref($first), std::ref($second)); var_dump($first, $second); diff --git a/tests/compiler/variadic/by-reference-inheritance.phpt b/tests/compiler/variadic/by-reference-inheritance.phpt index cde662bc..e18f002b 100644 --- a/tests/compiler/variadic/by-reference-inheritance.phpt +++ b/tests/compiler/variadic/by-reference-inheritance.phpt @@ -2,7 +2,6 @@ By-reference variadic signatures remain compatible across interfaces and inheritance --FILE-- increment($first, $second); var_dump($first, $second); } diff --git a/tests/compiler/variadic/by-reference-types.phpt b/tests/compiler/variadic/by-reference-types.phpt index a1e65e3c..87a994db 100644 --- a/tests/compiler/variadic/by-reference-types.phpt +++ b/tests/compiler/variadic/by-reference-types.phpt @@ -2,7 +2,6 @@ Typed by-reference variadics validate, widen float arguments and write through unions and objects --FILE-- value, $second->value); diff --git a/tests/compiler/variadic/by-reference-unpack.phpt b/tests/compiler/variadic/by-reference-unpack.phpt index d2775a1c..4a4eb4ff 100644 --- a/tests/compiler/variadic/by-reference-unpack.phpt +++ b/tests/compiler/variadic/by-reference-unpack.phpt @@ -28,7 +28,7 @@ function main(): void var_dump(increment_all(...$first, ...$second)); var_dump($first, $second); - $external = 60; + $external = std::any(60); $references = [&$external]; increment_all(...$references); var_dump($external, $references); diff --git a/tests/std/array/array_column_scalar_index_strict_types.phpt b/tests/std/array/array_column_scalar_index_strict_types.phpt index fbb4a641..6b81ef6f 100644 --- a/tests/std/array/array_column_scalar_index_strict_types.phpt +++ b/tests/std/array/array_column_scalar_index_strict_types.phpt @@ -4,7 +4,6 @@ Test array_column(): Index argument with various types in strict type mode --FILE-- --FILE--