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

trait_exists() returns nullable value, according to psalm stubs #7478

Closed
Ocramius opened this issue Jan 24, 2022 · 12 comments · Fixed by #7554
Closed

trait_exists() returns nullable value, according to psalm stubs #7478

Ocramius opened this issue Jan 24, 2022 · 12 comments · Fixed by #7554
Labels
bug easy problems Issues that can be fixed without background knowledge of Psalm Help wanted internal stubs/callmap

Comments

@Ocramius
Copy link
Contributor

Ocramius commented Jan 24, 2022

See Roave/BetterReflection#983 (comment)
See https://psalm.dev/r/c41a43805d

In vimeo/psalm:4.18.1, trait_exists() is declared as trait_exists(string): ?bool: it should perhaps return bool at all time (not nullable).

<?php

function traitDoesIndeedExist(string $traitName): bool
{
    return trait_exists($traitName);
}

Produces

Psalm output (using commit c7d938b): 

ERROR: NullableReturnStatement - 5:12 - The declared return type 'bool' for traitDoesIndeedExist is not nullable, but the function returns 'bool|null'

ERROR: InvalidNullableReturnType - 3:51 - The declared return type 'bool' for traitDoesIndeedExist is not nullable, but 'bool|null' contains null
 
Psalm detected 1 fixable issue(s)

Definition seems to be imprecise in https://github.com/vimeo/psalm/blob/f1c4b62f5c65e887892e768dbaff6207ded14cee/dictionaries/CallMap.php

/cc @voku

@psalm-github-bot
Copy link

psalm-github-bot bot commented Jan 24, 2022

I found these snippets:

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

function traitDoesIndeedExist(string $traitName): bool
{
    return trait_exists($traitName);
}
Psalm output (using commit c7d938b):

ERROR: NullableReturnStatement - 5:12 - The declared return type 'bool' for traitDoesIndeedExist is not nullable, but the function returns 'bool|null'

ERROR: InvalidNullableReturnType - 3:51 - The declared return type 'bool' for traitDoesIndeedExist is not nullable, but 'bool|null' contains null

@AndrolGenhald
Copy link
Collaborator

AndrolGenhald commented Jan 24, 2022

The documentation is contradictory, it gives a return type of bool but says "Returns true if trait exists, false if not, null in case of an error."

I don't know how to read PHP's source with all it's preprocessor stuff well enough to say for sure, but I think this might have changed for PHP 7. I would guess that this would cause a null return value, but since PHP 7, as far as I can tell, it looks like it should only return bool. I could easily be wrong about that though.

@AndrolGenhald
Copy link
Collaborator

Here's a case where it returns null for PHP < 8.0: https://3v4l.org/XpHmh.
Not sure how much we care about that since we should be showing an issue for incorrect parameters anyway.

@Ocramius
Copy link
Contributor Author

Indeed, assuming the function is defined as having 2 parameters, then : bool return should be OK.

@weirdan
Copy link
Collaborator

weirdan commented Jan 24, 2022

Not sure how much we care about that

We don't. Psalm has a policy of ignoring ZPP nulls like that.

@orklah
Copy link
Collaborator

orklah commented Jan 24, 2022

We have an unofficial rule where any type returned only when the params are wrong (and are reported by Psalm) can be ignored in our callmaps to avoid cluttering

@orklah
Copy link
Collaborator

orklah commented Jan 25, 2022

Well, I think we can safely fix that in callmaps. Anyone want to create the PR? :)

@orklah orklah added bug easy problems Issues that can be fixed without background knowledge of Psalm Help wanted internal stubs/callmap labels Jan 25, 2022
Ocramius added a commit to Ocramius/psalm that referenced this issue Feb 1, 2022
Fixes vimeo#7478

As discussed in the upstream issue, `trait_exists()` always returns `bool`: while
it can return `null` when the arguments passed to it do not match (either no arguments, or
3 or more arguments), we do not support that scenario, as that already doesn't respect the
type signature of this function.

We cut to the point: always make it `bool`, which is the scenario that works under healthy
operational conditions.

Ref: Roave/BetterReflection#983 (comment)
Ref: https://psalm.dev/r/c41a43805d
Ref: vimeo#7478 (comment)
Ref: vimeo#7478 (comment)
Ref: https://3v4l.org/XpHmh
Ocramius added a commit to Ocramius/psalm that referenced this issue Feb 1, 2022
Fixes vimeo#7478

As discussed in the upstream issue, `trait_exists()` always returns `bool`: while
it can return `null` when the arguments passed to it do not match (either no arguments, or
3 or more arguments), we do not support that scenario, as that already doesn't respect the
type signature of this function.

We cut to the point: always make it `bool`, which is the scenario that works under healthy
operational conditions.

Ref: Roave/BetterReflection#983 (comment)
Ref: https://psalm.dev/r/c41a43805d
Ref: vimeo#7478 (comment)
Ref: vimeo#7478 (comment)
Ref: https://3v4l.org/XpHmh
@Ocramius
Copy link
Contributor Author

Ocramius commented Feb 1, 2022

@orklah sorry, took me a while to actually get to clone + change the file (github editor does not allow for that anymore, due to its size :D )

Ocramius added a commit to Ocramius/psalm that referenced this issue Feb 1, 2022
Fixes vimeo#7478

As discussed in the upstream issue, `trait_exists()` always returns `bool`: while
it can return `null` when the arguments passed to it do not match (either no arguments, or
3 or more arguments), we do not support that scenario, as that already doesn't respect the
type signature of this function.

We cut to the point: always make it `bool`, which is the scenario that works under healthy
operational conditions.

Ref: Roave/BetterReflection#983 (comment)
Ref: https://psalm.dev/r/c41a43805d
Ref: vimeo#7478 (comment)
Ref: vimeo#7478 (comment)
Ref: https://3v4l.org/XpHmh
orklah added a commit that referenced this issue Feb 1, 2022
…returns-boolean

Ensure `trait_exists()` always returns `bool`
cmb69 added a commit to php/doc-en that referenced this issue Feb 1, 2022
@cmb69
Copy link

cmb69 commented Feb 1, 2022

JFTR: ZPP failures are not supposed to be documented in the PHP manual for each function/method; there is already a general clause regarding internal functions:

If the parameters given to a function are not what it expects, such as passing an array where a string is expected, the return value of the function is undefined. In this case it will likely return null but this is just a convention, and cannot be relied upon. As of PHP 8.0.0, a TypeError exception is supposed to be thrown in this case.

So yes, this is a php/doc-en bug, which has just been fixed.

@AndrolGenhald
Copy link
Collaborator

@cmb69 Thanks for the info, I'll report it next time I notice one.

@Ocramius
Copy link
Contributor Author

Ocramius commented Feb 2, 2022

Ref: php/doc-en@de99fc7

Seems like nullability wasn't documented in the docbook types, but just in the description.

@cmb69
Copy link

cmb69 commented Feb 3, 2022

@Ocramius, the signatures are autogenerated from the stub files now, but occassionally related changes in other parts of the docs are overlooked.

mumumu added a commit to php/doc-ja that referenced this issue Feb 6, 2022
tiffany-taylor pushed a commit to tiffany-taylor/doc-en that referenced this issue Jan 16, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug easy problems Issues that can be fixed without background knowledge of Psalm Help wanted internal stubs/callmap
Projects
None yet
Development

Successfully merging a pull request may close this issue.

5 participants