1
Fork 0

Account for Box::new(impl Future) and emit help use Box::pin

This commit is contained in:
Esteban Küber 2020-02-12 11:11:55 -08:00
parent a852fb7413
commit 80cdb0af7d
5 changed files with 84 additions and 30 deletions

View file

@ -24,8 +24,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
self.annotate_expected_due_to_let_ty(err, expr);
self.suggest_compatible_variants(err, expr, expected, expr_ty);
self.suggest_ref_or_into(err, expr, expected, expr_ty);
if self.suggest_calling_boxed_future_when_appropriate(err, expr, expected, expr_ty) {
return;
}
self.suggest_boxing_when_appropriate(err, expr, expected, expr_ty);
self.suggest_calling_boxed_future_when_appropriate(err, expr, expected, expr_ty);
self.suggest_missing_await(err, expr, expected, expr_ty);
}

View file

@ -5053,18 +5053,18 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
expr: &hir::Expr<'_>,
expected: Ty<'tcx>,
found: Ty<'tcx>,
) {
) -> bool {
// Handle #68197.
if self.tcx.hir().is_const_context(expr.hir_id) {
// Do not suggest `Box::new` in const context.
return;
return false;
}
let pin_did = self.tcx.lang_items().pin_type();
match expected.kind {
ty::Adt(def, _) if Some(def.did) != pin_did => return,
ty::Adt(def, _) if Some(def.did) != pin_did => return false,
// This guards the `unwrap` and `mk_box` below.
_ if pin_did.is_none() || self.tcx.lang_items().owned_box().is_none() => return,
_ if pin_did.is_none() || self.tcx.lang_items().owned_box().is_none() => return false,
_ => {}
}
let boxed_found = self.tcx.mk_box(found);
@ -5073,12 +5073,22 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
self.can_coerce(new_found, expected),
self.sess().source_map().span_to_snippet(expr.span),
) {
err.span_suggestion(
expr.span,
"you need to pin and box this expression",
format!("Box::pin({})", snippet),
Applicability::MachineApplicable,
);
match found.kind {
ty::Adt(def, _) if def.is_box() => {
err.help("use `Box::pin`");
}
_ => {
err.span_suggestion(
expr.span,
"you need to pin and box this expression",
format!("Box::pin({})", snippet),
Applicability::MachineApplicable,
);
}
}
true
} else {
false
}
}

View file

@ -1,15 +0,0 @@
// edition:2018
// run-rustfix
#![allow(dead_code)]
use std::future::Future;
use std::pin::Pin;
type BoxFuture<'a, T> = Pin<Box<dyn Future<Output = T> + Send + 'a>>;
// ^^^^^^^^^ This would come from the `futures` crate in real code.
fn foo<F: Future<Output=i32> + Send + 'static>(x: F) -> BoxFuture<'static, i32> {
// We could instead use an `async` block, but this way we have no std spans.
Box::pin(x) //~ ERROR mismatched types
}
fn main() {}

View file

@ -1,5 +1,4 @@
// edition:2018
// run-rustfix
#![allow(dead_code)]
use std::future::Future;
use std::pin::Pin;
@ -11,5 +10,17 @@ fn foo<F: Future<Output=i32> + Send + 'static>(x: F) -> BoxFuture<'static, i32>
// We could instead use an `async` block, but this way we have no std spans.
x //~ ERROR mismatched types
}
fn bar<F: Future<Output=i32> + Send + 'static>(x: F) -> BoxFuture<'static, i32> {
Box::new(x) //~ ERROR mismatched types
//~^ HELP use `Box::pin`
}
fn baz<F: Future<Output=i32> + Send + 'static>(x: F) -> BoxFuture<'static, i32> {
Pin::new(x) //~ ERROR mismatched types
//~^ ERROR the trait bound
}
fn qux<F: Future<Output=i32> + Send + 'static>(x: F) -> BoxFuture<'static, i32> {
Pin::new(Box::new(x)) //~ ERROR mismatched types
//~^ ERROR the trait bound
}
fn main() {}

View file

@ -1,5 +1,5 @@
error[E0308]: mismatched types
--> $DIR/expected-boxed-future-isnt-pinned.rs:12:5
--> $DIR/expected-boxed-future-isnt-pinned.rs:11:5
|
LL | fn foo<F: Future<Output=i32> + Send + 'static>(x: F) -> BoxFuture<'static, i32> {
| - this type parameter ----------------------- expected `std::pin::Pin<std::boxed::Box<(dyn std::future::Future<Output = i32> + std::marker::Send + 'static)>>` because of return type
@ -15,6 +15,52 @@ LL | x
= help: type parameters must be constrained to match other types
= note: for more information, visit https://doc.rust-lang.org/book/ch10-02-traits.html#traits-as-parameters
error: aborting due to previous error
error[E0308]: mismatched types
--> $DIR/expected-boxed-future-isnt-pinned.rs:14:5
|
LL | fn bar<F: Future<Output=i32> + Send + 'static>(x: F) -> BoxFuture<'static, i32> {
| ----------------------- expected `std::pin::Pin<std::boxed::Box<(dyn std::future::Future<Output = i32> + std::marker::Send + 'static)>>` because of return type
LL | Box::new(x)
| ^^^^^^^^^^^ expected struct `std::pin::Pin`, found struct `std::boxed::Box`
|
= note: expected struct `std::pin::Pin<std::boxed::Box<(dyn std::future::Future<Output = i32> + std::marker::Send + 'static)>>`
found struct `std::boxed::Box<F>`
= help: use `Box::pin`
For more information about this error, try `rustc --explain E0308`.
error[E0308]: mismatched types
--> $DIR/expected-boxed-future-isnt-pinned.rs:18:14
|
LL | fn baz<F: Future<Output=i32> + Send + 'static>(x: F) -> BoxFuture<'static, i32> {
| - this type parameter
LL | Pin::new(x)
| ^
| |
| expected struct `std::boxed::Box`, found type parameter `F`
| help: store this in the heap by calling `Box::new`: `Box::new(x)`
|
= note: expected struct `std::boxed::Box<dyn std::future::Future<Output = i32> + std::marker::Send>`
found type parameter `F`
= help: type parameters must be constrained to match other types
= note: for more information, visit https://doc.rust-lang.org/book/ch10-02-traits.html#traits-as-parameters
= 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
error[E0277]: the trait bound `dyn std::future::Future<Output = i32> + std::marker::Send: std::marker::Unpin` is not satisfied
--> $DIR/expected-boxed-future-isnt-pinned.rs:18:5
|
LL | Pin::new(x)
| ^^^^^^^^ the trait `std::marker::Unpin` is not implemented for `dyn std::future::Future<Output = i32> + std::marker::Send`
|
= note: required by `std::pin::Pin::<P>::new`
error[E0277]: the trait bound `dyn std::future::Future<Output = i32> + std::marker::Send: std::marker::Unpin` is not satisfied
--> $DIR/expected-boxed-future-isnt-pinned.rs:22:5
|
LL | Pin::new(Box::new(x))
| ^^^^^^^^ the trait `std::marker::Unpin` is not implemented for `dyn std::future::Future<Output = i32> + std::marker::Send`
|
= note: required by `std::pin::Pin::<P>::new`
error: aborting due to 5 previous errors
Some errors have detailed explanations: E0277, E0308.
For more information about an error, try `rustc --explain E0277`.