Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Handle BcMath\Number operators for simple cases #3787

Open
wants to merge 7 commits into
base: 2.1.x
Choose a base branch
from

Conversation

schlndh
Copy link
Contributor

@schlndh schlndh commented Jan 19, 2025

Partially fixes: phpstan/phpstan#12099
Fixes: phpstan/phpstan#7937, phpstan/phpstan#8555
It's loosely based on #3660
Here is a demonstration of how the operators behave with various types: https://3v4l.org/jYX5J#v8.4.3

I skipped the complicated stuff. The main issue is unions. IMO it's too difficult to handle unions correctly in the extension. It would probably make more sense for PHPStan to handle the unions itself and offload only non-unions to extensions (e.g. X|int + X|float needs to know what int + float is).

I also ignored a few preexisting bugs/inconsistencies (null and never types). They can be solved later.

The result changed because getSortedTypes is called somewhere which
sorts the exponent's union type and leads to a change in the result.
@@ -395,4 +395,9 @@ public function substrReturnFalseInsteadOfEmptyString(): bool
return $this->versionId < 80000;
}

public function supportsBcMathNumberOperatorOverloading(): bool
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I copied this from the original PR. But I'm not sure whether it's correct. I assume that the reason we even need this is because earlier PHP versions might use a polyfill (which wouldn't have the operators overloaded). But PHP 8.4 can also use a polyfill, because bcmath is an optional extension.

Comment on lines -50 to +54
assertType('int<4, 27>|int<16, 81>', pow($range, $x));
assertType('int<4, 27>|int<16, 81>', $range ** $x);
assertType('int<4, 81>', pow($range, $x));
assertType('int<4, 81>', $range ** $x);

assertType('int<4, 27>|int<16, 64>', pow($x, $range));
assertType('int<4, 27>|int<16, 64>', $x ** $range);
assertType('int<4, 64>', pow($x, $range));
assertType('int<4, 64>', $x ** $range);
Copy link
Contributor Author

@schlndh schlndh Jan 19, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a result of UnionType::getSortedTypes being called. I haven't looked into it, but I guess it's a bug in TypeCombinator::union, because the result of a union shouldn't depend on the order of parameters.

EDIT: I had to fix it, because it broke the test on PHP <8.4 due to the extension only running on 8.4 and above.

assertType('true', $a or $b);
}

public function bcVsNever(Number $a): void
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's a bunch of inconsistencies in how never type is handled. I assume that all of these operations should result in *NEVER*, but I'm ignoring it for this PR.

@schlndh schlndh marked this pull request as draft January 19, 2025 09:47
It was fixed by fixing union(int, int<null, -1>, int<1, null>) = int.
IntegerRangeType::fromInterval(8, 27),
],
IntegerRangeType::class,
'int<4, 81>',
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Was: int<4, 27>|int<16, 81>.

IntegerRangeType::fromInterval(16, 81),
],
IntegerRangeType::class,
'int<4, 81>',
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Was: int<4, 7>|int<8, 81> (testUnionInversed)

IntegerRangeType::fromInterval(1, null),
],
IntegerType::class,
'int',
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Was: int|int<min, -1> (testUnionInversed)

@schlndh schlndh marked this pull request as ready for review January 19, 2025 11:51
@phpstan-bot
Copy link
Collaborator

This pull request has been marked as ready for review.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
2 participants