Skip to content

Add IDE type narrowing to generated validator mixins - #1802

Merged
alganet merged 1 commit into
mainfrom
ide-narrowing
Sep 10, 2026
Merged

Add IDE type narrowing to generated validator mixins#1802
alganet merged 1 commit into
mainfrom
ide-narrowing

Conversation

@alganet

@alganet alganet commented Jun 26, 2026

Copy link
Copy Markdown
Member

Part of a PR group: Fluent - FluentGen - Validation


Make validator chains narrow types for IDEs and PHPStan without the FluentAnalysis extension, driven entirely by the generated src/Mixins PHPDoc.

  • Annotate src/Validators with #[Assurance] / #[AssuranceSubject] declaring each rule's assured type.
  • Regenerate src/Mixins: Chain becomes generic (@template-covariant TSure); static entry methods narrow to Chain; assert()/check() carry an unconditional @phpstan-assert TSure. Container rules (key/property/length/ max/min) and the concrete prefix forms (nullOrIntType, keyIntType, allIntType) narrow; argument-wrapping and compose forms stay Chain so a raw (non-fluent) Validator argument is still accepted.
  • isValid() intentionally does not narrow: its only conditional form is a two-way guard, unsound for inexact rules on the false branch.
  • Add the tests/inference static-narrowing suite (no extension config) and run it in CI; scope the phpstan/phpcs accommodations for generated mixins.

This PR group adds advanced static (no PHPStan extension needed) type support and narrowing for fluent chains, pioneering it for Validation (StringFormatter should also be compatible with this approach)

image

In the example above, the devsense extension for VSCode is correctly infering an int[] (iterable int) from a each(int()) fluent validation chain.

More examples in tests/inference/assertions/static-narrowing.php.


Notes:

  • Most of the big diff is generated mixins, the PR is actually small.
  • This work is related, but distinct from Integrate Fluent, FluentGen and FluentAnalysis #1730. FluentAnalysis offers dynamic type narrowing with much richer narrowings (but IDEs can't run the extension). This one offers basic, static narrowing for IDEs such as devsense (tested) and IntelliJ (untested).

@codecov

codecov Bot commented Jun 26, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 97.14%. Comparing base (639f02f) to head (3d288ea).

Additional details and impacted files
@@            Coverage Diff            @@
##               main    #1802   +/-   ##
=========================================
  Coverage     97.14%   97.14%           
  Complexity     1096     1096           
=========================================
  Files           198      198           
  Lines          2554     2554           
=========================================
  Hits           2481     2481           
  Misses           73       73           

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@alganet

alganet commented Jun 26, 2026

Copy link
Copy Markdown
Member Author

@henriquemoody these are in draft because of the branch-alias (we need to amend the real composer versions when we do the release dance).

However, although not packagist-ready yet, they are open for review of the code. I requested review only here to avoid spam but you're free to comment in any of the 3.

@henriquemoody henriquemoody left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

This is trully trully awesome!!

Comment thread src/Validators/TrueVal.php
Comment thread src/Validators/Undef.php Outdated
Comment thread src/Validators/BoolVal.php
Comment thread src/Validators/DateTimeDiff.php Outdated
Comment thread src/Validators/FalseVal.php
Comment thread src/Validators/KeyExists.php
Comment thread src/Validators/PropertyExists.php
Comment thread src/Validators/ScalarVal.php Outdated
Comment thread src/Validators/ShortCircuit.php
Comment thread src/Validators/Templated.php Outdated
@alganet
alganet force-pushed the ide-narrowing branch 3 times, most recently from 07ccc7d to 3ec0d33 Compare June 26, 2026 19:43
@alganet

alganet commented Jun 26, 2026

Copy link
Copy Markdown
Member Author

I have removed the #[Assurance attributes that are not relevant for this PR, keeping only the ones that actively contribute to the IDE-only static narrowing. The ones removed belong to the full FluentAnalysis phpstan-extension integration that doesn't really affect IDE behavior.

Hopefully, this would make clear what IDEs can do and what they cannot (the static-narrowing.php file is a good reference card though, and remains the same).

@alganet
alganet force-pushed the ide-narrowing branch 2 times, most recently from 67ea602 to d26a84c Compare September 5, 2026 17:29
@alganet
alganet marked this pull request as ready for review September 5, 2026 17:29
Make validator chains narrow types for IDEs and PHPStan without the
FluentAnalysis extension, driven entirely by the generated src/Mixins PHPDoc.

- Annotate src/Validators with #[Assurance] / #[AssuranceSubject] declaring
  each rule's assured type.
- Regenerate src/Mixins: Chain becomes generic (@template-covariant TSure);
  static entry methods narrow to Chain<concrete>; assert()/check() carry an
  unconditional @phpstan-assert TSure. Container rules (key/property/length/
  max/min) and the concrete prefix forms (nullOrIntType, keyIntType,
  allIntType) narrow; argument-wrapping and compose forms stay Chain<mixed>
  so a raw (non-fluent) Validator argument is still accepted.
- isValid() intentionally does not narrow: its only conditional form is a
  two-way guard, unsound for inexact rules on the false branch.
- Add the tests/inference static-narrowing suite (no extension config) and
  run it in CI; scope the phpstan/phpcs accommodations for generated mixins.

@henriquemoody henriquemoody left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

This is absolutely amazing! I'm so happy you got this one working, it really puts Validation on the next level!

Comment thread src-dev/Commands/LintMixinCommand.php
Comment thread tests/inference/assertions/static-narrowing.php
@alganet
alganet merged commit f46099a into main Sep 10, 2026
12 checks passed
@alganet
alganet deleted the ide-narrowing branch September 10, 2026 21:22
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 participants