Skip to content

Commit

Permalink
Merge pull request #7326 from orklah/short_closures_returning_never
Browse files Browse the repository at this point in the history
allow short closure to return never
  • Loading branch information
orklah committed Jan 9, 2022
2 parents fe46082 + cbb0c63 commit 413da78
Show file tree
Hide file tree
Showing 3 changed files with 41 additions and 0 deletions.
6 changes: 6 additions & 0 deletions src/Psalm/Internal/Analyzer/FunctionLikeAnalyzer.php
Expand Up @@ -464,6 +464,12 @@ public function analyze(
$this->track_mutations = true;
}

if ($this->function instanceof ArrowFunction && $storage->return_type && $storage->return_type->isNever()) {
// ArrowFunction perform a return implicitly so if the return type is never, we have to suppress the error
// note: the never can only come from phpdoc. PHP will refuse short closures with never in signature
$statements_analyzer->addSuppressedIssues(['NoValue']);
}

$statements_analyzer->analyze($function_stmts, $context, $global_context, true);

if ($codebase->alter_code
Expand Down
10 changes: 10 additions & 0 deletions src/Psalm/Internal/Analyzer/ScopeAnalyzer.php
Expand Up @@ -94,6 +94,16 @@ public static function getControlActions(
($stmt instanceof PhpParser\Node\Stmt\Expression && $stmt->expr instanceof PhpParser\Node\Expr\Exit_)
) {
if (!$return_is_exit && $stmt instanceof PhpParser\Node\Stmt\Return_) {
$stmt_return_type = null;
if ($nodes && $stmt->expr) {
$stmt_return_type = $nodes->getType($stmt->expr);
}

// don't consider a return if the expression never returns (e.g. a throw inside a short closure)
if ($stmt_return_type && ($stmt_return_type->isNever() || $stmt_return_type->isEmpty())) {
return array_values(array_unique(array_merge($control_actions, [self::ACTION_END])));
}

return array_values(array_unique(array_merge($control_actions, [self::ACTION_RETURN])));
}

Expand Down
25 changes: 25 additions & 0 deletions tests/ClosureTest.php
Expand Up @@ -735,6 +735,31 @@ public static function __callStatic(string $name, array $args): mixed {
[],
'8.1',
],
'arrowFunctionReturnsNeverImplictly' => [
'<?php
$bar = ["foo", "bar"];
$bam = array_map(
fn(string $a) => throw new Exception($a),
$bar
);',
'assertions' => [],
'error_levels' => [],
'8.1'
],
'arrowFunctionReturnsNeverExplictly' => [
'<?php
$bar = ["foo", "bar"];
$bam = array_map(
/** @return never */
fn(string $a) => die(),
$bar
);',
'assertions' => [],
'error_levels' => [],
'8.1'
],
];
}

Expand Down

0 comments on commit 413da78

Please sign in to comment.