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

Add return types to methods where they can be inferred #342

Closed
wants to merge 2 commits into from

Conversation

muglug
Copy link
Contributor

@muglug muglug commented Jan 23, 2017

Running my static analysis tool with --update-docblocks produces this diff (which I thought may be useful in light of these changes).

@nikic
Copy link
Owner

nikic commented Jan 24, 2017

Is it possible to disable generation of @return void annotations? I'm not using those anywhere, as I consider the absence of @return in a doc-block to indicate that there is no meaningful return value.

@muglug
Copy link
Contributor Author

muglug commented Jan 24, 2017

Sure! I've added a config to control whether void return types are added, and I've updated this PR's commit accordingly.

@@ -114,6 +114,9 @@ public function getReformattedText() {
return $text;
}

/**
* @return float
Copy link
Owner

Choose a reason for hiding this comment

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

Shouldn't this type infer to int|float, as strlen() returns int?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

There was existing logic to support ints being cast to floats in function calls, and it (falsely) trickled into the type simplification logic – fixed here: vimeo/psalm@5ec2a97

@@ -43,6 +47,10 @@ public function parse($code, ErrorHandler $errorHandler = null) {
throw $firstError;
}

/**
* @return (null|Error|\PhpParser\Node\Stmt[])[]
* @psalm-return array<int, null|Error|array<mixed, \PhpParser\Node\Stmt>>
Copy link
Owner

Choose a reason for hiding this comment

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

Seen above that Psalm also supports something like @psalm-return array{nodeType:string, text:mixed, line:mixed, filePos:mixed}. If this here were @psalm-return array{0:null|Node\Stmt[], 1:null|Error} then the list() unpacking in the method above could see that Error is not a possible return type.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Unfortunately 0 and 1 as keys imply that they are strings, so argument unpacking wouldn't work there. A solution is either to add string array offsets (and change what the method returns, and how it's used above) or just strip out the return types for now.

Obviously PHP 7.1's array key destructuring would simplify that diff, but happy that PhpParser is PHP 5-compatible.

Copy link
Owner

Choose a reason for hiding this comment

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

PHP does not distinguish between integer keys and integral string keys. So here all of [$a, $b], [0 => $a, 1 => $b] and ["0" => $a, "1" => $b] are equivalent (both in terms of array creation and unpacking). I'm fine with just stripping the return type, just wondering why Psalm makes this distinction, i.e., why are "shapes" only created for arrays with string keys, rather than also arrays with fixed-structure integral keys? Is this because there might be false positives where such a return value is intended as a normal array (which just happens to have the same non-uniform types on all paths) rather than a shape?

@nikic
Copy link
Owner

nikic commented Jan 24, 2017

Overall, nice results. There's a few cases where the return type is too broad (e.g. NameResolver::getResolvedClassName() can't return null), but inferring that would be non-trivial (something like CPA could determine that null is only returned if both arguments are null and in this case at most one of them is).

@muglug
Copy link
Contributor Author

muglug commented Jan 24, 2017

Thanks! To that last point, how about throwing an exception if both $name1 and $name2 are null in PhpParser\Node\Name::concat? It seems like that can never happen, at least in PhpParser's own usage of that method. Doing so would erase the null value from that return type, and solve that particular issue.

@muglug
Copy link
Contributor Author

muglug commented Jan 24, 2017

Yup, there's no reason why Psalm shouldn't be able to understand that formulation for ObjectLike types when processing ArrayDimFetch and when destructuring lists. I will ticket and add soonish.

Generating that type is considerably less trivial (as there are a bunch of different desired outcomes depending on the different return statements in a function), but I'll ticket that as well.

@@ -602,6 +615,9 @@ protected function fixupStartAttributes(Node $to, Node $from) {
}
}

/**
* @return string
Copy link
Owner

Choose a reason for hiding this comment

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

Noticed while merging: This return type is off. It should be inferred as string|Name|Node\Identifier, as there are return $names and a return new Node\Identifier via ternary.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Ah bugger. Sorry. It's because both classes have a __toString method, and Psalm gets confused when merging the types. Fixing...

@nikic
Copy link
Owner

nikic commented Jan 25, 2017

Merged via e3b87f4, with more updates in bfea338, where I manually improved some of the types and added descriptions + param annotations for everything.

I did not merge the changes to the Standard pretty printer, as there basically all methods return strings and I think adding explicit doc comments there is more noisy than helpful.

Thanks!

@nikic nikic closed this Jan 25, 2017
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants