Skip to content

Conversation

@VincentLanglet
Copy link
Contributor

}
if ($enumNode->scalarType === null && $stmt->expr !== null) {
$errors[] = RuleErrorBuilder::message(sprintf(
'Enum %s is not backed, but case %s has value.',
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The message changed from

Enum %s is not backed, but case %s has value %s.

to

Enum %s is not backed, but case %s has value.

I'm not sure you're okay with this or if

  • it should be behind bleedingEdge
  • it should be behind some extra condition (and have two differents messages ?)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why would the message change? If it has value, we can still include it in the error message.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The check was

if ($stmt->expr instanceof Node\Scalar\Int_ || $stmt->expr instanceof Node\Scalar\String_) {

and is changed to

if ($enumNode->scalarType === null && $stmt->expr !== null) {

so I cannot safely access to $stmt->value

I made 8e72e2b to revert this change for Int/String/Float, but the test show the issue with other things like

	case E = false;
	case F = Foo::A;

where no value is displayed. Is there some helper method to get a value/name from an Expr ? Or is it ok like this ?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can either use ExprPrinter on $stmt->expr, or you can get type of $stmt->expr with InitializerExprTypeResolver and do ->describe(VerbosityLevel::value()) on the type. I like the 2nd option more.


$exprType = $scope->getType($stmt->expr);
$constantValues = $exprType->getConstantScalarValues();
if (count($constantValues) === 1) {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

By setting enum cases value here, instead of in the condition

if ($stmt->expr instanceof Node\Scalar\Int_ || $stmt->expr instanceof Node\Scalar\String_)

I also catch other constant values like the one set with a class Constant.

Cf test

enum Backed: int {
	case One = Foo::A;
	case Two = Foo::A;
}

@VincentLanglet VincentLanglet force-pushed the enumSanity branch 2 times, most recently from 22ab2d1 to 37b0e41 Compare November 10, 2025 08:47
@ondrejmirtes
Copy link
Member

CS build fail

@ondrejmirtes ondrejmirtes merged commit d194c2c into phpstan:2.1.x Dec 5, 2025
635 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

"Enum Order is not backed" when value is not-int/string

3 participants