55use PHPStan \Analyser \Scope ;
66use PHPStan \DependencyInjection \AutowiredService ;
77use PHPStan \Php \PhpVersion ;
8- use PHPStan \ShouldNotHappenException ;
98use PHPStan \TrinaryLogic ;
109use PHPStan \Type \Accessory \AccessoryArrayListType ;
1110use PHPStan \Type \Accessory \NonEmptyArrayType ;
@@ -39,14 +38,10 @@ public function getReturnValueType(Type $arrayType, Type $columnType, Scope $sco
3938 }
4039
4140 $ iterableValueType = $ arrayType ->getIterableValueType ();
42- $ returnValueType = $ this ->getOffsetOrProperty ($ iterableValueType , $ columnType , $ scope, false );
41+ [ $ returnValueType, $ certainty ] = $ this ->getOffsetOrProperty ($ iterableValueType , $ columnType , $ scope );
4342
44- if ($ returnValueType === null ) {
45- $ returnValueType = $ this ->getOffsetOrProperty ($ iterableValueType , $ columnType , $ scope , true );
43+ if (!$ certainty ->yes ()) {
4644 $ iterableAtLeastOnce = TrinaryLogic::createMaybe ();
47- if ($ returnValueType === null ) {
48- throw new ShouldNotHappenException ();
49- }
5045 }
5146
5247 return [$ returnValueType , $ iterableAtLeastOnce ];
@@ -57,15 +52,12 @@ public function getReturnIndexType(Type $arrayType, Type $indexType, Scope $scop
5752 if (!$ indexType ->isNull ()->yes ()) {
5853 $ iterableValueType = $ arrayType ->getIterableValueType ();
5954
60- $ type = $ this ->getOffsetOrProperty ($ iterableValueType , $ indexType , $ scope, false );
61- if ($ type !== null ) {
55+ [ $ type, $ certainty ] = $ this ->getOffsetOrProperty ($ iterableValueType , $ indexType , $ scope );
56+ if ($ certainty -> yes () ) {
6257 return $ type ;
6358 }
6459
65- $ type = $ this ->getOffsetOrProperty ($ iterableValueType , $ indexType , $ scope , true );
66- if ($ type !== null ) {
67- return TypeCombinator::union ($ type , new IntegerType ());
68- }
60+ return TypeCombinator::union ($ type , new IntegerType ());
6961 }
7062
7163 return new IntegerType ();
@@ -96,25 +88,20 @@ public function handleConstantArray(ConstantArrayType $arrayType, Type $columnTy
9688 $ builder = ConstantArrayTypeBuilder::createEmpty ();
9789
9890 foreach ($ arrayType ->getValueTypes () as $ i => $ iterableValueType ) {
99- $ valueType = $ this ->getOffsetOrProperty ($ iterableValueType , $ columnType , $ scope, false );
100- if ($ valueType === null ) {
91+ [ $ valueType, $ certainty ] = $ this ->getOffsetOrProperty ($ iterableValueType , $ columnType , $ scope );
92+ if (! $ certainty -> yes () ) {
10193 return null ;
10294 }
10395 if ($ valueType instanceof NeverType) {
10496 continue ;
10597 }
10698
10799 if (!$ indexType ->isNull ()->yes ()) {
108- $ type = $ this ->getOffsetOrProperty ($ iterableValueType , $ indexType , $ scope, false );
109- if ($ type !== null ) {
100+ [ $ type, $ certainty ] = $ this ->getOffsetOrProperty ($ iterableValueType , $ indexType , $ scope );
101+ if ($ certainty -> yes () ) {
110102 $ keyType = $ type ;
111103 } 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- }
104+ $ keyType = TypeCombinator::union ($ type , new IntegerType ());
118105 }
119106 } else {
120107 $ keyType = null ;
@@ -129,11 +116,14 @@ public function handleConstantArray(ConstantArrayType $arrayType, Type $columnTy
129116 return $ builder ->getArray ();
130117 }
131118
132- private function getOffsetOrProperty (Type $ type , Type $ offsetOrProperty , Scope $ scope , bool $ allowMaybe ): ?Type
119+ /**
120+ * @return array{Type, TrinaryLogic}
121+ */
122+ private function getOffsetOrProperty (Type $ type , Type $ offsetOrProperty , Scope $ scope ): array
133123 {
134124 $ offsetIsNull = $ offsetOrProperty ->isNull ();
135125 if ($ offsetIsNull ->yes ()) {
136- return $ type ;
126+ return [ $ type, TrinaryLogic:: createYes ()] ;
137127 }
138128
139129 $ returnTypes = [];
@@ -145,13 +135,13 @@ private function getOffsetOrProperty(Type $type, Type $offsetOrProperty, Scope $
145135 if (!$ type ->canAccessProperties ()->no ()) {
146136 $ propertyTypes = $ offsetOrProperty ->getConstantStrings ();
147137 if ($ propertyTypes === []) {
148- return new MixedType ();
138+ return [ new MixedType (), TrinaryLogic:: createMaybe ()] ;
149139 }
150140 foreach ($ propertyTypes as $ propertyType ) {
151141 $ propertyName = $ propertyType ->getValue ();
152142 $ hasProperty = $ type ->hasProperty ($ propertyName );
153143 if ($ hasProperty ->maybe ()) {
154- return $ allowMaybe ? new MixedType () : null ;
144+ return [ new MixedType (), TrinaryLogic:: createMaybe ()] ;
155145 }
156146 if (!$ hasProperty ->yes ()) {
157147 continue ;
@@ -161,21 +151,22 @@ private function getOffsetOrProperty(Type $type, Type $offsetOrProperty, Scope $
161151 }
162152 }
163153
154+ $ certainty = TrinaryLogic::createYes ();
164155 if ($ type ->isOffsetAccessible ()->yes ()) {
165156 $ hasOffset = $ type ->hasOffsetValueType ($ offsetOrProperty );
166- if (! $ allowMaybe && $ hasOffset ->maybe ()) {
167- return null ;
157+ if ($ hasOffset ->maybe ()) {
158+ $ certainty = TrinaryLogic:: createMaybe () ;
168159 }
169160 if (!$ hasOffset ->no ()) {
170161 $ returnTypes [] = $ type ->getOffsetValueType ($ offsetOrProperty );
171162 }
172163 }
173164
174165 if ($ returnTypes === []) {
175- return new NeverType ();
166+ return [ new NeverType (), TrinaryLogic:: createYes ()] ;
176167 }
177168
178- return TypeCombinator::union (...$ returnTypes );
169+ return [ TypeCombinator::union (...$ returnTypes ), $ certainty ] ;
179170 }
180171
181172 private function castToArrayKeyType (Type $ type ): Type
0 commit comments