@@ -39,14 +39,10 @@ public function getReturnValueType(Type $arrayType, Type $columnType, Scope $sco
3939 }
4040
4141 $ iterableValueType = $ arrayType ->getIterableValueType ();
42- $ returnValueType = $ this ->getOffsetOrProperty ($ iterableValueType , $ columnType , $ scope, false );
42+ [ $ returnValueType, $ certainty ] = $ this ->getOffsetOrProperty ($ iterableValueType , $ columnType , $ scope );
4343
44- if ($ returnValueType === null ) {
45- $ returnValueType = $ this ->getOffsetOrProperty ($ iterableValueType , $ columnType , $ scope , true );
44+ if (!$ certainty ->yes ()) {
4645 $ iterableAtLeastOnce = TrinaryLogic::createMaybe ();
47- if ($ returnValueType === null ) {
48- throw new ShouldNotHappenException ();
49- }
5046 }
5147
5248 return [$ returnValueType , $ iterableAtLeastOnce ];
@@ -57,15 +53,12 @@ public function getReturnIndexType(Type $arrayType, Type $indexType, Scope $scop
5753 if (!$ indexType ->isNull ()->yes ()) {
5854 $ iterableValueType = $ arrayType ->getIterableValueType ();
5955
60- $ type = $ this ->getOffsetOrProperty ($ iterableValueType , $ indexType , $ scope, false );
61- if ($ type !== null ) {
56+ [ $ type, $ certainty ] = $ this ->getOffsetOrProperty ($ iterableValueType , $ indexType , $ scope );
57+ if ($ certainty -> yes () ) {
6258 return $ type ;
6359 }
6460
65- $ type = $ this ->getOffsetOrProperty ($ iterableValueType , $ indexType , $ scope , true );
66- if ($ type !== null ) {
67- return TypeCombinator::union ($ type , new IntegerType ());
68- }
61+ return TypeCombinator::union ($ type , new IntegerType ());
6962 }
7063
7164 return new IntegerType ();
@@ -96,25 +89,20 @@ public function handleConstantArray(ConstantArrayType $arrayType, Type $columnTy
9689 $ builder = ConstantArrayTypeBuilder::createEmpty ();
9790
9891 foreach ($ arrayType ->getValueTypes () as $ i => $ iterableValueType ) {
99- $ valueType = $ this ->getOffsetOrProperty ($ iterableValueType , $ columnType , $ scope, false );
100- if ($ valueType === null ) {
92+ [ $ valueType, $ certainty ] = $ this ->getOffsetOrProperty ($ iterableValueType , $ columnType , $ scope );
93+ if (! $ certainty -> yes () ) {
10194 return null ;
10295 }
10396 if ($ valueType instanceof NeverType) {
10497 continue ;
10598 }
10699
107100 if (!$ indexType ->isNull ()->yes ()) {
108- $ type = $ this ->getOffsetOrProperty ($ iterableValueType , $ indexType , $ scope, false );
109- if ($ type !== null ) {
101+ [ $ type, $ certainty ] = $ this ->getOffsetOrProperty ($ iterableValueType , $ indexType , $ scope );
102+ if ($ certainty -> yes () ) {
110103 $ keyType = $ type ;
111104 } else {
112- $ type = $ this ->getOffsetOrProperty ($ iterableValueType , $ indexType , $ scope , true );
113- if ($ type !== null ) {
114- $ keyType = TypeCombinator::union ($ type , new IntegerType ());
115- } else {
116- $ keyType = null ;
117- }
105+ $ keyType = TypeCombinator::union ($ type , new IntegerType ());
118106 }
119107 } else {
120108 $ keyType = null ;
@@ -129,11 +117,14 @@ public function handleConstantArray(ConstantArrayType $arrayType, Type $columnTy
129117 return $ builder ->getArray ();
130118 }
131119
132- private function getOffsetOrProperty (Type $ type , Type $ offsetOrProperty , Scope $ scope , bool $ allowMaybe ): ?Type
120+ /**
121+ * @return array{Type, TrinaryLogic}
122+ */
123+ private function getOffsetOrProperty (Type $ type , Type $ offsetOrProperty , Scope $ scope ): array
133124 {
134125 $ offsetIsNull = $ offsetOrProperty ->isNull ();
135126 if ($ offsetIsNull ->yes ()) {
136- return $ type ;
127+ return [ $ type, TrinaryLogic:: createYes ()] ;
137128 }
138129
139130 $ returnTypes = [];
@@ -145,13 +136,13 @@ private function getOffsetOrProperty(Type $type, Type $offsetOrProperty, Scope $
145136 if (!$ type ->canAccessProperties ()->no ()) {
146137 $ propertyTypes = $ offsetOrProperty ->getConstantStrings ();
147138 if ($ propertyTypes === []) {
148- return $ allowMaybe ? new MixedType () : null ;
139+ return [ new MixedType (), TrinaryLogic:: createMaybe ()] ;
149140 }
150141 foreach ($ propertyTypes as $ propertyType ) {
151142 $ propertyName = $ propertyType ->getValue ();
152143 $ hasProperty = $ type ->hasProperty ($ propertyName );
153144 if ($ hasProperty ->maybe ()) {
154- return $ allowMaybe ? new MixedType () : null ;
145+ return [ new MixedType (), TrinaryLogic:: createMaybe ()] ;
155146 }
156147 if (!$ hasProperty ->yes ()) {
157148 continue ;
@@ -161,21 +152,22 @@ private function getOffsetOrProperty(Type $type, Type $offsetOrProperty, Scope $
161152 }
162153 }
163154
155+ $ certainty = TrinaryLogic::createYes ();
164156 if ($ type ->isOffsetAccessible ()->yes ()) {
165157 $ hasOffset = $ type ->hasOffsetValueType ($ offsetOrProperty );
166- if (! $ allowMaybe && $ hasOffset ->maybe ()) {
167- return null ;
158+ if ($ hasOffset ->maybe ()) {
159+ $ certainty = TrinaryLogic:: createMaybe () ;
168160 }
169161 if (!$ hasOffset ->no ()) {
170162 $ returnTypes [] = $ type ->getOffsetValueType ($ offsetOrProperty );
171163 }
172164 }
173165
174166 if ($ returnTypes === []) {
175- return new NeverType ();
167+ return [ new NeverType (), TrinaryLogic:: createYes ()] ;
176168 }
177169
178- return TypeCombinator::union (...$ returnTypes );
170+ return [ TypeCombinator::union (...$ returnTypes ), $ certainty ] ;
179171 }
180172
181173 private function castToArrayKeyType (Type $ type ): Type
0 commit comments