From 153cdf0f24fcd0144fbbc352af2b42720c447584 Mon Sep 17 00:00:00 2001 From: Tomas Votruba Date: Thu, 30 Jul 2026 22:29:05 +0200 Subject: [PATCH] [Php80] Skip promoting a property the parent declares without a native type --- .../skip_untyped_parent_property.php.inc | 19 +++++++++++++++ .../Source/UntypedPropertyParent.php | 13 +++++++++++ ...ertyAssignToConstructorPromotionRector.php | 23 +++++++++++++++++++ 3 files changed, 55 insertions(+) create mode 100644 rules-tests/Php80/Rector/Class_/ClassPropertyAssignToConstructorPromotionRector/Fixture/skip_untyped_parent_property.php.inc create mode 100644 rules-tests/Php80/Rector/Class_/ClassPropertyAssignToConstructorPromotionRector/Source/UntypedPropertyParent.php diff --git a/rules-tests/Php80/Rector/Class_/ClassPropertyAssignToConstructorPromotionRector/Fixture/skip_untyped_parent_property.php.inc b/rules-tests/Php80/Rector/Class_/ClassPropertyAssignToConstructorPromotionRector/Fixture/skip_untyped_parent_property.php.inc new file mode 100644 index 00000000000..4ca0eec8ddc --- /dev/null +++ b/rules-tests/Php80/Rector/Class_/ClassPropertyAssignToConstructorPromotionRector/Fixture/skip_untyped_parent_property.php.inc @@ -0,0 +1,19 @@ +model = $model; + } +} diff --git a/rules-tests/Php80/Rector/Class_/ClassPropertyAssignToConstructorPromotionRector/Source/UntypedPropertyParent.php b/rules-tests/Php80/Rector/Class_/ClassPropertyAssignToConstructorPromotionRector/Source/UntypedPropertyParent.php new file mode 100644 index 00000000000..f5e532c00f5 --- /dev/null +++ b/rules-tests/Php80/Rector/Class_/ClassPropertyAssignToConstructorPromotionRector/Source/UntypedPropertyParent.php @@ -0,0 +1,13 @@ +shouldSkipUntypedParentProperty($classReflection, $propertyName)) { + continue; + } + $hasChanged = true; // remove property from class @@ -347,6 +351,25 @@ private function processUnionType(Property $property, Param $param): void $param->type = $this->staticTypeMapper->mapPHPStanTypeToPhpParserNode($paramType, TypeKind::PARAM); } + /** + * A parent property declared without a native type cannot be typed by a child. Promotion moves the param + * type onto the property, so promoting such a property makes the class fatal: + * "Type of Child::$property must not be defined (as in class Parent)". + */ + private function shouldSkipUntypedParentProperty(ClassReflection $classReflection, string $propertyName): bool + { + foreach ($classReflection->getParents() as $parentClassReflection) { + if (! $parentClassReflection->hasNativeProperty($propertyName)) { + continue; + } + + return ! $parentClassReflection->getNativeProperty($propertyName) + ->hasNativeType(); + } + + return false; + } + private function shouldSkipParam(Param $param): bool { if ($param->variadic) {