diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs index 364152475e94d..fdb3859022125 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs @@ -3178,6 +3178,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { self.suggest_tuple_wrapping(err, root_obligation, obligation); } + self.suggest_shadowed_inherent_method(err, obligation, trait_predicate); } fn add_help_message_for_fn_trait( diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs index 14aff65d4b518..ee2f8d9783cfe 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs @@ -4916,6 +4916,79 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { } } + pub(super) fn suggest_shadowed_inherent_method( + &self, + err: &mut Diag<'_>, + obligation: &PredicateObligation<'tcx>, + trait_predicate: ty::PolyTraitPredicate<'tcx>, + ) { + let ObligationCauseCode::FunctionArg { call_hir_id, .. } = obligation.cause.code() else { + return; + }; + let Node::Expr(call) = self.tcx.hir_node(*call_hir_id) else { return }; + let hir::ExprKind::MethodCall(segment, rcvr, args, ..) = call.kind else { return }; + let Some(typeck) = &self.typeck_results else { return }; + let Some(rcvr_ty) = typeck.expr_ty_adjusted_opt(rcvr) else { return }; + let rcvr_ty = self.resolve_vars_if_possible(rcvr_ty); + let autoderef = (self.autoderef_steps)(rcvr_ty); + for (ty, def_id) in autoderef.iter().filter_map(|(ty, obligations)| { + if let ty::Adt(def, _) = ty.kind() + && *ty != rcvr_ty.peel_refs() + && obligations.iter().all(|obligation| self.predicate_may_hold(obligation)) + { + Some((ty, def.did())) + } else { + None + } + }) { + for impl_def_id in self.tcx.inherent_impls(def_id) { + if *impl_def_id == trait_predicate.def_id() { + continue; + } + for m in self + .tcx + .provided_trait_methods(*impl_def_id) + .filter(|m| m.name() == segment.ident.name) + { + let fn_sig = self.tcx.fn_sig(m.def_id); + if fn_sig.skip_binder().inputs().skip_binder().len() != args.len() + 1 { + continue; + } + let rcvr_ty = fn_sig.skip_binder().input(0).skip_binder(); + let (mutability, _ty) = match rcvr_ty.kind() { + ty::Ref(_, ty, hir::Mutability::Mut) => ("&mut ", ty), + ty::Ref(_, ty, _) => ("&", ty), + _ => ("", &rcvr_ty), + }; + let path = self.tcx.def_path_str(def_id); + err.note(format!( + "there's an inherent method on `{ty}` of the same name, which can be \ + auto-dereferenced from `{rcvr_ty}`" + )); + err.multipart_suggestion( + format!( + "to access the inherent method on `{ty}`, use the fully-qualified path", + ), + vec![ + ( + call.span.until(rcvr.span), + format!("{path}::{}({}", m.name(), mutability), + ), + match &args { + [] => ( + rcvr.span.shrink_to_hi().with_hi(call.span.hi()), + ")".to_string(), + ), + [first, ..] => (rcvr.span.between(first.span), ", ".to_string()), + }, + ], + Applicability::MaybeIncorrect, + ); + } + } + } + } + pub(super) fn explain_hrtb_projection( &self, diag: &mut Diag<'_>, diff --git a/tests/ui-fulldeps/session-diagnostic/diagnostic-derive-doc-comment-field.stderr b/tests/ui-fulldeps/session-diagnostic/diagnostic-derive-doc-comment-field.stderr index 9149baaa40871..48a338db297e5 100644 --- a/tests/ui-fulldeps/session-diagnostic/diagnostic-derive-doc-comment-field.stderr +++ b/tests/ui-fulldeps/session-diagnostic/diagnostic-derive-doc-comment-field.stderr @@ -13,6 +13,7 @@ help: the nightly-only, unstable trait `IntoDiagArg` is not implemented for `Not LL | struct NotIntoDiagArg; | ^^^^^^^^^^^^^^^^^^^^^ = help: normalized in stderr + = note: there's an inherent method on `DiagInner` of the same name, which can be auto-dereferenced from `&mut DiagInner` note: required by a bound in `Diag::<'a, G>::arg` --> $COMPILER_DIR/rustc_errors/src/diagnostic.rs:LL:CC ::: $COMPILER_DIR/rustc_errors/src/diagnostic.rs:LL:CC diff --git a/tests/ui-fulldeps/session-diagnostic/diagnostic-derive-inline.stderr b/tests/ui-fulldeps/session-diagnostic/diagnostic-derive-inline.stderr index 48138fc9fb55a..28800016cea9b 100644 --- a/tests/ui-fulldeps/session-diagnostic/diagnostic-derive-inline.stderr +++ b/tests/ui-fulldeps/session-diagnostic/diagnostic-derive-inline.stderr @@ -589,6 +589,7 @@ help: the nightly-only, unstable trait `IntoDiagArg` is not implemented for `Hel LL | struct Hello {} | ^^^^^^^^^^^^ = help: normalized in stderr + = note: there's an inherent method on `DiagInner` of the same name, which can be auto-dereferenced from `&mut DiagInner` note: required by a bound in `Diag::<'a, G>::arg` --> $COMPILER_DIR/rustc_errors/src/diagnostic.rs:LL:CC ::: $COMPILER_DIR/rustc_errors/src/diagnostic.rs:LL:CC diff --git a/tests/ui/methods/shadowed-intrinsic-method-deref.fixed b/tests/ui/methods/shadowed-intrinsic-method-deref.fixed new file mode 100644 index 0000000000000..927c168af5682 --- /dev/null +++ b/tests/ui/methods/shadowed-intrinsic-method-deref.fixed @@ -0,0 +1,21 @@ +//@ run-rustfix +#![allow(unused_imports)] +use std::rc::Rc; +use std::cell::RefCell; +use std::borrow::Borrow; // Without this import, the code would compile. + +pub struct S { + flag: bool, +} + +type SCell = Rc>; + +fn main() { + // Type annotations just for clarity + let s : SCell = Rc::new(RefCell::new(S {flag: false})); + let sb : &S = &RefCell::borrow(&s); + //~^ ERROR: the trait bound `Rc>: Borrow` is not satisfied [E0277] + //~| NOTE: the trait `Borrow` is not implemented for `Rc>` + //~| NOTE: there's an inherent method on `RefCell` of the same name + println!("{:?}", sb.flag); +} diff --git a/tests/ui/methods/shadowed-intrinsic-method-deref.rs b/tests/ui/methods/shadowed-intrinsic-method-deref.rs new file mode 100644 index 0000000000000..1e8ddb152d87f --- /dev/null +++ b/tests/ui/methods/shadowed-intrinsic-method-deref.rs @@ -0,0 +1,21 @@ +//@ run-rustfix +#![allow(unused_imports)] +use std::rc::Rc; +use std::cell::RefCell; +use std::borrow::Borrow; // Without this import, the code would compile. + +pub struct S { + flag: bool, +} + +type SCell = Rc>; + +fn main() { + // Type annotations just for clarity + let s : SCell = Rc::new(RefCell::new(S {flag: false})); + let sb : &S = &s.borrow(); + //~^ ERROR: the trait bound `Rc>: Borrow` is not satisfied [E0277] + //~| NOTE: the trait `Borrow` is not implemented for `Rc>` + //~| NOTE: there's an inherent method on `RefCell` of the same name + println!("{:?}", sb.flag); +} diff --git a/tests/ui/methods/shadowed-intrinsic-method-deref.stderr b/tests/ui/methods/shadowed-intrinsic-method-deref.stderr new file mode 100644 index 0000000000000..4e0c5dfc55f09 --- /dev/null +++ b/tests/ui/methods/shadowed-intrinsic-method-deref.stderr @@ -0,0 +1,20 @@ +error[E0277]: the trait bound `Rc>: Borrow` is not satisfied + --> $DIR/shadowed-intrinsic-method-deref.rs:16:22 + | +LL | let sb : &S = &s.borrow(); + | ^^^^^^ the trait `Borrow` is not implemented for `Rc>` + | +help: the trait `Borrow` is not implemented for `Rc>` + but trait `Borrow>` is implemented for it + --> $SRC_DIR/alloc/src/rc.rs:LL:COL + = help: for that trait implementation, expected `RefCell`, found `S` + = note: there's an inherent method on `RefCell` of the same name, which can be auto-dereferenced from `&RefCell` +help: to access the inherent method on `RefCell`, use the fully-qualified path + | +LL - let sb : &S = &s.borrow(); +LL + let sb : &S = &RefCell::borrow(&s); + | + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0277`.