- Add loadPristineAst method to CompilerBase for independent AST loading
- Introduce PreparedProjectCacheTrait with conservative whole-project caching mechanism
- Implement translation unit splitting for large C++ files with splitLargeTranslationUnit
- Add preprocessing warning count tracking in CompilerDiagnosticTrait
- Enhance gen_stub.php to use cached AST when available instead of reparsing
- Improve incremental compilation checks with splitTranslationUnits validation
- Add comprehensive test coverage for AST caching, prepared project cache, and translation unit splitting
- Optimize precompiled header manager with dependency digest caching and improved invalidation
- Implement file digest memoization for faster native compilation input processing
- Add support for persistent AST cache reuse across compiler processes
- 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
* fix(gen_stub): register enum-case class constants as persistent AST constants
A class constant valued by an enum case was registered with the folded
scalar (the backing value, or the case name for pure cases), so
constant('K::CB'), $cls::CB and reflection observed an int/string where
PHP has the case object, and K::CB === E::B was false on every dynamic
path. Enum case objects have request lifetime and can never sit in the
persistent class-entry tables, in any request-init rebinding scheme
least of all: writing a request-owned object into the shared table is
unsafe under concurrent ZTS requests.
Reuse the engine's own mechanism for internal enums instead: the
constant is declared as a persistent IS_CONSTANT_AST holding the
Enum::Case fetch, so Zend separates the class constants table into
request-local mutable storage on first access, evaluates the fetch
there, and cleans it up at request shutdown. Identity is preserved for
static access, constant(), dynamic class access and reflection, with no
module-lifecycle hooks and no registration-order sensitivity.
Case identity flows through compile-time constant evaluation as an
EnumCaseRef value instead of a scalar, so it also survives constant
expressions (true ? E::A : E::B), constant chains, typed class
constants (declared type and AST value are registered together), and
internal enum cases such as RoundingMode::HalfEven, which previously
aborted stub generation. The runtime expression path (php::getEnumCase)
is unchanged.
The preprocessor also no longer reads the raw ->value property off
arbitrary case expressions (`case A = 1 + 1;` warned and was recorded
as a pure case): only literal backing values are recorded eagerly, and
no compile-time consumer needs the evaluated scalar - gen_stub
evaluates the registration value from the AST itself.
* fix(gen_stub): constrain enum-case AST registration to class constants
The persistent IS_CONSTANT_AST representation leaked into property and
parameter defaults, whose persistent tables reject refcounted zvals:
startup died with "Internal zvals cannot be refcounted". EvaluatedValue
now carries the case identity in a dedicated field while its value
degrades to what those consumers read before case identity existed
(the host case object for internal enums, the literal backing value or
case name for compiled ones), and only class-constant registration opts
into the AST. Property/parameter defaults keep flowing through their
existing runtime-restore machinery unchanged.
Also parenthesize a folded constant operand before appending a member
access: the C++ ternary of `const VALUE = cond ? E::A : E::B;` bound
`.attr("value")` to its else branch only, so `K::VALUE->value`
evaluated to the case object instead of its backing value.
* fix(gen_stub): give persistent AST constants a complete teardown lifecycle
destroy_zend_class() asserts (in debug builds) that every persistent
AST constant remaining on an internal class is CONST_ENUM_INIT, and its
teardown frees only the allocation referenced by Z_AST — the previous
representation left a CLASS_CONST root behind (assertion failure at
shutdown on 8.4/8.5 debug builds) and leaked the two separately
allocated children.
The AST is now built in one contiguous persistent allocation (ast_ref,
root, both zval children — mirroring Zend's own persistent enum AST
builder), and every generated file with AST constants emits a release
function that runs from the module's MSHUTDOWN, before Zend's class
teardown: it frees the single block and restores the constant slot to
null, so destroy_zend_class() never sees a foreign AST. Request-local
mutable copies are unaffected (no request is live at MSHUTDOWN).
CONST_ENUM_INIT itself is not usable here: that node constructs a new
case object rather than fetching the canonical registered one, which
would break case identity again.
* fix(codegen): reject lifecycles that cannot release AST constants
The typephp_release_ast_constants_*() teardown ran only from MSHUTDOWN,
which is not a general pre-class-destruction hook: for a
MODULE_TEMPORARY module loaded through dl(), module_destructor() runs
clean_module_classes() before the shutdown callback, so the foreign
ZEND_AST_CLASS_CONST reached destroy_zend_class() first and still
tripped the debug assertion; and a MINIT that fails after registering
such a constant never sets module_started, so MSHUTDOWN is not
guaranteed to run at all.
The generated module now enforces the lifecycle contract instead of
assuming it. When the module declares any enum-case AST constant, MINIT
opens with a guard that rejects MODULE_TEMPORARY (zend_error E_WARNING,
return FAILURE) before a single class is registered — with nothing in
the class table, teardown is trivially safe. MINIT is also restructured
so that every step that can return FAILURE precedes the first
register_class_*() call: the AST constants are installed by the
infallible tail (class registration, then symbol registration), so a
FAILURE return can never leave a foreign AST in the persistent tables.
The generator itself throws if a future change introduces a FAILURE
return after registration begins. The MSHUTDOWN release is unchanged
and remains the supported, persistent-module path.
EnumCaseAstConstantLifecycleTest asserts the guard exists exactly when
AST constants exist, that it precedes every registration step, that no
FAILURE return follows the first class registration, and that MSHUTDOWN
releases the constants before any other teardown. The enum-case phpt
gains a never-accessed constant so the full process shutdown it already
performs also covers a pristine persistent AST; a dl()-path phpt is not
feasible because the harness only builds standalone binaries whose
module is registered persistently (documented in the test file).
- Replace global $translator variable with Translator::getInstance() method
- Add singleton instance management to Translator class
- Update compiler.php to use singleton pattern instead of global variable
- Update gen_stub.php to use getTranslator() helper function
- Add translator instance test to verify singleton behavior
- Remove unnecessary global declarations throughout codebase
getCExpr() emitted int class constants, property defaults and parameter
defaults with strval(), so `const M = PHP_INT_MIN;` produced
`ZVAL_LONG(&const_M_value, -9223372036854775808)`. C parses that as
unary minus applied to the literal 9223372036854775808, which exceeds
long long and is ill-formed, so the generated extension source does not
compile. The expression path already handles this via genIntegerLiteral
(ZEND_LONG_MIN); give the stub metadata path the same spelling.
The float paths (17-digit round-trip, -0.0 sign, INF/NAN) were already
fixed upstream in 2d81626a; the new test pins those literals down
together with the int boundary values.
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.
When generating arginfo for union/intersection types with 2+ class types,
the ZEND_TYPE_INIT_CLASS macro was using toEscapedName() which preserves
backslashes (e.g. yuandian\\Database\\Db\\Expression\\Raw), but
C identifiers cannot contain backslashes.
This caused compilation errors like:
error: stray '\' in program
Fix: use toVarEscapedName() which replaces namespace separators with
underscores, consistent with the single-class-type branch (line 2901).
- 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
- 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
- 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
- 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
- Removed "any", "box", and "stream" aliases mapping to ZEND_STR_MIXED
- Added test case to verify property names are not rewritten through pseudo-type string aliases
- Created attribute metadata test to ensure string arguments maintain original values
- Prevented potential conflicts between pseudo-type aliases and actual property/argument names
- Add hooks property to PropertyInfo class with get/set method mappings
- Register property hooks as Zend metadata during AOT compilation
- Implement proper virtual property handling with ZEND_VIRTUAL_PROPERTY_OFFSET
- Support object introspection via Reflection and iteration with hook invocation
- Add reflection metadata exposure through ReflectionProperty::hasHooks() and getHooks()
- Implement backing storage detection to distinguish virtual vs backed properties
- Add comprehensive test coverage for property hooks introspection and reflection
- Document lazy object limitation with persistent AOT class entries in PHP 8.4
- Update documentation to reflect property hooks compilation strategy changes
- Add detectTypeOfExpr support for unary and binary logical operators
- Implement proper bool conversion for big integer, float and decimal types
- Update convertBoolExpr to skip conversion when type is already BOOL
- Add convertConditionExpr method to handle big number truth values
- Modify empty() implementation to use numeric truth values for big numbers
- Enhance ternary operator type detection with conditional logic
- Update loop control parsing to use condition expression conversion
- Add proper type assertions for XOR logical operations
- Remove redundant isValidDefineName tests from TraitsTest
- Simplify ConstantExpressionValidationVisitor initialization
- Initialize cValue variable in gen_stub.php for constant assertions
- Add comprehensive tests for big number logical and unary operators
- Add operator error boundary tests with PHP-compatible exception types
- Add reverse and compound operator tests for big numeric types
- Changed defaultValue check to default property comparison in CallArgumentGenerator
- Added genDefaultArgumentExpr call for proper default value resolution
- Updated findNativeClassConst signature to accept accessing class parameter
- Modified checkAccessibleByClassName to use accessing class context
- Updated getClassConstValue calls to pass current class context
- Added comprehensive test case for private class constant parameter defaults
- Update ReturnInfo::equalsApartFromPhpDocAndRefcount to consider PHPDoc types
in arginfo equivalence checks to prevent incorrect Reflection type exposure
- Rename method from equalsApartFromPhpDocAndRefcount to equalsApartFromRefcount
for better clarity and consistency
- Modify Translator.php to use hasClass and hasInterface methods instead of
symbols->hasClass and symbols->hasInterface for proper dependency resolution
- Add comprehensive tests for class registration preserving reverse inheritance
- Add tests for magic methods with implicit return types maintaining distinct
Zend arginfo during registration
- Include tests for interface registration handling child-before-parent scenarios
- Add cross-namespace interface dependency resolution tests
- Create diamond inheritance pattern registration preservation tests
- Add printerGenerated property to ClassDef entity
- Implement removeMethod function in ClassDef for method removal
- Add comprehensive tests for getter, setter, with, printer and notnull attributes
- Create new CompileTimeAttribute utility class for attribute handling
- Implement GetterLowering for generating getter methods from attributes
- Add NotNullLowering for validating non-null parameters
- Implement PrinterLowering for generating toString methods
- Add PropertyMethodLowering for setter and with method generation
- Update gen_stub.php to recognize new compile-time attributes
- Enhance Preprocessor with printer generation logic
- Add symbol repository function removal capability
- Update Translator with printer generation predicate
- Modify Visitor to handle new attribute transformations
- Add polyfill definitions for Getter, Setter, With
- Add exported property to ClassDef and FunctionDef entities
- Implement #[NoExport] compile-time attribute processing
- Exclude NoExport-marked declarations from library stub generation
- Preserve original names during AST name resolution
- Add comprehensive test coverage for NoExport functionality
- Document NoExport attribute usage in MIXED_CPP_PHP.md
- Support NoExport with various namespace resolution patterns
- Apply NoExport cascading from classes to their methods
- Generate proper extern declarations for non-exported symbols
- Replace appendCapturedStmtLines helper with direct formatCapturedStmtLines calls
- Change createPropertyAccessResolver from private to protected for extensibility
- Change resolveNativeInstanceProperty from private to protected for extensibility
- Change resolveNativeStaticProperty from private to protected for extensibility
- Change applyNativePropertyAccessResult from private to protected for extensibility
- Change containsNullsafeChain from private to protected for extensibility
- Replace parseTypeDecl output parameter with resolveTypeDecl returning array
- Change sortFiles to getSortedFiles returning sorted array instead of modifying input
- Update name resolution to handle imported namespace prefixes correctly
- Enhance property hook backing access detection with additional conditions
- Add redis extension availability check to test skip conditions
- Document compiler self-hosting constraints regarding reference parameters across traits
- Replaced all occurrences of native_types::type_* with Type::* constants
- Replaced all occurrences of complex_types::type_* with Type::* constants
- Updated ExtensionProvider annotation to use ExtensionProvider::Keyword
- Modified std array, vector, map, ordered_map, bigfloat, bigint, decimal tests
- Updated stream, array multidimensional, unsafe pointer, and type mismatch tests
- Changed camel case keyword extension to use Type::Any constant
- Updated documentation to reflect Type::* constant usage instead of type_* constants
- Add ExtensionProvider attribute class to define extension targets
- Convert function-based extensions to class-based ExtensionProvider pattern
- Support various target types including native_types, complex_types, and class names
- Parse ExtensionProvider attributes during preprocessing phase
- Generate proper extension method calls using provider classes
- Update test cases to use ExtensionProvider syntax instead of function prefixes
- Remove old extension function name patterns and related logic
- Add validation for extension provider method signatures and parameters
- Support both snake_case and camel
- Move Reflection class from TypePhp to TypePhp\Resolver namespace
- Rename ArgInfo.php to TypePhp\Entity\ArgInfo and update all references
- Move AstNodeType.php to TypePhp\Parser\AstNodeType with namespace update
- Update Symbol.php import paths to use TypePhp\Generator\Symbol
- Move Constants.php to TypePhp\Metadata\Constants with namespace change
- Rename FileScanner.php to TypePhp\Build\FileScanner with namespace update
- Move MagicMethodDetector.php to TypePhp\Resolver\MagicMethodDetector
- Rename PropertyHookLowering.php to TypePhp\Transform\PropertyHookLowering
- Move Visitor.php to TypePhp\Transform\Visitor with namespace update
- Update all test files to reflect new class