From aebf71be933715668f2fdab05e3548534b1565d7 Mon Sep 17 00:00:00 2001 From: Markus Staab Date: Tue, 23 Dec 2025 21:20:44 +0100 Subject: [PATCH 1/2] Prevent unnecessary work in TypeTraverser::map() callbacks --- src/Analyser/MutatingScope.php | 7 ++++--- src/Reflection/InitializerExprTypeResolver.php | 8 +++++--- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/src/Analyser/MutatingScope.php b/src/Analyser/MutatingScope.php index be05271cf1..e5c72eed3c 100644 --- a/src/Analyser/MutatingScope.php +++ b/src/Analyser/MutatingScope.php @@ -3232,10 +3232,11 @@ public function enterPropertyHook( private function transformStaticType(Type $type): Type { return TypeTraverser::map($type, function (Type $type, callable $traverse): Type { - if (!$this->isInClass()) { - return $type; - } if ($type instanceof StaticType) { + if (!$this->isInClass()) { + return $type; + } + $classReflection = $this->getClassReflection(); $changedType = $type->changeBaseClass($classReflection); if ($classReflection->isFinal() && !$type instanceof ThisType) { diff --git a/src/Reflection/InitializerExprTypeResolver.php b/src/Reflection/InitializerExprTypeResolver.php index c76661d6d2..0729ed5e0a 100644 --- a/src/Reflection/InitializerExprTypeResolver.php +++ b/src/Reflection/InitializerExprTypeResolver.php @@ -2400,9 +2400,11 @@ public function getClassConstFetchTypeByReflection(Name|Expr $class, string $con } if (strtolower($constantName) === 'class') { + $reflectionProvider = $this->getReflectionProvider(); + return TypeTraverser::map( $constantClassType, - function (Type $type, callable $traverse): Type { + static function (Type $type, callable $traverse) use ($reflectionProvider): Type { if ($type instanceof UnionType || $type instanceof IntersectionType) { return $traverse($type); } @@ -2428,8 +2430,8 @@ function (Type $type, callable $traverse): Type { new GenericClassStringType($type), new AccessoryLiteralStringType(), ); - } elseif ($objectClassNames !== [] && $this->getReflectionProvider()->hasClass($objectClassNames[0])) { - $reflection = $this->getReflectionProvider()->getClass($objectClassNames[0]); + } elseif ($objectClassNames !== [] && $reflectionProvider->hasClass($objectClassNames[0])) { + $reflection = $reflectionProvider->getClass($objectClassNames[0]); if ($reflection->isFinalByKeyword()) { return new ConstantStringType($reflection->getName(), true); } From 4059f7e3e6aa6092f42cc9772e290be9c54651d6 Mon Sep 17 00:00:00 2001 From: Markus Staab Date: Tue, 23 Dec 2025 21:24:43 +0100 Subject: [PATCH 2/2] Update MutatingScope.php --- src/Analyser/MutatingScope.php | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/Analyser/MutatingScope.php b/src/Analyser/MutatingScope.php index e5c72eed3c..f4603d1fee 100644 --- a/src/Analyser/MutatingScope.php +++ b/src/Analyser/MutatingScope.php @@ -3231,13 +3231,17 @@ public function enterPropertyHook( private function transformStaticType(Type $type): Type { + if (!$this->isInClass()) { + return $type; + } + return TypeTraverser::map($type, function (Type $type, callable $traverse): Type { if ($type instanceof StaticType) { - if (!$this->isInClass()) { - return $type; + $classReflection = $this->getClassReflection(); + if ($classReflection === null) { + throw new ShouldNotHappenException(); } - $classReflection = $this->getClassReflection(); $changedType = $type->changeBaseClass($classReflection); if ($classReflection->isFinal() && !$type instanceof ThisType) { $changedType = $changedType->getStaticObjectType();