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

Improve the return type of array_map() for constant arrays #3156

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

Conversation

zonuexe
Copy link
Contributor

@zonuexe zonuexe commented Jun 13, 2024

assertType("array{'0', '1'}", array_map(strval(...), $a));
assertType("array{'0', '1'}", array_map(str(...), $a));
assertType("array{'0'|'1', '0'|'1'}", array_map(fn ($v) => strval($v), $a));
assertType("array{'0'|'1', '0'|'1'}", array_map(fn ($v) => (string)$v, $a));
Copy link
Contributor Author

Choose a reason for hiding this comment

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

The ClosureType::$returnType is bound to the union of the other elements of the array with the type of the callback. I'm looking for a way to get around that.

$callback = new Name($callName);
} elseif ($callback instanceof FuncCall && $callback->isFirstClassCallable() &&
$callback->getAttribute('phpstan_cache_printer') !== null &&
preg_match('/\A(?<name>\\\\?[^()]+)\(...\)\z/', $callback->getAttribute('phpstan_cache_printer'), $m) === 1
Copy link
Contributor Author

Choose a reason for hiding this comment

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

To avoid binding the ClosureType::$returnType to a union with the results of other elements, I have replaced it with a direct call to the original function. I don't want to misuse the phpstan_cache_printer attribute, but there doesn't seem to be any other suitable source of the original function.


if ($callableType->isCallable()->yes()) {
$valueTypes = [new NeverType()];
foreach ($callableType->getCallableParametersAcceptors($scope) as $parametersAcceptor) {
$valueTypes[] = $parametersAcceptor->getReturnType();
}
$valueType = TypeCombinator::union(...$valueTypes);
$callback = $functionCall->getArgs()[0]->value;
if ($callback instanceof String_) {
Copy link
Member

Choose a reason for hiding this comment

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

This entire code block isn't the right solution. You don't need to do any of that. You should be able to achieve the same thing with just:

$callback = $functionCall->getArgs()[0]->value;
$callbackReturnType = $scope->getType(new FuncCall($callback, [
    new Arg(new TypeExpr($constantArray->getValueTypes()[$i])),
]));

If that doesn't work for some expressions, then the root cause is elsewhere.

@zonuexe zonuexe force-pushed the feature/improve-array_map-type branch from b5cae3f to 31ae118 Compare June 27, 2024 18:27
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
2 participants