Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 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
2 changes: 1 addition & 1 deletion compiler/rustc_hir_typeck/src/expr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1293,7 +1293,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
segment.ident,
SelfSource::MethodCall(rcvr),
error,
Some((rcvr, args)),
Some((rcvr, args, expr)),
expected,
false,
) {
Expand Down
45 changes: 36 additions & 9 deletions compiler/rustc_hir_typeck/src/method/suggest.rs
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
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>> {
Expand Down Expand Up @@ -257,7 +257,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
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 =
Expand All @@ -282,7 +282,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
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>,
Expand Down Expand Up @@ -953,6 +953,33 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {

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| {
Expand Down Expand Up @@ -1111,7 +1138,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
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,
Expand Down Expand Up @@ -1192,7 +1219,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
&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>,
Expand Down Expand Up @@ -1343,7 +1370,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
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;
Expand Down Expand Up @@ -1415,7 +1442,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
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<_>>()
Expand Down Expand Up @@ -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<'_>,
Expand All @@ -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()),
Expand Down
13 changes: 13 additions & 0 deletions tests/ui/self/arbitrary_self_type_mut_difference.rs
Original file line number Diff line number Diff line change
@@ -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 changes: 27 additions & 0 deletions tests/ui/self/arbitrary_self_type_mut_difference.stderr
Original file line number Diff line number Diff line change
@@ -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`.
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
// run-rustfix
#![allow(dead_code)]
mod first {
trait Foo { fn m(self: Box<Self>); }
fn foo<T: Foo>(a: T) {
Box::new(a).m(); //~ ERROR no method named `m` found
}
}
mod second {
use std::sync::Arc;
trait Bar { fn m(self: Arc<Self>); }
fn bar(b: impl Bar) {
Arc::new(b).m(); //~ ERROR no method named `m` found
}
}

fn main() {}
17 changes: 17 additions & 0 deletions tests/ui/self/arbitrary_self_types_needing_box_or_arc_wrapping.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
// run-rustfix
#![allow(dead_code)]
mod first {
trait Foo { fn m(self: Box<Self>); }
fn foo<T: Foo>(a: T) {
a.m(); //~ ERROR no method named `m` found
}
}
mod second {
use std::sync::Arc;
trait Bar { fn m(self: Arc<Self>); }
fn bar(b: impl Bar) {
b.m(); //~ ERROR no method named `m` found
}
}

fn main() {}
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
error[E0599]: no method named `m` found for type parameter `T` in the current scope
--> $DIR/arbitrary_self_types_needing_box_or_arc_wrapping.rs:6:11
|
LL | trait Foo { fn m(self: Box<Self>); }
| - --------- the method might not be found because of this arbitrary self type
| |
| the method is available for `Box<T>` here
LL | fn foo<T: Foo>(a: T) {
| - method `m` not found for this type parameter
LL | a.m();
| ^ method not found in `T`
...
LL | trait Bar { fn m(self: Arc<Self>); }
| --------- the method might not be found because of this arbitrary self type
|
help: consider wrapping the receiver expression with the appropriate type
|
LL | Box::new(a).m();
| +++++++++ +

error[E0599]: no method named `m` found for type parameter `impl Bar` in the current scope
--> $DIR/arbitrary_self_types_needing_box_or_arc_wrapping.rs:13:11
|
LL | trait Foo { fn m(self: Box<Self>); }
| --------- the method might not be found because of this arbitrary self type
...
LL | trait Bar { fn m(self: Arc<Self>); }
| - --------- the method might not be found because of this arbitrary self type
| |
| the method is available for `Arc<impl Bar>` here
LL | fn bar(b: impl Bar) {
| -------- method `m` not found for this type parameter
LL | b.m();
| ^ method not found in `impl Bar`
|
help: consider wrapping the receiver expression with the appropriate type
|
LL | Arc::new(b).m();
| +++++++++ +

error: aborting due to 2 previous errors

For more information about this error, try `rustc --explain E0599`.
12 changes: 12 additions & 0 deletions tests/ui/self/arbitrary_self_types_needing_mut_pin.fixed
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
// run-rustfix
use std::pin::Pin;
struct S;

impl S {
fn x(self: Pin<&mut Self>) {
}
}

fn main() {
Pin::new(&mut S).x(); //~ ERROR no method named `x` found
}
12 changes: 12 additions & 0 deletions tests/ui/self/arbitrary_self_types_needing_mut_pin.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
// run-rustfix
use std::pin::Pin;
struct S;

impl S {
fn x(self: Pin<&mut Self>) {
}
}

fn main() {
S.x(); //~ ERROR no method named `x` found
}
20 changes: 20 additions & 0 deletions tests/ui/self/arbitrary_self_types_needing_mut_pin.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
error[E0599]: no method named `x` found for struct `S` in the current scope
--> $DIR/arbitrary_self_types_needing_mut_pin.rs:11:7
|
LL | struct S;
| -------- method `x` not found for this struct
...
LL | fn x(self: Pin<&mut Self>) {
| - the method is available for `Pin<&mut S>` here
...
LL | S.x();
| ^ method not found in `S`
|
help: consider wrapping the receiver expression with the appropriate type
|
LL | Pin::new(&mut S).x();
| +++++++++++++ +

error: aborting due to previous error

For more information about this error, try `rustc --explain E0599`.
13 changes: 13 additions & 0 deletions tests/ui/self/arbitrary_self_types_pin_needing_borrow.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
use std::pin::Pin;
struct S;

impl S {
fn x(self: Pin<&mut Self>) {
}
}

fn main() {
Pin::new(S).x();
//~^ ERROR the trait bound `S: Deref` is not satisfied
//~| ERROR no method named `x` found for struct `Pin` in the current scope
}
33 changes: 33 additions & 0 deletions tests/ui/self/arbitrary_self_types_pin_needing_borrow.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
error[E0277]: the trait bound `S: Deref` is not satisfied
--> $DIR/arbitrary_self_types_pin_needing_borrow.rs:10:14
|
LL | Pin::new(S).x();
| -------- ^ the trait `Deref` is not implemented for `S`
| |
| required by a bound introduced by this call
|
note: required by a bound in `Pin::<P>::new`
--> $SRC_DIR/core/src/pin.rs:LL:COL
help: consider borrowing here
|
LL | Pin::new(&S).x();
| +
LL | Pin::new(&mut S).x();
| ++++

error[E0599]: no method named `x` found for struct `Pin` in the current scope
--> $DIR/arbitrary_self_types_pin_needing_borrow.rs:10:17
|
LL | Pin::new(S).x();
| ^ method not found in `Pin<S>`
|
note: method is available for `Pin<&mut S>`
--> $DIR/arbitrary_self_types_pin_needing_borrow.rs:5:5
|
LL | fn x(self: Pin<&mut Self>) {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^

error: aborting due to 2 previous errors

Some errors have detailed explanations: E0277, E0599.
For more information about an error, try `rustc --explain E0277`.