Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

PHPDoc-based type narrowing #1317

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

Merged
ondrejmirtes merged 24 commits into phpstan:1.9.x from rvanvelzen:asserts
Oct 3, 2022
Merged

PHPDoc-based type narrowing #1317

ondrejmirtes merged 24 commits into phpstan:1.9.x from rvanvelzen:asserts
Oct 3, 2022

Conversation

@rvanvelzen
Copy link
Contributor

@rvanvelzen rvanvelzen commented May 16, 2022

Implementation for phpstan/phpstan#7110. I already had a big chunk of this quite soon, so I finished most of it.

Just putting this out there, hopefully you didn't already start on this 🥲

herndlm, BackEndTea, voku, axlon, and sasezaki reacted with thumbs up emoji szepeviktor and axlon reacted with rocket emoji
Copy link
Contributor

herndlm commented May 16, 2022
edited
Loading

Oh, nice! Looks like we could get rid then of almost all of the custom expression building in the phpstan-assert* extensions :)

Copy link
Member

Awesome, I haven't, I'm too deep in InitializerExprTypeResolver now (and also in my Verona phpDay talk) so great, I appreciate this :) I'm gonna go through the code soon, I just gonna list of some of my extra ideas for rules around this (you might have already done some of them, but I need to get them off my chest first :):

  • Similarly to how subject/target is checked in conditional types, @phpstan-assert should also be checked for sanity.
    • So for example - @param int + @phpstan-assert int - doesn't narrow down the type
    • @param int + @phpstan-assert int|string - doesn't narrow down the type
    • @param string + @phpstan-assert int - can never happen
    • Also needs to work with generics @template T of int + @param T + @phpstan-assert positive-int is fine
    • But @template T of int + @param T + @phpstan-assert int doesn't narrow down the type
  • The same rule should check if the referenced parameter in @phpstan-assert exists
  • Check that the feature works with generics - e.g. @phpstan-assert T after we know what T is inferred as.
  • Check that the @phpstan-assert can be put in stub files and that it works too.
  • Check that ImpossibleCheckTypeFunctionCallRule automatically picks up that function is narrowing down something that's already narrowed. (Nothing special should be needed, everything should already work based on the code in TypeSpecifier and ImpossibleCheckTypeHelper).

Before I dive into the review, can you please check this list? :) Thanks.

Copy link
Member

Just to be sure - if you're gonna work on these, please add them as new commits, it makes the review easier :)

To see how stubs-related functionality is tested, look at https://github.com/phpstan/phpstan-src/blob/1.7.x/tests/PHPStan/Analyser/ClassConstantStubFileTest.php.

Copy link
Contributor Author

None of that list is tested right now, just the very basic type narrowing. I'll look into that soon, thanks :)

Copy link
Member

I'm glad that I hit the nail on the head :)

Also I'll probably question some of your reflection choices (where to put the new information), but I need to think about it and I'll shuffle things around myself later :)

Copy link
Contributor Author

@rvanvelzen rvanvelzen May 19, 2022

Choose a reason for hiding this comment

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

This is really tricky, but I couldn't think of something else.

Copy link
Member

I really like how it's coming together :) After this one is merged, I also look forward to support for properties and methods besides parameter names :)

Copy link
Contributor Author

There's some work left to be done here, but it should be ready for review.

I'm not sure if the always true/false errors should pop up from these asserts - a function could very well narrow a type down without that being the only thing the function does. This could actually be handled by specifying types from conditional return types. I have a PR almost ready for that.

All that aside: I'll be on holiday for the next 2 weeks so I won't be able to spend much time on this. If you point out any issues I'll gladly work on them but I just don't know how quickly that will be. Thanks for understanding :)

Copy link
Member

I'm not sure if the always true/false errors should pop up from these asserts - a function could very well narrow a type down without that being the only thing the function does.

That's my worry as well but I'd like to see in practice if it's a real concern or not. In theory someone could write @phpstan-assert above functions that do other things as side effects as well, but maybe it doesn't happen in practice and it's still useful to report things like "this int is already an int".

It'd be nice to have these "impossible or always-true type checks" reported only in bleeding edge, but I'm not sure we can easily isolate these cases from the already existing ones in rules like ImpossibleCheckTypeFunctionCallRule etc.

This could actually be handled by specifying types from conditional return types. I have a PR almost ready for that.

I have no idea what you mean by that, so I'm intrigued to see it :)

All that aside: I'll be on holiday for the next 2 weeks so I won't be able to spend much time on this.

I hope you won't mind if we're going to postpone this feature for PHPStan 1.8. There's already a lot of stuff ready in PHPStan 1.7 (and it doesn't mean we can't release 1.8 immediately after the PHPDoc-based type narrowing is merged too) and I'd like to gather real-world feedback on it soon. Thank you for understanding.

Copy link
Contributor Author

Sure, it's absolutely fine to let this sit until after 1.7 is released :)

Copy link
Contributor

BackEndTea commented May 24, 2022
edited
Loading

In theory someone could write @phpstan-assert above functions that do other things as side effects as well, but maybe it doesn't happen in practice and it's still useful to report things like "this int is already an int".

As far as i know this is the current behavior in psalm, which is why not all methods in webmozarts/assert have an @psalm-assert annotation.
So it would probably be best to mimic this behavior in PHPStan. And maybe it helps promote people to write smaller functions that only do 1 thing, either a side effect or a validation.

Copy link
Member

BTW Do you have plans to support this syntax? Thanks! @psalm-assert =ExpectedType $actual

Copy link
Contributor

What would that do? Does that mean $actual is optional/nullable?

Copy link
Contributor Author

Not necessarily for the initial implementation, but I do plan on adding that as well.

Copy link
Member

What would that do?

I have no idea, doesn't seem documented: https://psalm.dev/docs/annotating_code/adding_assertions/

/cc @orklah What does @psalm-assert =ExpectedType $actual do? And is there any other syntax to be aware of?

Copy link
Contributor Author

Those are equality assertions, though the documentation for it is hard to find: https://psalm.dev/annotating_code/assertion_syntax/

Copy link
Contributor Author

I believe this has become a bit too large and complex. I'd like to break it up into a few pieces to make it easier to reason about.

Copy link
Member

Feel free to do what you think is best 😊 My idea for reflection is that I'm not sure if I want it on ParametersAcceptor vs. MethodReflection/FunctionReflection. I think it fits the latter better.

Copy link
Contributor

mvorisek commented Jun 3, 2022

this PR seems to implement phpstan/phpstan#7385, please include the demo https://phpstan.org/r/53ba9b04-685e-404c-ba77-a9616ca75ace code in the tests

Copy link
Member

BTW @rvanvelzen This one would be a great thing to finish :) My idea is that instead of ParametersAcceptorWithAsserts / FunctionVariant etc., the getAsserts() could be on ExtendedMethodReflection + FunctionReflection.

Copy link
Contributor Author

@ondrejmirtes it's on my list to work on, but I need/want to finish phpstan/phpdoc-parser#139 first but I'm not really happy with the current version :/

Copy link
Contributor

orklah commented Aug 9, 2022

/cc @orklah What does @psalm-assert =ExpectedType $actual do? And is there any other syntax to be aware of?

Wow, just saw this in my notifications, sorry I seem to have missed it completely before.

The = in assertions is used to express the IsIdentical assertion. You also have the ~ to express the IsLooselyEqual assertion
And both of those can be negated (i.e. !~ is IsNotLooselyEqual). It allows to express every !=, !==, == or === we can encounter. I'm still unsure in which case we use our IsType/IsNotType assertion compared to those.

Copy link
Member

I'm quite happy with the CI results, I'll make Rector freak out less about it (it's one of the problems I already suspected and mentioned) and then we can improve it on top of 1.9.x branch :)

Copy link
Member

I want to merge this because we're already stepping on each other's toes (I have some local commits but you force-pushed meanwhile :))

@rvanvelzen rvanvelzen marked this pull request as ready for review October 3, 2022 12:14
Copy link
Member

We can do so much more stuff once this is merged!

I can't wait :)

mad-briller, axlon, and staabm reacted with heart emoji

@ondrejmirtes ondrejmirtes merged commit 737d6bf into phpstan:1.9.x Oct 3, 2022
Copy link
Member

Thank you very much!

Copy link
Member

OMG, I love this so much! ace76ce

canvural, staabm, and mvorisek reacted with heart emoji axlon reacted with rocket emoji

Copy link
Contributor

mvorisek commented Oct 3, 2022

Hi @rvanvelzen, can this PR be used to solve phpstan/phpstan#7385?

Copy link
Contributor Author

I don't think so, because $this on its own isn't assertable right now.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Reviewers

@ondrejmirtes ondrejmirtes ondrejmirtes approved these changes

+1 more reviewer

@staabm staabm staabm left review comments

Reviewers whose approvals may not affect merge requirements

Assignees

No one assigned

Labels

None yet

Projects

None yet

Milestone

No milestone

Development

Successfully merging this pull request may close these issues.

AltStyle によって変換されたページ (->オリジナル) /