diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs index 219413121d812..ffc4f8cf3d3b3 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs @@ -882,6 +882,8 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { obligation.cause.code() { &parent_code + } else if let ObligationCauseCode::ItemObligation(_) = obligation.cause.code() { + obligation.cause.code() } else if let ExpnKind::Desugaring(DesugaringKind::ForLoop) = span.ctxt().outer_expn_data().kind { @@ -930,10 +932,25 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { self.mk_trait_obligation_with_new_self_ty(param_env, trait_pred_and_new_ty); self.predicate_must_hold_modulo_regions(&obligation) }; - let imm_result = mk_result(trait_pred_and_imm_ref); - let mut_result = mk_result(trait_pred_and_mut_ref); + let imm_ref_self_ty_satisfies_pred = mk_result(trait_pred_and_imm_ref); + let mut_ref_self_ty_satisfies_pred = mk_result(trait_pred_and_mut_ref); + + let (ref_inner_ty_satisfies_pred, ref_inner_ty_mut) = + if let ObligationCauseCode::ItemObligation(_) = obligation.cause.code() + && let ty::Ref(_, ty, mutability) = old_pred.self_ty().skip_binder().kind() + { + ( + mk_result(old_pred.map_bound(|trait_pred| (trait_pred, *ty))), + matches!(mutability, hir::Mutability::Mut), + ) + } else { + (false, false) + }; - if imm_result || mut_result { + if imm_ref_self_ty_satisfies_pred + || mut_ref_self_ty_satisfies_pred + || ref_inner_ty_satisfies_pred + { if let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(span) { // We have a very specific type of error, where just borrowing this argument // might solve the problem. In cases like this, the important part is the @@ -973,7 +990,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { // } // ``` - if imm_result && mut_result { + if imm_ref_self_ty_satisfies_pred && mut_ref_self_ty_satisfies_pred { err.span_suggestions( span.shrink_to_lo(), "consider borrowing here", @@ -981,13 +998,14 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { Applicability::MaybeIncorrect, ); } else { + let is_mut = mut_ref_self_ty_satisfies_pred || ref_inner_ty_mut; err.span_suggestion_verbose( span.shrink_to_lo(), &format!( "consider{} borrowing here", - if mut_result { " mutably" } else { "" } + if is_mut { " mutably" } else { "" } ), - format!("&{}", if mut_result { "mut " } else { "" }), + format!("&{}", if is_mut { "mut " } else { "" }), Applicability::MaybeIncorrect, ); } @@ -1001,7 +1019,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { if let ObligationCauseCode::ImplDerivedObligation(cause) = &*code { try_borrowing(cause.derived.parent_trait_pred, &[]) } else if let ObligationCauseCode::BindingObligation(_, _) - | ObligationCauseCode::ItemObligation(_) = code + | ObligationCauseCode::ItemObligation(..) = code { try_borrowing(poly_trait_pred, &never_suggest_borrow) } else { diff --git a/src/test/ui/suggestions/suggest-adding-reference-to-trait-assoc-item.fixed b/src/test/ui/suggestions/suggest-adding-reference-to-trait-assoc-item.fixed new file mode 100644 index 0000000000000..e9b8a9caa484a --- /dev/null +++ b/src/test/ui/suggestions/suggest-adding-reference-to-trait-assoc-item.fixed @@ -0,0 +1,15 @@ +// run-rustfix +#![allow(unused_variables)] + +fn foo(foo: &mut usize) { + todo!() +} + +fn bar(bar: &usize) { + todo!() +} + +fn main() { + foo(&mut Default::default()); //~ the trait bound `&mut usize: Default` is not satisfied + bar(&Default::default()); //~ the trait bound `&usize: Default` is not satisfied +} diff --git a/src/test/ui/suggestions/suggest-adding-reference-to-trait-assoc-item.rs b/src/test/ui/suggestions/suggest-adding-reference-to-trait-assoc-item.rs new file mode 100644 index 0000000000000..5fae21cccef23 --- /dev/null +++ b/src/test/ui/suggestions/suggest-adding-reference-to-trait-assoc-item.rs @@ -0,0 +1,15 @@ +// run-rustfix +#![allow(unused_variables)] + +fn foo(foo: &mut usize) { + todo!() +} + +fn bar(bar: &usize) { + todo!() +} + +fn main() { + foo(Default::default()); //~ the trait bound `&mut usize: Default` is not satisfied + bar(Default::default()); //~ the trait bound `&usize: Default` is not satisfied +} diff --git a/src/test/ui/suggestions/suggest-adding-reference-to-trait-assoc-item.stderr b/src/test/ui/suggestions/suggest-adding-reference-to-trait-assoc-item.stderr new file mode 100644 index 0000000000000..b930d22a3915e --- /dev/null +++ b/src/test/ui/suggestions/suggest-adding-reference-to-trait-assoc-item.stderr @@ -0,0 +1,25 @@ +error[E0277]: the trait bound `&mut usize: Default` is not satisfied + --> $DIR/suggest-adding-reference-to-trait-assoc-item.rs:13:9 + | +LL | foo(Default::default()); + | ^^^^^^^^^^^^^^^^ expected an implementor of trait `Default` + | +help: consider mutably borrowing here + | +LL | foo(&mut Default::default()); + | ++++ + +error[E0277]: the trait bound `&usize: Default` is not satisfied + --> $DIR/suggest-adding-reference-to-trait-assoc-item.rs:14:9 + | +LL | bar(Default::default()); + | ^^^^^^^^^^^^^^^^ expected an implementor of trait `Default` + | +help: consider borrowing here + | +LL | bar(&Default::default()); + | + + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0277`.