Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit 156fa1c

Browse files
committedJun 11, 2024
For E0277 suggest adding Result return type for function which using QuesionMark ? in the body.
1 parent f3ff2f1 commit 156fa1c

6 files changed

+168
-0
lines changed
 

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

+41
Original file line numberDiff line numberDiff line change
@@ -4586,6 +4586,47 @@ 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+
&& self.tcx.is_diagnostic_item(sym::FromResidual, trait_ref.def_id())
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+
{
4617+
// The span will point to the closing curly brace `}` of the block.
4618+
sugg_spans.push((
4619+
b.span.shrink_to_hi().with_lo(b.span.hi() - BytePos(1)),
4620+
"\n Ok(())\n}".to_string(),
4621+
));
4622+
}
4623+
err.multipart_suggestion_verbose(
4624+
format!("consider adding return type"),
4625+
sugg_spans,
4626+
Applicability::MaybeIncorrect,
4627+
);
4628+
}
4629+
}
45894630
}
45904631

45914632
/// 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,29 @@
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+
//~^ ERROR the `?` operator can only be used in a function
12+
13+
Ok(())
14+
}
15+
16+
fn test2() -> Result<(), Box<dyn std::error::Error>> {
17+
let mut _file = File::create("foo.txt")?;
18+
//~^ ERROR the `?` operator can only be used in a function
19+
println!();
20+
21+
Ok(())
22+
}
23+
24+
fn main() -> Result<(), Box<dyn std::error::Error>> {
25+
let mut _file = File::create("foo.txt")?;
26+
//~^ ERROR the `?` operator can only be used in a function
27+
28+
Ok(())
29+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
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 test2() {
15+
let mut _file = File::create("foo.txt")?;
16+
//~^ ERROR the `?` operator can only be used in a function
17+
println!();
18+
}
19+
20+
fn main() {
21+
let mut _file = File::create("foo.txt")?;
22+
//~^ ERROR the `?` operator can only be used in a function
23+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
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 +
16+
LL + Ok(())
17+
LL + }
18+
|
19+
20+
error[E0277]: the `?` operator can only be used in a function that returns `Result` or `Option` (or another type that implements `FromResidual`)
21+
--> $DIR/return-from-residual-sugg-issue-125997.rs:15:44
22+
|
23+
LL | fn test2() {
24+
| ---------- this function should return `Result` or `Option` to accept `?`
25+
LL | let mut _file = File::create("foo.txt")?;
26+
| ^ cannot use the `?` operator in a function that returns `()`
27+
|
28+
= help: the trait `FromResidual<Result<Infallible, std::io::Error>>` is not implemented for `()`
29+
help: consider adding return type
30+
|
31+
LL ~ fn test2() -> Result<(), Box<dyn std::error::Error>> {
32+
LL | let mut _file = File::create("foo.txt")?;
33+
LL |
34+
LL | println!();
35+
LL +
36+
LL + Ok(())
37+
LL + }
38+
|
39+
40+
error[E0277]: the `?` operator can only be used in a function that returns `Result` or `Option` (or another type that implements `FromResidual`)
41+
--> $DIR/return-from-residual-sugg-issue-125997.rs:21:44
42+
|
43+
LL | fn main() {
44+
| --------- this function should return `Result` or `Option` to accept `?`
45+
LL | let mut _file = File::create("foo.txt")?;
46+
| ^ cannot use the `?` operator in a function that returns `()`
47+
|
48+
= help: the trait `FromResidual<Result<Infallible, std::io::Error>>` is not implemented for `()`
49+
help: consider adding return type
50+
|
51+
LL ~ fn main() -> Result<(), Box<dyn std::error::Error>> {
52+
LL | let mut _file = File::create("foo.txt")?;
53+
LL |
54+
LL +
55+
LL + Ok(())
56+
LL + }
57+
|
58+
59+
error: aborting due to 3 previous errors
60+
61+
For more information about this error, try `rustc --explain E0277`.

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

+10
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,16 @@ 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 | try_trait_generic::<()>();
17+
LL +
18+
LL + Ok(())
19+
LL + }
20+
|
1121

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

0 commit comments

Comments
 (0)
Failed to load comments.