Skip to content

Add build rule declaring native types from PHPDoc types - #7009

Open
ondrejmirtes wants to merge 4 commits into
2.3.xfrom
missing-native-type-rule
Open

ondrejmirtes wants to merge 4 commits into
2.3.xfrom
missing-native-type-rule

Conversation

@ondrejmirtes

@ondrejmirtes ondrejmirtes commented Nov 9, 2026 •

Copy link
Copy Markdown
Member

Adds MissingNativeTypeRule to the build rules and applies its fixes to phpstan-src.

For each parameter, return type and property without a native type, the rule converts the PHPDoc type with Type::toNativePhpTypeNode() and checks it by resolving the node back with ParserNodeTypeToPHPStanType:

  • parameter types must be contravariant with the native types of the overridden parent and interface methods (constructors only against abstract ones)
  • return and property types are added only where nothing can override them (private, final, final class, enum, function) and must be covariant with the parent's native return type, so @api interfaces and non-final classes do not break their implementers
  • promoted parameters follow the property rules (no callable)
  • the backward compatibility promise: no parameter types on non-private methods of @api classes or methods tagged @api (constructors excepted), no types on non-private properties of @api classes
  • no standalone null, true, false, never or DNF types, because build/downgrade.php cannot lower them for PHP 7.4–8.1
  • the PHPDoc tag is removed by PhpDocEditor only when the native type says exactly the same and the tag has no description; an explicit mixed[] stays next to array

Skipped: by-reference parameters, magic methods other than __construct/__invoke, traits, defaults the native type would not accept, and multi-property statements.

The other commits are the output of bin/phpstan --fix, plus:

  • regenerated turbo declarations for the 19 shadowed classes whose signatures changed (generated with PHP 8.5 like CI)
  • native MutatingScope::pushInFunctionCall() declares the same parameter type as NodeCallbackScope's override, otherwise the extension fails to load

Verified locally: make phpstan, the full test suite with and without the extension, signature-parity.php, smoke.php, side-by-side.php, and byte-identical level 10 analysis of src/ with the extension on and off.

Reports parameters, return types and properties without a native type
when their PHPDoc type can be declared natively, and fixes them: declares
the native type and removes the PHPDoc tag when the native type says the same.

Return and property types are added only where nothing can override them,
parameter types only when contravariant with the overridden methods.

Amp-Thread-ID: https://ampcode.com/threads/T-01a1bed4-966e-7640-a834-06bba746e1f1
Fixed by MissingNativeTypeRule, now registered in build/phpstan.neon.
The turbo extension declarations are regenerated for the shadowed classes
whose signatures changed. The native MutatingScope::pushInFunctionCall()
declares the same parameter type as NodeCallbackScope's override, and the
native IntegerRangeType::createAll*() accept only int|float like their twin.

Amp-Thread-ID: https://ampcode.com/threads/T-01a1bed4-966e-7640-a834-06bba746e1f1
Parameters of non-private methods in @api classes or tagged @api keep their PHPDoc types,
as do non-private properties of @api classes.
Standalone null, true, false, never and DNF types are not added because
build/downgrade.php cannot lower them for PHP 7.4-8.1.

Amp-Thread-ID: https://ampcode.com/threads/T-01a1bed4-966e-7640-a834-06bba746e1f1
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.

1 participant