12
12
use PHPStan \Rules \RuleLevelHelper ;
13
13
use PHPStan \Type \BenevolentUnionType ;
14
14
use PHPStan \Type \ErrorType ;
15
+ use PHPStan \Type \MixedType ;
16
+ use PHPStan \Type \NeverType ;
15
17
use PHPStan \Type \Type ;
18
+ use PHPStan \Type \TypeCombinator ;
16
19
use PHPStan \Type \TypeUtils ;
17
20
use PHPStan \Type \VerbosityLevel ;
18
21
use function count ;
@@ -60,6 +63,14 @@ public function check(
60
63
}
61
64
62
65
if ($ type ->hasOffsetValueType ($ dimType )->no ()) {
66
+ if ($ type ->isArray ()->yes ()) {
67
+ $ validArrayDimType = TypeCombinator::intersect (AllowedArrayKeysTypes::getType (), $ dimType );
68
+ if ($ validArrayDimType instanceof NeverType) {
69
+ // Already reported by InvalidKeyInArrayDimFetchRule
70
+ return [];
71
+ }
72
+ }
73
+
63
74
return [
64
75
RuleErrorBuilder::message (sprintf ('Offset %s does not exist on %s. ' , $ dimType ->describe (count ($ dimType ->getConstantStrings ()) > 0 ? VerbosityLevel::precise () : VerbosityLevel::value ()), $ type ->describe (VerbosityLevel::value ())))
65
76
->identifier ('offsetAccess.notFound ' )
@@ -76,28 +87,34 @@ public function check(
76
87
$ flattenedTypes = TypeUtils::flattenTypes ($ type );
77
88
}
78
89
90
+ $ validArrayDimType = $ dimType instanceof MixedType
91
+ ? $ dimType
92
+ : TypeCombinator::intersect (AllowedArrayKeysTypes::getType (), $ dimType );
93
+
79
94
foreach ($ flattenedTypes as $ innerType ) {
95
+ $ dimTypeToCheck = $ innerType ->isArray ()->yes () ? $ validArrayDimType : $ dimType ;
96
+
80
97
if (
81
98
$ this ->reportPossiblyNonexistentGeneralArrayOffset
82
99
&& $ innerType ->isArray ()->yes ()
83
100
&& !$ innerType ->isConstantArray ()->yes ()
84
- && !$ innerType ->hasOffsetValueType ($ dimType )->yes ()
101
+ && !$ innerType ->hasOffsetValueType ($ dimTypeToCheck )->yes ()
85
102
) {
86
103
$ report = true ;
87
104
break ;
88
105
}
89
106
if (
90
107
$ this ->reportPossiblyNonexistentConstantArrayOffset
91
108
&& $ innerType ->isConstantArray ()->yes ()
92
- && !$ innerType ->hasOffsetValueType ($ dimType )->yes ()
109
+ && !$ innerType ->hasOffsetValueType ($ dimTypeToCheck )->yes ()
93
110
) {
94
111
$ report = true ;
95
112
break ;
96
113
}
97
- if ($ dimType instanceof BenevolentUnionType) {
98
- $ flattenedInnerTypes = [$ dimType ];
114
+ if ($ dimTypeToCheck instanceof BenevolentUnionType) {
115
+ $ flattenedInnerTypes = [$ dimTypeToCheck ];
99
116
} else {
100
- $ flattenedInnerTypes = TypeUtils::flattenTypes ($ dimType );
117
+ $ flattenedInnerTypes = TypeUtils::flattenTypes ($ dimTypeToCheck );
101
118
}
102
119
foreach ($ flattenedInnerTypes as $ innerDimType ) {
103
120
if (
0 commit comments