-
Notifications
You must be signed in to change notification settings - Fork 13.4k
For E0277 suggest adding Result
return type for function when using QuestionMark ?
in the body.
#126187
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
For E0277 suggest adding Result
return type for function when using QuestionMark ?
in the body.
#126187
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -4586,6 +4586,47 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { | |
_ => "/* value */".to_string(), | ||
}) | ||
} | ||
|
||
fn suggest_add_result_as_return_type( | ||
&self, | ||
obligation: &PredicateObligation<'tcx>, | ||
err: &mut Diag<'_>, | ||
trait_ref: ty::PolyTraitRef<'tcx>, | ||
) { | ||
if ObligationCauseCode::QuestionMark != *obligation.cause.code().peel_derives() { | ||
return; | ||
} | ||
|
||
let node = self.tcx.hir_node_by_def_id(obligation.cause.body_id); | ||
if let hir::Node::Item(item) = node | ||
&& let hir::ItemKind::Fn(sig, _, body_id) = item.kind | ||
&& let hir::FnRetTy::DefaultReturn(ret_span) = sig.decl.output | ||
&& self.tcx.is_diagnostic_item(sym::FromResidual, trait_ref.def_id()) | ||
&& let ty::Tuple(l) = trait_ref.skip_binder().args.type_at(0).kind() | ||
&& l.len() == 0 | ||
&& let ty::Adt(def, _) = trait_ref.skip_binder().args.type_at(1).kind() | ||
&& self.tcx.is_diagnostic_item(sym::Result, def.did()) | ||
{ | ||
let body = self.tcx.hir().body(body_id); | ||
let mut sugg_spans = | ||
vec![(ret_span, " -> Result<(), Box<dyn std::error::Error>>".to_string())]; | ||
|
||
if let hir::ExprKind::Block(b, _) = body.value.kind | ||
&& b.expr.is_none() | ||
{ | ||
sugg_spans.push(( | ||
// The span will point to the closing curly brace `}` of the block. | ||
b.span.shrink_to_hi().with_lo(b.span.hi() - BytePos(1)), | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. since we know there must be at least one statement, you can instead do There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Thank you. I tried this way. But when the last stmt is a macro call like There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ah indeed. hmm... Maybe we should change the value of I don't think the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Hello, thank you very much. async fn test2() {
let mut file = File::create("foo.txt")?;
println!();
} The fix result will be : async fn test2() -> Result<(), Box<dyn std::error::Error>> {
Ok(())
} The span seems point to the body correct. But after fixed the expr Because the current logic does not handle the closure situation, and I have not thought of an effective way to repair the closure, I think we can skip it in this PR. |
||
"\n Ok(())\n}".to_string(), | ||
)); | ||
} | ||
err.multipart_suggestion_verbose( | ||
format!("consider adding return type"), | ||
sugg_spans, | ||
Applicability::MaybeIncorrect, | ||
); | ||
} | ||
} | ||
} | ||
|
||
/// Add a hint to add a missing borrow or remove an unnecessary one. | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
//@ run-rustfix | ||
|
||
#![allow(unused_imports)] | ||
#![allow(dead_code)] | ||
|
||
use std::fs::File; | ||
use std::io::prelude::*; | ||
|
||
fn test1() -> Result<(), Box<dyn std::error::Error>> { | ||
let mut _file = File::create("foo.txt")?; | ||
//~^ ERROR the `?` operator can only be used in a function | ||
|
||
Ok(()) | ||
} | ||
|
||
fn test2() -> Result<(), Box<dyn std::error::Error>> { | ||
let mut _file = File::create("foo.txt")?; | ||
//~^ ERROR the `?` operator can only be used in a function | ||
println!(); | ||
|
||
Ok(()) | ||
} | ||
|
||
macro_rules! mac { | ||
() => { | ||
fn test3() -> Result<(), Box<dyn std::error::Error>> { | ||
let mut _file = File::create("foo.txt")?; | ||
//~^ ERROR the `?` operator can only be used in a function | ||
println!(); | ||
|
||
Ok(()) | ||
} | ||
}; | ||
} | ||
|
||
fn main() -> Result<(), Box<dyn std::error::Error>> { | ||
let mut _file = File::create("foo.txt")?; | ||
//~^ ERROR the `?` operator can only be used in a function | ||
mac!(); | ||
|
||
Ok(()) | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
//@ run-rustfix | ||
|
||
#![allow(unused_imports)] | ||
#![allow(dead_code)] | ||
|
||
use std::fs::File; | ||
use std::io::prelude::*; | ||
|
||
fn test1() { | ||
let mut _file = File::create("foo.txt")?; | ||
//~^ ERROR the `?` operator can only be used in a function | ||
} | ||
|
||
fn test2() { | ||
let mut _file = File::create("foo.txt")?; | ||
//~^ ERROR the `?` operator can only be used in a function | ||
println!(); | ||
} | ||
|
||
macro_rules! mac { | ||
() => { | ||
fn test3() { | ||
let mut _file = File::create("foo.txt")?; | ||
//~^ ERROR the `?` operator can only be used in a function | ||
println!(); | ||
} | ||
}; | ||
} | ||
|
||
fn main() { | ||
let mut _file = File::create("foo.txt")?; | ||
//~^ ERROR the `?` operator can only be used in a function | ||
mac!(); | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,86 @@ | ||
error[E0277]: the `?` operator can only be used in a function that returns `Result` or `Option` (or another type that implements `FromResidual`) | ||
--> $DIR/return-from-residual-sugg-issue-125997.rs:10:44 | ||
| | ||
LL | fn test1() { | ||
| ---------- this function should return `Result` or `Option` to accept `?` | ||
LL | let mut _file = File::create("foo.txt")?; | ||
| ^ cannot use the `?` operator in a function that returns `()` | ||
| | ||
= help: the trait `FromResidual<Result<Infallible, std::io::Error>>` is not implemented for `()` | ||
help: consider adding return type | ||
| | ||
LL ~ fn test1() -> Result<(), Box<dyn std::error::Error>> { | ||
LL | let mut _file = File::create("foo.txt")?; | ||
LL | | ||
LL + | ||
LL + Ok(()) | ||
LL + } | ||
| | ||
|
||
error[E0277]: the `?` operator can only be used in a function that returns `Result` or `Option` (or another type that implements `FromResidual`) | ||
--> $DIR/return-from-residual-sugg-issue-125997.rs:15:44 | ||
| | ||
LL | fn test2() { | ||
| ---------- this function should return `Result` or `Option` to accept `?` | ||
LL | let mut _file = File::create("foo.txt")?; | ||
| ^ cannot use the `?` operator in a function that returns `()` | ||
| | ||
= help: the trait `FromResidual<Result<Infallible, std::io::Error>>` is not implemented for `()` | ||
help: consider adding return type | ||
| | ||
LL ~ fn test2() -> Result<(), Box<dyn std::error::Error>> { | ||
LL | let mut _file = File::create("foo.txt")?; | ||
LL | | ||
LL | println!(); | ||
LL + | ||
LL + Ok(()) | ||
LL + } | ||
| | ||
|
||
error[E0277]: the `?` operator can only be used in a function that returns `Result` or `Option` (or another type that implements `FromResidual`) | ||
--> $DIR/return-from-residual-sugg-issue-125997.rs:31:44 | ||
| | ||
LL | fn main() { | ||
| --------- this function should return `Result` or `Option` to accept `?` | ||
LL | let mut _file = File::create("foo.txt")?; | ||
| ^ cannot use the `?` operator in a function that returns `()` | ||
| | ||
= help: the trait `FromResidual<Result<Infallible, std::io::Error>>` is not implemented for `()` | ||
help: consider adding return type | ||
| | ||
LL ~ fn main() -> Result<(), Box<dyn std::error::Error>> { | ||
LL | let mut _file = File::create("foo.txt")?; | ||
LL | | ||
LL | mac!(); | ||
LL + | ||
LL + Ok(()) | ||
LL + } | ||
| | ||
|
||
error[E0277]: the `?` operator can only be used in a function that returns `Result` or `Option` (or another type that implements `FromResidual`) | ||
--> $DIR/return-from-residual-sugg-issue-125997.rs:23:52 | ||
| | ||
LL | fn test3() { | ||
| ---------- this function should return `Result` or `Option` to accept `?` | ||
LL | let mut _file = File::create("foo.txt")?; | ||
| ^ cannot use the `?` operator in a function that returns `()` | ||
... | ||
LL | mac!(); | ||
| ------ in this macro invocation | ||
| | ||
= help: the trait `FromResidual<Result<Infallible, std::io::Error>>` is not implemented for `()` | ||
= note: this error originates in the macro `mac` (in Nightly builds, run with -Z macro-backtrace for more info) | ||
help: consider adding return type | ||
| | ||
LL ~ fn test3() -> Result<(), Box<dyn std::error::Error>> { | ||
LL | let mut _file = File::create("foo.txt")?; | ||
LL | | ||
LL | println!(); | ||
LL ~ | ||
LL + Ok(()) | ||
LL + } | ||
| | ||
|
||
error: aborting due to 4 previous errors | ||
|
||
For more information about this error, try `rustc --explain E0277`. |
Uh oh!
There was an error while loading. Please reload this page.