@@ -552,13 +552,7 @@ public function canAccessProperties(): TrinaryLogic
552552
553553 public function hasProperty (string $ propertyName ): TrinaryLogic
554554 {
555- foreach ($ this ->types as $ type ) {
556- if ($ type ->isObject ()->no () && $ type ->hasProperty ($ propertyName )->no ()) {
557- return TrinaryLogic::createNo ();
558- }
559- }
560-
561- return $ this ->intersectResults (static fn (Type $ type ): TrinaryLogic => $ type ->hasProperty ($ propertyName ));
555+ return $ this ->intersectResultsWithNonObjectGuard (static fn (Type $ type ): TrinaryLogic => $ type ->hasProperty ($ propertyName ));
562556 }
563557
564558 public function getProperty (string $ propertyName , ClassMemberAccessAnswerer $ scope ): ExtendedPropertyReflection
@@ -591,13 +585,7 @@ public function getUnresolvedPropertyPrototype(string $propertyName, ClassMember
591585
592586 public function hasInstanceProperty (string $ propertyName ): TrinaryLogic
593587 {
594- foreach ($ this ->types as $ type ) {
595- if ($ type ->isObject ()->no () && $ type ->hasInstanceProperty ($ propertyName )->no ()) {
596- return TrinaryLogic::createNo ();
597- }
598- }
599-
600- return $ this ->intersectResults (static fn (Type $ type ): TrinaryLogic => $ type ->hasInstanceProperty ($ propertyName ));
588+ return $ this ->intersectResultsWithNonObjectGuard (static fn (Type $ type ): TrinaryLogic => $ type ->hasInstanceProperty ($ propertyName ));
601589 }
602590
603591 public function getInstanceProperty (string $ propertyName , ClassMemberAccessAnswerer $ scope ): ExtendedPropertyReflection
@@ -630,13 +618,7 @@ public function getUnresolvedInstancePropertyPrototype(string $propertyName, Cla
630618
631619 public function hasStaticProperty (string $ propertyName ): TrinaryLogic
632620 {
633- foreach ($ this ->types as $ type ) {
634- if ($ type ->isObject ()->no () && $ type ->hasStaticProperty ($ propertyName )->no ()) {
635- return TrinaryLogic::createNo ();
636- }
637- }
638-
639- return $ this ->intersectResults (static fn (Type $ type ): TrinaryLogic => $ type ->hasStaticProperty ($ propertyName ));
621+ return $ this ->intersectResultsWithNonObjectGuard (static fn (Type $ type ): TrinaryLogic => $ type ->hasStaticProperty ($ propertyName ));
640622 }
641623
642624 public function getStaticProperty (string $ propertyName , ClassMemberAccessAnswerer $ scope ): ExtendedPropertyReflection
@@ -674,13 +656,7 @@ public function canCallMethods(): TrinaryLogic
674656
675657 public function hasMethod (string $ methodName ): TrinaryLogic
676658 {
677- foreach ($ this ->types as $ type ) {
678- if ($ type ->isObject ()->no () && $ type ->hasMethod ($ methodName )->no ()) {
679- return TrinaryLogic::createNo ();
680- }
681- }
682-
683- return $ this ->intersectResults (static fn (Type $ type ): TrinaryLogic => $ type ->hasMethod ($ methodName ));
659+ return $ this ->intersectResultsWithNonObjectGuard (static fn (Type $ type ): TrinaryLogic => $ type ->hasMethod ($ methodName ));
684660 }
685661
686662 public function getMethod (string $ methodName , ClassMemberAccessAnswerer $ scope ): ExtendedMethodReflection
@@ -718,13 +694,7 @@ public function canAccessConstants(): TrinaryLogic
718694
719695 public function hasConstant (string $ constantName ): TrinaryLogic
720696 {
721- foreach ($ this ->types as $ type ) {
722- if ($ type ->isObject ()->no () && $ type ->hasConstant ($ constantName )->no ()) {
723- return TrinaryLogic::createNo ();
724- }
725- }
726-
727- return $ this ->intersectResults (static fn (Type $ type ): TrinaryLogic => $ type ->hasConstant ($ constantName ));
697+ return $ this ->intersectResultsWithNonObjectGuard (static fn (Type $ type ): TrinaryLogic => $ type ->hasConstant ($ constantName ));
728698 }
729699
730700 public function getConstant (string $ constantName ): ClassConstantReflection
@@ -1513,6 +1483,23 @@ private function intersectResults(
15131483 return TrinaryLogic::lazyMaxMin ($ types , $ getResult );
15141484 }
15151485
1486+ /**
1487+ * @param callable(Type $type): TrinaryLogic $getResult
1488+ */
1489+ private function intersectResultsWithNonObjectGuard (callable $ getResult ): TrinaryLogic
1490+ {
1491+ $ results = [];
1492+ foreach ($ this ->types as $ type ) {
1493+ $ result = $ getResult ($ type );
1494+ if ($ type ->isObject ()->no () && $ result ->no ()) {
1495+ return TrinaryLogic::createNo ();
1496+ }
1497+ $ results [] = $ result ;
1498+ }
1499+
1500+ return TrinaryLogic::maxMin (...$ results );
1501+ }
1502+
15161503 /**
15171504 * @param callable(Type $type): Type $getType
15181505 */
0 commit comments