mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-29 10:13:54 +00:00
Rollup merge of #128084 - surechen:fix_125997_v1, r=cjgillot
Suggest adding Result return type for associated method in E0277. Recommit #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 #125997 r? `@cjgillot`
This commit is contained in:
commit
d21b6f2715
@ -4610,6 +4610,9 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// For E0277 when use `?` operator, suggest adding
|
||||||
|
// a suitable return type in `FnSig`, and a default
|
||||||
|
// return value at the end of the function's body.
|
||||||
pub(super) fn suggest_add_result_as_return_type(
|
pub(super) fn suggest_add_result_as_return_type(
|
||||||
&self,
|
&self,
|
||||||
obligation: &PredicateObligation<'tcx>,
|
obligation: &PredicateObligation<'tcx>,
|
||||||
@ -4620,19 +4623,47 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Only suggest for local function and associated method,
|
||||||
|
// because this suggest adding both return type in
|
||||||
|
// the `FnSig` and a default return value in the body, so it
|
||||||
|
// is not suitable for foreign function without a local body,
|
||||||
|
// and neighter for trait method which may be also implemented
|
||||||
|
// in other place, so shouldn't change it's FnSig.
|
||||||
|
fn choose_suggest_items<'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);
|
let node = self.tcx.hir_node_by_def_id(obligation.cause.body_id);
|
||||||
if let hir::Node::Item(item) = node
|
if let Some((fn_decl, body_id)) = choose_suggest_items(self.tcx, node)
|
||||||
&& let hir::ItemKind::Fn(sig, _, body_id) = item.kind
|
&& let hir::FnRetTy::DefaultReturn(ret_span) = fn_decl.output
|
||||||
&& let hir::FnRetTy::DefaultReturn(ret_span) = sig.decl.output
|
|
||||||
&& self.tcx.is_diagnostic_item(sym::FromResidual, trait_pred.def_id())
|
&& self.tcx.is_diagnostic_item(sym::FromResidual, trait_pred.def_id())
|
||||||
&& trait_pred.skip_binder().trait_ref.args.type_at(0).is_unit()
|
&& 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()
|
&& let ty::Adt(def, _) = trait_pred.skip_binder().trait_ref.args.type_at(1).kind()
|
||||||
&& self.tcx.is_diagnostic_item(sym::Result, def.did())
|
&& self.tcx.is_diagnostic_item(sym::Result, def.did())
|
||||||
{
|
{
|
||||||
let body = self.tcx.hir().body(body_id);
|
|
||||||
let mut sugg_spans =
|
let mut sugg_spans =
|
||||||
vec![(ret_span, " -> Result<(), Box<dyn std::error::Error>>".to_string())];
|
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
|
if let hir::ExprKind::Block(b, _) = body.value.kind
|
||||||
&& b.expr.is_none()
|
&& b.expr.is_none()
|
||||||
{
|
{
|
||||||
|
@ -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>> {
|
fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||||
let mut _file = File::create("foo.txt")?;
|
let mut _file = File::create("foo.txt")?;
|
||||||
//~^ ERROR the `?` operator can only be used in a function
|
//~^ ERROR the `?` operator can only be used in a function
|
||||||
|
@ -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() {
|
fn main() {
|
||||||
let mut _file = File::create("foo.txt")?;
|
let mut _file = File::create("foo.txt")?;
|
||||||
//~^ ERROR the `?` operator can only be used in a function
|
//~^ ERROR the `?` operator can only be used in a function
|
||||||
|
@ -37,8 +37,47 @@ LL + Ok(())
|
|||||||
LL + }
|
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`)
|
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() {
|
LL | fn main() {
|
||||||
| --------- this function should return `Result` or `Option` to accept `?`
|
| --------- this function should return `Result` or `Option` to accept `?`
|
||||||
@ -81,6 +120,6 @@ LL + Ok(())
|
|||||||
LL + }
|
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`.
|
For more information about this error, try `rustc --explain E0277`.
|
||||||
|
Loading…
Reference in New Issue
Block a user