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

PossiblyNullReference when using assert and mutation free #3820

Closed
digilist opened this issue Jul 15, 2020 · 5 comments
Closed

PossiblyNullReference when using assert and mutation free #3820

digilist opened this issue Jul 15, 2020 · 5 comments
Labels

Comments

@digilist
Copy link

Please take a look at this example: https://psalm.dev/r/ec2ee79823

It gives the following error:

ERROR: PossiblyNullReference - 22:49 - Cannot call method isNotNull on possibly null value

By removing the @psalm-mutation-free annotation on the isNotNull function the code is valid and does not detect any error. I think that's a bug, flagging the method as non mutable invalidates the assert clause.

@psalm-github-bot
Copy link

I found these snippets:

https://psalm.dev/r/ec2ee79823
<?php

class A {
    private ?A $other = null;
    
    public function setVar(A $other): void
    {
        $this->other = $other;
    }
    
    /**
     * @psalm-mutation-free
     * @psalm-assert !null $this->other
     */
    public function isNotNull(): bool
    {
        return $this->other !== null;
    }
    
    public function doSomething(): void
    {
        if ($this->isNotNull() && $this->other->isNotNull()) {
        }
    }
}
Psalm output (using commit 06ee1b7):

ERROR: PossiblyNullReference - 22:49 - Cannot call method isNotNull on possibly null value

@weirdan
Copy link
Collaborator

weirdan commented Jul 15, 2020

Actually you want @psalm-assert-if-true there: https://psalm.dev/r/e6a7d153e3

@psalm-github-bot
Copy link

I found these snippets:

https://psalm.dev/r/e6a7d153e3
<?php

class A {
    private ?A $other = null;
    
    public function setVar(A $other): void
    {
        $this->other = $other;
    }
    
    /**
     * @psalm-mutation-free
     * @psalm-assert-if-true !null $this->other
     */
    public function isNotNull(): bool
    {
        return $this->other !== null;
    }
    
    public function doSomething(): void
    {
        if ($this->isNotNull() && $this->other->isNotNull()) {
        }
    }
}
Psalm output (using commit 06ee1b7):

No issues!

@weirdan
Copy link
Collaborator

weirdan commented Jul 15, 2020

Still looks like a bug: it appears non-conditional assertions are not in effect for the rest of the expression. However they are properly accounted for outside of that if: https://psalm.dev/r/e540bcbd7a

@psalm-github-bot
Copy link

I found these snippets:

https://psalm.dev/r/e540bcbd7a
<?php

class A {
    private ?A $other = null;
    
    public function setVar(A $other): void
    {
        $this->other = $other;
    }
    
    /**
     * @psalm-mutation-free
     * @psalm-assert !null $this->other
     */
    public function isNotNull(): bool
    {
        if ($this->other === null) { 
            throw new RuntimeException('oops');
        }
        return true;
    }
    
    public function doSomething(): void
    {
        // is_null() below is redundant, Psalm fails to notice this
        if ($this->isNotNull() && is_null($this->other)) {}
        
        // does not complain below because assertion worked as expected
        if ($this->other->isNotNull()) {}  
    }

}
Psalm output (using commit 06ee1b7):

No issues!

@weirdan weirdan added the bug label Jul 15, 2020
@muglug muglug added bug and removed bug labels Jul 15, 2020
@muglug muglug closed this as completed in 8fbc8de Jul 15, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

3 participants