Skip to content

Commit

Permalink
Merge pull request #7829 from AndrolGenhald/bugfix/int-range-namespac…
Browse files Browse the repository at this point in the history
…ed-keywords

Fix namespaced min/max int range keyword issue introduced in #7775
  • Loading branch information
orklah committed Mar 31, 2022
2 parents 05a3806 + 0bdf942 commit 1fc5c1c
Show file tree
Hide file tree
Showing 2 changed files with 31 additions and 30 deletions.
50 changes: 20 additions & 30 deletions src/Psalm/Internal/Type/TypeParser.php
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@
use function array_unique;
use function array_unshift;
use function array_values;
use function assert;
use function constant;
use function count;
use function defined;
Expand Down Expand Up @@ -822,38 +823,27 @@ private static function getTypeFromGenericTree(
if (count($generic_params) !== 2) {
throw new TypeParseTreeException('int range must have 2 params');
}
assert(count($parse_tree->children) === 2);

$param0_union_types = array_values($generic_params[0]->getAtomicTypes());
$param1_union_types = array_values($generic_params[1]->getAtomicTypes());

if (count($param0_union_types) > 1 || count($param1_union_types) > 1) {
throw new TypeParseTreeException('Union types are not allowed in int range type');
}

if (!($param0_union_types[0] instanceof TNamedObject) && !($param0_union_types[0] instanceof TLiteralInt) ||
!($param1_union_types[0] instanceof TNamedObject) && !($param1_union_types[0] instanceof TLiteralInt)) {
throw new TypeParseTreeException('Unsupported parameter');
}

if ($param0_union_types[0] instanceof TNamedObject
&& $param0_union_types[0]->value !== TIntRange::BOUND_MIN) {
throw new TypeParseTreeException('Incorrect named object as a min boundary');
}

if ($param1_union_types[0] instanceof TNamedObject
&& $param1_union_types[0]->value !== TIntRange::BOUND_MAX) {
throw new TypeParseTreeException('Incorrect named object as a max boundary');
}
$get_int_range_bound = function (ParseTree $parse_tree, Union $generic_param, string $bound_name): ?int {
if (!$parse_tree instanceof Value
|| count($generic_param->getAtomicTypes()) > 1
|| (!$generic_param->getSingleAtomic() instanceof TLiteralInt
&& $parse_tree->value !== $bound_name
&& $parse_tree->text !== $bound_name
)
) {
throw new TypeParseTreeException(
"Invalid type \"{$generic_param->getId()}\" as int $bound_name boundary"
);
}

$min_bound = null;
$max_bound = null;
$generic_param_atomic = $generic_param->getSingleAtomic();
return $generic_param_atomic instanceof TLiteralInt ? $generic_param_atomic->value : null;
};

if ($param0_union_types[0] instanceof TLiteralInt) {
$min_bound = $param0_union_types[0]->value;
}
if ($param1_union_types[0] instanceof TLiteralInt) {
$max_bound = $param1_union_types[0]->value;
}
$min_bound = $get_int_range_bound($parse_tree->children[0], $generic_params[0], TIntRange::BOUND_MIN);
$max_bound = $get_int_range_bound($parse_tree->children[1], $generic_params[1], TIntRange::BOUND_MAX);

if ($min_bound === null && $max_bound === null) {
return new TInt();
Expand All @@ -865,7 +855,7 @@ private static function getTypeFromGenericTree(

if (is_int($min_bound) && is_int($max_bound) && $min_bound > $max_bound) {
throw new TypeParseTreeException(
"Min bound can't be greater than max bound, int<" . $min_bound . "," . $max_bound . "> given"
"Min bound can't be greater than max bound, int<$min_bound, $max_bound> given"
);
}

Expand Down
11 changes: 11 additions & 0 deletions tests/IntRangeTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -697,6 +697,17 @@ function doAnalysis(): void
'$_arr===' => 'non-empty-array<int<0, max>, int<0, max>>',
],
],
'minMaxInNamespace' => [
'<?php
namespace Foo {
/**
* @param int<0, max> $_a
* @param int<min, 0> $_b
*/
function bar(int $_a, int $_b): void {}
}
',
]
];
}

Expand Down

0 comments on commit 1fc5c1c

Please sign in to comment.