Skip to content

Resolve Static throw points #4128

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

Open
wants to merge 5 commits into
base: 2.1.x
Choose a base branch
from

Conversation

VincentLanglet
Copy link
Contributor

@VincentLanglet VincentLanglet force-pushed the fix/11900 branch 2 times, most recently from 3e23c43 to fd0fa25 Compare July 20, 2025 10:12
Copy link
Member

@ondrejmirtes ondrejmirtes left a comment

Choose a reason for hiding this comment

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

These are not the right places to do this fix. The MethodReflection has to already answer correctly.

The key lies in UnresolvedMethodPrototypeReflection (interface). ObjectType and StaticType return different implementations of this interface.

The two most important implementations are:

  • CallbackUnresolvedMethodPrototypeReflection (used in StaticType)
  • CalledOnTypeUnresolvedMethodPrototypeReflection (used in ObjectType)

When called on StaticType, the type has to stay the same/base class only being updated.

When called on ObjectType, the throw type has to be resolved to the current final type.

@VincentLanglet
Copy link
Contributor Author

These are not the right places to do this fix. The MethodReflection has to already answer correctly.

The key lies in UnresolvedMethodPrototypeReflection (interface). ObjectType and StaticType return different implementations of this interface.

The two most important implementations are:

  • CallbackUnresolvedMethodPrototypeReflection (used in StaticType)
  • CalledOnTypeUnresolvedMethodPrototypeReflection (used in ObjectType)

When called on StaticType, the type has to stay the same/base class only being updated.

When called on ObjectType, the throw type has to be resolved to the current final type.

Ok, so I did the fix in CallbackUnresolvedMethodPrototypeReflection & CalledOnTypeUnresolvedMethodPrototypeReflection and it works fine for the method and the static method.

But I still get error for the case 3 and 4 (constructor and property hooks) without a specific fix.
Do you know how to achieve the same "static" strategy for constructor & property hooks @ondrejmirtes ?

Should I just split the PR in two and just test the case 1 and 2 for now (without the fix 3 and 4) which already close the issue and cover most of real-life cases ?

@ondrejmirtes
Copy link
Member

Should I just split the PR in two and just test the case 1 and 2 for now (without the fix 3 and 4)

Yes please, then open a PR with failing tests after this one is merged

@VincentLanglet
Copy link
Contributor Author

Should I just split the PR in two and just test the case 1 and 2 for now (without the fix 3 and 4)

Yes please, then open a PR with failing tests after this one is merged

PR updated

Copy link
Member

@ondrejmirtes ondrejmirtes left a comment

Choose a reason for hiding this comment

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

  1. Please remove the property hook and the constructor throws and also the 8.4 requirement.
  2. Please add a thorough test for a dead catch rule to make it obvious this really works properly when calling a method on an object variable vs. on $this. Also that changeBaseClass works.

@VincentLanglet
Copy link
Contributor Author

Please add a thorough test for a dead catch rule to make it obvious this really works properly when calling a method on an object variable vs. on $this. Also that changeBaseClass works.

Sorry I'm not sure to understand what should be the test. Could you give me a snippet ?

I don't see how TestDataException or ADataException will be reported as a dead catch

@ondrejmirtes
Copy link
Member

@VincentLanglet Thinking about it, this should rather be a TypeInferenceTestCase in /nsrt/ testing assertType of $e in catch blocks. That way we can test the exact exception type the method throws.

  1. $obj->foo() with @throws static should result in $obj type.
  2. $this->foo() with @throws static should result in StaticType
  3. $this->foo() with @throws static from a parent class should result in an updated StaticType
  4. $this->foo() with @throws static in a final class should result in a ObjectType (I think, at least that's what it was at some point)

Copy link
Member

@ondrejmirtes ondrejmirtes left a comment

Choose a reason for hiding this comment

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

Also, one more place needs fixing. MutatingScope::enterClassMethod should also transformStaticType on $throwType.

Not sure how to test that. Maybe there's already a rule that asks that on $scope->getFunction(). Maybe we need to write a fake one just for tests.

@VincentLanglet
Copy link
Contributor Author

@VincentLanglet Thinking about it, this should rather be a TypeInferenceTestCase in /nsrt/ testing assertType of $e in catch blocks. That way we can test the exact exception type the method throws.

  1. $obj->foo() with @throws static should result in $obj type.
  2. $this->foo() with @throws static should result in StaticType
  3. $this->foo() with @throws static from a parent class should result in an updated StaticType
  4. $this->foo() with @throws static in a final class should result in a ObjectType (I think, at least that's what it was at some point)

I'm not sure about what I should catch since if you look at https://phpstan.org/r/030ef155-337f-4b7d-8361-7bf9f4f6c225
The dumpType return the type caught an not the real type thrown.

Also, one more place needs fixing. MutatingScope::enterClassMethod should also transformStaticType on $throwType.

I assume it should be the same for enterPropertyHook ?

Not sure how to test that.

I dunno either since I'm not even sure about the impact of changing enterClassMethod/enterPropertyHook.

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.

When exceptions check is turned on, phpstan doesn't identifies the exception thrown correctly
2 participants