diff --git a/src/Reflection/InitializerExprTypeResolver.php b/src/Reflection/InitializerExprTypeResolver.php index 8b38c5a383..589f2d1c0e 100644 --- a/src/Reflection/InitializerExprTypeResolver.php +++ b/src/Reflection/InitializerExprTypeResolver.php @@ -611,8 +611,17 @@ public function getBitwiseAndType(Expr $left, Expr $right, callable $getTypeCall return $this->getNeverType($leftType, $rightType); } - $leftTypes = $leftType->getConstantScalarTypes(); - $rightTypes = $rightType->getConstantScalarTypes(); + if ($leftType instanceof IntegerRangeType) { + $leftTypes = $leftType->getFiniteTypes(); + } else { + $leftTypes = $leftType->getConstantScalarTypes(); + } + if ($rightType instanceof IntegerRangeType) { + $rightTypes = $rightType->getFiniteTypes(); + } else { + $rightTypes = $rightType->getConstantScalarTypes(); + } + $leftTypesCount = count($leftTypes); $rightTypesCount = count($rightTypes); if ($leftTypesCount > 0 && $rightTypesCount > 0) { @@ -680,8 +689,17 @@ public function getBitwiseOrType(Expr $left, Expr $right, callable $getTypeCallb return $this->getNeverType($leftType, $rightType); } - $leftTypes = $leftType->getConstantScalarTypes(); - $rightTypes = $rightType->getConstantScalarTypes(); + if ($leftType instanceof IntegerRangeType) { + $leftTypes = $leftType->getFiniteTypes(); + } else { + $leftTypes = $leftType->getConstantScalarTypes(); + } + if ($rightType instanceof IntegerRangeType) { + $rightTypes = $rightType->getFiniteTypes(); + } else { + $rightTypes = $rightType->getConstantScalarTypes(); + } + $leftTypesCount = count($leftTypes); $rightTypesCount = count($rightTypes); if ($leftTypesCount > 0 && $rightTypesCount > 0) { @@ -739,8 +757,17 @@ public function getBitwiseXorType(Expr $left, Expr $right, callable $getTypeCall return $this->getNeverType($leftType, $rightType); } - $leftTypes = $leftType->getConstantScalarTypes(); - $rightTypes = $rightType->getConstantScalarTypes(); + if ($leftType instanceof IntegerRangeType) { + $leftTypes = $leftType->getFiniteTypes(); + } else { + $leftTypes = $leftType->getConstantScalarTypes(); + } + if ($rightType instanceof IntegerRangeType) { + $rightTypes = $rightType->getFiniteTypes(); + } else { + $rightTypes = $rightType->getConstantScalarTypes(); + } + $leftTypesCount = count($leftTypes); $rightTypesCount = count($rightTypes); if ($leftTypesCount > 0 && $rightTypesCount > 0) { diff --git a/tests/PHPStan/Rules/Properties/TypesAssignedToPropertiesRuleTest.php b/tests/PHPStan/Rules/Properties/TypesAssignedToPropertiesRuleTest.php index 31bc2859c2..ba4240e047 100644 --- a/tests/PHPStan/Rules/Properties/TypesAssignedToPropertiesRuleTest.php +++ b/tests/PHPStan/Rules/Properties/TypesAssignedToPropertiesRuleTest.php @@ -956,6 +956,18 @@ public function testBug13035(): void $this->analyse([__DIR__ . '/data/bug-13035.php'], []); } + public function testBug7912(): void + { + $this->checkExplicitMixed = true; + $this->checkImplicitMixed = true; + $this->analyse([__DIR__ . '/data/bug-7912.php'], [ + [ + 'Property Bug7912\A::$has (int<0, 1>) does not accept 999.', + 35, + ], + ]); + } + public function testBug13654(): void { $this->checkExplicitMixed = true; diff --git a/tests/PHPStan/Rules/Properties/data/bug-7912.php b/tests/PHPStan/Rules/Properties/data/bug-7912.php new file mode 100644 index 0000000000..3bafd8d3ce --- /dev/null +++ b/tests/PHPStan/Rules/Properties/data/bug-7912.php @@ -0,0 +1,43 @@ + */ + public int $has = 0; + + /** @var int<0,1> */ + public int $not = 0; +} + +class B +{ + /** @var int<0,1> */ + public int $has = 1; +} + +$a = new A(); +$b = new B(); + +// The following versions throw an error, even though | between 0,1 will always be 0,1 +$a->has |= $b->has; +$a->has = $a->has | $b->has; + +// The following versions don't: +$a->has = 0 | 1; +$a->has |= 1; + +$int = 1; +$a->has |= $int; + +// This properly errors: +$a->has |= 999; + +// And these all work: +/** @var int<0,1> */ +$c = 0; +/** @var int<0,1> */ +$e = 1; +$c |= $e; +$c |= $a->has;