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

Native type does not know anything about purity #3797

Open
wants to merge 3 commits into
base: 1.12.x
Choose a base branch
from

Conversation

VincentLanglet
Copy link
Contributor

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 disagree with this on a conceptual level. With a closure like fn () => sleep(5), only native types are involved and we still know it's impure.

With one-off fixes like that, we'd be chaising our own tail for a long time (finding more stuff to fix all the time, which is frustrating). I propose a different fix. In https://github.com/phpstan/phpstan-src/blob/2.1.x/src/Rules/PhpDoc/VarTagTypeRuleHelper.php there are about 9 isSuperTypeOf calls.

  1. Instead of calling them directly on a type, introduce a private method that accepts $type, $varTagType and calls isSuperTypeOf inside. That way we only need to change a single place.
  2. After calling this isSuperTypeOf, in case an error would be reported, run one more check. Take the $type (the native type of the expression), do Type::toPhpDocNode() and then create a Type again with TypeNodeResolver. This will "clean up" everything that's not expressible with PHPDocs.
  3. Call isSuperTypeOf again with the new $type that's the result of operation from 2).

@VincentLanglet
Copy link
Contributor Author

  1. After calling this isSuperTypeOf, in case an error would be reported, run one more check. Take the $type (the native type of the expression), do Type::toPhpDocNode() and then create a Type again with TypeNodeResolver. This will "clean up" everything that's not expressible with PHPDocs.

TypeNodeResolver::resolve needs a NameScope. How do I get one here ?

@ondrejmirtes
Copy link
Member

I think null is fine? Or an empty one. We won't be resolving any relative names, I hope.

@ondrejmirtes
Copy link
Member

Anyway, this is just a guess what could work, maybe it's still going to break for some cases.

@VincentLanglet
Copy link
Contributor Author

I think null is fine? Or an empty one. We won't be resolving any relative names, I hope.

Indeed.

I saw there was 5 occurences of new NameScope(null, []) do you think it could be useful to provide a
NameScope::createEmpty() method ?

image


private function isSuperTypeOfVarType(Type $type, Type $varTagType): TrinaryLogic
{
$type = $this->typeNodeResolver->resolve($type->toPhpDocNode(), new NameScope(null, []));
Copy link
Contributor Author

Choose a reason for hiding this comment

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

After calling this isSuperTypeOf, in case an error would be reported, run one more check.

Seems like if I do this every time it works. I would say it's avoid two calls to isSuperTypeOf (?)

Also since sometimes checks are

!$this->isSuperTypeOfVarType($type, $varTagType)->yes()

and sometimes it's

$this->isSuperTypeOfVarType($type, $varTagType)->no()

It was unclear to me if I should have call toPhpDocNode for maybe results. So I did it every time.

Copy link
Member

Choose a reason for hiding this comment

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

Please do what I suggested. I don't want to break any existing use-cases, that's why I want to do the "new" thing right before when the original error message would appear. To decrease the number of reported errors, not to potentially incraese it.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Sure, but I don't understand how I'll know "an error would be reported" easily since sometime the usage will be
!$this->isSuperTypeOfVarType($type, $varTagType)->yes() and sometimes it will be
$this->isSuperTypeOfVarType($type, $varTagType)->no().

The following implementation

private function isSuperTypeOfVarType(Type $type, Type $varTagType): TrinaryLogic
	{
	    $result = $type->isSuperTypeOf($varTagType);
        if ($result->yes()) {
             return $result;
        }
	
		$type = $this->typeNodeResolver->resolve($type->toPhpDocNode(), new NameScope(null, []));

		return $type->isSuperTypeOf($varTagType);
	}

is not satisfying since for case where the usage is

$this->isSuperTypeOfVarType($type, $varTagType)->no()

I use the strategy toPhpDocNode for nothing since the first isSuperTypeOf wouldn't have report any error.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I have the implementation
d8b9c48

But I dunno if it's satisfying enough


private function isSuperTypeOfVarType(Type $type, Type $varTagType): TrinaryLogic
{
$type = $this->typeNodeResolver->resolve($type->toPhpDocNode(), new NameScope(null, []));
Copy link
Member

Choose a reason for hiding this comment

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

Please do what I suggested. I don't want to break any existing use-cases, that's why I want to do the "new" thing right before when the original error message would appear. To decrease the number of reported errors, not to potentially incraese it.

@ondrejmirtes
Copy link
Member

We don't need to be too smart. We csn have two different methods - one for !yes(), one for no ().

@VincentLanglet
Copy link
Contributor Author

We don't need to be too smart. We csn have two different methods - one for !yes(), one for no ().

I created isSuperTypeOfVarType and isAtLeastMaybeSuperTypeOfVarType

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.

@var with type Closure(): list<HelloWorld> is not subtype of native type Closure(): array
2 participants