Skip to content

Keep the analysed PHP version as the floor of a PHP_VERSION_ID < X guard - #6746

Open
HawkForge wants to merge 2 commits into
phpstan:2.3.xfrom
HawkForge:fix/php-version-id-narrowing-below-configured
Open

HawkForge wants to merge 2 commits into
phpstan:2.3.xfrom
HawkForge:fix/php-version-id-narrowing-below-configured

Conversation

@HawkForge

Copy link
Copy Markdown
Contributor

Fixes phpstan/phpstan#15425. Thanks @lstrojny for the report and the reproducer.

When a single PHP version is analysed (a fixed phpVersion, or no version range from the config or composer.json), PHP_VERSION_ID is int<50207, max>. Scope::getPhpVersion() treats that as "no information" and answers with the analysed version. A guard like if (PHP_VERSION_ID < 80400) narrows the constant to int<50207, 80399>, and getPhpVersion() returned that range as is, so inside the branch the version dropped to PHP 5.2.7. Since 2.3 the "supported only on PHP X" rules read the version from the scope, so with phpVersion: 80500 a class with promoted properties in that branch got the non-ignorable property.promotedNotSupported error. A guard the analysed version passes, like PHP_VERSION_ID < 80600, hit the same error.

Only the upper bound of such a range comes from the guard. getPhpVersion() now raises the lower bound to the analysed version, or to the guard's upper bound when the guard excludes the analysed version. With phpVersion: 80500, PHP_VERSION_ID < 80600 gives int<80500, 80599> and PHP_VERSION_ID < 80400 gives 80399. Guards that set a lower bound (PHP_VERSION_ID >= 80300, the bug-13133 case) and configured version ranges are unchanged. A PHP_VERSION_ID < 80000 branch still reports promoted properties, as testConditionallyDeclaredClass expects. The narrowed type of the PHP_VERSION_ID constant itself does not change.

MutatingScope is shadowed by turbo-ext, so MutatingScope.cpp gets the same change and the generated header is regenerated. turbo-ext/tests/scope-family.php gets two guarded scopes pinned to phpVersion: 80500 (one where the guard excludes the analysed version, one where it doesn't). The smoke test fails on them if the native side is wrong. A separate commit bumps the expected turbo version.

InvalidPromotedPropertiesRuleTest::testBug15425 analyses the issue's snippet and expects no errors. Without the fix it fails with Promoted properties are supported only on PHP 8.0 and later. The full test suite passes with and without the turbo extension loaded.

Closes phpstan/phpstan#15425

When a single PHP version is analysed (a fixed `phpVersion`, or no version
range from the config or composer.json), PHP_VERSION_ID is int<50207, max>
and Scope::getPhpVersion() treats that as no information and answers with
the analysed version. A guard like `if (PHP_VERSION_ID < 80400)` narrows
the constant to int<50207, 80399>, and getPhpVersion() returned that range
as is, so the version dropped to PHP 5.2.7 inside the branch. Since the
"supported only on PHP X" rules read the version from the scope, a class
with promoted properties in such a branch got a non-ignorable
property.promotedNotSupported error with `phpVersion: 80500`.

Only the upper bound of that range comes from the guard. Raise the lower
bound to the analysed version, or to the guard's upper bound when the guard
excludes the analysed version. Guards with a lower bound
(`PHP_VERSION_ID >= 80300`) and configured version ranges are unchanged.
The turbo-ext mirror gets the same change.

Closes phpstan/phpstan#15425
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.

2.3.0: property.promotedNotSupported in a PHP_VERSION_ID-guarded branch when phpVersion is fixed

1 participant