Skip to content

Commit 5585f31

Browse files
committed
Account for existing bindings when suggesting pinning
When we encounter a situation where we'd suggest `pin!()`, we now account for that expression exising 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 #125661.
1 parent 1a840e7 commit 5585f31

File tree

2 files changed

+62
-10
lines changed

2 files changed

+62
-10
lines changed

compiler/rustc_hir_typeck/src/method/suggest.rs

+60-8
Original file line numberDiff line numberDiff line change
@@ -3326,14 +3326,66 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
33263326
.source_map()
33273327
.indentation_before(rcvr.span)
33283328
.unwrap_or_else(|| " ".to_string());
3329-
err.multipart_suggestion(
3330-
"consider pinning the expression",
3331-
vec![
3332-
(rcvr.span.shrink_to_lo(), format!("let mut pinned = std::pin::pin!(")),
3333-
(rcvr.span.shrink_to_hi(), format!(");\n{indent}pinned.{pin_call}()")),
3334-
],
3335-
Applicability::MaybeIncorrect,
3336-
);
3329+
let mut expr = rcvr;
3330+
while let Node::Expr(call_expr) = self.tcx.parent_hir_node(expr.hir_id)
3331+
&& let hir::ExprKind::MethodCall(hir::PathSegment { .. }, ..) =
3332+
call_expr.kind
3333+
{
3334+
expr = call_expr;
3335+
}
3336+
match self.tcx.parent_hir_node(expr.hir_id) {
3337+
Node::LetStmt(stmt)
3338+
if let Some(init) = stmt.init
3339+
&& let Ok(code) =
3340+
self.tcx.sess.source_map().span_to_snippet(rcvr.span) =>
3341+
{
3342+
// We need to take care to account for the existing binding when we
3343+
// suggest the code.
3344+
err.multipart_suggestion(
3345+
"consider pinning the expression",
3346+
vec![
3347+
(
3348+
stmt.span.shrink_to_lo(),
3349+
format!(
3350+
"let mut pinned = std::pin::pin!({code});\n{indent}"
3351+
),
3352+
),
3353+
(
3354+
init.span.until(rcvr.span.shrink_to_hi()),
3355+
format!("pinned.{pin_call}()"),
3356+
),
3357+
],
3358+
Applicability::MaybeIncorrect,
3359+
);
3360+
}
3361+
Node::Block(_) | Node::Stmt(_) => {
3362+
// There's no binding, so we can provide a slightly nicer looking
3363+
// suggestion.
3364+
err.multipart_suggestion(
3365+
"consider pinning the expression",
3366+
vec![
3367+
(
3368+
rcvr.span.shrink_to_lo(),
3369+
format!("let mut pinned = std::pin::pin!("),
3370+
),
3371+
(
3372+
rcvr.span.shrink_to_hi(),
3373+
format!(");\n{indent}pinned.{pin_call}()"),
3374+
),
3375+
],
3376+
Applicability::MaybeIncorrect,
3377+
);
3378+
}
3379+
_ => {
3380+
// We don't quite know what the users' code looks like, so we don't
3381+
// provide a pinning suggestion.
3382+
err.span_help(
3383+
rcvr.span,
3384+
"consider pinning the expression with `std::pin::pin!()` and \
3385+
assigning that to a new binding",
3386+
);
3387+
}
3388+
}
33373389
// We don't care about the other suggestions.
33383390
alt_rcvr_sugg = true;
33393391
}

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

+2-2
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,8 @@ LL | let res = self.fut.poll(cx);
99
|
1010
help: consider pinning the expression
1111
|
12-
LL ~ let res = let mut pinned = std::pin::pin!(self.fut);
13-
LL ~ pinned.as_mut().poll(cx);
12+
LL ~ let mut pinned = std::pin::pin!(self.fut);
13+
LL ~ let res = pinned.as_mut().poll(cx);
1414
|
1515

1616
error: aborting due to 1 previous error

0 commit comments

Comments
 (0)