mirror of
https://github.com/rust-lang/rust.git
synced 2025-05-14 02:49:40 +00:00
Rollup merge of #89870 - tmandry:box-pin, r=estebank
Suggest Box::pin when Pin::new is used instead This fixes an incorrect diagnostic. **Based on #89390**; only the last commit is specific to this PR. "Ignore whitespace changes" also helps here.
This commit is contained in:
commit
e2c28ad1e7
@ -8,11 +8,11 @@ use rustc_errors::{Applicability, DiagnosticBuilder};
|
|||||||
use rustc_hir as hir;
|
use rustc_hir as hir;
|
||||||
use rustc_hir::def::{CtorOf, DefKind};
|
use rustc_hir::def::{CtorOf, DefKind};
|
||||||
use rustc_hir::lang_items::LangItem;
|
use rustc_hir::lang_items::LangItem;
|
||||||
use rustc_hir::{Expr, ExprKind, ItemKind, Node, Stmt, StmtKind};
|
use rustc_hir::{Expr, ExprKind, ItemKind, Node, Path, QPath, Stmt, StmtKind, TyKind};
|
||||||
use rustc_infer::infer;
|
use rustc_infer::infer;
|
||||||
use rustc_middle::lint::in_external_macro;
|
use rustc_middle::lint::in_external_macro;
|
||||||
use rustc_middle::ty::{self, Binder, Ty};
|
use rustc_middle::ty::{self, Binder, Ty};
|
||||||
use rustc_span::symbol::kw;
|
use rustc_span::symbol::{kw, sym};
|
||||||
|
|
||||||
use std::iter;
|
use std::iter;
|
||||||
|
|
||||||
@ -350,6 +350,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// When encountering an `impl Future` where `BoxFuture` is expected, suggest `Box::pin`.
|
/// When encountering an `impl Future` where `BoxFuture` is expected, suggest `Box::pin`.
|
||||||
|
#[instrument(skip(self, err))]
|
||||||
pub(in super::super) fn suggest_calling_boxed_future_when_appropriate(
|
pub(in super::super) fn suggest_calling_boxed_future_when_appropriate(
|
||||||
&self,
|
&self,
|
||||||
err: &mut DiagnosticBuilder<'_>,
|
err: &mut DiagnosticBuilder<'_>,
|
||||||
@ -368,13 +369,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
if pin_did.is_none() || self.tcx.lang_items().owned_box().is_none() {
|
if pin_did.is_none() || self.tcx.lang_items().owned_box().is_none() {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
match expected.kind() {
|
|
||||||
ty::Adt(def, _) if Some(def.did) == pin_did => (),
|
|
||||||
_ => return false,
|
|
||||||
}
|
|
||||||
let box_found = self.tcx.mk_box(found);
|
let box_found = self.tcx.mk_box(found);
|
||||||
let pin_box_found = self.tcx.mk_lang_item(box_found, LangItem::Pin).unwrap();
|
let pin_box_found = self.tcx.mk_lang_item(box_found, LangItem::Pin).unwrap();
|
||||||
let pin_found = self.tcx.mk_lang_item(found, LangItem::Pin).unwrap();
|
let pin_found = self.tcx.mk_lang_item(found, LangItem::Pin).unwrap();
|
||||||
|
match expected.kind() {
|
||||||
|
ty::Adt(def, _) if Some(def.did) == pin_did => {
|
||||||
if self.can_coerce(pin_box_found, expected) {
|
if self.can_coerce(pin_box_found, expected) {
|
||||||
debug!("can coerce {:?} to {:?}, suggesting Box::pin", pin_box_found, expected);
|
debug!("can coerce {:?} to {:?}, suggesting Box::pin", pin_box_found, expected);
|
||||||
match found.kind() {
|
match found.kind() {
|
||||||
@ -405,6 +404,37 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
false
|
false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
ty::Adt(def, _) if def.is_box() && self.can_coerce(box_found, expected) => {
|
||||||
|
// Check if the parent expression is a call to Pin::new. If it
|
||||||
|
// is and we were expecting a Box, ergo Pin<Box<expected>>, we
|
||||||
|
// can suggest Box::pin.
|
||||||
|
let parent = self.tcx.hir().get_parent_node(expr.hir_id);
|
||||||
|
let fn_name = match self.tcx.hir().find(parent) {
|
||||||
|
Some(Node::Expr(Expr { kind: ExprKind::Call(fn_name, _), .. })) => fn_name,
|
||||||
|
_ => return false,
|
||||||
|
};
|
||||||
|
match fn_name.kind {
|
||||||
|
ExprKind::Path(QPath::TypeRelative(
|
||||||
|
hir::Ty {
|
||||||
|
kind: TyKind::Path(QPath::Resolved(_, Path { res: recv_ty, .. })),
|
||||||
|
..
|
||||||
|
},
|
||||||
|
method,
|
||||||
|
)) if Some(recv_ty.def_id()) == pin_did && method.ident.name == sym::new => {
|
||||||
|
err.span_suggestion(
|
||||||
|
fn_name.span,
|
||||||
|
"use `Box::pin` to pin and box this expression",
|
||||||
|
"Box::pin".to_string(),
|
||||||
|
Applicability::MachineApplicable,
|
||||||
|
);
|
||||||
|
true
|
||||||
|
}
|
||||||
|
_ => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// A common error is to forget to add a semicolon at the end of a block, e.g.,
|
/// A common error is to forget to add a semicolon at the end of a block, e.g.,
|
||||||
///
|
///
|
||||||
|
@ -15,9 +15,6 @@ fn bar<F: Future<Output=i32> + Send + 'static>(x: F) -> BoxFuture<'static, i32>
|
|||||||
Box::new(x) //~ ERROR mismatched types
|
Box::new(x) //~ ERROR mismatched types
|
||||||
}
|
}
|
||||||
|
|
||||||
// This case is still subpar:
|
|
||||||
// `Pin::new(x)`: store this in the heap by calling `Box::new`: `Box::new(x)`
|
|
||||||
// Should suggest changing the code from `Pin::new` to `Box::pin`.
|
|
||||||
fn baz<F: Future<Output=i32> + Send + 'static>(x: F) -> BoxFuture<'static, i32> {
|
fn baz<F: Future<Output=i32> + Send + 'static>(x: F) -> BoxFuture<'static, i32> {
|
||||||
Pin::new(x) //~ ERROR mismatched types
|
Pin::new(x) //~ ERROR mismatched types
|
||||||
//~^ ERROR E0277
|
//~^ ERROR E0277
|
||||||
|
@ -27,23 +27,20 @@ LL | Box::new(x)
|
|||||||
= help: use `Box::pin`
|
= help: use `Box::pin`
|
||||||
|
|
||||||
error[E0308]: mismatched types
|
error[E0308]: mismatched types
|
||||||
--> $DIR/expected-boxed-future-isnt-pinned.rs:22:14
|
--> $DIR/expected-boxed-future-isnt-pinned.rs:19:14
|
||||||
|
|
|
|
||||||
LL | fn baz<F: Future<Output=i32> + Send + 'static>(x: F) -> BoxFuture<'static, i32> {
|
LL | fn baz<F: Future<Output=i32> + Send + 'static>(x: F) -> BoxFuture<'static, i32> {
|
||||||
| - this type parameter
|
| - this type parameter
|
||||||
LL | Pin::new(x)
|
LL | Pin::new(x)
|
||||||
| ^ expected struct `Box`, found type parameter `F`
|
| -------- ^ expected struct `Box`, found type parameter `F`
|
||||||
|
| |
|
||||||
|
| help: use `Box::pin` to pin and box this expression: `Box::pin`
|
||||||
|
|
|
|
||||||
= note: expected struct `Box<dyn Future<Output = i32> + Send>`
|
= note: expected struct `Box<dyn Future<Output = i32> + Send>`
|
||||||
found type parameter `F`
|
found type parameter `F`
|
||||||
= note: for more on the distinction between the stack and the heap, read https://doc.rust-lang.org/book/ch15-01-box.html, https://doc.rust-lang.org/rust-by-example/std/box.html, and https://doc.rust-lang.org/std/boxed/index.html
|
|
||||||
help: store this in the heap by calling `Box::new`
|
|
||||||
|
|
|
||||||
LL | Pin::new(Box::new(x))
|
|
||||||
| +++++++++ +
|
|
||||||
|
|
||||||
error[E0277]: `dyn Future<Output = i32> + Send` cannot be unpinned
|
error[E0277]: `dyn Future<Output = i32> + Send` cannot be unpinned
|
||||||
--> $DIR/expected-boxed-future-isnt-pinned.rs:22:5
|
--> $DIR/expected-boxed-future-isnt-pinned.rs:19:5
|
||||||
|
|
|
|
||||||
LL | Pin::new(x)
|
LL | Pin::new(x)
|
||||||
| ^^^^^^^^ the trait `Unpin` is not implemented for `dyn Future<Output = i32> + Send`
|
| ^^^^^^^^ the trait `Unpin` is not implemented for `dyn Future<Output = i32> + Send`
|
||||||
@ -56,7 +53,7 @@ LL | pub const fn new(pointer: P) -> Pin<P> {
|
|||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
error[E0277]: `dyn Future<Output = i32> + Send` cannot be unpinned
|
error[E0277]: `dyn Future<Output = i32> + Send` cannot be unpinned
|
||||||
--> $DIR/expected-boxed-future-isnt-pinned.rs:27:5
|
--> $DIR/expected-boxed-future-isnt-pinned.rs:24:5
|
||||||
|
|
|
|
||||||
LL | Pin::new(Box::new(x))
|
LL | Pin::new(Box::new(x))
|
||||||
| ^^^^^^^^ the trait `Unpin` is not implemented for `dyn Future<Output = i32> + Send`
|
| ^^^^^^^^ the trait `Unpin` is not implemented for `dyn Future<Output = i32> + Send`
|
||||||
@ -69,7 +66,7 @@ LL | pub const fn new(pointer: P) -> Pin<P> {
|
|||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
error[E0308]: mismatched types
|
error[E0308]: mismatched types
|
||||||
--> $DIR/expected-boxed-future-isnt-pinned.rs:31:5
|
--> $DIR/expected-boxed-future-isnt-pinned.rs:28:5
|
||||||
|
|
|
|
||||||
LL | fn zap() -> BoxFuture<'static, i32> {
|
LL | fn zap() -> BoxFuture<'static, i32> {
|
||||||
| ----------------------- expected `Pin<Box<(dyn Future<Output = i32> + Send + 'static)>>` because of return type
|
| ----------------------- expected `Pin<Box<(dyn Future<Output = i32> + Send + 'static)>>` because of return type
|
||||||
|
Loading…
Reference in New Issue
Block a user