Skip to content

Commit 80cdb0a

Browse files
committed
Account for Box::new(impl Future) and emit help use Box::pin
1 parent a852fb7 commit 80cdb0a

File tree

5 files changed

+84
-30
lines changed

5 files changed

+84
-30
lines changed

src/librustc_typeck/check/demand.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
2424
self.annotate_expected_due_to_let_ty(err, expr);
2525
self.suggest_compatible_variants(err, expr, expected, expr_ty);
2626
self.suggest_ref_or_into(err, expr, expected, expr_ty);
27+
if self.suggest_calling_boxed_future_when_appropriate(err, expr, expected, expr_ty) {
28+
return;
29+
}
2730
self.suggest_boxing_when_appropriate(err, expr, expected, expr_ty);
28-
self.suggest_calling_boxed_future_when_appropriate(err, expr, expected, expr_ty);
2931
self.suggest_missing_await(err, expr, expected, expr_ty);
3032
}
3133

src/librustc_typeck/check/mod.rs

Lines changed: 20 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -5053,18 +5053,18 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
50535053
expr: &hir::Expr<'_>,
50545054
expected: Ty<'tcx>,
50555055
found: Ty<'tcx>,
5056-
) {
5056+
) -> bool {
50575057
// Handle #68197.
50585058

50595059
if self.tcx.hir().is_const_context(expr.hir_id) {
50605060
// Do not suggest `Box::new` in const context.
5061-
return;
5061+
return false;
50625062
}
50635063
let pin_did = self.tcx.lang_items().pin_type();
50645064
match expected.kind {
5065-
ty::Adt(def, _) if Some(def.did) != pin_did => return,
5065+
ty::Adt(def, _) if Some(def.did) != pin_did => return false,
50665066
// This guards the `unwrap` and `mk_box` below.
5067-
_ if pin_did.is_none() || self.tcx.lang_items().owned_box().is_none() => return,
5067+
_ if pin_did.is_none() || self.tcx.lang_items().owned_box().is_none() => return false,
50685068
_ => {}
50695069
}
50705070
let boxed_found = self.tcx.mk_box(found);
@@ -5073,12 +5073,22 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
50735073
self.can_coerce(new_found, expected),
50745074
self.sess().source_map().span_to_snippet(expr.span),
50755075
) {
5076-
err.span_suggestion(
5077-
expr.span,
5078-
"you need to pin and box this expression",
5079-
format!("Box::pin({})", snippet),
5080-
Applicability::MachineApplicable,
5081-
);
5076+
match found.kind {
5077+
ty::Adt(def, _) if def.is_box() => {
5078+
err.help("use `Box::pin`");
5079+
}
5080+
_ => {
5081+
err.span_suggestion(
5082+
expr.span,
5083+
"you need to pin and box this expression",
5084+
format!("Box::pin({})", snippet),
5085+
Applicability::MachineApplicable,
5086+
);
5087+
}
5088+
}
5089+
true
5090+
} else {
5091+
false
50825092
}
50835093
}
50845094

src/test/ui/suggestions/expected-boxed-future-isnt-pinned.fixed

Lines changed: 0 additions & 15 deletions
This file was deleted.

src/test/ui/suggestions/expected-boxed-future-isnt-pinned.rs

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
// edition:2018
2-
// run-rustfix
32
#![allow(dead_code)]
43
use std::future::Future;
54
use std::pin::Pin;
@@ -11,5 +10,17 @@ fn foo<F: Future<Output=i32> + Send + 'static>(x: F) -> BoxFuture<'static, i32>
1110
// We could instead use an `async` block, but this way we have no std spans.
1211
x //~ ERROR mismatched types
1312
}
13+
fn bar<F: Future<Output=i32> + Send + 'static>(x: F) -> BoxFuture<'static, i32> {
14+
Box::new(x) //~ ERROR mismatched types
15+
//~^ HELP use `Box::pin`
16+
}
17+
fn baz<F: Future<Output=i32> + Send + 'static>(x: F) -> BoxFuture<'static, i32> {
18+
Pin::new(x) //~ ERROR mismatched types
19+
//~^ ERROR the trait bound
20+
}
21+
fn qux<F: Future<Output=i32> + Send + 'static>(x: F) -> BoxFuture<'static, i32> {
22+
Pin::new(Box::new(x)) //~ ERROR mismatched types
23+
//~^ ERROR the trait bound
24+
}
1425

1526
fn main() {}

src/test/ui/suggestions/expected-boxed-future-isnt-pinned.stderr

Lines changed: 49 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
error[E0308]: mismatched types
2-
--> $DIR/expected-boxed-future-isnt-pinned.rs:12:5
2+
--> $DIR/expected-boxed-future-isnt-pinned.rs:11:5
33
|
44
LL | fn foo<F: Future<Output=i32> + Send + 'static>(x: F) -> BoxFuture<'static, i32> {
55
| - 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
1515
= help: type parameters must be constrained to match other types
1616
= note: for more information, visit https://doc.rust-lang.org/book/ch10-02-traits.html#traits-as-parameters
1717

18-
error: aborting due to previous error
18+
error[E0308]: mismatched types
19+
--> $DIR/expected-boxed-future-isnt-pinned.rs:14:5
20+
|
21+
LL | fn bar<F: Future<Output=i32> + Send + 'static>(x: F) -> BoxFuture<'static, i32> {
22+
| ----------------------- expected `std::pin::Pin<std::boxed::Box<(dyn std::future::Future<Output = i32> + std::marker::Send + 'static)>>` because of return type
23+
LL | Box::new(x)
24+
| ^^^^^^^^^^^ expected struct `std::pin::Pin`, found struct `std::boxed::Box`
25+
|
26+
= note: expected struct `std::pin::Pin<std::boxed::Box<(dyn std::future::Future<Output = i32> + std::marker::Send + 'static)>>`
27+
found struct `std::boxed::Box<F>`
28+
= help: use `Box::pin`
29+
30+
error[E0308]: mismatched types
31+
--> $DIR/expected-boxed-future-isnt-pinned.rs:18:14
32+
|
33+
LL | fn baz<F: Future<Output=i32> + Send + 'static>(x: F) -> BoxFuture<'static, i32> {
34+
| - this type parameter
35+
LL | Pin::new(x)
36+
| ^
37+
| |
38+
| expected struct `std::boxed::Box`, found type parameter `F`
39+
| help: store this in the heap by calling `Box::new`: `Box::new(x)`
40+
|
41+
= note: expected struct `std::boxed::Box<dyn std::future::Future<Output = i32> + std::marker::Send>`
42+
found type parameter `F`
43+
= help: type parameters must be constrained to match other types
44+
= note: for more information, visit https://doc.rust-lang.org/book/ch10-02-traits.html#traits-as-parameters
45+
= 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
46+
47+
error[E0277]: the trait bound `dyn std::future::Future<Output = i32> + std::marker::Send: std::marker::Unpin` is not satisfied
48+
--> $DIR/expected-boxed-future-isnt-pinned.rs:18:5
49+
|
50+
LL | Pin::new(x)
51+
| ^^^^^^^^ the trait `std::marker::Unpin` is not implemented for `dyn std::future::Future<Output = i32> + std::marker::Send`
52+
|
53+
= note: required by `std::pin::Pin::<P>::new`
54+
55+
error[E0277]: the trait bound `dyn std::future::Future<Output = i32> + std::marker::Send: std::marker::Unpin` is not satisfied
56+
--> $DIR/expected-boxed-future-isnt-pinned.rs:22:5
57+
|
58+
LL | Pin::new(Box::new(x))
59+
| ^^^^^^^^ the trait `std::marker::Unpin` is not implemented for `dyn std::future::Future<Output = i32> + std::marker::Send`
60+
|
61+
= note: required by `std::pin::Pin::<P>::new`
62+
63+
error: aborting due to 5 previous errors
1964

20-
For more information about this error, try `rustc --explain E0308`.
65+
Some errors have detailed explanations: E0277, E0308.
66+
For more information about an error, try `rustc --explain E0277`.

0 commit comments

Comments
 (0)