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 2880ec2

Browse files
authoredJun 12, 2024
Unrolled build for rust-lang#126187
Rollup merge of rust-lang#126187 - surechen:fix_125997, r=oli-obk For E0277 suggest adding `Result` return type for function when using QuestionMark `?` in the body. Adding suggestions for following function in E0277. ```rust fn main() { let mut _file = File::create("foo.txt")?; } ``` to ```rust fn main() -> Result<(), Box<dyn std::error::Error>> { let mut _file = File::create("foo.txt")?; return Ok(()); } ``` According to the issue rust-lang#125997, only the code examples in the issue are targeted, but the issue covers a wider range of situations. <!-- If this PR is related to an unstable feature or an otherwise tracked effort, please link to the relevant tracking issue here. If you don't know of a related tracking issue or there are none, feel free to ignore this. This PR will get automatically assigned to a reviewer. In case you would like a specific user to review your work, you can assign it to them by using r​? <reviewer name> -->
2 parents 02c7a59 + 0b3fec9 commit 2880ec2

File tree

7 files changed

+218
-0
lines changed

7 files changed

+218
-0
lines changed
 

‎compiler/rustc_hir/src/hir.rs

+1
Original file line numberDiff line numberDiff line change
@@ -1038,6 +1038,7 @@ pub struct Block<'hir> {
10381038
pub hir_id: HirId,
10391039
/// Distinguishes between `unsafe { ... }` and `{ ... }`.
10401040
pub rules: BlockCheckMode,
1041+
/// The span includes the curly braces `{` and `}` around the block.
10411042
pub span: Span,
10421043
/// If true, then there may exist `break 'a` values that aim to
10431044
/// break out of this block early.

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

+41
Original file line numberDiff line numberDiff line change
@@ -4587,6 +4587,47 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
45874587
_ => "/* value */".to_string(),
45884588
})
45894589
}
4590+
4591+
fn suggest_add_result_as_return_type(
4592+
&self,
4593+
obligation: &PredicateObligation<'tcx>,
4594+
err: &mut Diag<'_>,
4595+
trait_ref: ty::PolyTraitRef<'tcx>,
4596+
) {
4597+
if ObligationCauseCode::QuestionMark != *obligation.cause.code().peel_derives() {
4598+
return;
4599+
}
4600+
4601+
let node = self.tcx.hir_node_by_def_id(obligation.cause.body_id);
4602+
if let hir::Node::Item(item) = node
4603+
&& let hir::ItemKind::Fn(sig, _, body_id) = item.kind
4604+
&& let hir::FnRetTy::DefaultReturn(ret_span) = sig.decl.output
4605+
&& self.tcx.is_diagnostic_item(sym::FromResidual, trait_ref.def_id())
4606+
&& let ty::Tuple(l) = trait_ref.skip_binder().args.type_at(0).kind()
4607+
&& l.len() == 0
4608+
&& let ty::Adt(def, _) = trait_ref.skip_binder().args.type_at(1).kind()
4609+
&& self.tcx.is_diagnostic_item(sym::Result, def.did())
4610+
{
4611+
let body = self.tcx.hir().body(body_id);
4612+
let mut sugg_spans =
4613+
vec![(ret_span, " -> Result<(), Box<dyn std::error::Error>>".to_string())];
4614+
4615+
if let hir::ExprKind::Block(b, _) = body.value.kind
4616+
&& b.expr.is_none()
4617+
{
4618+
sugg_spans.push((
4619+
// The span will point to the closing curly brace `}` of the block.
4620+
b.span.shrink_to_hi().with_lo(b.span.hi() - BytePos(1)),
4621+
"\n 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+
}
45904631
}
45914632

45924633
/// 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
@@ -611,6 +611,10 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
611611
&mut err,
612612
trait_predicate,
613613
);
614+
self.suggest_add_result_as_return_type(&obligation,
615+
&mut err,
616+
trait_ref);
617+
614618
if self.suggest_add_reference_to_arg(
615619
&obligation,
616620
&mut err,
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
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+
macro_rules! mac {
25+
() => {
26+
fn test3() -> Result<(), Box<dyn std::error::Error>> {
27+
let mut _file = File::create("foo.txt")?;
28+
//~^ ERROR the `?` operator can only be used in a function
29+
println!();
30+
31+
Ok(())
32+
}
33+
};
34+
}
35+
36+
fn main() -> Result<(), Box<dyn std::error::Error>> {
37+
let mut _file = File::create("foo.txt")?;
38+
//~^ ERROR the `?` operator can only be used in a function
39+
mac!();
40+
41+
Ok(())
42+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
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+
macro_rules! mac {
21+
() => {
22+
fn test3() {
23+
let mut _file = File::create("foo.txt")?;
24+
//~^ ERROR the `?` operator can only be used in a function
25+
println!();
26+
}
27+
};
28+
}
29+
30+
fn main() {
31+
let mut _file = File::create("foo.txt")?;
32+
//~^ ERROR the `?` operator can only be used in a function
33+
mac!();
34+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
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:31: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 | mac!();
55+
LL +
56+
LL + Ok(())
57+
LL + }
58+
|
59+
60+
error[E0277]: the `?` operator can only be used in a function that returns `Result` or `Option` (or another type that implements `FromResidual`)
61+
--> $DIR/return-from-residual-sugg-issue-125997.rs:23:52
62+
|
63+
LL | fn test3() {
64+
| ---------- this function should return `Result` or `Option` to accept `?`
65+
LL | let mut _file = File::create("foo.txt")?;
66+
| ^ cannot use the `?` operator in a function that returns `()`
67+
...
68+
LL | mac!();
69+
| ------ in this macro invocation
70+
|
71+
= help: the trait `FromResidual<Result<Infallible, std::io::Error>>` is not implemented for `()`
72+
= note: this error originates in the macro `mac` (in Nightly builds, run with -Z macro-backtrace for more info)
73+
help: consider adding return type
74+
|
75+
LL ~ fn test3() -> Result<(), Box<dyn std::error::Error>> {
76+
LL | let mut _file = File::create("foo.txt")?;
77+
LL |
78+
LL | println!();
79+
LL ~
80+
LL + Ok(())
81+
LL + }
82+
|
83+
84+
error: aborting due to 4 previous errors
85+
86+
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.