@@ -1057,6 +1057,8 @@ private function resolveArrayShapeNode(ArrayShapeNode $typeNode, NameScope $name
10571057 $ offsetType = new ConstantStringType ($ itemNode ->keyName ->name );
10581058 } elseif ($ itemNode ->keyName instanceof ConstExprStringNode) {
10591059 $ offsetType = new ConstantStringType ($ itemNode ->keyName ->value );
1060+ } elseif ($ itemNode ->keyName instanceof ConstFetchNode) {
1061+ $ offsetType = $ this ->resolveConstFetchNode ($ itemNode ->keyName , $ nameScope );
10601062 } elseif ($ itemNode ->keyName !== null ) {
10611063 throw new ShouldNotHappenException ('Unsupported key node type: ' . get_class ($ itemNode ->keyName ));
10621064 }
@@ -1118,107 +1120,112 @@ private function resolveConstTypeNode(ConstTypeNode $typeNode, NameScope $nameSc
11181120 }
11191121
11201122 if ($ constExpr instanceof ConstFetchNode) {
1121- if ($ constExpr ->className === '' ) {
1122- throw new ShouldNotHappenException (); // global constant should get parsed as class name in IdentifierTypeNode
1123- }
1123+ return $ this ->resolveConstFetchNode ($ constExpr , $ nameScope );
1124+ }
11241125
1125- if ($ nameScope ->getClassName () !== null ) {
1126- switch (strtolower ($ constExpr ->className )) {
1127- case 'static ' :
1128- case 'self ' :
1129- $ className = $ nameScope ->getClassName ();
1130- break ;
1126+ if ($ constExpr instanceof ConstExprFloatNode) {
1127+ return new ConstantFloatType ((float ) $ constExpr ->value );
1128+ }
11311129
1132- case 'parent ' :
1133- if ($ this ->getReflectionProvider ()->hasClass ($ nameScope ->getClassName ())) {
1134- $ classReflection = $ this ->getReflectionProvider ()->getClass ($ nameScope ->getClassName ());
1135- if ($ classReflection ->getParentClass () === null ) {
1136- return new ErrorType ();
1130+ if ($ constExpr instanceof ConstExprIntegerNode) {
1131+ return new ConstantIntegerType ((int ) $ constExpr ->value );
1132+ }
11371133
1138- }
1134+ if ($ constExpr instanceof ConstExprStringNode) {
1135+ return new ConstantStringType ($ constExpr ->value );
1136+ }
11391137
1140- $ className = $ classReflection ->getParentClass ()->getName ();
1141- }
1142- break ;
1143- }
1144- }
1138+ return new ErrorType ();
1139+ }
11451140
1146- if (!isset ($ className )) {
1147- $ className = $ nameScope ->resolveStringName ($ constExpr ->className );
1148- }
1141+ private function resolveConstFetchNode (ConstFetchNode $ constExpr , NameScope $ nameScope ): Type
1142+ {
1143+ if ($ constExpr ->className === '' ) {
1144+ throw new ShouldNotHappenException (); // global constant should get parsed as class name in IdentifierTypeNode
1145+ }
11491146
1150- if (!$ this ->getReflectionProvider ()->hasClass ($ className )) {
1151- return new ErrorType ();
1152- }
1147+ if ($ nameScope ->getClassName () !== null ) {
1148+ switch (strtolower ($ constExpr ->className )) {
1149+ case 'static ' :
1150+ case 'self ' :
1151+ $ className = $ nameScope ->getClassName ();
1152+ break ;
11531153
1154- $ classReflection = $ this ->getReflectionProvider ()->getClass ($ className );
1154+ case 'parent ' :
1155+ if ($ this ->getReflectionProvider ()->hasClass ($ nameScope ->getClassName ())) {
1156+ $ classReflection = $ this ->getReflectionProvider ()->getClass ($ nameScope ->getClassName ());
1157+ if ($ classReflection ->getParentClass () === null ) {
1158+ return new ErrorType ();
11551159
1156- $ constantName = $ constExpr ->name ;
1157- if (Strings::contains ($ constantName , '* ' )) {
1158- // convert * into .*? and escape everything else so the constants can be matched against the pattern
1159- $ pattern = '{^ ' . str_replace ('\\* ' , '.*? ' , preg_quote ($ constantName )) . '$}D ' ;
1160- $ constantTypes = [];
1161- foreach ($ classReflection ->getNativeReflection ()->getReflectionConstants () as $ reflectionConstant ) {
1162- $ classConstantName = $ reflectionConstant ->getName ();
1163- if (Strings::match ($ classConstantName , $ pattern ) === null ) {
1164- continue ;
1165- }
1160+ }
11661161
1167- if ($ classReflection ->isEnum () && $ classReflection ->hasEnumCase ($ classConstantName )) {
1168- $ constantTypes [] = new EnumCaseObjectType ($ classReflection ->getName (), $ classConstantName );
1169- continue ;
1162+ $ className = $ classReflection ->getParentClass ()->getName ();
11701163 }
1164+ break ;
1165+ }
1166+ }
11711167
1172- $ declaringClassName = $ reflectionConstant ->getDeclaringClass ()->getName ();
1173- if (!$ this ->getReflectionProvider ()->hasClass ($ declaringClassName )) {
1174- continue ;
1175- }
1168+ if (!isset ($ className )) {
1169+ $ className = $ nameScope ->resolveStringName ($ constExpr ->className );
1170+ }
11761171
1177- $ constantTypes [] = $ this ->initializerExprTypeResolver ->getType (
1178- $ reflectionConstant ->getValueExpression (),
1179- InitializerExprContext::fromClassReflection (
1180- $ this ->getReflectionProvider ()->getClass ($ declaringClassName ),
1181- ),
1182- );
1183- }
1172+ if (!$ this ->getReflectionProvider ()->hasClass ($ className )) {
1173+ return new ErrorType ();
1174+ }
11841175
1185- if (count ($ constantTypes ) === 0 ) {
1186- return new ErrorType ();
1176+ $ classReflection = $ this ->getReflectionProvider ()->getClass ($ className );
1177+
1178+ $ constantName = $ constExpr ->name ;
1179+ if (Strings::contains ($ constantName , '* ' )) {
1180+ // convert * into .*? and escape everything else so the constants can be matched against the pattern
1181+ $ pattern = '{^ ' . str_replace ('\\* ' , '.*? ' , preg_quote ($ constantName )) . '$}D ' ;
1182+ $ constantTypes = [];
1183+ foreach ($ classReflection ->getNativeReflection ()->getReflectionConstants () as $ reflectionConstant ) {
1184+ $ classConstantName = $ reflectionConstant ->getName ();
1185+ if (Strings::match ($ classConstantName , $ pattern ) === null ) {
1186+ continue ;
11871187 }
11881188
1189- return TypeCombinator::union (...$ constantTypes );
1190- }
1189+ if ($ classReflection ->isEnum () && $ classReflection ->hasEnumCase ($ classConstantName )) {
1190+ $ constantTypes [] = new EnumCaseObjectType ($ classReflection ->getName (), $ classConstantName );
1191+ continue ;
1192+ }
11911193
1192- if (!$ classReflection ->hasConstant ($ constantName )) {
1193- return new ErrorType ();
1194- }
1194+ $ declaringClassName = $ reflectionConstant ->getDeclaringClass ()->getName ();
1195+ if (!$ this ->getReflectionProvider ()->hasClass ($ declaringClassName )) {
1196+ continue ;
1197+ }
11951198
1196- if ($ classReflection ->isEnum () && $ classReflection ->hasEnumCase ($ constantName )) {
1197- return new EnumCaseObjectType ($ classReflection ->getName (), $ constantName );
1199+ $ constantTypes [] = $ this ->initializerExprTypeResolver ->getType (
1200+ $ reflectionConstant ->getValueExpression (),
1201+ InitializerExprContext::fromClassReflection (
1202+ $ this ->getReflectionProvider ()->getClass ($ declaringClassName ),
1203+ ),
1204+ );
11981205 }
11991206
1200- $ reflectionConstant = $ classReflection ->getNativeReflection ()->getReflectionConstant ($ constantName );
1201- if ($ reflectionConstant === false ) {
1207+ if (count ($ constantTypes ) === 0 ) {
12021208 return new ErrorType ();
12031209 }
1204- $ declaringClass = $ reflectionConstant ->getDeclaringClass ();
12051210
1206- return $ this -> initializerExprTypeResolver -> getType ( $ reflectionConstant -> getValueExpression (), InitializerExprContext:: fromClass ( $ declaringClass -> getName (), $ declaringClass -> getFileName () ?: null ) );
1211+ return TypeCombinator:: union (... $ constantTypes );
12071212 }
12081213
1209- if ($ constExpr instanceof ConstExprFloatNode ) {
1210- return new ConstantFloatType (( float ) $ constExpr -> value );
1214+ if (! $ classReflection -> hasConstant ( $ constantName ) ) {
1215+ return new ErrorType ( );
12111216 }
12121217
1213- if ($ constExpr instanceof ConstExprIntegerNode ) {
1214- return new ConstantIntegerType (( int ) $ constExpr -> value );
1218+ if ($ classReflection -> isEnum () && $ classReflection -> hasEnumCase ( $ constantName ) ) {
1219+ return new EnumCaseObjectType ( $ classReflection -> getName (), $ constantName );
12151220 }
12161221
1217- if ($ constExpr instanceof ConstExprStringNode) {
1218- return new ConstantStringType ($ constExpr ->value );
1222+ $ reflectionConstant = $ classReflection ->getNativeReflection ()->getReflectionConstant ($ constantName );
1223+ if ($ reflectionConstant === false ) {
1224+ return new ErrorType ();
12191225 }
1226+ $ declaringClass = $ reflectionConstant ->getDeclaringClass ();
12201227
1221- return new ErrorType ( );
1228+ return $ this -> initializerExprTypeResolver -> getType ( $ reflectionConstant -> getValueExpression (), InitializerExprContext:: fromClass ( $ declaringClass -> getName (), $ declaringClass -> getFileName () ?: null ) );
12221229 }
12231230
12241231 private function resolveOffsetAccessNode (OffsetAccessTypeNode $ typeNode , NameScope $ nameScope ): Type
0 commit comments