An unpacked call carries a single Node\Arg regardless of its runtime
arity, so the arity check alone still accepted intval(...$args) as a
single-argument Native conversion and lowered the array itself:
intval(...['ff', 16]) // php::toInt(withBase) -> int(1)
strval(...['42']) // php::toString(single) -> "Array" + warning
A named argument has the same shape and need not be the value being
converted: intval(bogus: 1) must raise "Unknown named parameter", not
fold to a cast of 1.
Reject both in dispatchConversion() so the runtime determines the
expanded arity and the parameter names, matching what
dispatchFuncCall() already does for every other builtin.
The first whitelist was too broad. ConstFetch, ClassConstFetch and the
base Node\Scalar type all admit expressions PHP must still evaluate, so
count([UNDEFINED_COUNT_LITERAL]), count([KnownClass::MISSING]) and
count(["{$object->property}"]) folded to 1, dropping two Errors and a
__get() call. The defined-variable check was not a purity proof either:
hasVar() only reports a compiler slot, not that the variable is still
initialized on every path after unset().
Narrow the fold to items whose evaluation cannot be observed:
- literal Int_, Float_ and String_ (an interpolated string is a distinct
InterpolatedString node, so String_ already excludes it);
- the language constants true, false and null only;
- unary plus/minus over a literal int or float;
- recursively safe nested arrays.
Variables, general constant and class constant fetches, interpolated
strings and every other expression stay on the runtime path, and
by-reference items are now rejected explicitly alongside keys and
unpacking.
Cover the three reported cases plus a by-reference item, a plain
variable read and a defined class constant in both the fold-decision
test and the PHPT.
Consolidate float-to-C++ literal generation into Utils::genFloatLiteral().
Previously:
- genCValue() stringified floats directly via (string), emitting 'INF', '-INF', 'NAN', or losing the floating-point decimal point for whole numbers like 1.0 -> '1'.
- BinaryOpTrait::genFloatLiteral() used sprintf('%.17g') without handling INF or NAN.
Now all float code generation paths delegate to Utils::genFloatLiteral(), mapping INF/-INF/NAN to std::numeric_limits<double> and ensuring whole numbers retain .0.
The four scalar conversions are lowered to a single-argument Native cast
by dispatchConversion, which reads args[0] and ignores the rest. intval()
takes a $base as its second argument, so it was silently discarded:
intval("ff", 16); // php::toInt("ff") -> 0, PHP gives 255
intval("0x1A", 16); // php::toInt("0x1A") -> 0, PHP gives 26
intval("101", 2); // php::toInt("101") -> 101, PHP gives 5
Nothing reports the loss: the program compiles clean and the number is
simply wrong, which is easy to miss in the code that most often uses a
base - parsing hex colors, permission masks and binary flags.
A conversion call with any arity other than one now falls through to the
dynamic path, where both arguments are passed to the runtime function.
Single-argument intval(), strval(), floatval() and boolval() keep their
Native cast, so the common case is unchanged.
type_conv.phpt gains the base cases, with a literal and a variable base;
none of them were covered anywhere in the test suite. ConversionArityTest
pins the lowering decision in the generated C++.
doFoldKnownClass folds class_exists() whenever the name is a literal the
symbol table knows. That table also holds traits, so a trait name folded
to true while PHP answers false:
trait Helper {}
class_exists('Helper'); // folded to true
$name = 'Helper';
class_exists($name); // reaches php::fn::class_exists, answers false
The same program therefore gives two different answers for the same
trait, decided only by whether the argument is a literal.
The runtime side is already right, and deliberately so: traits are
compile-time AST templates in TypePHP, which is why
tests/compiler/stdlib/class_exists.phpt expects trait_exists() to be
false. Only the constant fold disagreed - with PHP and with the
compiler's own runtime.
A trait name now folds to false. Classes and enums keep folding to true,
which matches PHP: an enum is a class, a trait is not.
class_exists.phpt gains the literal and non-literal trait cases, and
ClassExistsTraitFoldTest pins the fold decision in the generated C++.
doFoldCountLiteral replaced `count([...])` with the number of AST items
and dropped the array literal entirely. That is only correct when the
item count equals the runtime element count and no element carries an
observable effect. Three common shapes break both assumptions:
count([bump(), bump()]); // folded to 2, bump() never ran
count(['a' => 1, 'a' => 2]); // folded to 2, PHP counts 1
count([...$rest, 9]); // folded to 2, PHP counts 6
The spread case is the most damaging: it silently yields a wrong number
in ordinary code that compiles without any diagnostic.
The fold now applies only when every item is unkeyed, is not a spread,
and holds an expression whose evaluation cannot be observed - a scalar,
a constant fetch, a unary sign over either, a nested literal that is
itself foldable, or a variable already known to be defined. An undefined
variable still reaches the dynamic path so it reports the same
diagnostic as PHP. Everything else keeps the runtime php::fn::count()
call, so `count([1, 2, 3])` and friends still fold as before.
Covered by tests/compiler/array/count-literal-fold.phpt for the runtime
semantics and by CountLiteralFoldTest for the fold/no-fold decision in
the generated C++.
- Add useImportAliases property to track import aliases by type domain
- Implement registerUseImportAlias method with duplicate detection logic
- Update use declaration processing to utilize import alias registration
- Make class and function aliases case-insensitive while constants remain case-sensitive
- Add comprehensive test coverage for import alias domain isolation
- Include negative test cases for duplicate alias detection across domains
- Move AST name resolution earlier in preprocessing steps
- Add proper error handling for PHP parser errors during traversal
- Remove TYPEPHP_PROJECT_NAME and TYPEPHP_RUNTIME_EXPORTS from common compile options
- Add dedicated getProjectRuntimeEntryCompileCommandOptions method for project-specific defines
- Update testEmbeddedCompileOptionsPassProjectNameForModuleAccessor to reflect new behavior
- Create new testProjectRuntimeEntryHasTargetDefineWithoutPchOrObjectCache
- Add testProjectIndependentMiscObjectsUseSharedCacheScope and testProjectIndependentMiscObjectCacheSurvivesTargetNameChange
- Update composer.json to use swoole/phpx ~2.6.4
- Modify object file caching logic to handle project-specific vs shared misc objects
- Add isProjectRuntimeEntryFile helper method for determining cache scope
- Update compileFile method to use source-specific compile options
- Handle different PHPX runtime source file layouts during embed mode builds
- Replace zend_string_init with zend_string_init_interned for persistent property defaults
- Use ZVAL_INTERNED_STR instead of ZVAL_STR for interned string values
- Add test case to verify persistent string metadata uses non-refcounted interned zval
- Reduce parallel test jobs from 8 to 4 to accommodate compiler test requirements
- Removed CLAUDE.md guidance file for Claude Code usage
- Removed code reuse improvement plan documentation
- Removed encapsulation review documentation
- Updated composer.json to specify phpstan version constraint
- Fixed namespace issues in Extractor.php exception handling
- Renamed main function in bin/extractor.php to avoid conflicts
- Updated LICENSE to standard GPL format
- Implement bin/analyze-test-coverage.php command line tool for coverage analysis
- Add TestCoverageAnalyzer class to generate PHP version x feature x evidence matrix
- Create markdown and JSON output formats for coverage reports
- Integrate AST node coverage with explicit denominators from php-parser
- Add strict mode for CI validation of parse issues and fixture references
- Update ClassTest.php to reflect new object-to-array conversion behavior
- Modify MethodCallTrait to remove fatal error on missing toArray methods
- Add documentation for test coverage analyzer usage and format
- Include package-lock.json with sharp dependency for image processing
- Added support for `ext-deps` as equivalent shorthand name for `extension-dependencies`
- Implemented validation to prevent using both config names simultaneously
- Updated documentation to reflect the new alias and usage restrictions
- Added test cases to verify ext-deps alias parsing works correctly
- Added test cases to ensure configuration error occurs when both names are used
- Refactored Translator.php to handle both configuration key variants
- Maintained backward compatibility with existing extension-dependencies usage
- Add test case for Zend class to array declaration with parameters rejection
- Add test case for Zend class to array declaration with wrong return type
- Add test case for known Zend class missing required toArray method
- Add test case for known Zend class resolving toArray through magic call
- Add test case for native class rejecting toArray parameters at declaration
- Update existing native class keyword return type test file
- Create new test file for native class to array parameters validation
- Add dynamic method test for toArray dispatch supporting real methods and __call
- Add support for (int), (bool), (float), (string), (array), (object) casts
in constant expressions across all declaration contexts
- Implement proper evaluation of cast expressions during stub generation
- Add comprehensive test coverage for constant expression casts in various
contexts including global constants, class constants, properties, and
parameters
- Update documentation to reflect PHP 8.5 cast support
- Enhance RuntimeAttributeFactoryLowering to handle array cast nodes
correctly
- Add validation and error handling for unsupported cast types in
constant expressions
- Implement final promoted property parsing with explicit visibility requirement
- Add support for exit(message: $value) named argument syntax
- Reject unknown named arguments in exit/die function calls
- Enforce explicit visibility declaration for final promoted properties
- Add test coverage for final promoted property inheritance errors
- Update documentation for supported PHP 8.4+ features and limitations
- Generate proper reflection metadata for final promoted properties
- Support native class final promoted property compilation
- Implement validation for promoted asymmetric properties requiring explicit types
- Add error handling for promoted asymmetric properties with wider set visibility
- Support constructor property promotion with asymmetric visibility modifiers
- Enable proper scope checking for promoted asymmetric properties in Zend-backed objects
- Preserve promoted/set visibility and implicit final reflection flags
- Add comprehensive test coverage for promoted asymmetric property scenarios
- Implement native object compilation support for asymmetric property access checks
- Remove pending status for ReflectionProperty::isPromoted() implementation
- Update documentation to reflect complete asymmetric property visibility support
- Extend Override attribute to support properties in addition to methods
- Add comprehensive property override validation including parent property matching
- Implement property shadowing prevention for private parent properties
- Add trait property override validation at use site
- Support promoted and hooked properties in override validation
- Update error messages to include property targets for override rejection
- Add internal marker preservation for property override validation
- Implement final property and property hook inheritance restrictions
- Add parent property hook call syntax support with validation
- Support PHP 8.4 final property metadata preservation in reflection
- Add property hook inheritance and reflection test cases
- Update native class property validation to prevent private property hiding
- Implement interface property hook final restriction
- Add property get hook reference return validation error
- Update stub generation with property
- Implement DNF method signatures with parameter contravariance and return covariance
- Add new test cases for DNF inheritance variance scenarios
- Extend stub generation to handle DNF union and intersection types
- Create DNF type declaration code generation in gen_stub.php
- Add support for DNF properties and dynamic property writes
- Implement closure support with DNF parameters and return types
- Add error handling for invalid DNF type operations
- Update inheritance checks to validate DNF parameter and return type compatibility
- Introduce test cases for DNF inheritance errors
- Refactor type comparison logic to support DNF clause subtyping relations
- Implement clone-with functionality with one/two argument support
- Add preservation of evaluation order for clone-with operations
- Support dynamic, numeric and object-valued properties in clone-with
- Handle error cases and stop property updates at first error
- Reject active references and unwrap sole remaining references
- Respect property scope and unlock readonly properties during cloning
- Add first-class callable and string callable support for clone
- Preserve lexical class scope in Zend call frames for method calls
- Update documentation with clone-with compatibility requirements
- Add comprehensive test coverage for clone-with features
- Implement scope argument handling in runtime function calls
- Add new NegativeCompatibilityTest class with 320 lines of test cases
- Implement closure and arrow function reference return validation with error messages
- Add foreach list destructuring reference binding validation and error reporting
- Move foreach by-reference variable validation to proper location in parser
- Update documentation to reflect foreach list destructuring reference limitations
- Refactor incompatibility classification documentation for clarity
- Remove outdated attribute argument limitation from documentation
- Create diagnostic reporter for controlled compiler boundary testing
- Add comprehensive test coverage for PHP incompatibility boundaries
- Ensure clean failure modes instead of crashes or invalid C++ emission
- Add php85 flag to control closure validation behavior based on PHP version
- Implement rejectUnsupportedClosure method to detect and reject closures in constant expressions
- Add validation for closures in class constant declarations with appropriate error messages
- Add validation for closures in property default values with appropriate error messages
- Add validation for closures in parameter default values with appropriate error messages
- Update documentation to reflect PHP 8.5 closure incompatibility in constants and defaults
- Add comprehensive test cases covering various closure usage scenarios in PHP 8.5
- Remove previously allowed PHP 8.5 class constant closure test case from validation tests
- Removed isConstFetch and isAssignOp methods from AstNodeType
- Removed corresponding test cases for isConstFetch and isAssignOp
- Updated CallArgumentGenerator to use setValue and appendValue instead of set and append
- Removed parseNamedCallArgs method from CallArgumentGenerator
- Removed unused getPlatformFullLinkFlags method from Clang backend
- Updated ClosureGenerator to use appendValue instead of append
- Removed abstract compileFile and linkObjects methods from CompilerBackend
- Removed unused getObjectPropVarInfo and getDecimalLiteralString methods
- Removed resetReturnType and mustNoCall methods from CompilerBase
- Removed testParseIncludesUsesNewArchitecture, testParseLdflagsUsesNewArchitecture,
testParseLibsUsesNewArchitecture and testBackwardCompatibility methods
- Removed isUniversalCtags property and related logic from Extractor
- Removed extractWithMetadata, generateStatistics and exportToMarkdown methods from Extractor
- Removed extractMetadata, extractComments, isPHPFunction and parseDocTags methods from Extractor
- Removed FINAL_TEST_SUCCESS.md file containing old test results
- Introduce LibraryExportedNative class with #[Native] attribute
- Add LibraryHiddenNative class with #[NoExport] and #[Native] attributes
- Create stub file for native class definitions
- Implement StubNativePoint class with native annotation and basic properties
- Add length method to StubNativePoint for geometric calculations
- Enable compiler support for native class annotations
- Prevent native classes from being exported through library stubs with proper error messages
- Add test cases to verify rejection of exported native classes in library builds
- Validate that NoExport native classes are omitted from library stub generation
- Implement check for native class usage in stub files with appropriate error handling
- Update hot path codegen to use appendValue method instead of append
- Add comprehensive test coverage for native class validation scenarios
- Add EntryScriptCodegenTest to verify entry script generation
- Create temporary project directory setup and teardown methods
- Implement testMainLinePaddingDoesNotBloatGeneratedExtension method
- Verify line padding uses runtime string construction instead of embedded newlines
- Add recursive directory removal utility for cleanup
- Ensure proper evaluation of main function with correct line offset
- Replace direct typephp_runtime_init calls with TYPEPHP_RUNTIME_INIT macro
- Add conditional linking for Unix PHP extensions to prevent duplicate ZendVM
- Implement dynamic lookup for macOS extensions to resolve host symbols
- Move typephp_helper.h from misc to include directory
- Update WASM interface generator to use project-specific runtime symbols
- Add tests for native module linking behavior and macOS extension options
- Refactor Translator to generate proper embed module entry functions
- Update documentation for new runtime initialization patterns
- Replace php_get_class with get_class throughout the codebase
- Replace php_get_persistent_class with get_persistent_class
- Replace php_get_func with get_func and update related helpers
- Replace php_get_persistent_method with get_persistent_method
- Replace php_get_persistent_prop with get_persistent_prop
- Replace php_globals_array with php::globalsArray
- Replace php_deindirect with php::deindirect
- Replace php_get_called_ce with php::getCalledCe
- Replace php_get_callable_scope with php::getCallableScope
- Replace php_get_str with get_str for literal string access
- Update build script to handle TypePHP project module accessor
- Add test case for helper symbol collision prevention
- Modify module initialization from app_init/app_clean to module_init/module_clean