- Add acceptsCallable property to ArgInfo entity to track callable type acceptance
- Implement logic to detect when function parameters accept callable types
- Add normalization of bare function callable arguments to string representation
- Create helper methods to check if types contain callable declarations
- Add resolution logic for bare identifier function names in callable context
- Update native class support to set acceptsCallable flag based on type checking
- Modify preprocessor to populate acceptsCallable field during argument parsing
- Remove deprecated typeDeclContainsCallable method and consolidate logic
- Add comprehensive test coverage for bare
- Replace sequential indexing with stable ID allocation for persistent entities
- Add StableIdRegistry to maintain consistent IDs across builds
- Implement incremental compilation with dependency tracking
- Add IncrementalBuildState for tracking file dependencies and dirty propagation
- Update anonymous class generation to use stable call site IDs
- Modify type ID allocation to start from 1 and avoid renumbering
- Add literal string ID allocation using stable registry
- Implement global variable usage recording and tracking
- Add dependency symbols for classes, functions, constants, and globals
- Update property and function index allocation to use stable IDs
- Add cache site ID allocation based on call site context
- Implement compilation statistics merging and delta calculation
- Add file writing with content comparison to avoid unnecessary writes
- Implement incremental build cache clearing functionality
- Add metadata restoration for incremental compilation
- Create dependency graph building and dirty file propagation logic
- Implement translation unit emission tracking for incremental builds
- Add materializeTrailingDefaults parameter to CallArgumentGenerator for default argument handling
- Implement native object stack slot allocation and promotion analysis
- Add nativeStackPromotions context tracking for non-escaping object allocations
- Generate NativeStackSlot declarations in compiler base code generation
- Update native method call generation to use direct member access patterns
- Add comprehensive native object member name validation and conflict detection
- Implement native destructor state management and finalization chains
- Add test cases for native class member name conflicts and stack promotion scenarios
- Replace nativeDeref calls with nativeRequireObject for improved object access safety
- Add native source project compilation workflow with project.xml configuration
- Implement closure reference capture analysis and type degradation for native objects
- Add WASI and nano mode function support checks with comprehensive API exclusions
- Introduce Composer native package discovery and validation system
- Add build scripts for WASI nano program compilation with browser module support
- Implement closure generator enhancements for reference capture handling
- Add CLI usage tests and compiler base API validations
- Integrate php-nano runtime dependencies and native package management
- Add type degradation analysis for closure use variables in generators and functions
- Replace manual array key parsing with direct Node\Scalar\Int_ creation
- Route all destructuring assignments through parseAssignFinally for proper type handling
- Remove redundant left expression type detection in assignment operations
- Fix argument index mapping in CallArgumentGenerator to use source indices correctly
- Restore outer context before closure reference validation to prevent type conflicts
- Remove unused local variable promotion logic in foreach reference binding
- Add explicit error messages for native variable reference capture attempts
- Track foreach target variables in SSA optimizer for proper type analysis
- Use numeric indices instead of case labels in switch statement generation
- Add comprehensive tests for varint type handling in foreach loops
- Replace any() with std::any() in test files and compiler logic
- Replace refval() with std::ref() for reference wrapping operations
- Replace expected() with std::expected() for branch prediction hints
- Replace unexpected() with std::unexpected() for branch prediction hints
- Remove deprecated objval() function and use toObject() keyword method
- Update parser to recognize std:: class expressions with case insensitivity
- Add comprehensive changelog documenting breaking API changes
- Update documentation to reflect new std:: namespace conventions
- Add tests for case-insensitive std class and method names
- Verify global function names remain available for user-defined functions
- Replace ArgList with VarList for fixed argument arrays to avoid dynamic Args allocation
- Add call argument limit assertion to prevent unbounded call generation
- Implement direct static method calls using callStaticMethod when possible
- Add alternating dynamic static call benchmarks for class and method variations
- Update documentation on request-local call slot destruction requirements
- Fix dynamic static call target evaluation order to precede argument evaluation
- Add tests for call argument limits and dynamic class evaluation ordering
- Add function call cache infrastructure with typephp_call_cached wrapper
- Implement method call caching using typephp_call_method_cached for named methods
- Add scoped method call caching via typephp_call_method_scoped_cached for dynamic scopes
- Create late-static-bound class entry tracking with getCalledCeExpr and getCalledClassExpr
- Implement lazy static property slot resolution with typephp_get_static_property_cached
- Add benchmark cases for dynamic static method calls and scoped method invocations
- Update call cache test expectations to reflect new cached call implementations
- Integrate call caching into function and method call compilation paths
- Add nullsafe method call caching support in nullsafe access trait
- Implement static property slot registration and resolution mechanisms
- Update native property handling to use cached static property access
- Add comprehensive test coverage for various dynamic call scenarios
- Implement exact-class fast path for zero-argument late-static calls with fallback mechanism
- Add static property fetch resolution using typephp_get_static_property symbol
- Enhance isset operations on static array properties with direct typephp_array_isset calls
- Update class reference detection to return Type::STR for class constant fetch expressions
- Add benchmark suite for static cache performance measurement including late static dispatch
- Modify compiler symbols to use typephp variants for called class and static property access
- Create comprehensive tests for static array single offset presence and late static call exact guards
- Update unit tests to reflect new symbol names and variable
- Add forceArrayArgs parameter to CallArgumentGenerator methods to properly handle
named arguments with setValue method instead of set
- Implement direct foreach array target optimization to improve iteration
performance by allowing direct assignment to variant variables
- Add comprehensive tests for dynamic call cache argument preservation
including small, large, named, unpacked, reference, and exception arguments
- Add tests for dynamic property access with string, referenced-string, and
converted names
- Add tests for foreach direct array targets preserving keys, values, references
- Update CI workflows to checkout PHPX from third_party directory instead of vendor
- Add smoke test for full static builds to verify module globals setup
- Enhance benchmark suite with additional dynamic call cases for different
argument counts (zero, two, four args) to separate cache lookup from argument
materialization costs
- Add case filtering option to property
* fix(preprocessor): reject variadic promoted properties and callable property/constant types
Two promotion/type gaps against Zend (probed on 8.4.13):
- `__construct(public int ...$x)` was accepted and even registered
the property before the variadic-position check ran. A variadic
parameter collects its arguments into an array, so there is no single
value to promote; Zend fatals with "Cannot declare variadic promoted
property". The check now precedes the property registration.
- `callable` is a calling-scope-dependent type, so Zend forbids it in
property types (declared, promoted, interface hooked) and class
constant types (class and interface), bare or as a nullable/union
member: "Property A::$x cannot have type ?callable" /
"Class constant A::X cannot have type callable". Intersection
members are left to the compound-type validation, which rejects
every non-class standard type there.
`void`/`never` property and parameter types were already rejected by
parseTypeDecl ("The type `void`/`never` is allowed only for return
type") - verified, no change needed; union members are covered by the
compound-type validation.
* test(preprocessor): cover promotion and property/constant type rules
* fix(preprocessor): reject callable inside intersection and DNF types
typeDeclContainsCallable() deliberately skipped IntersectionType, so a
DNF-nested callable such as `public (Traversable&callable)|stdClass
$value;` sailed past the property checks and died in gen_stub on
assert(!$type->isBuiltin); a bare `Traversable&callable` property
compiled outright.
Zend rejects callable while compiling the intersection type itself,
with its own diagnostic ("Type callable cannot be part of an
intersection type", probed on 8.4.13), in every declaration context and
ahead of the property/constant-specific bans — `callable|(Traversable&
callable)` reports the intersection conflict, not the property one.
A dedicated assertTypeDeclIntersectionsHaveNoCallable() walk (nullable,
union, intersection members) now runs before the existing
typeDeclContainsCallable() checks in all contexts this branch guards:
class properties, promoted properties (both via addClassProperty),
typed class constants, and interface properties/constants. Tests cover
the bare intersection member, DNF in first and second union member,
the promoted and constant/interface variants, and a callable-free DNF
property that must keep compiling.
* fix(preprocessor): validate callable intersections on the common type-declaration path
assertTypeDeclIntersectionsHaveNoCallable() was invoked only from the
property and class/interface-constant paths, so the same invalid type
in a function parameter or return declaration bypassed the check and
reached the later generator path:
function consume(Traversable&callable $value): void {}
function produce(): Traversable&callable {}
Zend rejects both while compiling the type itself ("Type callable
cannot be part of an intersection type", probed on 8.4.13), in every
declaration context.
The walk now lives in parseTypeDecl(), the declaration funnel behind
resolveTypeDecl() that parameters, returns, properties, promoted
properties, class and interface constants, and interface hooked
properties already flow through; the per-context calls are gone, and
the diagnostic points at the offending intersection member. Closure
and arrow-function signatures resolved no full type node anywhere, so
doGenClosure() now routes them through the same funnel - except bare
class names, which the native-object walk there already resolves (and,
inside trait methods, rewrites) via parseTypeDecl().
The property and constant paths resolve the declaration before
applying their own bare/nullable/union callable bans, so a type like
`callable|(Traversable&callable)` keeps reporting the intersection
conflict first, as Zend does.
New negative tests: parameter and return intersections, callable in a
DNF parameter member, and closure parameter and return intersections
(each probed against Zend 8.4.13); positive tests keep bare `callable`
parameters and callable-free DNF properties compiling.
* fix(codegen): keep Zend operand read order around hoisted side effects
Lowering a later call argument or concat operand that materializes
captured statements (an assignment, a call result) appended them to the
enclosing statement, executing the side effect before earlier operands
were read: two($j, $j = 5) with $j = 1 produced "5,5" (Zend "1,5") and
$m . "," . ($m = 9) produced "9,9" (Zend "1,9").
Call arguments: Zend SENDs strictly left to right, so when a later
argument hoists statements, every earlier by-value plain-variable
argument is snapshotted into a temporary at its own argument position.
By-reference parameters, unpacked arguments, $this and $GLOBALS are
left alone.
Concat chains: Zend reads a CV operand when its CONCAT opcode executes,
so in the left-associated chain the first two items are read together
at the first op (after both items' side effects: $s . ($s = 'b') . $s
is "bbb") and each later item after the side effects of everything up
to itself. The flattened braced-list lowering now snapshots a
plain-variable item exactly at that read position, deferring the first
item's snapshot until the second item has been lowered.
Plain arithmetic is intentionally unchanged: Zend's ADD reads the CV at
op time, so $k + ($k = 5) is 10 in both worlds, and the existing
codegen already matches.
* test(codegen): platform-neutral integer-literal suffixes in eval-order assertions
* fix(codegen): detect wrapped side effects when ordering operand reads
Zend sends call arguments strictly left to right and reads a concat
operand's CV when its opcode executes: an assignment nested in a later
argument runs after every earlier by-value argument has been sent, so
pairValue($i, (int) ($i = 5)) passes the old value ("1,5"), and the
same holds when the assignment is wrapped in !, unary +/-, ~, or @.
shouldMaterializeOrderedOperand() only descended through BinaryOp
nodes, so an assignment inside any other expression wrapper was not
classified as side-effecting: no earlier operand was snapshotted and
the assignment could even stay inline in the C++ argument list
(php::toInt(i = 5LL)), mutating the variable at an unsequenced point.
Deriving the decision from the captured statements lowering produces
would miss exactly these inline cases, so the classifier now recurses
structurally through every sub-expression: any wrapper of a
side-effecting node is itself side-effecting. Closure and arrow
function bodies do not run at creation time and stop the walk; throw,
yield, yield from, and backtick expressions join the side-effecting
leaves.
Zend's ADD opcode still reads its CV at op time, so $k + ($k = 5)
keeps its existing codegen (10 in both worlds, no snapshot).
* fix(codegen): type materialized wrapper operands as dynamic temporaries
A wrapper expression around a side effect (-strlen($s), a cast, error
suppression) is now materialized for evaluation order, but the temp-type
fallback typed it by the detected PHP type. The lowered C++ can still be
dynamic — an unqualified namespaced call lowers to php::call(...), a
Variant — so a php::Int temporary failed to compile in the self-build.
Follow the call/binary-op policy: native scalar types only in
native-types mode, otherwise a dynamic temporary.
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.
- 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 support for __NAMESPACE__ magic constant resolution in namespace, class, and global scopes
- Add support for __PROPERTY__ magic constant that resolves to property name within property context
- Implement namespace\name relative name resolution for functions, constants, classes, and members
- Update AnonClassGenerator to properly parse identifiers instead of using toString()
- Extend CompilerBase to handle Scalar_MagicConst_Namespace and Scalar_MagicConst_Property
- Modify class inheritance and interface implementation to use parseIdentifier for proper name resolution
- Add comprehensive tests for namespace magic constant behavior across different scopes
- Add tests for property magic constant resolving correctly in property contexts only
- Implement runtime attribute factory lowering with proper namespace context handling
- Update visitor pattern to track property magic boundaries and namespace context correctly
- Document incompatibility with PHP 8.5 #[NoDiscard]
- 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
- 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
- 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
- Remove makeScopedCallableMap helper function
- Change preg_replace_callback_array strategy from 'map' to 'dynamic-map'
- Add dynamic-map strategy support in CompilerBase for efficient callback processing
- Update documentation to reflect new callback map implementation approach
- Modify tests to verify UserCodeScopeGuard usage instead of makeScopedCallableMap
- Add test case with static closure in preg_replace_callback_array
- Add explicit null return statement when mixed return type is added to anonymous class methods
- Extend anonymous class with ImportedVisitor base class in test case
- Add inspect method implementation in anonymous class to check object instances
- Update expected test output to include NULL result
- Add proper visitor class with inspect method in test namespace
- Include necessary use statements for Visitor class in anonymous class consumer tests
- Updated resolveAnonClassTypeNames to resolveAnonClassNames with improved name resolution
- Added proper handling of imported names in anonymous class method bodies
- Ensured fully qualified names are embedded when anonymous classes are evaluated
- Added test case for anonymous class method bodies preserving namespace imports
- Fixed function call trait to check global name instead of local name for unsupported functions
- Added tests for destructor exception handling boundaries
- Improved include error handling and shutdown exception handler behavior
- Added unsupported function detection for extract function with proper error messages
- Updated swoole/phpx dependency from ~2.5.3 to ~2.5.5
- Add test case for repeated dynamic static calls not reusing released trampoline
- Add test case for repeated static calls to runtime-defined magic class
- Throw LogicException in getFuncPtr when class method name is detected
- Update getFuncPtr to reject class method names with proper error message
- Replace getFuncPtr with getMethodPtr for static method calls in method call trait
- Update Closure::fromCallable handling to use getMethodPtr instead of getFuncPtr
- Fix Python module trait to use getMethodPtr for PyCore methods
- Update translator to clear function and class maps on every request shutdown
- Refactor property access resolver to use compiled class declaration for parent lookup
- Add test to verify subclass lookup uses compiled class declaration when parent index is missing
- Update request shutdown test to run in all build modes with proper assertions
- Add specific test for function pointer cache rejecting class method names
- Rename hasDynamicCall to needsUnpackedCallbackScope in MethodDef
- Replace genScopeSwitchCode with genUnpackedCallbackScopeGuard
- Change prepareScopedCallback to use php::UserCodeScopeGuard
- Add callableScopeVar to FunctionContext for reusable scope management
- Update compiler logic to track unpacked callback scope requirements
- Generate single reusable CallableScope variable per method when needed
- Add comprehensive documentation for scope management design
- Create tests for callback context reuse and scope restoration
- Add non-static self callable test case
- Update method name references in traits test suite