* 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
- Implement property hook lowering to getter/setter method calls
- Add support for private(set) and protected(set) asymmetric visibility
- Generate appropriate error handling for read-only hooked properties
- Support compound assignments and increment/decrement operations on hooked properties
- Add proper visibility checks for asymmetric property setters
- Update documentation to reflect new property hook capabilities
- Add comprehensive test coverage for property hook functionality
- Introduce --php-version CLI option to specify accepted PHP syntax version
- Add support for PHP 8.5 pipe operator with left-to-right evaluation
- Implement PHP version validation in project configuration parsing
- Update parser factory usage to respect configured PHP version
- Add tests for pipe operator functionality and PHP version controls
- Modify stub generation to use configured PHP version
- Update documentation with new --php-version option details
- Implement FiberGenerator trait with yield/yield from parsing
- Add generator detection and preparation logic in function compilation
- Generate TypePHP\FiberGenerator objects that implement Iterator
- Support yield expressions and statements with key-value pairs
- Enable yield from delegation with array and traversable forwarding
- Register fiber generator class entry during module initialization
- Update runtime initialization to use typephp_runtime_init
- Replace php_aot_ prefixed helpers with typephp_ prefixed versions
- Add comprehensive generator test suite covering various scenarios
- Document generator limitations and compatibility restrictions
- Mark dynamic PHP foreach over native generators as XFAIL case
- Add isPromoted property to PropertyInfo class
- Include isPromoted flag in PropertyInfo constructor and initialization
- Set ZEND_ACC_PROMOTED flag for promoted properties in PHP 8.0+
- Update Preprocessor to track promoted status during property creation
- Add promoted flag to PropertyDef entity
- Remove xfails for promoted property tests since they now pass
- Handle promoted properties in constructor parameter processing
- Updated CompilerBase.php to use convertIntExpr for bitwise not operations on variables
- Modified gen_stub.php to always use var_export for default value conversion
- Enhanced object_property test to follow strict type checking with TypeError handling
- Added native property test for bitwise not class constant assignments
- Updated Translator.php to return raw values instead of CValue wrappers for constants
- Improved documentation consistency across project overview files
- Added strict types declaration to property assignment test cases
- Updated namespace declarations from PhpAot\Php to TypePhp in all source files
- Modified import statements to use TypePhp instead of PhpAot\Php throughout the codebase
- Adjusted composer.json autoload configuration to map TypePhp namespace to src directories
- Updated documentation references from PhpAot\Php to TypePhp in comments and markdown files
- Changed class references in test files to use new TypePhp namespace
- Updated bootstrap and utility scripts to reference TypePhp namespace
- Removed abstract base class inheritance in CompilerBase class
- Added new properties and methods for indentation and mode handling in CompilerBase
- Updated exception handling to use new TypePhp\Exception namespace