Skip to content

Commit 6f2d8a0

Browse files
committed
Suggest box/pin/arc ing receiver on method calls
1 parent 2917eda commit 6f2d8a0

17 files changed

+113
-97
lines changed

compiler/rustc_typeck/src/check/expr.rs

+29-6
Original file line numberDiff line numberDiff line change
@@ -973,7 +973,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
973973
error: MethodError<'tcx>,
974974
) {
975975
let rcvr = &args[0];
976-
let try_alt_rcvr = |err: &mut DiagnosticBuilder<'_>, new_rcvr_t| {
976+
let try_alt_rcvr = |err: &mut DiagnosticBuilder<'_>, new_rcvr_t, pre: &str, post: &str| {
977977
if let Some(new_rcvr_t) = new_rcvr_t {
978978
if let Ok(pick) = self.lookup_probe(
979979
span,
@@ -986,11 +986,24 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
986986
// Make sure the method is defined for the *actual* receiver:
987987
// we don't want to treat `Box<Self>` as a receiver if
988988
// it only works because of an autoderef to `&self`
989-
if pick.autoderefs == 0 {
989+
if pick.autoderefs == 0
990+
// We don't want to suggest a container type when the missing method is
991+
// `.clone()`, otherwise we'd suggest `Arc::new(foo).clone()`, which is
992+
// far from what the user really wants.
993+
&& Some(pick.item.container.id()) != self.tcx.lang_items().clone_trait()
994+
{
990995
err.span_label(
991996
pick.item.ident.span,
992997
&format!("the method is available for `{}` here", new_rcvr_t),
993998
);
999+
err.multipart_suggestion(
1000+
"consider wrapping the receiver expression with the appropriate type",
1001+
vec![
1002+
(rcvr.span.shrink_to_lo(), format!("{}({}", pre, post)),
1003+
(rcvr.span.shrink_to_hi(), ")".to_string()),
1004+
],
1005+
Applicability::MaybeIncorrect,
1006+
);
9941007
}
9951008
}
9961009
}
@@ -1008,10 +1021,20 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
10081021
// Try alternative arbitrary self types that could fulfill this call.
10091022
// FIXME: probe for all types that *could* be arbitrary self-types, not
10101023
// just this list.
1011-
try_alt_rcvr(&mut err, self.tcx.mk_lang_item(rcvr_t, LangItem::OwnedBox));
1012-
try_alt_rcvr(&mut err, self.tcx.mk_lang_item(rcvr_t, LangItem::Pin));
1013-
try_alt_rcvr(&mut err, self.tcx.mk_diagnostic_item(rcvr_t, sym::Arc));
1014-
try_alt_rcvr(&mut err, self.tcx.mk_diagnostic_item(rcvr_t, sym::Rc));
1024+
for (rcvr_t, post) in &[
1025+
(rcvr_t, ""),
1026+
(self.tcx.mk_mut_ref(&ty::ReErased, rcvr_t), "&mut "),
1027+
(self.tcx.mk_imm_ref(&ty::ReErased, rcvr_t), "&"),
1028+
] {
1029+
for (rcvr_t, pre) in &[
1030+
(self.tcx.mk_lang_item(rcvr_t, LangItem::OwnedBox), "Box::new"),
1031+
(self.tcx.mk_lang_item(rcvr_t, LangItem::Pin), "Pin::new"),
1032+
(self.tcx.mk_diagnostic_item(rcvr_t, sym::Arc), "Arc::new"),
1033+
(self.tcx.mk_diagnostic_item(rcvr_t, sym::Rc), "Rc::new"),
1034+
] {
1035+
try_alt_rcvr(&mut err, *rcvr_t, pre, post);
1036+
}
1037+
}
10151038
}
10161039
err.emit();
10171040
}

compiler/rustc_typeck/src/check/method/mod.rs

+2
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ pub struct MethodCallee<'tcx> {
4545
pub sig: ty::FnSig<'tcx>,
4646
}
4747

48+
#[derive(Debug)]
4849
pub enum MethodError<'tcx> {
4950
// Did not find an applicable method, but we did find various near-misses that may work.
5051
NoMatch(NoMatchData<'tcx>),
@@ -66,6 +67,7 @@ pub enum MethodError<'tcx> {
6667

6768
// Contains a list of static methods that may apply, a list of unsatisfied trait predicates which
6869
// could lead to matches if satisfied, and a list of not-in-scope traits which may work.
70+
#[derive(Debug)]
6971
pub struct NoMatchData<'tcx> {
7072
pub static_candidates: Vec<CandidateSource>,
7173
pub unsatisfied_predicates: Vec<(ty::Predicate<'tcx>, Option<ty::Predicate<'tcx>>)>,
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
use std::{
2+
future::Future,
3+
pin::Pin,
4+
task::{Context, Poll},
5+
};
6+
7+
struct Sleep;
8+
9+
impl Future for Sleep {
10+
type Output = ();
11+
12+
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
13+
Poll::Ready(())
14+
}
15+
}
16+
17+
impl Drop for Sleep {
18+
fn drop(&mut self) {}
19+
}
20+
21+
fn sleep() -> Sleep {
22+
Sleep
23+
}
24+
25+
26+
struct MyFuture {
27+
sleep: Sleep,
28+
}
29+
30+
impl MyFuture {
31+
fn new() -> Self {
32+
Self {
33+
sleep: sleep(),
34+
}
35+
}
36+
}
37+
38+
impl Future for MyFuture {
39+
type Output = ();
40+
41+
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
42+
self.sleep.poll(cx)
43+
//~^ ERROR no method named `poll` found for struct `Sleep` in the current scope
44+
}
45+
}
46+
47+
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
error[E0599]: no method named `poll` found for struct `Sleep` in the current scope
2+
--> $DIR/pin-needed-to-poll.rs:42:20
3+
|
4+
LL | struct Sleep;
5+
| ------------- method `poll` not found for this
6+
...
7+
LL | self.sleep.poll(cx)
8+
| ^^^^ method not found in `Sleep`
9+
|
10+
::: $SRC_DIR/core/src/future/future.rs:LL:COL
11+
|
12+
LL | fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output>;
13+
| ---- the method is available for `Pin<&mut Sleep>` here
14+
|
15+
= help: items from traits can only be used if the trait is implemented and in scope
16+
= note: the following trait defines an item `poll`, perhaps you need to implement it:
17+
candidate #1: `Future`
18+
help: consider wrapping the receiver expression with the appropriate type
19+
|
20+
LL | Pin::new(&mut self.sleep).poll(cx)
21+
| ^^^^^^^^^^^^^ ^
22+
23+
error: aborting due to previous error
24+
25+
For more information about this error, try `rustc --explain E0599`.

src/test/ui/copy-a-resource.stderr

-8
Original file line numberDiff line numberDiff line change
@@ -6,14 +6,6 @@ LL | struct Foo {
66
...
77
LL | let _y = x.clone();
88
| ^^^^^ method not found in `Foo`
9-
|
10-
::: $SRC_DIR/core/src/clone.rs:LL:COL
11-
|
12-
LL | fn clone(&self) -> Self;
13-
| -----
14-
| |
15-
| the method is available for `Arc<Foo>` here
16-
| the method is available for `Rc<Foo>` here
179
|
1810
= help: items from traits can only be used if the trait is implemented and in scope
1911
= note: the following trait defines an item `clone`, perhaps you need to implement it:

src/test/ui/derives/derive-assoc-type-not-impl.stderr

-8
Original file line numberDiff line numberDiff line change
@@ -12,14 +12,6 @@ LL | struct NotClone;
1212
...
1313
LL | Bar::<NotClone> { x: 1 }.clone();
1414
| ^^^^^ method cannot be called on `Bar<NotClone>` due to unsatisfied trait bounds
15-
|
16-
::: $SRC_DIR/core/src/clone.rs:LL:COL
17-
|
18-
LL | fn clone(&self) -> Self;
19-
| -----
20-
| |
21-
| the method is available for `Arc<Bar<NotClone>>` here
22-
| the method is available for `Rc<Bar<NotClone>>` here
2315
|
2416
= note: the following trait bounds were not satisfied:
2517
`NotClone: Clone`

src/test/ui/issues/issue-2823.stderr

-8
Original file line numberDiff line numberDiff line change
@@ -6,14 +6,6 @@ LL | struct C {
66
...
77
LL | let _d = c.clone();
88
| ^^^^^ method not found in `C`
9-
|
10-
::: $SRC_DIR/core/src/clone.rs:LL:COL
11-
|
12-
LL | fn clone(&self) -> Self;
13-
| -----
14-
| |
15-
| the method is available for `Arc<C>` here
16-
| the method is available for `Rc<C>` here
179
|
1810
= help: items from traits can only be used if the trait is implemented and in scope
1911
= note: the following trait defines an item `clone`, perhaps you need to implement it:

src/test/ui/issues/issue-69725.stderr

-8
Original file line numberDiff line numberDiff line change
@@ -8,14 +8,6 @@ LL | let _ = Struct::<A>::new().clone();
88
|
99
LL | pub struct Struct<A>(A);
1010
| ------------------------ doesn't satisfy `Struct<A>: Clone`
11-
|
12-
::: $SRC_DIR/core/src/clone.rs:LL:COL
13-
|
14-
LL | fn clone(&self) -> Self;
15-
| -----
16-
| |
17-
| the method is available for `Arc<Struct<A>>` here
18-
| the method is available for `Rc<Struct<A>>` here
1911
|
2012
= note: the following trait bounds were not satisfied:
2113
`A: Clone`

src/test/ui/non-copyable-void.stderr

-8
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,6 @@ error[E0599]: no method named `clone` found for enum `c_void` in the current sco
33
|
44
LL | let _z = (*y).clone();
55
| ^^^^^ method not found in `c_void`
6-
|
7-
::: $SRC_DIR/core/src/clone.rs:LL:COL
8-
|
9-
LL | fn clone(&self) -> Self;
10-
| -----
11-
| |
12-
| the method is available for `Arc<c_void>` here
13-
| the method is available for `Rc<c_void>` here
146

157
error: aborting due to previous error
168

src/test/ui/noncopyable-class.stderr

-8
Original file line numberDiff line numberDiff line change
@@ -6,14 +6,6 @@ LL | struct Foo {
66
...
77
LL | let _y = x.clone();
88
| ^^^^^ method not found in `Foo`
9-
|
10-
::: $SRC_DIR/core/src/clone.rs:LL:COL
11-
|
12-
LL | fn clone(&self) -> Self;
13-
| -----
14-
| |
15-
| the method is available for `Arc<Foo>` here
16-
| the method is available for `Rc<Foo>` here
179
|
1810
= help: items from traits can only be used if the trait is implemented and in scope
1911
= note: the following trait defines an item `clone`, perhaps you need to implement it:

src/test/ui/self/point-at-arbitrary-self-type-method.stderr

+5
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,11 @@ LL | fn foo(self: Box<Self>) {}
99
...
1010
LL | A.foo();
1111
| ^^^ method not found in `A`
12+
|
13+
help: consider wrapping the receiver expression with the appropriate type
14+
|
15+
LL | Box::new(A).foo();
16+
| ^^^^^^^^^ ^
1217

1318
error: aborting due to previous error
1419

src/test/ui/self/point-at-arbitrary-self-type-trait-method.stderr

+5
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,11 @@ LL | struct A;
1010
...
1111
LL | A.foo()
1212
| ^^^ method not found in `A`
13+
|
14+
help: consider wrapping the receiver expression with the appropriate type
15+
|
16+
LL | Box::new(A).foo()
17+
| ^^^^^^^^^ ^
1318

1419
error: aborting due to previous error
1520

src/test/ui/suggestions/lifetimes/missing-lifetimes-in-signature.nll.stderr

-11
This file was deleted.

src/test/ui/traits/negative-impls/explicitly-unimplemented-error-message.stderr

-8
Original file line numberDiff line numberDiff line change
@@ -6,14 +6,6 @@ LL | struct Qux;
66
...
77
LL | Qux.clone();
88
| ^^^^^ method not found in `Qux`
9-
|
10-
::: $SRC_DIR/core/src/clone.rs:LL:COL
11-
|
12-
LL | fn clone(&self) -> Self;
13-
| -----
14-
| |
15-
| the method is available for `Arc<Qux>` here
16-
| the method is available for `Rc<Qux>` here
179
|
1810
= help: items from traits can only be used if the trait is implemented and in scope
1911
= note: the trait `Clone` defines an item `clone`, but is explicitely unimplemented

src/test/ui/union/union-derive-clone.stderr

-8
Original file line numberDiff line numberDiff line change
@@ -25,14 +25,6 @@ LL | struct CloneNoCopy;
2525
...
2626
LL | let w = u.clone();
2727
| ^^^^^ method cannot be called on `U5<CloneNoCopy>` due to unsatisfied trait bounds
28-
|
29-
::: $SRC_DIR/core/src/clone.rs:LL:COL
30-
|
31-
LL | fn clone(&self) -> Self;
32-
| -----
33-
| |
34-
| the method is available for `Arc<U5<CloneNoCopy>>` here
35-
| the method is available for `Rc<U5<CloneNoCopy>>` here
3628
|
3729
= note: the following trait bounds were not satisfied:
3830
`CloneNoCopy: Copy`

src/test/ui/unique-object-noncopyable.stderr

-8
Original file line numberDiff line numberDiff line change
@@ -10,14 +10,6 @@ LL | trait Foo {
1010
LL | let _z = y.clone();
1111
| ^^^^^ method cannot be called on `Box<dyn Foo>` due to unsatisfied trait bounds
1212
|
13-
::: $SRC_DIR/core/src/clone.rs:LL:COL
14-
|
15-
LL | fn clone(&self) -> Self;
16-
| -----
17-
| |
18-
| the method is available for `Arc<Box<dyn Foo>>` here
19-
| the method is available for `Rc<Box<dyn Foo>>` here
20-
|
2113
::: $SRC_DIR/alloc/src/boxed.rs:LL:COL
2214
|
2315
LL | / pub struct Box<

src/test/ui/unique-pinned-nocopy.stderr

-8
Original file line numberDiff line numberDiff line change
@@ -7,14 +7,6 @@ LL | struct R {
77
LL | let _j = i.clone();
88
| ^^^^^ method cannot be called on `Box<R>` due to unsatisfied trait bounds
99
|
10-
::: $SRC_DIR/core/src/clone.rs:LL:COL
11-
|
12-
LL | fn clone(&self) -> Self;
13-
| -----
14-
| |
15-
| the method is available for `Arc<Box<R>>` here
16-
| the method is available for `Rc<Box<R>>` here
17-
|
1810
::: $SRC_DIR/alloc/src/boxed.rs:LL:COL
1911
|
2012
LL | / pub struct Box<

0 commit comments

Comments
 (0)