phpstan: Match expression does not handle remaining value with an array value

Bug report

match() definitely handles all values, but phpstan do not think so.

Code snippet that reproduces the problem

https://phpstan.org/r/b07c57ab-5084-4149-9c8b-21c1e14d2377

Expected output

No error.

About this issue

  • Original URL
  • State: closed
  • Created 3 years ago
  • Reactions: 35
  • Comments: 24 (11 by maintainers)

Commits related to this issue

Most upvoted comments

AFAIK, the default pattern is not mandatory so PHPStan should allow expressions when it’s missing.

For those who come from google, you probably just want to add a default arm to your match expression.

This was possible to solve thanks to: https://github.com/phpstan/phpstan-src/commit/7912caf4b66bdff65d3d6795d4c584c17ece5e51

I realized that [bool, bool] is in fact [true, true]|[true, false]|[false, true]|[false, false]. So I wrote Type::getFiniteTypes() to generate these combinations.

After that I took advantage of the new method when removing types: https://github.com/phpstan/phpstan-src/commit/b5cf52b916ad4d155f1809356c96cbe924f51dbe

And finally I made it work inside match condition: https://github.com/phpstan/phpstan-src/commit/0cdda0b210a623ee299323da80771c2c84c602f9

@mostafa-rz After the latest commit in 1.7.x, PHPStan now reports different result with your code snippet:

@@ @@
-PHP 8.1 (1 error)
+PHP 8.1
 ==========
 
-16: Match expression does not handle remaining value: int<-1, 1>
+No errors
 
 PHP 7.1 – 8.0 (2 errors)
 ==========
Full report

PHP 8.1

No errors

PHP 7.1 – 8.0 (2 errors)

Line Error
2 Syntax error, unexpected T_STRING on line 2
4 Syntax error, unexpected T_CASE on line 4

same goes for string:

$value *= match ($identifier) {
  'g', 'm', 'k' => 1024,
};

https://phpstan.org/r/37736108-b211-4406-a94e-cec1e5b14c18

Note that this is now fixed for the spaceship operator with a correct syntax: https://phpstan.org/r/200e398c-d2a5-4370-aaf9-2cfa6864a409

<?php declare(strict_types = 1);
enum TrendEnum
{
    case UP;
    case NEUTRAL;
    case DOWN;
}

class HelloWorld
{
	public function sayHello(): mixed
	{
		$foo = fn(): int => rand();
		$bar = fn(): int => rand();

		return match ($foo <=> $bar) {
                    1 => TrendEnum::UP,
                    0 => TrendEnum::NEUTRAL,
                   -1 => TrendEnum::DOWN,
              };
	}
}

Commenting one match-arm also lead to the expected result. I think this can be closed.

But the array of bool still is not handled.

<?php declare(strict_types = 1);

class HelloWorld
{
	public function sayHello(): int
	{
		$verified = fn(): bool => rand() === 1;
		
		return match([$verified(), $verified()]) {
			[true, true] => 1,
			[true, false] => 2,
			[false, true] => 3,
			[false, false] => 4,
		};
		
	}
}

@jaroslavtyc Please reproduce your problem on phpstan.org/try and open a separate issue.

https://github.com/phpstan/phpstan/issues/8969

@SomeBdyElse There’s a feature request about this: https://github.com/phpstan/phpstan/issues/8042 (it has a hint on how to implement it)

AFAIK, the default pattern is not mandatory so PHPStan should allow expressions when it’s missing.

exactly currently we have to do this

        default => throw new UnhandledMatchError($type),

to please phpstan while keeping the default (no pun intended) behaviour

@jkuchar After the latest commit in dev-master, PHPStan now reports different result with your code snippet:

@@ @@
 PHP 8.0 (1 error)
 ==========
 
- 9: Match expression does not handle remaining value: array(bool, bool)
+-1: Internal error: PHPStan\Rules\Methods\WrongCaseOfInheritedMethodRule::findMethod(): Argument #2 ($classReflection) must be of type PHPStan\Reflection\ClassReflection, null given, called in /var/task/vendor/phpstan/phpstan-strict-rules/src/Rules/Methods/WrongCaseOfInheritedMethodRule.php on line 40
+Run PHPStan with --debug option and post the stack trace to:
+https://github.com/phpstan/phpstan/issues/new?template=Bug_report.md
 
 PHP 7.4 (4 errors)
 ==========
Full report

PHP 8.0 (1 error)

Line Error
-1 Internal error: PHPStan\Rules\Methods\WrongCaseOfInheritedMethodRule::findMethod(): Argument #2 ($classReflection) must be of type PHPStan\Reflection\ClassReflection, null given, called in /var/task/vendor/phpstan/phpstan-strict-rules/src/Rules/Methods/WrongCaseOfInheritedMethodRule.php on line 40Run PHPStan with --debug option and post the stack trace to:https://github.com/phpstan/phpstan/issues/new?template=Bug_report.md

PHP 7.4 (4 errors)

Line Error
10 Syntax error, unexpected T_DOUBLE_ARROW on line 10
11 Syntax error, unexpected T_DOUBLE_ARROW on line 11
12 Syntax error, unexpected T_DOUBLE_ARROW on line 12
13 Syntax error, unexpected T_DOUBLE_ARROW on line 13

PHP 7.1 – 7.3 (5 errors)

Line Error
7 Syntax error, unexpected ':' on line 7
10 Syntax error, unexpected T_DOUBLE_ARROW on line 10
11 Syntax error, unexpected T_DOUBLE_ARROW on line 11
12 Syntax error, unexpected T_DOUBLE_ARROW on line 12
13 Syntax error, unexpected T_DOUBLE_ARROW on line 13