Skip to content

Commit 5daeba9

Browse files
committed
For E0277 suggest adding Result return type for function which using QuesionMark ? in the body.
fixes #125997
1 parent f3ff2f1 commit 5daeba9

File tree

6 files changed

+142
-0
lines changed

6 files changed

+142
-0
lines changed

compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs

+52
Original file line numberDiff line numberDiff line change
@@ -4586,6 +4586,58 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
45864586
_ => "/* value */".to_string(),
45874587
})
45884588
}
4589+
4590+
fn suggest_add_result_as_return_type(
4591+
&self,
4592+
obligation: &PredicateObligation<'tcx>,
4593+
err: &mut Diag<'_>,
4594+
trait_ref: ty::PolyTraitRef<'tcx>,
4595+
) {
4596+
if ObligationCauseCode::QuestionMark != *obligation.cause.code().peel_derives() {
4597+
return;
4598+
}
4599+
4600+
let node = self.tcx.hir_node_by_def_id(obligation.cause.body_id);
4601+
if let hir::Node::Item(item) = node
4602+
&& let hir::ItemKind::Fn(sig, _, body_id) = item.kind
4603+
&& let hir::FnRetTy::DefaultReturn(ret_span) = sig.decl.output
4604+
&& trait_ref.skip_binder().args.len() == 2
4605+
&& let ty::Tuple(l) = trait_ref.skip_binder().args.type_at(0).kind()
4606+
&& l.len() == 0
4607+
&& let ty::Adt(def, _) = trait_ref.skip_binder().args.type_at(1).kind()
4608+
&& self.tcx.is_diagnostic_item(sym::Result, def.did())
4609+
{
4610+
let body = self.tcx.hir().body(body_id);
4611+
let mut sugg_spans =
4612+
vec![(ret_span, " -> Result<(), Box<dyn std::error::Error>>".to_string())];
4613+
4614+
if let hir::ExprKind::Block(b, _) = body.value.kind
4615+
&& b.expr.is_none()
4616+
&& let Some(s) = b.stmts.last()
4617+
&& !is_ret_expr(s)
4618+
{
4619+
sugg_spans.push((
4620+
s.span.shrink_to_hi().until(body.value.span.shrink_to_hi()),
4621+
"\n\n return Ok(());\n}".to_string(),
4622+
));
4623+
}
4624+
err.multipart_suggestion_verbose(
4625+
format!("consider adding return type"),
4626+
sugg_spans,
4627+
Applicability::MaybeIncorrect,
4628+
);
4629+
}
4630+
4631+
fn is_ret_expr<'hir>(stmt: &hir::Stmt<'hir>) -> bool {
4632+
if let hir::StmtKind::Semi(expr) = stmt.kind
4633+
&& let hir::ExprKind::Ret(Some(_)) = expr.kind
4634+
{
4635+
true
4636+
} else {
4637+
false
4638+
}
4639+
}
4640+
}
45894641
}
45904642

45914643
/// Add a hint to add a missing borrow or remove an unnecessary one.

compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs

+4
Original file line numberDiff line numberDiff line change
@@ -612,6 +612,10 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
612612
&mut err,
613613
trait_predicate,
614614
);
615+
self.suggest_add_result_as_return_type(&obligation,
616+
&mut err,
617+
trait_ref);
618+
615619
if self.suggest_add_reference_to_arg(
616620
&obligation,
617621
&mut err,
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
//@ run-rustfix
2+
3+
#![allow(unused_imports)]
4+
#![allow(dead_code)]
5+
6+
use std::fs::File;
7+
use std::io::prelude::*;
8+
9+
fn test1() -> Result<(), Box<dyn std::error::Error>> {
10+
let mut _file = File::create("foo.txt")?;
11+
12+
return Ok(());
13+
}
14+
15+
fn main() -> Result<(), Box<dyn std::error::Error>> {
16+
let mut _file = File::create("foo.txt")?;
17+
18+
return Ok(());
19+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
//@ run-rustfix
2+
3+
#![allow(unused_imports)]
4+
#![allow(dead_code)]
5+
6+
use std::fs::File;
7+
use std::io::prelude::*;
8+
9+
fn test1() {
10+
let mut _file = File::create("foo.txt")?;
11+
//~^ ERROR the `?` operator can only be used in a function
12+
}
13+
14+
fn main() {
15+
let mut _file = File::create("foo.txt")?;
16+
//~^ ERROR the `?` operator can only be used in a function
17+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
error[E0277]: the `?` operator can only be used in a function that returns `Result` or `Option` (or another type that implements `FromResidual`)
2+
--> $DIR/return-from-residual-sugg-issue-125997.rs:10:44
3+
|
4+
LL | fn test1() {
5+
| ---------- this function should return `Result` or `Option` to accept `?`
6+
LL | let mut _file = File::create("foo.txt")?;
7+
| ^ cannot use the `?` operator in a function that returns `()`
8+
|
9+
= help: the trait `FromResidual<Result<Infallible, std::io::Error>>` is not implemented for `()`
10+
help: consider adding return type
11+
|
12+
LL ~ fn test1() -> Result<(), Box<dyn std::error::Error>> {
13+
LL ~ let mut _file = File::create("foo.txt")?;
14+
LL +
15+
LL + return Ok(());
16+
LL + }
17+
|
18+
19+
error[E0277]: the `?` operator can only be used in a function that returns `Result` or `Option` (or another type that implements `FromResidual`)
20+
--> $DIR/return-from-residual-sugg-issue-125997.rs:15:44
21+
|
22+
LL | fn main() {
23+
| --------- this function should return `Result` or `Option` to accept `?`
24+
LL | let mut _file = File::create("foo.txt")?;
25+
| ^ cannot use the `?` operator in a function that returns `()`
26+
|
27+
= help: the trait `FromResidual<Result<Infallible, std::io::Error>>` is not implemented for `()`
28+
help: consider adding return type
29+
|
30+
LL ~ fn main() -> Result<(), Box<dyn std::error::Error>> {
31+
LL ~ let mut _file = File::create("foo.txt")?;
32+
LL +
33+
LL + return Ok(());
34+
LL + }
35+
|
36+
37+
error: aborting due to 2 previous errors
38+
39+
For more information about this error, try `rustc --explain E0277`.

tests/ui/try-trait/try-operator-on-main.stderr

+11
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,17 @@ LL | std::fs::File::open("foo")?;
88
| ^ cannot use the `?` operator in a function that returns `()`
99
|
1010
= help: the trait `FromResidual<Result<Infallible, std::io::Error>>` is not implemented for `()`
11+
help: consider adding return type
12+
|
13+
LL ~ fn main() -> Result<(), Box<dyn std::error::Error>> {
14+
LL | // error for a `Try` type on a non-`Try` fn
15+
...
16+
LL | // an unrelated use of `Try`
17+
LL ~ try_trait_generic::<()>();
18+
LL +
19+
LL + return Ok(());
20+
LL + }
21+
|
1122

1223
error[E0277]: the `?` operator can only be applied to values that implement `Try`
1324
--> $DIR/try-operator-on-main.rs:10:5

0 commit comments

Comments
 (0)