@@ -61,7 +61,16 @@ class ObjectType implements TypeWithClassName, SubtractableType
6161 use UndecidedComparisonTypeTrait;
6262 use NonGeneralizableTypeTrait;
6363
64- private const EXTRA_OFFSET_CLASSES = ['SimpleXMLElement ' , 'DOMNodeList ' , 'Threaded ' ];
64+ private const EXTRA_OFFSET_CLASSES = [
65+ 'DOMNamedNodeMap ' ,
66+ 'Dom\NamedNodeMap ' ,
67+ 'DOMNodeList ' ,
68+ 'Dom\NodeList ' ,
69+ 'Dom\HTMLCollection ' ,
70+ 'Dom\DtdNamedNodeMap ' ,
71+ 'SimpleXMLElement ' ,
72+ 'Threaded ' ,
73+ ];
6574
6675 private ?Type $ subtractedType ;
6776
@@ -1067,19 +1076,26 @@ public function looseCompare(Type $type, PhpVersion $phpVersion): BooleanType
10671076 : new BooleanType ();
10681077 }
10691078
1070- private function isExtraOffsetAccessibleClass (): TrinaryLogic
1079+ private function isExtraOffsetAccessibleClass (AccessOffsetMode $ mode ): TrinaryLogic
10711080 {
10721081 $ classReflection = $ this ->getClassReflection ();
10731082 if ($ classReflection === null ) {
10741083 return TrinaryLogic::createMaybe ();
10751084 }
10761085
1086+ // TODO Narrow down NodeList/Map types
10771087 foreach (self ::EXTRA_OFFSET_CLASSES as $ extraOffsetClass ) {
1078- if ($ classReflection ->getName () === $ extraOffsetClass ) {
1079- return TrinaryLogic::createYes ();
1080- }
1081- if ($ classReflection ->isSubclassOf ($ extraOffsetClass )) {
1082- return TrinaryLogic::createYes ();
1088+ if (
1089+ $ classReflection ->getName () === $ extraOffsetClass
1090+ || $ classReflection ->isSubclassOf ($ extraOffsetClass )
1091+ ) {
1092+ return match ($ extraOffsetClass ) {
1093+ 'DOMNamedNodeMap ' , 'Dom\NamedNodeMap ' , 'DOMNodeList ' , 'Dom\NodeList ' , 'Dom\HTMLCollection ' , 'Dom\DtdNamedNodeMap ' => match ($ mode ) {
1094+ AccessOffsetMode::Read, AccessOffsetMode::Exist => TrinaryLogic::createYes (),
1095+ default => TrinaryLogic::createNo (),
1096+ },
1097+ default => TrinaryLogic::createYes (),
1098+ };
10831099 }
10841100 }
10851101
@@ -1097,14 +1113,16 @@ private function isExtraOffsetAccessibleClass(): TrinaryLogic
10971113 public function isOffsetAccessible (): TrinaryLogic
10981114 {
10991115 return $ this ->isInstanceOf (ArrayAccess::class)->or (
1100- $ this ->isExtraOffsetAccessibleClass (),
1116+ // TODO Back propagate this?
1117+ $ this ->isExtraOffsetAccessibleClass (AccessOffsetMode::Read),
11011118 );
11021119 }
11031120
11041121 public function isOffsetAccessLegal (AccessOffsetMode $ mode ): TrinaryLogic
11051122 {
1106- // TODO Narrow down NodeList/Map types
1107- return $ this ->isOffsetAccessible ();
1123+ return $ this ->isInstanceOf (ArrayAccess::class)->or (
1124+ $ this ->isExtraOffsetAccessibleClass ($ mode ),
1125+ );
11081126 }
11091127
11101128 public function hasOffsetValueType (Type $ offsetType ): TrinaryLogic
0 commit comments