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

count(array) should be positive-int|0, while count(Countable) should be int #4997

Closed
Ocramius opened this issue Jan 13, 2021 · 3 comments · Fixed by #4999
Closed

count(array) should be positive-int|0, while count(Countable) should be int #4997

Ocramius opened this issue Jan 13, 2021 · 3 comments · Fixed by #4999
Labels

Comments

@Ocramius
Copy link
Contributor

https://psalm.dev/r/c5d1ba8607

<?php

/** @psalm-return positive-int|0 */
function gimmePositiveCount(array $input): int
{
    return \count($input);
}


/** @psalm-return positive-int|0 */
function gimmeCount(\Countable $input): int
{
    return \count($input); // expected violation here - `Countable#count()` can return negative!
}
Psalm output (using commit 1afce4d): 

INFO: LessSpecificReturnStatement - 6:12 - The type 'int' is more general than the declared return type 'int(0)|positive-int' for gimmePositiveCount

INFO: MoreSpecificReturnType - 3:19 - The declared return type 'int(0)|positive-int' for gimmePositiveCount is more specific than the inferred return type 'int'

INFO: LessSpecificReturnStatement - 13:12 - The type 'int' is more general than the declared return type 'int(0)|positive-int' for gimmeCount

INFO: MoreSpecificReturnType - 10:19 - The declared return type 'int(0)|positive-int' for gimmeCount is more specific than the inferred return type 'int'

In practice, count() needs better stubs:

  • count(array): positive-int|0
  • count(Countable): int

I'll try and see if I can send a patch :-)

@psalm-github-bot
Copy link

I found these snippets:

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

/** @psalm-return positive-int|0 */
function gimmePositiveCount(array $input): int
{
    return \count($input);
}


/** @psalm-return positive-int|0 */
function gimmeCount(\Countable $input): int
{
    return \count($input); // expected violation here - `Countable#count()` can return negative!
}
Psalm output (using commit 1afce4d):

INFO: LessSpecificReturnStatement - 6:12 - The type 'int' is more general than the declared return type 'int(0)|positive-int' for gimmePositiveCount

INFO: MoreSpecificReturnType - 3:19 - The declared return type 'int(0)|positive-int' for gimmePositiveCount is more specific than the inferred return type 'int'

INFO: LessSpecificReturnStatement - 13:12 - The type 'int' is more general than the declared return type 'int(0)|positive-int' for gimmeCount

INFO: MoreSpecificReturnType - 10:19 - The declared return type 'int(0)|positive-int' for gimmeCount is more specific than the inferred return type 'int'

@weirdan weirdan added the bug label Jan 13, 2021
@orklah
Copy link
Collaborator

orklah commented Jan 13, 2021

I'm gonna be extremely naive here and say that noone sane could have returned a negative int in count. Could we maybe consider this an error anyway and say that every count return 0|positive-int ?

@Ocramius
Copy link
Contributor Author

Not at type level, no.

Ocramius added a commit to Ocramius/psalm that referenced this issue Jan 13, 2021
…ourceBundle` counting, as well as handling hardcoded 2-element-arrays cases

This patch:

 * adds support for `count(\SimpleXmlElement)` (https://www.php.net/manual/en/simplexmlelement.count.php)
 * adds support for `count(\ResourceBundle)` (https://www.php.net/manual/en/resourcebundle.count.php)
 * removes usage of global constants from stub (not supported - see https://www.php.net/manual/en/function.count.php)
 * adds support for identifying fixed-element-count arrays, for example `count(callable&array)`, which is always `2`
Ocramius added a commit to Ocramius/psalm that referenced this issue Jan 13, 2021
…eInt` for `count(TNonEmptyArray)` and `count(TNonEmptyList)`
Ocramius added a commit to Ocramius/psalm that referenced this issue Jan 13, 2021
…r` refining

The `FunctionCallReturnTypeFetcher` is responsible for defining the precise type of a `\count(T)`
expression when given a `T`, so we baked the whole type resolution for `positive-int`, `0` and
`positive-int|0` directly in there.

While this complicates things, it is also true that it is not possible right now (for the stubs)
to provide the level of detail around `count()` that is required by the type inference system
for such a complex function with so many different semantics.
muglug pushed a commit that referenced this issue Jan 13, 2021
…r `positive-int` on known arrays (#4999)

* #4997 added more precise stub for `count()` returning `0` or `positive-int` on known types

* #4997 updated `count()` to support `\SimpleXmlElement` and `\ResourceBundle` counting, as well as handling hardcoded 2-element-arrays cases

This patch:

 * adds support for `count(\SimpleXmlElement)` (https://www.php.net/manual/en/simplexmlelement.count.php)
 * adds support for `count(\ResourceBundle)` (https://www.php.net/manual/en/resourcebundle.count.php)
 * removes usage of global constants from stub (not supported - see https://www.php.net/manual/en/function.count.php)
 * adds support for identifying fixed-element-count arrays, for example `count(callable&array)`, which is always `2`

* #4997 adapted `FunctionCallReturnTypeFetcher` to infer `TPositiveInt` for `count(TNonEmptyArray)` and `count(TNonEmptyList)`

* The `FunctionCallReturnTypeFetcher` is responsible for defining the precise type of a `\count(T)`
expression when given a `T`, so we baked the whole type resolution for `positive-int`, `0` and
`positive-int|0` directly in there.

While this complicates things, it is also true that it is not possible right now (for the stubs)
to provide the level of detail around `count()` that is required by the type inference system
for such a complex function with so many different semantics.
danog pushed a commit to danog/psalm that referenced this issue Jan 29, 2021
…`0` or `positive-int` on known arrays (vimeo#4999)

* vimeo#4997 added more precise stub for `count()` returning `0` or `positive-int` on known types

* vimeo#4997 updated `count()` to support `\SimpleXmlElement` and `\ResourceBundle` counting, as well as handling hardcoded 2-element-arrays cases

This patch:

 * adds support for `count(\SimpleXmlElement)` (https://www.php.net/manual/en/simplexmlelement.count.php)
 * adds support for `count(\ResourceBundle)` (https://www.php.net/manual/en/resourcebundle.count.php)
 * removes usage of global constants from stub (not supported - see https://www.php.net/manual/en/function.count.php)
 * adds support for identifying fixed-element-count arrays, for example `count(callable&array)`, which is always `2`

* vimeo#4997 adapted `FunctionCallReturnTypeFetcher` to infer `TPositiveInt` for `count(TNonEmptyArray)` and `count(TNonEmptyList)`

* The `FunctionCallReturnTypeFetcher` is responsible for defining the precise type of a `\count(T)`
expression when given a `T`, so we baked the whole type resolution for `positive-int`, `0` and
`positive-int|0` directly in there.

While this complicates things, it is also true that it is not possible right now (for the stubs)
to provide the level of detail around `count()` that is required by the type inference system
for such a complex function with so many different semantics.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
3 participants