Skip to content

Commit 89e2702

Browse files
authored
Unrolled build for rust-lang#128084
Rollup merge of rust-lang#128084 - surechen:fix_125997_v1, r=cjgillot Suggest adding Result return type for associated method in E0277. Recommit rust-lang#126515 because I messed up during rebase, Suggest adding Result return type for associated method in E0277. For following: ```rust struct A; impl A { fn test4(&self) { let mut _file = File::create("foo.txt")?; //~^ ERROR the `?` operator can only be used in a method } ``` Suggest: ```rust impl A { fn test4(&self) -> Result<(), Box<dyn std::error::Error>> { let mut _file = File::create("foo.txt")?; //~^ ERROR the `?` operator can only be used in a method Ok(()) } } ``` For rust-lang#125997 r? `@cjgillot`
2 parents 804be74 + b4b991e commit 89e2702

File tree

4 files changed

+111
-7
lines changed

4 files changed

+111
-7
lines changed

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

+36-5
Original file line numberDiff line numberDiff line change
@@ -4610,6 +4610,9 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
46104610
})
46114611
}
46124612

4613+
// For E0277 when use `?` operator, suggest adding
4614+
// a suitable return type in `FnSig`, and a default
4615+
// return value at the end of the function's body.
46134616
pub(super) fn suggest_add_result_as_return_type(
46144617
&self,
46154618
obligation: &PredicateObligation<'tcx>,
@@ -4620,19 +4623,47 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
46204623
return;
46214624
}
46224625

4626+
// Only suggest for local function and associated method,
4627+
// because this suggest adding both return type in
4628+
// the `FnSig` and a default return value in the body, so it
4629+
// is not suitable for foreign function without a local body,
4630+
// and neighter for trait method which may be also implemented
4631+
// in other place, so shouldn't change it's FnSig.
4632+
fn choose_suggest_items<'tcx, 'hir>(
4633+
tcx: TyCtxt<'tcx>,
4634+
node: hir::Node<'hir>,
4635+
) -> Option<(&'hir hir::FnDecl<'hir>, hir::BodyId)> {
4636+
match node {
4637+
hir::Node::Item(item) if let hir::ItemKind::Fn(sig, _, body_id) = item.kind => {
4638+
Some((sig.decl, body_id))
4639+
}
4640+
hir::Node::ImplItem(item)
4641+
if let hir::ImplItemKind::Fn(sig, body_id) = item.kind =>
4642+
{
4643+
let parent = tcx.parent_hir_node(item.hir_id());
4644+
if let hir::Node::Item(item) = parent
4645+
&& let hir::ItemKind::Impl(imp) = item.kind
4646+
&& imp.of_trait.is_none()
4647+
{
4648+
return Some((sig.decl, body_id));
4649+
}
4650+
None
4651+
}
4652+
_ => None,
4653+
}
4654+
}
4655+
46234656
let node = self.tcx.hir_node_by_def_id(obligation.cause.body_id);
4624-
if let hir::Node::Item(item) = node
4625-
&& let hir::ItemKind::Fn(sig, _, body_id) = item.kind
4626-
&& let hir::FnRetTy::DefaultReturn(ret_span) = sig.decl.output
4657+
if let Some((fn_decl, body_id)) = choose_suggest_items(self.tcx, node)
4658+
&& let hir::FnRetTy::DefaultReturn(ret_span) = fn_decl.output
46274659
&& self.tcx.is_diagnostic_item(sym::FromResidual, trait_pred.def_id())
46284660
&& trait_pred.skip_binder().trait_ref.args.type_at(0).is_unit()
46294661
&& let ty::Adt(def, _) = trait_pred.skip_binder().trait_ref.args.type_at(1).kind()
46304662
&& self.tcx.is_diagnostic_item(sym::Result, def.did())
46314663
{
4632-
let body = self.tcx.hir().body(body_id);
46334664
let mut sugg_spans =
46344665
vec![(ret_span, " -> Result<(), Box<dyn std::error::Error>>".to_string())];
4635-
4666+
let body = self.tcx.hir().body(body_id);
46364667
if let hir::ExprKind::Block(b, _) = body.value.kind
46374668
&& b.expr.is_none()
46384669
{

tests/ui/return/return-from-residual-sugg-issue-125997.fixed

+19
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,25 @@ macro_rules! mac {
3333
};
3434
}
3535

36+
struct A;
37+
38+
impl A {
39+
fn test4(&self) -> Result<(), Box<dyn std::error::Error>> {
40+
let mut _file = File::create("foo.txt")?;
41+
//~^ ERROR the `?` operator can only be used in a method
42+
43+
Ok(())
44+
}
45+
46+
fn test5(&self) -> Result<(), Box<dyn std::error::Error>> {
47+
let mut _file = File::create("foo.txt")?;
48+
//~^ ERROR the `?` operator can only be used in a method
49+
println!();
50+
51+
Ok(())
52+
}
53+
}
54+
3655
fn main() -> Result<(), Box<dyn std::error::Error>> {
3756
let mut _file = File::create("foo.txt")?;
3857
//~^ ERROR the `?` operator can only be used in a function

tests/ui/return/return-from-residual-sugg-issue-125997.rs

+15
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,21 @@ macro_rules! mac {
2727
};
2828
}
2929

30+
struct A;
31+
32+
impl A {
33+
fn test4(&self) {
34+
let mut _file = File::create("foo.txt")?;
35+
//~^ ERROR the `?` operator can only be used in a method
36+
}
37+
38+
fn test5(&self) {
39+
let mut _file = File::create("foo.txt")?;
40+
//~^ ERROR the `?` operator can only be used in a method
41+
println!();
42+
}
43+
}
44+
3045
fn main() {
3146
let mut _file = File::create("foo.txt")?;
3247
//~^ ERROR the `?` operator can only be used in a function

tests/ui/return/return-from-residual-sugg-issue-125997.stderr

+41-2
Original file line numberDiff line numberDiff line change
@@ -37,8 +37,47 @@ LL + Ok(())
3737
LL + }
3838
|
3939

40+
error[E0277]: the `?` operator can only be used in a method that returns `Result` or `Option` (or another type that implements `FromResidual`)
41+
--> $DIR/return-from-residual-sugg-issue-125997.rs:34:48
42+
|
43+
LL | fn test4(&self) {
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 method 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 test4(&self) -> 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[E0277]: the `?` operator can only be used in a method that returns `Result` or `Option` (or another type that implements `FromResidual`)
60+
--> $DIR/return-from-residual-sugg-issue-125997.rs:39:48
61+
|
62+
LL | fn test5(&self) {
63+
| --------------- this function should return `Result` or `Option` to accept `?`
64+
LL | let mut _file = File::create("foo.txt")?;
65+
| ^ cannot use the `?` operator in a method that returns `()`
66+
|
67+
= help: the trait `FromResidual<Result<Infallible, std::io::Error>>` is not implemented for `()`
68+
help: consider adding return type
69+
|
70+
LL ~ fn test5(&self) -> Result<(), Box<dyn std::error::Error>> {
71+
LL | let mut _file = File::create("foo.txt")?;
72+
LL |
73+
LL | println!();
74+
LL ~
75+
LL + Ok(())
76+
LL + }
77+
|
78+
4079
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
80+
--> $DIR/return-from-residual-sugg-issue-125997.rs:46:44
4281
|
4382
LL | fn main() {
4483
| --------- this function should return `Result` or `Option` to accept `?`
@@ -81,6 +120,6 @@ LL + Ok(())
81120
LL + }
82121
|
83122

84-
error: aborting due to 4 previous errors
123+
error: aborting due to 6 previous errors
85124

86125
For more information about this error, try `rustc --explain E0277`.

0 commit comments

Comments
 (0)