Repository navigation
Conversation
Property defaults such as TextRole::Unset->value are valid constant expressions since PHP 8.2 (php/php-src#8625). The declaration validator already accepted them, but the stub generator's constant-expression evaluator rejected Expr_PropertyFetch and aborted compilation with an uncaught exception. Handle enum case ->value/->name fetches in EvaluatedValue's fallback closure: evaluate the receiver to an EnumCaseRef and fold through the shared resolveCompileTimeEnumCaseBackingValue (relaxed private to public so stub generation reuses the declaration evaluator rules, including internal enums and unit-enum rejection). Every other property fetch keeps the existing diagnostic.
End-to-end runtime coverage for folding enum case ->value/->name into property defaults: int-backed and string-backed ->value, unit-enum ->name, plus the enum-typed bare-case control. The EXPECT section was validated against native PHP 8.4.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Enum::Case->value/->nameare valid constant expressions since PHP 8.2(php/php-src#8625) and native PHP
accepts them as property defaults. TypePHP's declaration validator already
allowed them, but the stub generator's constant-expression evaluator rejected
Expr_PropertyFetch, aborting compilation. This PR makes the stub-sideevaluator fold enum case
->value/->name, bringing the two evaluators backin sync.
Repro (before)
Before:
The class-constant indirection (
private const R = TextRole::Unset->value;then
= self::R) fails identically, since the initializer itself is aPropertyFetch.After: compiles and the AOT binary prints
-1, matching native PHP 8.4.Root cause
Two constant-expression evaluators were out of sync:
Enum::Case->value?src/Transform/ConstantExpressionValidator.php,Expr\PropertyFetchwhitelisted)src/Resolver/ClassConstantValueTrait.php,resolveCompileTimeEnumCaseBackingValue)src/gen_stub.php,EvaluatedValue::createFromExpressionfallback)ConstFetch/ClassConstFetchThere was zero test coverage of
int $x = Enum::Case->valueas a propertydefault anywhere in the repo, which is why the gap survived.
Changes
src/gen_stub.php(+25) — in theConstExprEvaluatorfallback closure,handle
Expr\PropertyFetch/Expr\NullsafePropertyFetchbefore theexisting "must be a global, non-magic constant" diagnostic:
EnumCaseRef, fold->nameto the case nameand
->valueto the backing value;null→null(mirrors the declaration evaluator);Undefined enum case property ...error;diagnostic (single source of truth, no message duplication).
src/Resolver/ClassConstantValueTrait.php(1 word) —resolveCompileTimeEnumCaseBackingValueprivate→public, so stubgeneration reuses the declaration evaluator's exact resolution rules
(internal enums via
constant(), unit enums rejected with"has no backing value") instead of duplicating them.
phpunit/src/EnumCaseValuePropertyDefaultTest.php(new) — unit coverage:int-backed
->value, string-backed->value,->name, and a negative caseasserting non-enum property fetches keep the existing diagnostic.
tests/compiler/object_property/enum-case-value-property-default.phpt(new) — end-to-end runtime coverage (int/string
->value, unit-enum->name, enum-typed bare-case control). The--EXPECT--section wasvalidated against native PHP 8.4.
Behavior preserved
int $x = SomeClass::NON_ENUM->propin a constant expression → samediagnostic as before.
(
EnumDeclarationRulesTest).TextRole $role = TextRole::Unset;)unchanged.
Testing
original
Expr_PropertyFetcherror (3 errors), and pass with the fix—
OK (4 tests, 8 assertions).EnumCaseValuePropertyDefaultTest+EnumDeclarationRulesTest):OK (30 tests, 57 assertions).Tests: 3127— the 14 failures are pre-existing environmentissues, reproduced identically with only these production edits reverted
(bash completion / build stats / linker — no enum overlap).
--dryexits 0 (was 255); full AOT build succeeds and the binaryprints
-1.phpstan: clean (src/gen_stub.phpis excluded byphpstan.neonasupstream-derived).
php-cs-fixer: no new issues.Note for reviewers
The new PHPT was not executed via
run-tests.php --compiler ./tpcbecause thechecked-in workflow expects a self-hosted
./tpc, and the locally availableone predates this fix; e2e behavior was verified through a full
bin/tpc.phpbuild of the repro instead. Please re-run the PHPT with a freshself-hosted compiler.
Commits
3368b5b4fix(enum): fold enum case property fetches in constant expressions5c18ea64test(compiler): add phpt coverage for enum case property defaults