Skip to content

Implement identical/equal comparisons on EnumCaseObjectType #2105

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 7 commits into from
Jan 9, 2023

Conversation

staabm
Copy link
Contributor

@staabm staabm commented Dec 13, 2022

implements the idea of #2095 (comment)

closes phpstan/phpstan#8042
closes phpstan/phpstan#8485
closes phpstan/phpstan#7721
closes phpstan/phpstan#4242
closes phpstan/phpstan#8240

re-implements #2095

@staabm
Copy link
Contributor Author

staabm commented Dec 13, 2022

I decided against implementing the check in ConstantConditionRuleHelper since the 2 rules in question which trigger the annoying errors, do not yet depend on this helper

@ondrejmirtes
Copy link
Member

Sure, these rules needed update too, but I really need this in the helper. The idea is to stop reporting each "always true" in the last elseif and last match arm :) Also make sure to test that these "always true" are still being reported when in not-last elseif and match arm etc. :) Thank you.

@staabm
Copy link
Contributor Author

staabm commented Dec 13, 2022

what about

public function doFoo()
{
$array = ['foofoofoofoofoofoofoo','foofoofoofoofoofoofob'];
foreach ($array as $value) {
if ('foofoofoofoofoofoofoo' === $value) {
echo 'nope';
} elseif ('foofoofoofoofoofoofob' === $value) {
echo 'nop nope';
}
}
}
}

do we expect a error on line 654, or should this also be prevented? before this PR we get an error there.

@staabm
Copy link
Contributor Author

staabm commented Dec 13, 2022

The idea is to stop reporting each "always true" in the last elseif and last match arm :)

ok reading this again, I think it should not be reported. we want to stop reporting of each "always true"

echo 'nope';
} elseif ('foofoofoofoofoofoofob' === $value) {
echo 'nop nope';
} elseif (rand(0, 1) === 0) {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

this is a new variant of the existing test in the same file on line 654, with a additional else-if so we can see the error are reported when its not the last else-if

@staabm staabm force-pushed the enum-equal branch 2 times, most recently from 9930911 to 98c0b3d Compare December 13, 2022 18:32
@staabm
Copy link
Contributor Author

staabm commented Dec 13, 2022

since this PR already fixes 4 open issues and AFAIK will fix the anoying errors the 1st implementation had I think we should consider merging it.

Taking the new visitor into account in ConstantConditionRuleHelper and all related rules can be done in a separate PR.. wdyt?

@staabm staabm marked this pull request as ready for review December 13, 2022 18:37
@phpstan-bot
Copy link
Collaborator

This pull request has been marked as ready for review.

@ondrejmirtes
Copy link
Member

Something is broken here, the pipeline didn't run. Also I don't see the expected changes in src/Rules/Comparison/ConstantConditionRuleHelper.php, only an unused use.

@staabm
Copy link
Contributor Author

staabm commented Dec 13, 2022

Also I don't see the expected changes in src/Rules/Comparison/ConstantConditionRuleHelper.php

I can add it back, but I figured its not required for the current PR feature-set/fixes and we could leave it out for a next PR.

see #2105 (comment)

@ondrejmirtes
Copy link
Member

To me to have all the "always true" changes together is more cohesive than only part of the changes for "always true" + enums fix.

To summarize, it'd be best to have two PRs:

  1. All changes for "always true"
  2. Enums comparison

But I'm fine to have everything in this single PR. Thanks.

@staabm staabm force-pushed the enum-equal branch 2 times, most recently from 3674e32 to 45bfbc9 Compare December 14, 2022 09:38
@staabm
Copy link
Contributor Author

staabm commented Dec 14, 2022

lets see:

  • MatchExpressionRule already prevents always-true in the last arm
  • I have skimmed thru the issue tracker for open "always-true" errors, which are not yet tested here -> couldn't find one
  • I have looked at Unreachable*Rules, but cannot think of a case which requires a new test/is missing

I am a bit lost, as I don't have an idea on how to move forwared here/what exactly needs to be done

@ondrejmirtes
Copy link
Member

There's also:

  • ConstantLooseComparisonRule
  • Rules that use checkAlwaysTrueCheckTypeFunctionCall: ImpossibleCheckTypeStaticMethodCallRule, ImpossibleCheckTypeMethodCallRule, ImpossibleCheckTypeFunctionCallRule (which means that examples like these should not be reported https://phpstan.org/r/c7affa79-7bcf-4eb5-baff-5f5c4c2587b0)
  • And finally the rules that use ConstantConditionRuleHelper::getBooleanType(). I don't need to come up with new examples - if you look at tests for these rules, and see something reported as "always true" and you put it into a last elseif, it shouldn't be reported anymore.

@staabm
Copy link
Contributor Author

staabm commented Dec 14, 2022

ok, lets see how you like the latest iteration.

I have worked thru all the mentioned rules. what a ride ;).

I think there is no need to adjust IfConstantConditionRule, TernaryOperatorConstantConditionRule, WhileLoopAlwaysFalseConditionRule, WhileLoopAlwaysTrueConditionRule.
all the other ones were extended with new test-cases and fixes

@staabm
Copy link
Contributor Author

staabm commented Dec 14, 2022

thinking about TernaryOperatorConstantConditionRule again..

this one might be doable:

class ConditionalAlwaysTrue
{
	public function doFoo(int $i, \stdClass $std)
	{
		if ($i > 0) {
		} elseif ($std ? 'foo' : 'bar') { // always-true should not be reported because last condition
		}

		if ($i > 0) {
		} elseif ($std ? 'foo' : 'bar') { // always-true should be reported, because another condition below
		} elseif (rand(0,1)) {
		}
	}
}

@ondrejmirtes
Copy link
Member

Please also add a test for phpstan/phpstan#8240, thanks.

@staabm staabm marked this pull request as draft December 15, 2022 18:50
@staabm
Copy link
Contributor Author

staabm commented Dec 15, 2022

phpstan/phpstan#8240 is interessting. its not fixed by the PR as is.

the problem is similar but different. the root cause is that, $foo in this snippet should be resolved in a union of all cases, but is resolved into a object type and therefore the match-arm cases are not substracted it seems. 

https://phpstan.org/r/7f7b8b7b-f780-41f0-a1fb-02276482859b

@staabm staabm marked this pull request as ready for review December 16, 2022 08:21
@phpstan-bot
Copy link
Collaborator

This pull request has been marked as ready for review.

@staabm staabm force-pushed the enum-equal branch 3 times, most recently from cf13749 to d6ad04c Compare December 19, 2022 21:16
@staabm staabm force-pushed the enum-equal branch 5 times, most recently from 518c546 to 8255fad Compare January 4, 2023 10:08
@ondrejmirtes ondrejmirtes changed the base branch from 1.9.x to 1.10.x January 9, 2023 12:31
@ondrejmirtes ondrejmirtes merged commit 4968ec6 into phpstan:1.10.x Jan 9, 2023
@staabm staabm deleted the enum-equal branch January 9, 2023 13:09
@ondrejmirtes
Copy link
Member

Thank you! I have more improvements in mind, I started them already: 565fb0f

@staabm
Copy link
Contributor Author

staabm commented Jan 9, 2023

cool. if you want me to work on more, just open a new issue and give me an idea what we are targeting :)

@ondrejmirtes
Copy link
Member

To match the current feature set, we need something like reportAlwaysTrueInLastCondition that's going to be false by default but it's going to be turned on in strict rules :) I'm not gonna open an issue, I'm gonna do it myself if no one beats me to it :)

@ondrejmirtes
Copy link
Member

Also there should be a tip about this config option when such error is reported.

@ondrejmirtes
Copy link
Member

And also: There is some complicated logic in UnreachableIfBranchesRule which we should rethink for bleedingEdge, because when "always true" is always reported, we might not need another rule to say the same thing...

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