Skip to content

Commit

Permalink
Suggest adding Result return type for associated method in E0277.
Browse files Browse the repository at this point in the history
  • Loading branch information
surechen committed Jun 15, 2024
1 parent bfa098e commit b9bf099
Show file tree
Hide file tree
Showing 4 changed files with 102 additions and 7 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -4598,19 +4598,41 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
return;
}

fn get_fn_decl<'tcx, 'hir>(
tcx: TyCtxt<'tcx>,
node: hir::Node<'hir>,
) -> Option<(&'hir hir::FnDecl<'hir>, hir::BodyId)> {
match node {
hir::Node::Item(item) if let hir::ItemKind::Fn(sig, _, body_id) = item.kind => {
Some((sig.decl, body_id))
}
hir::Node::ImplItem(item)
if let hir::ImplItemKind::Fn(sig, body_id) = item.kind =>
{
let parent = tcx.parent_hir_node(item.hir_id());
if let hir::Node::Item(item) = parent
&& let hir::ItemKind::Impl(imp) = item.kind
&& imp.of_trait.is_none()
{
return Some((sig.decl, body_id));
}
None
}
_ => None,
}
}

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
if let Some((fn_decl, body_id)) = get_fn_decl(self.tcx, node)
&& let hir::FnRetTy::DefaultReturn(ret_span) = fn_decl.output
&& self.tcx.is_diagnostic_item(sym::FromResidual, trait_pred.def_id())
&& trait_pred.skip_binder().trait_ref.args.type_at(0).is_unit()
&& let ty::Adt(def, _) = trait_pred.skip_binder().trait_ref.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())];

let body = self.tcx.hir().body(body_id);
if let hir::ExprKind::Block(b, _) = body.value.kind
&& b.expr.is_none()
{
Expand Down
19 changes: 19 additions & 0 deletions tests/ui/return/return-from-residual-sugg-issue-125997.fixed
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,25 @@ macro_rules! mac {
};
}

struct A;

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(())
}

fn test5(&self) -> Result<(), Box<dyn std::error::Error>> {
let mut _file = File::create("foo.txt")?;
//~^ ERROR the `?` operator can only be used in a method
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
Expand Down
15 changes: 15 additions & 0 deletions tests/ui/return/return-from-residual-sugg-issue-125997.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,21 @@ macro_rules! mac {
};
}

struct A;

impl A {
fn test4(&self) {
let mut _file = File::create("foo.txt")?;
//~^ ERROR the `?` operator can only be used in a method
}

fn test5(&self) {
let mut _file = File::create("foo.txt")?;
//~^ ERROR the `?` operator can only be used in a method
println!();
}
}

fn main() {
let mut _file = File::create("foo.txt")?;
//~^ ERROR the `?` operator can only be used in a function
Expand Down
43 changes: 41 additions & 2 deletions tests/ui/return/return-from-residual-sugg-issue-125997.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,47 @@ LL + Ok(())
LL + }
|

error[E0277]: the `?` operator can only be used in a method that returns `Result` or `Option` (or another type that implements `FromResidual`)
--> $DIR/return-from-residual-sugg-issue-125997.rs:34:48
|
LL | fn test4(&self) {
| --------------- this function should return `Result` or `Option` to accept `?`
LL | let mut _file = File::create("foo.txt")?;
| ^ cannot use the `?` operator in a method that returns `()`
|
= help: the trait `FromResidual<Result<Infallible, std::io::Error>>` is not implemented for `()`
help: consider adding return type
|
LL ~ fn test4(&self) -> 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 method that returns `Result` or `Option` (or another type that implements `FromResidual`)
--> $DIR/return-from-residual-sugg-issue-125997.rs:39:48
|
LL | fn test5(&self) {
| --------------- this function should return `Result` or `Option` to accept `?`
LL | let mut _file = File::create("foo.txt")?;
| ^ cannot use the `?` operator in a method that returns `()`
|
= help: the trait `FromResidual<Result<Infallible, std::io::Error>>` is not implemented for `()`
help: consider adding return type
|
LL ~ fn test5(&self) -> 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
--> $DIR/return-from-residual-sugg-issue-125997.rs:46:44
|
LL | fn main() {
| --------- this function should return `Result` or `Option` to accept `?`
Expand Down Expand Up @@ -81,6 +120,6 @@ LL + Ok(())
LL + }
|

error: aborting due to 4 previous errors
error: aborting due to 6 previous errors

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

0 comments on commit b9bf099

Please sign in to comment.