mirror of
https://github.com/rust-lang/rust.git
synced 2026-04-26 13:01:27 +03:00
Detect inherent method behind deref being shadowed by trait method
```
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);
|
```
In the example above, method `borrow` is available both on `<RefCell<S> as Borrow<S>>` *and* on `RefCell<S>`. Adding the import `use std::borrow::Borrow;` causes `s.borrow()` to find the former instead of the latter. We now point out that the other exists, and provide a suggestion on how to call it.
This commit is contained in:
@@ -3178,6 +3178,7 @@ fn try_to_add_help_message(
|
||||
|
||||
self.suggest_tuple_wrapping(err, root_obligation, obligation);
|
||||
}
|
||||
self.suggest_shadowed_inherent_method(err, obligation, trait_predicate);
|
||||
}
|
||||
|
||||
fn add_help_message_for_fn_trait(
|
||||
|
||||
@@ -4916,6 +4916,79 @@ pub(super) fn suggest_tuple_wrapping(
|
||||
}
|
||||
}
|
||||
|
||||
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<'_>,
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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`.
|
||||
Reference in New Issue
Block a user