Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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<'_>,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
21 changes: 21 additions & 0 deletions tests/ui/methods/shadowed-intrinsic-method-deref.fixed
Original file line number Diff line number Diff line change
@@ -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<RefCell<S>>;

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<RefCell<S>>: Borrow<S>` is not satisfied [E0277]
//~| NOTE: the trait `Borrow<S>` is not implemented for `Rc<RefCell<S>>`
//~| NOTE: there's an inherent method on `RefCell<S>` of the same name
println!("{:?}", sb.flag);
}
21 changes: 21 additions & 0 deletions tests/ui/methods/shadowed-intrinsic-method-deref.rs
Original file line number Diff line number Diff line change
@@ -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<RefCell<S>>;

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<RefCell<S>>: Borrow<S>` is not satisfied [E0277]
//~| NOTE: the trait `Borrow<S>` is not implemented for `Rc<RefCell<S>>`
//~| NOTE: there's an inherent method on `RefCell<S>` of the same name
println!("{:?}", sb.flag);
}
20 changes: 20 additions & 0 deletions tests/ui/methods/shadowed-intrinsic-method-deref.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
error[E0277]: the trait bound `Rc<RefCell<S>>: Borrow<S>` is not satisfied
--> $DIR/shadowed-intrinsic-method-deref.rs:16:22
|
LL | let sb : &S = &s.borrow();
| ^^^^^^ the trait `Borrow<S>` is not implemented for `Rc<RefCell<S>>`
|
help: the trait `Borrow<S>` is not implemented for `Rc<RefCell<S>>`
but trait `Borrow<RefCell<S>>` is implemented for it
--> $SRC_DIR/alloc/src/rc.rs:LL:COL
= help: for that trait implementation, expected `RefCell<S>`, found `S`
= note: there's an inherent method on `RefCell<S>` of the same name, which can be auto-dereferenced from `&RefCell<T>`
help: to access the inherent method on `RefCell<S>`, 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`.
Loading