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 #57994.
This commit is contained in:
parent
3071e0aef6
commit
2c3fd1a23a
@ -2495,10 +2495,14 @@ fn suggest_traits_to_import(
|
|||||||
// Try alternative arbitrary self types that could fulfill this call.
|
// Try alternative arbitrary self types that could fulfill this call.
|
||||||
// FIXME: probe for all types that *could* be arbitrary self-types, not
|
// FIXME: probe for all types that *could* be arbitrary self-types, not
|
||||||
// just this list.
|
// just this list.
|
||||||
for (rcvr_ty, post) in &[
|
for (rcvr_ty, post, pin_call) in &[
|
||||||
(rcvr_ty, ""),
|
(rcvr_ty, "", ""),
|
||||||
(Ty::new_mut_ref(self.tcx, self.tcx.lifetimes.re_erased, rcvr_ty), "&mut "),
|
(
|
||||||
(Ty::new_imm_ref(self.tcx, self.tcx.lifetimes.re_erased, rcvr_ty), "&"),
|
Ty::new_mut_ref(self.tcx, self.tcx.lifetimes.re_erased, rcvr_ty),
|
||||||
|
"&mut ",
|
||||||
|
"as_mut",
|
||||||
|
),
|
||||||
|
(Ty::new_imm_ref(self.tcx, self.tcx.lifetimes.re_erased, rcvr_ty), "&", "as_ref"),
|
||||||
] {
|
] {
|
||||||
match self.lookup_probe_for_diagnostic(
|
match self.lookup_probe_for_diagnostic(
|
||||||
item_name,
|
item_name,
|
||||||
@ -2532,6 +2536,17 @@ fn suggest_traits_to_import(
|
|||||||
Err(_) => (),
|
Err(_) => (),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let pred = ty::TraitRef::new(
|
||||||
|
self.tcx,
|
||||||
|
self.tcx.lang_items().unpin_trait().unwrap(),
|
||||||
|
[*rcvr_ty],
|
||||||
|
);
|
||||||
|
let unpin = self.predicate_must_hold_considering_regions(&Obligation::new(
|
||||||
|
self.tcx,
|
||||||
|
ObligationCause::misc(rcvr.span, self.body_id),
|
||||||
|
self.param_env,
|
||||||
|
pred,
|
||||||
|
));
|
||||||
for (rcvr_ty, pre) in &[
|
for (rcvr_ty, pre) in &[
|
||||||
(Ty::new_lang_item(self.tcx, *rcvr_ty, LangItem::OwnedBox), "Box::new"),
|
(Ty::new_lang_item(self.tcx, *rcvr_ty, LangItem::OwnedBox), "Box::new"),
|
||||||
(Ty::new_lang_item(self.tcx, *rcvr_ty, LangItem::Pin), "Pin::new"),
|
(Ty::new_lang_item(self.tcx, *rcvr_ty, LangItem::Pin), "Pin::new"),
|
||||||
@ -2555,7 +2570,7 @@ fn suggest_traits_to_import(
|
|||||||
// Explicitly ignore the `Pin::as_ref()` method as `Pin` does not
|
// Explicitly ignore the `Pin::as_ref()` method as `Pin` does not
|
||||||
// implement the `AsRef` trait.
|
// implement the `AsRef` trait.
|
||||||
let skip = skippable.contains(&did)
|
let skip = skippable.contains(&did)
|
||||||
|| (("Pin::new" == *pre) && (sym::as_ref == item_name.name))
|
|| (("Pin::new" == *pre) && ((sym::as_ref == item_name.name) || !unpin))
|
||||||
|| 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);
|
|| 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);
|
||||||
// Make sure the method is defined for the *actual* receiver: we don't
|
// Make sure the method is defined for the *actual* receiver: we don't
|
||||||
// want to treat `Box<Self>` as a receiver if it only works because of
|
// want to treat `Box<Self>` as a receiver if it only works because of
|
||||||
@ -2579,6 +2594,39 @@ fn suggest_traits_to_import(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// We special case the situation where `Pin::new` wouldn't work, and isntead
|
||||||
|
// suggest using the `pin!()` macro instead.
|
||||||
|
if let Some(new_rcvr_t) = Ty::new_lang_item(self.tcx, *rcvr_ty, LangItem::Pin)
|
||||||
|
&& !alt_rcvr_sugg
|
||||||
|
&& !unpin
|
||||||
|
&& sym::as_ref != item_name.name
|
||||||
|
&& *pin_call != ""
|
||||||
|
&& let Ok(pick) = self.lookup_probe_for_diagnostic(
|
||||||
|
item_name,
|
||||||
|
new_rcvr_t,
|
||||||
|
rcvr,
|
||||||
|
ProbeScope::AllTraits,
|
||||||
|
return_type,
|
||||||
|
)
|
||||||
|
&& !skippable.contains(&Some(pick.item.container_id(self.tcx)))
|
||||||
|
&& pick.autoderefs == 0
|
||||||
|
&& 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)
|
||||||
|
{
|
||||||
|
let indent = self.tcx.sess
|
||||||
|
.source_map()
|
||||||
|
.indentation_before(rcvr.span)
|
||||||
|
.unwrap_or_else(|| " ".to_string());
|
||||||
|
err.multipart_suggestion(
|
||||||
|
"consider pinning the expression",
|
||||||
|
vec![
|
||||||
|
(rcvr.span.shrink_to_lo(), format!("let mut pinned = std::pin::pin!(")),
|
||||||
|
(rcvr.span.shrink_to_hi(), format!(");\n{indent}pinned.{pin_call}()")),
|
||||||
|
],
|
||||||
|
Applicability::MaybeIncorrect,
|
||||||
|
);
|
||||||
|
// We don't care about the other suggestions.
|
||||||
|
alt_rcvr_sugg = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if self.suggest_valid_traits(err, valid_out_of_scope_traits) {
|
if self.suggest_valid_traits(err, valid_out_of_scope_traits) {
|
||||||
|
16
tests/ui/async-await/issue-108572.fixed
Normal file
16
tests/ui/async-await/issue-108572.fixed
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
// edition: 2021
|
||||||
|
// run-rustfix
|
||||||
|
#![allow(unused_must_use, dead_code)]
|
||||||
|
|
||||||
|
use std::future::Future;
|
||||||
|
fn foo() -> impl Future<Output=()> {
|
||||||
|
async { }
|
||||||
|
}
|
||||||
|
|
||||||
|
fn bar(cx: &mut std::task::Context<'_>) {
|
||||||
|
let fut = foo();
|
||||||
|
let mut pinned = std::pin::pin!(fut);
|
||||||
|
pinned.as_mut().poll(cx);
|
||||||
|
//~^ ERROR no method named `poll` found for opaque type `impl Future<Output = ()>` in the current scope [E0599]
|
||||||
|
}
|
||||||
|
fn main() {}
|
@ -1,12 +1,15 @@
|
|||||||
// edition: 2021
|
// edition: 2021
|
||||||
|
// run-rustfix
|
||||||
|
#![allow(unused_must_use, dead_code)]
|
||||||
|
|
||||||
use std::future::Future;
|
use std::future::Future;
|
||||||
fn foo() -> impl Future<Output=()> {
|
fn foo() -> impl Future<Output=()> {
|
||||||
async { }
|
async { }
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() {
|
fn bar(cx: &mut std::task::Context<'_>) {
|
||||||
let fut = foo();
|
let fut = foo();
|
||||||
fut.poll();
|
fut.poll(cx);
|
||||||
//~^ ERROR no method named `poll` found for opaque type `impl Future<Output = ()>` in the current scope [E0599]
|
//~^ ERROR no method named `poll` found for opaque type `impl Future<Output = ()>` in the current scope [E0599]
|
||||||
}
|
}
|
||||||
|
fn main() {}
|
||||||
|
@ -1,11 +1,16 @@
|
|||||||
error[E0599]: no method named `poll` found for opaque type `impl Future<Output = ()>` in the current scope
|
error[E0599]: no method named `poll` found for opaque type `impl Future<Output = ()>` in the current scope
|
||||||
--> $DIR/issue-108572.rs:10:9
|
--> $DIR/issue-108572.rs:12:9
|
||||||
|
|
|
|
||||||
LL | fut.poll();
|
LL | fut.poll(cx);
|
||||||
| ^^^^ method not found in `impl Future<Output = ()>`
|
| ^^^^ method not found in `impl Future<Output = ()>`
|
||||||
|
|
|
|
||||||
= help: method `poll` found on `Pin<&mut impl Future<Output = ()>>`, see documentation for `std::pin::Pin`
|
= help: method `poll` found on `Pin<&mut impl Future<Output = ()>>`, see documentation for `std::pin::Pin`
|
||||||
= 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
|
= 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
|
||||||
|
help: consider pinning the expression
|
||||||
|
|
|
||||||
|
LL ~ let mut pinned = std::pin::pin!(fut);
|
||||||
|
LL ~ pinned.as_mut().poll(cx);
|
||||||
|
|
|
||||||
|
|
||||||
error: aborting due to previous error
|
error: aborting due to previous error
|
||||||
|
|
||||||
|
@ -6,14 +6,12 @@ LL | struct Sleep;
|
|||||||
...
|
...
|
||||||
LL | self.sleep.poll(cx)
|
LL | self.sleep.poll(cx)
|
||||||
| ^^^^ method not found in `Sleep`
|
| ^^^^ method not found in `Sleep`
|
||||||
--> $SRC_DIR/core/src/future/future.rs:LL:COL
|
|
||||||
|
|
|
|
||||||
= note: the method is available for `Pin<&mut Sleep>` here
|
help: consider pinning the expression
|
||||||
|
|
|
|
||||||
help: consider wrapping the receiver expression with the appropriate type
|
LL ~ let mut pinned = std::pin::pin!(self.sleep);
|
||||||
|
LL ~ pinned.as_mut().poll(cx)
|
||||||
|
|
|
|
||||||
LL | Pin::new(&mut self.sleep).poll(cx)
|
|
||||||
| +++++++++++++ +
|
|
||||||
|
|
||||||
error: aborting due to previous error
|
error: aborting due to previous error
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user