Skip to content

Commit d4867d7

Browse files
authored
Unrolled build for rust-lang#114654
Rollup merge of rust-lang#114654 - estebank:suggest-pin-macro, r=davidtwco Suggest `pin!()` instead of `Pin::new()` when appropriate When encountering a type that needs to be pinned but that is `!Unpin`, suggest using the `pin!()` macro. Fix rust-lang#57994.
2 parents e3c631b + 6b58fbf commit d4867d7

File tree

7 files changed

+105
-22
lines changed

7 files changed

+105
-22
lines changed

compiler/rustc_hir_typeck/src/method/suggest.rs

+68-6
Original file line numberDiff line numberDiff line change
@@ -2494,10 +2494,18 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
24942494
// Try alternative arbitrary self types that could fulfill this call.
24952495
// FIXME: probe for all types that *could* be arbitrary self-types, not
24962496
// just this list.
2497-
for (rcvr_ty, post) in &[
2498-
(rcvr_ty, ""),
2499-
(Ty::new_mut_ref(self.tcx, self.tcx.lifetimes.re_erased, rcvr_ty), "&mut "),
2500-
(Ty::new_imm_ref(self.tcx, self.tcx.lifetimes.re_erased, rcvr_ty), "&"),
2497+
for (rcvr_ty, post, pin_call) in &[
2498+
(rcvr_ty, "", None),
2499+
(
2500+
Ty::new_mut_ref(self.tcx, self.tcx.lifetimes.re_erased, rcvr_ty),
2501+
"&mut ",
2502+
Some("as_mut"),
2503+
),
2504+
(
2505+
Ty::new_imm_ref(self.tcx, self.tcx.lifetimes.re_erased, rcvr_ty),
2506+
"&",
2507+
Some("as_ref"),
2508+
),
25012509
] {
25022510
match self.lookup_probe_for_diagnostic(
25032511
item_name,
@@ -2531,6 +2539,17 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
25312539
Err(_) => (),
25322540
}
25332541

2542+
let pred = ty::TraitRef::new(
2543+
self.tcx,
2544+
self.tcx.lang_items().unpin_trait().unwrap(),
2545+
[*rcvr_ty],
2546+
);
2547+
let unpin = self.predicate_must_hold_considering_regions(&Obligation::new(
2548+
self.tcx,
2549+
ObligationCause::misc(rcvr.span, self.body_id),
2550+
self.param_env,
2551+
pred,
2552+
));
25342553
for (rcvr_ty, pre) in &[
25352554
(Ty::new_lang_item(self.tcx, *rcvr_ty, LangItem::OwnedBox), "Box::new"),
25362555
(Ty::new_lang_item(self.tcx, *rcvr_ty, LangItem::Pin), "Pin::new"),
@@ -2554,7 +2573,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
25542573
// Explicitly ignore the `Pin::as_ref()` method as `Pin` does not
25552574
// implement the `AsRef` trait.
25562575
let skip = skippable.contains(&did)
2557-
|| (("Pin::new" == *pre) && (sym::as_ref == item_name.name))
2576+
|| (("Pin::new" == *pre) && ((sym::as_ref == item_name.name) || !unpin))
25582577
|| inputs_len.is_some_and(|inputs_len| pick.item.kind == ty::AssocKind::Fn && self.tcx.fn_sig(pick.item.def_id).skip_binder().skip_binder().inputs().len() != inputs_len);
25592578
// Make sure the method is defined for the *actual* receiver: we don't
25602579
// want to treat `Box<Self>` as a receiver if it only works because of
@@ -2566,7 +2585,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
25662585
);
25672586
err.multipart_suggestion(
25682587
"consider wrapping the receiver expression with the \
2569-
appropriate type",
2588+
appropriate type",
25702589
vec![
25712590
(rcvr.span.shrink_to_lo(), format!("{pre}({post}")),
25722591
(rcvr.span.shrink_to_hi(), ")".to_string()),
@@ -2578,6 +2597,49 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
25782597
}
25792598
}
25802599
}
2600+
// We special case the situation where `Pin::new` wouldn't work, and instead
2601+
// suggest using the `pin!()` macro instead.
2602+
if let Some(new_rcvr_t) = Ty::new_lang_item(self.tcx, *rcvr_ty, LangItem::Pin)
2603+
// We didn't find an alternative receiver for the method.
2604+
&& !alt_rcvr_sugg
2605+
// `T: !Unpin`
2606+
&& !unpin
2607+
// The method isn't `as_ref`, as it would provide a wrong suggestion for `Pin`.
2608+
&& sym::as_ref != item_name.name
2609+
// Either `Pin::as_ref` or `Pin::as_mut`.
2610+
&& let Some(pin_call) = pin_call
2611+
// Search for `item_name` as a method accessible on `Pin<T>`.
2612+
&& let Ok(pick) = self.lookup_probe_for_diagnostic(
2613+
item_name,
2614+
new_rcvr_t,
2615+
rcvr,
2616+
ProbeScope::AllTraits,
2617+
return_type,
2618+
)
2619+
// We skip some common traits that we don't want to consider because autoderefs
2620+
// would take care of them.
2621+
&& !skippable.contains(&Some(pick.item.container_id(self.tcx)))
2622+
// We don't want to go through derefs.
2623+
&& pick.autoderefs == 0
2624+
// Check that the method of the same name that was found on the new `Pin<T>`
2625+
// receiver has the same number of arguments that appear in the user's code.
2626+
&& inputs_len.is_some_and(|inputs_len| pick.item.kind == ty::AssocKind::Fn && self.tcx.fn_sig(pick.item.def_id).skip_binder().skip_binder().inputs().len() == inputs_len)
2627+
{
2628+
let indent = self.tcx.sess
2629+
.source_map()
2630+
.indentation_before(rcvr.span)
2631+
.unwrap_or_else(|| " ".to_string());
2632+
err.multipart_suggestion(
2633+
"consider pinning the expression",
2634+
vec![
2635+
(rcvr.span.shrink_to_lo(), format!("let mut pinned = std::pin::pin!(")),
2636+
(rcvr.span.shrink_to_hi(), format!(");\n{indent}pinned.{pin_call}()")),
2637+
],
2638+
Applicability::MaybeIncorrect,
2639+
);
2640+
// We don't care about the other suggestions.
2641+
alt_rcvr_sugg = true;
2642+
}
25812643
}
25822644
}
25832645
if self.suggest_valid_traits(err, valid_out_of_scope_traits) {
+16
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
// edition: 2021
2+
// run-rustfix
3+
#![allow(unused_must_use, dead_code)]
4+
5+
use std::future::Future;
6+
fn foo() -> impl Future<Output=()> {
7+
async { }
8+
}
9+
10+
fn bar(cx: &mut std::task::Context<'_>) {
11+
let fut = foo();
12+
let mut pinned = std::pin::pin!(fut);
13+
pinned.as_mut().poll(cx);
14+
//~^ ERROR no method named `poll` found for opaque type `impl Future<Output = ()>` in the current scope [E0599]
15+
}
16+
fn main() {}

tests/ui/async-await/issue-108572.rs

+5-2
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,15 @@
11
// edition: 2021
2+
// run-rustfix
3+
#![allow(unused_must_use, dead_code)]
24

35
use std::future::Future;
46
fn foo() -> impl Future<Output=()> {
57
async { }
68
}
79

8-
fn main() {
10+
fn bar(cx: &mut std::task::Context<'_>) {
911
let fut = foo();
10-
fut.poll();
12+
fut.poll(cx);
1113
//~^ ERROR no method named `poll` found for opaque type `impl Future<Output = ()>` in the current scope [E0599]
1214
}
15+
fn main() {}

tests/ui/async-await/issue-108572.stderr

+7-2
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,16 @@
11
error[E0599]: no method named `poll` found for opaque type `impl Future<Output = ()>` in the current scope
2-
--> $DIR/issue-108572.rs:10:9
2+
--> $DIR/issue-108572.rs:12:9
33
|
4-
LL | fut.poll();
4+
LL | fut.poll(cx);
55
| ^^^^ method not found in `impl Future<Output = ()>`
66
|
77
= help: method `poll` found on `Pin<&mut impl Future<Output = ()>>`, see documentation for `std::pin::Pin`
88
= help: self type must be pinned to call `Future::poll`, see https://rust-lang.github.io/async-book/04_pinning/01_chapter.html#pinning-in-practice
9+
help: consider pinning the expression
10+
|
11+
LL ~ let mut pinned = std::pin::pin!(fut);
12+
LL ~ pinned.as_mut().poll(cx);
13+
|
914

1015
error: aborting due to previous error
1116

tests/ui/async-await/pin-needed-to-poll.stderr

+3-5
Original file line numberDiff line numberDiff line change
@@ -6,14 +6,12 @@ LL | struct Sleep;
66
...
77
LL | self.sleep.poll(cx)
88
| ^^^^ method not found in `Sleep`
9-
--> $SRC_DIR/core/src/future/future.rs:LL:COL
109
|
11-
= note: the method is available for `Pin<&mut Sleep>` here
10+
help: consider pinning the expression
1211
|
13-
help: consider wrapping the receiver expression with the appropriate type
12+
LL ~ let mut pinned = std::pin::pin!(self.sleep);
13+
LL ~ pinned.as_mut().poll(cx)
1414
|
15-
LL | Pin::new(&mut self.sleep).poll(cx)
16-
| +++++++++++++ +
1715

1816
error: aborting due to previous error
1917

tests/ui/self/arbitrary_self_types_needing_mut_pin.fixed

+2-1
Original file line numberDiff line numberDiff line change
@@ -8,5 +8,6 @@ impl S {
88
}
99

1010
fn main() {
11-
Pin::new(&mut S).x(); //~ ERROR no method named `x` found
11+
let mut pinned = std::pin::pin!(S);
12+
pinned.as_mut().x(); //~ ERROR no method named `x` found
1213
}

tests/ui/self/arbitrary_self_types_needing_mut_pin.stderr

+4-6
Original file line numberDiff line numberDiff line change
@@ -4,16 +4,14 @@ error[E0599]: no method named `x` found for struct `S` in the current scope
44
LL | struct S;
55
| -------- method `x` not found for this struct
66
...
7-
LL | fn x(self: Pin<&mut Self>) {
8-
| - the method is available for `Pin<&mut S>` here
9-
...
107
LL | S.x();
118
| ^ method not found in `S`
129
|
13-
help: consider wrapping the receiver expression with the appropriate type
10+
help: consider pinning the expression
11+
|
12+
LL ~ let mut pinned = std::pin::pin!(S);
13+
LL ~ pinned.as_mut().x();
1414
|
15-
LL | Pin::new(&mut S).x();
16-
| +++++++++++++ +
1715

1816
error: aborting due to previous error
1917

0 commit comments

Comments
 (0)