Skip to content

Conversation

fluffycondor
Copy link
Contributor

Fixes phpstan/phpstan#7814
As the docs says:

numeric-string is a string that would pass an is_numeric() check.

https://phpstan.org/writing-php-code/phpdoc-types#other-advanced-string-types
So, numeric-string should be also subtracted from any type not passed is_numeric, because is_numeric is the numeric-string determiner itself.

But I've added a test that shows there's a bug with numeric-string subtraction from mixed. It's still mixed. I would be glad if someone give me an advice how to fix it :)

@fluffycondor fluffycondor force-pushed the is-numeric-negated-intersection branch from e2ab2dc to cb77b30 Compare August 24, 2022 14:26
@fluffycondor
Copy link
Contributor Author

I've investigated a bit why that test with mixed~numeric-string doesn't work.
After using is_string mixed actually turns into string, and then PHPStan need to subtract numeric-string from string. It doesn't work, so I've removed the test.

Actually, it's a hard problem.
At first I've tried to express it through string&mixed~numeric-string, but I got an infinite loop while running tests.
Then I tried to implements SubtractableType on StringType, but TypeCombinator::intersectWithSubtractedType() can't intersect two SubtractableType properly in some cases. In some tests subtractable type was just dropped for some reason.
E.g. this test:

			[
				new Expr\BinaryOp\BooleanOr(
					new Expr\BinaryOp\BooleanAnd(
						$this->createFunctionCall('is_string', 'a'),
						new NotIdentical(new String_(''), new Variable('a')),
					),
					new Identical(new Expr\ConstFetch(new Name('null')), new Variable('a')),
				),
				['$a' => 'non-empty-string|null'],
				['$a' => 'mixed~non-empty-string & ~null'],
			],

becomes just mixed & ~null in $context->false(). Unfortunately, I wasn't able to investigate it deeper.

@staabm
Copy link
Contributor

staabm commented Aug 29, 2022

I tested the mixed~numeric-string case locally and I think this works now after #1656 got merged, when the change from this PR is applied.

my local test:

<?php

function foo2(mixed $s): void
{
	if (!is_numeric($s)) {
		\PHPStan\dumpType($s);
	}
}
php bin/phpstan analyze test.php  --debug
Note: Using configuration file /Users/staabm/workspace/phpstan-src/phpstan.neon.dist.
/Users/staabm/workspace/phpstan-src/test.php
 ------ ---------------------------------------------
  Line   test.php
 ------ ---------------------------------------------
  6      Dumped type: mixed~float|int|numeric-string
 ------ ---------------------------------------------

@fluffycondor please give me a ping in case you won't have time to finish it and I should push it over the finishing line

@ondrejmirtes ondrejmirtes force-pushed the is-numeric-negated-intersection branch from 089042f to 5376cd1 Compare August 30, 2022 06:50
@ondrejmirtes ondrejmirtes merged commit 493284c into phpstan:1.8.x Aug 30, 2022
@ondrejmirtes
Copy link
Member

Thank you!

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

Successfully merging this pull request may close these issues.

numeric-string drops from negated intersections
3 participants