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
This commit is contained in:
parent
cefe1dcef0
commit
b4b991e66f
4 changed files with 111 additions and 7 deletions
|
@ -4612,6 +4612,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(
|
||||
&self,
|
||||
obligation: &PredicateObligation<'tcx>,
|
||||
|
@ -4622,19 +4625,47 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
|
|||
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);
|
||||
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)) = choose_suggest_items(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()
|
||||
{
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue