-
-
Notifications
You must be signed in to change notification settings - Fork 2.5k
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
Handle return type properly #6438
Conversation
|
syn::ReturnType::Type(_, ret_type) => ret_type, | ||
}; | ||
|
||
enum ContainsLoopVisitor { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Will have to rename this
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm using this enum to find a possible never
type, but it might be tough to make this exhaustive in a forward-compatible way. There's panic!
, std::process::exit
, loop
, and core::panicking::panic_explicit()
that I know of, but there may be others.
That doesn't include any user-defined functions that return !
.
I was getting compiler warnings if I output something like:
let main_body: Result<(), Error> = loop {
some_fn().await?;
};
(because the type is obviously wrong)
So I'm not sure that this approach really makes sense...
impl syn::visit::Visit<'_> for ContainsLoopVisitor { | ||
fn visit_expr_loop(&mut self, _: &syn::ExprLoop) { | ||
*self = ContainsLoopVisitor::Found; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is definitely super wasteful to parse the entire syntax tree until hitting a loop.
Visit
has 182 methods and I could add skip!
to all of them if *self == Found
but that's a lof of nothing code just to fix an error message
// but that doesn't work as `Output` for our boxed `Future`, so | ||
// default to `()` (the same type as the function output). | ||
syn::ReturnType::Default => &unit_type, | ||
syn::ReturnType::Type(_, ret_type) if ret_type == &never_type => &unit_type, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think I can actually remove this branch
I can fix the |
Thanks for the PR. This seems to be an approach I said in #3039 (comment)? If so you have to handle at least never type and impl traits. See also #5619 (comment). |
NotFound, | ||
} | ||
|
||
impl syn::visit::Visit<'_> for ContainsLoopVisitor { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why does this need to search the input.stmts? Wouldn't it work by just checking the return value?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
When you say the "return value," do you mean the last statement? I guess any statement that contained a loop
that doesn't exit would have to be the last statement otherwise any statements that follow would be dead code.
So that would be an improvement, but that doesn't change the fact that using visit
could potentially be expensive (with very little gained).
// but that doesn't work as `Output` for our boxed `Future`, so | ||
// default to `()` (the same type as the function output). | ||
syn::ReturnType::Default => &unit_type, | ||
syn::ReturnType::Type(_, ret_type) if ret_type == &never_type => &unit_type, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think you can use matches!(&**ret_type, syn::Type::Never(..))
instead of ==
.
@@ -24,7 +24,7 @@ proc-macro = true | |||
[dependencies] | |||
proc-macro2 = "1.0.60" | |||
quote = "1" | |||
syn = { version = "2.0", features = ["full"] } | |||
syn = { version = "2.0", features = ["full", "extra-traits", "visit"] } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Both extra-traits and visit are not very good from a view of compile-time...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Haha, yup.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do you think this is doable without these though? I'm asking more about visit
, there are workarounds for the PartialEq
implementation that I'm using from extra-traits
.
As discussed on #6306 (comment), I will close this since the path forward is unclear. Still, thank you for taking the time to submit a PR. |
Hey, thanks for taking the time to review @Darksonn! All good, I'm sure someone will figure it out at some point. |
Motivation
Closes #6306
Solution
Explicitly state the return type of the last statement such that the compiler gives the proper error if the types do not match.
I'm looking for some initial feedback. As I'm writing this description, I'm realizing that I could probably wrap the entire body instead of just the last statement.
The error now looks like this: