Skip to content
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

declare assert-if-true for filesystem functions #1993

Draft
wants to merge 3 commits into
base: 1.11.x
Choose a base branch
from

Conversation

staabm
Copy link
Contributor

@staabm staabm commented Nov 13, 2022

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.

Two problems here:

  1. chdir($dir) ? 'foo' : 'bar' - in the else branch $dir will be considered ''
  2. If you pass non-empty-string to chdir(...), you'll get "always true" error.

Both can be solved with =non-empty-string. See: phpstan/phpstan#8348 + phpstan/phpstan#8351

@clxmstaab clxmstaab force-pushed the file-fn branch 2 times, most recently from 49564b7 to 766c8d9 Compare November 14, 2022 14: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.

To make sure that = actually fixes these problems, you should have tested the else condition types and also put a test about this in ImpossibleCheckTypeFunctionCallRule (before adding the = everywhere). Please verify this was originally a problem and that it's fixed after the change. I'm sure you can find the previous version in your reflog :) It's e117fce or 49564b7.

@staabm
Copy link
Contributor Author

staabm commented Nov 20, 2022

good point.

2) PHPStan\Rules\Comparison\ImpossibleCheckTypeFunctionCallRuleTest::testBug6788
Failed asserting that two strings are identical.
--- Expected
+++ Actual
@@ @@
-'
+'13: Call to function chdir() with non-empty-string will always evaluate to true.
+    💡 Because the type is coming from a PHPDoc, you can turn off this check by setting <fg=cyan>treatPhpDocTypesAsCertain: false</> in your <fg=cyan>%configurationFile%</>.
+15: Call to function chdir() with non-falsy-string will always evaluate to true.
+    💡 Because the type is coming from a PHPDoc, you can turn off this check by setting <fg=cyan>treatPhpDocTypesAsCertain: false</> in your <fg=cyan>%configurationFile%</>.
 '

@staabm staabm changed the base branch from 1.9.x to 1.11.x June 12, 2024 12:02
@staabm
Copy link
Contributor Author

staabm commented Jun 12, 2024

the last commit is fixing cases like

<?php

namespace Bug4816;

use function PHPStan\Testing\assertType;

function (string $x): void {
	if (is_dir($x)) {
		assertType('true', is_dir($x));
	}
};

(so we don't regress 1eaef04)


my understanding is, that because this PR adds stubs with @phpstan-assert the specifier does no longer invoke handleDefaultTruthyOrFalseyContext in

$assertions = $functionReflection->getAsserts();
if ($assertions->getAll() !== []) {
$parametersAcceptor ??= ParametersAcceptorSelector::selectFromArgs($scope, $expr->getArgs(), $functionReflection->getVariants(), $functionReflection->getNamedArgumentsVariants());
$asserts = $assertions->mapTypes(static fn (Type $type) => TemplateTypeHelper::resolveTemplateTypes(
$type,
$parametersAcceptor->getResolvedTemplateTypeMap(),
$parametersAcceptor instanceof ParametersAcceptorWithPhpDocs ? $parametersAcceptor->getCallSiteVarianceMap() : TemplateTypeVarianceMap::createEmpty(),
TemplateTypeVariance::createInvariant(),
));
$specifiedTypes = $this->specifyTypesFromAsserts($context, $expr, $asserts, $parametersAcceptor, $scope);
if ($specifiedTypes !== null) {
return $specifiedTypes;
}
}
}
return $this->handleDefaultTruthyOrFalseyContext($context, $rootExpr, $expr, $scope);

and that the reason why my previous code sample did regress. After adding handleDefaultTruthyOrFalseyContext I can see other things regress though :).

@rvanvelzen could you give me a hand? why do we not invoke handleDefaultTruthyOrFalseyContext when taking the path thru specifyTypesFromAsserts. is this expected or an oversight?

btw: I noticed we also don't invoke handleDefaultTruthyOrFalseyContext when we take the path thru specifyTypesFromConditionalReturnType.

@thg2k
Copy link
Contributor

thg2k commented Jun 12, 2024

I had no idea that the assertion would actually assert the opposite if the condition is not met. This is very counter-intuitive for me.. I think the behavior with "=" should be the default and there should rather be another modifier to request the double behavior.

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.

Improve support for is_file and family
3 participants