Skip to content

Commit

Permalink
Unrolled build for rust-lang#125684
Browse files Browse the repository at this point in the history
Rollup merge of rust-lang#125684 - estebank:pin-to-binding-suggestion, r=pnkfelix

Account for existing bindings when suggesting `pin!()`

When we encounter a situation where we'd suggest `pin!()`, we now account for that expression existing as part of an assignment and provide an appropriate suggestion:

```
error[E0599]: no method named `poll` found for type parameter `F` in the current scope
  --> $DIR/pin-needed-to-poll-3.rs:19:28
   |
LL | impl<F> Future for FutureWrapper<F>
   |      - method `poll` not found for this type parameter
...
LL |         let res = self.fut.poll(cx);
   |                            ^^^^ method not found in `F`
   |
help: consider pinning the expression
   |
LL ~         let mut pinned = std::pin::pin!(self.fut);
LL ~         let res = pinned.as_mut().poll(cx);
   |
```

Fix rust-lang#125661.
  • Loading branch information
rust-timer authored Jun 12, 2024
2 parents d0227c6 + 5585f31 commit c3eb62a
Show file tree
Hide file tree
Showing 3 changed files with 103 additions and 8 deletions.
68 changes: 60 additions & 8 deletions compiler/rustc_hir_typeck/src/method/suggest.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3360,14 +3360,66 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
.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,
);
let mut expr = rcvr;
while let Node::Expr(call_expr) = self.tcx.parent_hir_node(expr.hir_id)
&& let hir::ExprKind::MethodCall(hir::PathSegment { .. }, ..) =
call_expr.kind
{
expr = call_expr;
}
match self.tcx.parent_hir_node(expr.hir_id) {
Node::LetStmt(stmt)
if let Some(init) = stmt.init
&& let Ok(code) =
self.tcx.sess.source_map().span_to_snippet(rcvr.span) =>
{
// We need to take care to account for the existing binding when we
// suggest the code.
err.multipart_suggestion(
"consider pinning the expression",
vec![
(
stmt.span.shrink_to_lo(),
format!(
"let mut pinned = std::pin::pin!({code});\n{indent}"
),
),
(
init.span.until(rcvr.span.shrink_to_hi()),
format!("pinned.{pin_call}()"),
),
],
Applicability::MaybeIncorrect,
);
}
Node::Block(_) | Node::Stmt(_) => {
// There's no binding, so we can provide a slightly nicer looking
// suggestion.
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 quite know what the users' code looks like, so we don't
// provide a pinning suggestion.
err.span_help(
rcvr.span,
"consider pinning the expression with `std::pin::pin!()` and \
assigning that to a new binding",
);
}
}
// We don't care about the other suggestions.
alt_rcvr_sugg = true;
}
Expand Down
25 changes: 25 additions & 0 deletions tests/ui/async-await/pin-needed-to-poll-3.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
use std::{
future::Future,
pin::Pin,
task::{Context, Poll},
};


struct FutureWrapper<F> {
fut: F,
}

impl<F> Future for FutureWrapper<F>
where
F: Future,
{
type Output = F::Output;

fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
let res = self.fut.poll(cx);
//~^ ERROR no method named `poll` found for type parameter `F` in the current scope
res
}
}

fn main() {}
18 changes: 18 additions & 0 deletions tests/ui/async-await/pin-needed-to-poll-3.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
error[E0599]: no method named `poll` found for type parameter `F` in the current scope
--> $DIR/pin-needed-to-poll-3.rs:19:28
|
LL | impl<F> Future for FutureWrapper<F>
| - method `poll` not found for this type parameter
...
LL | let res = self.fut.poll(cx);
| ^^^^ method not found in `F`
|
help: consider pinning the expression
|
LL ~ let mut pinned = std::pin::pin!(self.fut);
LL ~ let res = pinned.as_mut().poll(cx);
|

error: aborting due to 1 previous error

For more information about this error, try `rustc --explain E0599`.

0 comments on commit c3eb62a

Please sign in to comment.