Skip to content

Fixed '$this instanceof X will always be false' in traits #2045

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
merged 5 commits into from
Jan 31, 2023

Conversation

staabm
Copy link
Contributor

@staabm staabm commented Dec 3, 2022

closes phpstan/phpstan#3632

test fails without the fix

1) PHPStan\Rules\Classes\ImpossibleInstanceOfRuleTest::testBug3632
Failed asserting that two strings are identical.
--- Expected
+++ Actual
@@ @@
-'
+'10: Instanceof between *NEVER* and Bug3632\OtherClass will always evaluate to false.
 '

@staabm staabm force-pushed the trait-instance-of branch from 45f4b29 to e5ebe9d Compare January 15, 2023 10:56
@staabm staabm marked this pull request as ready for review January 15, 2023 11:56
@staabm staabm marked this pull request as draft January 15, 2023 12:55
@staabm staabm force-pushed the trait-instance-of branch from c6c3cfc to d052ca0 Compare January 15, 2023 14:33
@staabm
Copy link
Contributor Author

staabm commented Jan 15, 2023

I have approached the problem from a few different angles. All worked more or less.

At the end I get the feeling maybe this should be fixed at the core by e.g. treating $this just like a simple ObjectType when analysing in trait context

@staabm staabm force-pushed the trait-instance-of branch from d052ca0 to d75abea Compare January 15, 2023 20:23
@staabm
Copy link
Contributor Author

staabm commented Jan 15, 2023

regarding the build: I can see the same errors in other PRs so I think these are unrelated

@staabm staabm marked this pull request as ready for review January 15, 2023 20:35
@phpstan-bot
Copy link
Collaborator

This pull request has been marked as ready for review.

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.

The underyling issues we need to fix is: https://phpstan.org/r/d8b183e1-7099-478e-af58-fdd5e8ab7d21

So it's not sufficient to try to if-else our way out of this problem in a single rule, we need to fix the typesystem here.

So something needs to happen to handling of Instanceof_ in TypeSpecifier.

@clxmstaab clxmstaab force-pushed the trait-instance-of branch 3 times, most recently from 9b059b0 to e571a81 Compare January 16, 2023 09:31
@staabm
Copy link
Contributor Author

staabm commented Jan 16, 2023

So something needs to happen to handling of Instanceof_ in TypeSpecifier.

that was a great hint, thank you. I feel dumb for searching the solution in a lot of other phpstan components, but not the TypeSpecifier :)

@staabm staabm force-pushed the trait-instance-of branch 2 times, most recently from 8389601 to 5e8963b Compare January 18, 2023 19:47
@ondrejmirtes
Copy link
Member

I decided this still doesn't work and we need a different approach. ThisType in a trait context needs to behave a bit differently than in a class. It needs to allow intersection with other classes, almost like an interface.

@staabm
Copy link
Contributor Author

staabm commented Jan 19, 2023

So the bottom line is, that we need a new type?

@ondrejmirtes
Copy link
Member

Some boolean arg in ThisType would suffice. But maybe TraitThisType would work too.

@staabm staabm force-pushed the trait-instance-of branch from f2180b4 to 9f41729 Compare January 21, 2023 10:43
@staabm staabm force-pushed the trait-instance-of branch from 9f41729 to e8b28a3 Compare January 21, 2023 10:44
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.

I see some problems with this PR.

  1. TypeSpecifier shouldn't be touched. Instead, MutatingScope::enterTrait should handle ThisType.
  2. Any changes to isSuperTypeOf logic needs to be heavily covered by tests in TypeCombinatorTest - in dataUnion and dataIntersection.
  3. There are some cases the method should return no: a) for a final class that does not use the trait. b) For an ObjectType with a trait name c) For a type that's already subtracted in ThisType. This influences how unions and intersections are gonna end up looking like.

@staabm staabm marked this pull request as draft January 31, 2023 09:15
@clxmstaab clxmstaab force-pushed the trait-instance-of branch 2 times, most recently from 041c226 to e53cd2d Compare January 31, 2023 10:09

$this->analyse([__DIR__ . '/../../Analyser/data/trait-instance-of.php'], [
[
'Instanceof between $this(TraitInstanceOf\ATrait1Class) and trait TraitInstanceOf\Trait2 will always evaluate to false.',
Copy link
Contributor Author

@staabm staabm Jan 31, 2023

Choose a reason for hiding this comment

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

for some reason this error is not reported. I get a error though, when running phpstan on this file in isolation.

otherwise I think this looks fine. I will add new TypeCombinator Tests now

Copy link
Member

Choose a reason for hiding this comment

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

That's ExistingClassInInstanceOfRule rule, not ImpossibleInstanceOfRule rule.

@clxmstaab clxmstaab force-pushed the trait-instance-of branch 5 times, most recently from 695c257 to 79bf7ef Compare January 31, 2023 12:50
@staabm staabm marked this pull request as ready for review January 31, 2023 12:50
@phpstan-bot
Copy link
Collaborator

This pull request has been marked as ready for review.

@clxmstaab clxmstaab force-pushed the trait-instance-of branch 2 times, most recently from a2d4993 to 1c526dc Compare January 31, 2023 12:59

Unverified

This commit is not signed, but one or more authors requires that any commit attributed to them is signed.
$this->expressionTypes,
$this->nativeExpressionTypes,
array_merge($this->expressionTypes, [
'$this' => $thisHolder,
Copy link
Member

Choose a reason for hiding this comment

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

No need for array_merge. Simply do this before:

$expressionTypes = $this->expressionTypes;
$expressionType['$this'] = $thisHolder;

And the same thing for nativeExpressionTypes.

Copy link
Contributor Author

@staabm staabm Jan 31, 2023

Choose a reason for hiding this comment

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

I see. I was inspired by another place where it was done this way. fixed both in 749fbab


$this->analyse([__DIR__ . '/../../Analyser/data/trait-instance-of.php'], [
[
'Instanceof between $this(TraitInstanceOf\ATrait1Class) and trait TraitInstanceOf\Trait2 will always evaluate to false.',
Copy link
Member

Choose a reason for hiding this comment

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

That's ExistingClassInInstanceOfRule rule, not ImpossibleInstanceOfRule rule.

@ondrejmirtes ondrejmirtes merged commit e1c8380 into phpstan:1.9.x Jan 31, 2023
@ondrejmirtes
Copy link
Member

Thank you.

@staabm
Copy link
Contributor Author

staabm commented Jan 31, 2023

thanks for the directions. I couldn't have finished this one without your feedback <3.

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.

Instanceof between *NEVER* and XXX will always evaluate to false
3 participants