mirror of
https://github.com/rust-lang/rust
synced 2024-10-14 20:46:49 +00:00
Detect method not found on arbitrary self type with different mutability
``` error[E0599]: no method named `x` found for struct `Pin<&S>` in the current scope --> $DIR/arbitrary_self_type_mut_difference.rs:11:18 | LL | Pin::new(&S).x(); | ^ help: there is a method with a similar name: `y` | note: method is available for `Pin<&mut S>` --> $DIR/arbitrary_self_type_mut_difference.rs:6:5 | LL | fn x(self: Pin<&mut Self>) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^ ``` Related to #57994, as one of the presented cases can lead to code like this.
This commit is contained in:
parent
c435af0d5c
commit
6d11b2f2af
|
@ -1293,7 +1293,7 @@ fn check_method_call(
|
|||
segment.ident,
|
||||
SelfSource::MethodCall(rcvr),
|
||||
error,
|
||||
Some((rcvr, args)),
|
||||
Some((rcvr, args, expr)),
|
||||
expected,
|
||||
false,
|
||||
) {
|
||||
|
|
|
@ -115,7 +115,7 @@ pub fn report_method_error(
|
|||
item_name: Ident,
|
||||
source: SelfSource<'tcx>,
|
||||
error: MethodError<'tcx>,
|
||||
args: Option<(&'tcx hir::Expr<'tcx>, &'tcx [hir::Expr<'tcx>])>,
|
||||
args: Option<(&'tcx hir::Expr<'tcx>, &'tcx [hir::Expr<'tcx>], &'tcx hir::Expr<'tcx>)>,
|
||||
expected: Expectation<'tcx>,
|
||||
trait_missing_method: bool,
|
||||
) -> Option<DiagnosticBuilder<'_, ErrorGuaranteed>> {
|
||||
|
@ -257,7 +257,7 @@ pub fn report_method_error(
|
|||
fn suggest_missing_writer(
|
||||
&self,
|
||||
rcvr_ty: Ty<'tcx>,
|
||||
args: (&'tcx hir::Expr<'tcx>, &'tcx [hir::Expr<'tcx>]),
|
||||
args: (&'tcx hir::Expr<'tcx>, &'tcx [hir::Expr<'tcx>], &'tcx hir::Expr<'tcx>),
|
||||
) -> DiagnosticBuilder<'_, ErrorGuaranteed> {
|
||||
let (ty_str, _ty_file) = self.tcx.short_ty_string(rcvr_ty);
|
||||
let mut err =
|
||||
|
@ -282,7 +282,7 @@ pub fn report_no_match_method_error(
|
|||
rcvr_ty: Ty<'tcx>,
|
||||
item_name: Ident,
|
||||
source: SelfSource<'tcx>,
|
||||
args: Option<(&'tcx hir::Expr<'tcx>, &'tcx [hir::Expr<'tcx>])>,
|
||||
args: Option<(&'tcx hir::Expr<'tcx>, &'tcx [hir::Expr<'tcx>], &'tcx hir::Expr<'tcx>)>,
|
||||
sugg_span: Span,
|
||||
no_match_data: &mut NoMatchData<'tcx>,
|
||||
expected: Expectation<'tcx>,
|
||||
|
@ -953,6 +953,33 @@ trait bound{s}",
|
|||
|
||||
unsatisfied_bounds = true;
|
||||
}
|
||||
} else if let ty::Adt(def, targs) = rcvr_ty.kind() && let Some((rcvr, _, expr)) = args {
|
||||
// This is useful for methods on arbitrary self types that might have a simple
|
||||
// mutability difference, like calling a method on `Pin<&mut Self>` that is on
|
||||
// `Pin<&Self>`.
|
||||
if targs.len() == 1 {
|
||||
let mut item_segment = hir::PathSegment::invalid();
|
||||
item_segment.ident = item_name;
|
||||
for t in [Ty::new_mut_ref, Ty::new_imm_ref, |_, _, t| t] {
|
||||
let new_args = tcx.mk_args_from_iter(
|
||||
targs
|
||||
.iter()
|
||||
.map(|arg| match arg.as_type() {
|
||||
Some(ty) => ty::GenericArg::from(
|
||||
t(tcx, tcx.lifetimes.re_erased, ty.peel_refs()),
|
||||
),
|
||||
_ => arg,
|
||||
})
|
||||
);
|
||||
let rcvr_ty = Ty::new_adt(tcx, *def, new_args);
|
||||
if let Ok(method) = self.lookup_method_for_diagnostic(rcvr_ty, &item_segment, span, expr, rcvr) {
|
||||
err.span_note(
|
||||
tcx.def_span(method.def_id),
|
||||
format!("{item_kind} is available for `{rcvr_ty}`"),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let label_span_not_found = |err: &mut Diagnostic| {
|
||||
|
@ -1111,7 +1138,7 @@ trait bound{s}",
|
|||
span,
|
||||
rcvr_ty,
|
||||
item_name,
|
||||
args.map(|(_, args)| args.len() + 1),
|
||||
args.map(|(_, args, _)| args.len() + 1),
|
||||
source,
|
||||
no_match_data.out_of_scope_traits.clone(),
|
||||
&unsatisfied_predicates,
|
||||
|
@ -1192,7 +1219,7 @@ fn note_candidates_on_method_error(
|
|||
&self,
|
||||
rcvr_ty: Ty<'tcx>,
|
||||
item_name: Ident,
|
||||
args: Option<(&'tcx hir::Expr<'tcx>, &'tcx [hir::Expr<'tcx>])>,
|
||||
args: Option<(&'tcx hir::Expr<'tcx>, &'tcx [hir::Expr<'tcx>], &'tcx hir::Expr<'tcx>)>,
|
||||
span: Span,
|
||||
err: &mut Diagnostic,
|
||||
sources: &mut Vec<CandidateSource>,
|
||||
|
@ -1343,7 +1370,7 @@ fn suggest_associated_call_syntax(
|
|||
rcvr_ty: Ty<'tcx>,
|
||||
source: SelfSource<'tcx>,
|
||||
item_name: Ident,
|
||||
args: Option<(&hir::Expr<'tcx>, &[hir::Expr<'tcx>])>,
|
||||
args: Option<(&hir::Expr<'tcx>, &[hir::Expr<'tcx>], &'tcx hir::Expr<'tcx>)>,
|
||||
sugg_span: Span,
|
||||
) {
|
||||
let mut has_unsuggestable_args = false;
|
||||
|
@ -1415,7 +1442,7 @@ fn suggest_associated_call_syntax(
|
|||
None
|
||||
};
|
||||
let mut applicability = Applicability::MachineApplicable;
|
||||
let args = if let Some((receiver, args)) = args {
|
||||
let args = if let Some((receiver, args, _)) = args {
|
||||
// The first arg is the same kind as the receiver
|
||||
let explicit_args = if first_arg.is_some() {
|
||||
std::iter::once(receiver).chain(args.iter()).collect::<Vec<_>>()
|
||||
|
@ -2995,7 +3022,7 @@ pub fn all_traits(tcx: TyCtxt<'_>) -> Vec<TraitInfo> {
|
|||
|
||||
fn print_disambiguation_help<'tcx>(
|
||||
item_name: Ident,
|
||||
args: Option<(&'tcx hir::Expr<'tcx>, &'tcx [hir::Expr<'tcx>])>,
|
||||
args: Option<(&'tcx hir::Expr<'tcx>, &'tcx [hir::Expr<'tcx>], &'tcx hir::Expr<'tcx>)>,
|
||||
err: &mut Diagnostic,
|
||||
trait_name: String,
|
||||
rcvr_ty: Ty<'_>,
|
||||
|
@ -3007,7 +3034,7 @@ fn print_disambiguation_help<'tcx>(
|
|||
fn_has_self_parameter: bool,
|
||||
) {
|
||||
let mut applicability = Applicability::MachineApplicable;
|
||||
let (span, sugg) = if let (ty::AssocKind::Fn, Some((receiver, args))) = (kind, args) {
|
||||
let (span, sugg) = if let (ty::AssocKind::Fn, Some((receiver, args, _))) = (kind, args) {
|
||||
let args = format!(
|
||||
"({}{})",
|
||||
rcvr_ty.ref_mutability().map_or("", |mutbl| mutbl.ref_prefix_str()),
|
||||
|
|
13
tests/ui/self/arbitrary_self_type_mut_difference.rs
Normal file
13
tests/ui/self/arbitrary_self_type_mut_difference.rs
Normal file
|
@ -0,0 +1,13 @@
|
|||
// Related to #57994.
|
||||
use std::pin::Pin;
|
||||
struct S;
|
||||
|
||||
impl S {
|
||||
fn x(self: Pin<&mut Self>) {} //~ NOTE method is available for `Pin<&mut S>`
|
||||
fn y(self: Pin<&Self>) {} //~ NOTE method is available for `Pin<&S>`
|
||||
}
|
||||
|
||||
fn main() {
|
||||
Pin::new(&S).x(); //~ ERROR no method named `x` found for struct `Pin<&S>` in the current scope
|
||||
Pin::new(&mut S).y(); //~ ERROR no method named `y` found for struct `Pin<&mut S>` in the current scope
|
||||
}
|
27
tests/ui/self/arbitrary_self_type_mut_difference.stderr
Normal file
27
tests/ui/self/arbitrary_self_type_mut_difference.stderr
Normal file
|
@ -0,0 +1,27 @@
|
|||
error[E0599]: no method named `x` found for struct `Pin<&S>` in the current scope
|
||||
--> $DIR/arbitrary_self_type_mut_difference.rs:11:18
|
||||
|
|
||||
LL | Pin::new(&S).x();
|
||||
| ^ help: there is a method with a similar name: `y`
|
||||
|
|
||||
note: method is available for `Pin<&mut S>`
|
||||
--> $DIR/arbitrary_self_type_mut_difference.rs:6:5
|
||||
|
|
||||
LL | fn x(self: Pin<&mut Self>) {}
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error[E0599]: no method named `y` found for struct `Pin<&mut S>` in the current scope
|
||||
--> $DIR/arbitrary_self_type_mut_difference.rs:12:22
|
||||
|
|
||||
LL | Pin::new(&mut S).y();
|
||||
| ^ help: there is a method with a similar name: `x`
|
||||
|
|
||||
note: method is available for `Pin<&S>`
|
||||
--> $DIR/arbitrary_self_type_mut_difference.rs:7:5
|
||||
|
|
||||
LL | fn y(self: Pin<&Self>) {}
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0599`.
|
Loading…
Reference in a new issue