2020use PHPStan \PhpDocParser \Ast \Type \UnionTypeNode ;
2121use Typhoon \PHPStanTypeParser \CustomTypeParser ;
2222use Typhoon \PHPStanTypeParser \TypeContext ;
23+ use Typhoon \Type \ArrayT ;
2324use Typhoon \Type \ObjectT ;
2425use Typhoon \Type \Type ;
2526use function Typhoon \Type \andT ;
26- use function Typhoon \Type \arrayT ;
2727use function Typhoon \Type \floatRangeT ;
2828use function Typhoon \Type \floatT ;
2929use function Typhoon \Type \intRangeT ;
3030use function Typhoon \Type \intT ;
31- use function Typhoon \Type \nonEmptyArrayT ;
3231use function Typhoon \Type \nullOrT ;
3332use function Typhoon \Type \orT ;
3433use function Typhoon \Type \stringT ;
6059 * @internal
6160 * @psalm-internal Typhoon\PHPStanTypeParser
6261 */
63- final class ContextualTypeParser
62+ final readonly class ContextualTypeParser
6463{
6564 public function __construct (
66- private readonly CustomTypeParser $ customTypeParser ,
67- private readonly TypeContext $ context ,
65+ private CustomTypeParser $ customTypeParser ,
66+ private TypeContext $ context ,
6867 ) {}
6968
7069 public function parseTypeNode (TypeNode $ node ): Type
@@ -87,7 +86,7 @@ private static function parseConstExpr(ConstExprNode $node): Type
8786 $ node instanceof ConstExprFalseNode => falseT,
8887 $ node instanceof ConstExprTrueNode => trueT,
8988 $ node instanceof ConstExprIntegerNode => match (true ) {
90- is_numeric ($ node ->value ) => intT ($ node ->value ),
89+ is_numeric ($ node ->value ) => intT (( int ) $ node ->value ),
9190 default => throw new \LogicException (),
9291 },
9392 $ node instanceof ConstExprFloatNode => match (true ) {
@@ -151,17 +150,17 @@ private function parseIdentifier(string $name, array $genericNodes = []): Type
151150 if ($ name === 'array ' ) {
152151 return match ($ number = \count ($ templateArguments )) {
153152 0 => arrayT,
154- 1 => arrayT (valueType: $ templateArguments [0 ]),
155- 2 => arrayT ($ templateArguments [0 ], $ templateArguments [1 ]),
153+ 1 => new ArrayT (valueType: $ templateArguments [0 ]),
154+ 2 => new ArrayT ($ templateArguments [0 ], $ templateArguments [1 ]),
156155 default => throw new \LogicException (\sprintf ('array type should have at most 2 type arguments, got %d ' , $ number )),
157156 };
158157 }
159158
160159 if ($ name === 'non-empty-array ' ) {
161160 return match ($ number = \count ($ templateArguments )) {
162- 0 => nonEmptyArrayT ( ),
163- 1 => nonEmptyArrayT (valueType: $ templateArguments [0 ]),
164- 2 => nonEmptyArrayT ($ templateArguments [0 ], $ templateArguments [1 ]),
161+ 0 => new ArrayT (isNonEmpty: true ),
162+ 1 => new ArrayT (valueType: $ templateArguments [0 ], isNonEmpty: true ),
163+ 2 => new ArrayT ($ templateArguments [0 ], $ templateArguments [1 ], isNonEmpty: true ),
165164 default => throw new \LogicException (\sprintf ('non-empty-array type should have at most 2 type arguments, got %d ' , $ number )),
166165 };
167166 }
@@ -178,8 +177,8 @@ private function parseInt(array $genericNodes): Type
178177 return match (\count ($ genericNodes )) {
179178 0 => intT,
180179 2 => intRangeT (
181- min: self ::parseRangeLimit ($ genericNodes [0 ], 'min ' , float: false ),
182- max: self ::parseRangeLimit ($ genericNodes [1 ], 'max ' , float: false ),
180+ min: self ::parseIntRangeLimit ($ genericNodes [0 ], 'min ' ),
181+ max: self ::parseIntRangeLimit ($ genericNodes [1 ], 'max ' ),
183182 ),
184183 default => throw new \LogicException (\sprintf (
185184 'Int range type should have 2 type arguments, got %d ' ,
@@ -196,8 +195,8 @@ private function parseFloat(array $genericNodes): Type
196195 return match (\count ($ genericNodes )) {
197196 0 => floatT,
198197 2 => floatRangeT (
199- min: self ::parseRangeLimit ($ genericNodes [0 ], 'min ' , float: true ),
200- max: self ::parseRangeLimit ($ genericNodes [1 ], 'max ' , float: true ),
198+ min: self ::parseFloatRangeLimit ($ genericNodes [0 ], 'min ' ),
199+ max: self ::parseFloatRangeLimit ($ genericNodes [1 ], 'max ' ),
201200 ),
202201 default => throw new \LogicException (\sprintf (
203202 'Float range type should have 2 type arguments, got %d ' ,
@@ -208,9 +207,8 @@ private function parseFloat(array $genericNodes): Type
208207
209208 /**
210209 * @param 'min'|'max' $name
211- * @return ?numeric-string
212210 */
213- private function parseRangeLimit (TypeNode $ type , string $ name, bool $ float ): ?string
211+ private function parseIntRangeLimit (TypeNode $ type , string $ name ): ?int
214212 {
215213 if ($ type instanceof IdentifierTypeNode) {
216214 if ($ type ->name === $ name ) {
@@ -226,11 +224,34 @@ private function parseRangeLimit(TypeNode $type, string $name, bool $float): ?st
226224
227225 $ expr = $ type ->constExpr ;
228226
229- if (($ float && $ expr instanceof ConstExprFloatNode) || $ expr instanceof ConstExprIntegerNode) {
230- if (!is_numeric ($ expr ->value )) {
231- throw new \LogicException ();
227+ if ($ expr instanceof ConstExprIntegerNode && is_numeric ($ expr ->value )) {
228+ return (int ) $ expr ->value ;
229+ }
230+
231+ throw new \LogicException ();
232+ }
233+
234+ /**
235+ * @param 'min'|'max' $name
236+ * @return ?numeric-string
237+ */
238+ private function parseFloatRangeLimit (TypeNode $ type , string $ name ): ?string
239+ {
240+ if ($ type instanceof IdentifierTypeNode) {
241+ if ($ type ->name === $ name ) {
242+ return null ;
232243 }
233244
245+ throw new \LogicException ();
246+ }
247+
248+ if (!$ type instanceof ConstTypeNode) {
249+ throw new \LogicException ();
250+ }
251+
252+ $ expr = $ type ->constExpr ;
253+
254+ if (($ expr instanceof ConstExprFloatNode || $ expr instanceof ConstExprIntegerNode) && is_numeric ($ expr ->value )) {
234255 return $ expr ->value ;
235256 }
236257
0 commit comments