Skip to content

Commit c39b04e

Browse files
committed
When expecting BoxFuture and using async {}, suggest Box::pin
1 parent 2d2be57 commit c39b04e

File tree

6 files changed

+101
-8
lines changed

6 files changed

+101
-8
lines changed

src/librustc/traits/error_reporting/suggestions.rs

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -701,10 +701,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
701701
})
702702
.collect::<Vec<_>>();
703703
// Add the suggestion for the return type.
704-
suggestions.push((
705-
ret_ty.span,
706-
format!("Box<{}{}>", if has_dyn { "" } else { "dyn " }, snippet),
707-
));
704+
suggestions.push((ret_ty.span, format!("Box<dyn {}>", trait_obj)));
708705
err.multipart_suggestion(
709706
"return a boxed trait object instead",
710707
suggestions,

src/librustc_typeck/check/demand.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
2525
self.suggest_compatible_variants(err, expr, expected, expr_ty);
2626
self.suggest_ref_or_into(err, expr, expected, expr_ty);
2727
self.suggest_boxing_when_appropriate(err, expr, expected, expr_ty);
28+
self.suggest_calling_boxed_future_when_appropriate(err, expr, expected, expr_ty);
2829
self.suggest_missing_await(err, expr, expected, expr_ty);
2930
}
3031

src/librustc_typeck/check/mod.rs

Lines changed: 40 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5038,10 +5038,46 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
50385038
Applicability::MachineApplicable,
50395039
);
50405040
err.note(
5041-
"for more on the distinction between the stack and the \
5042-
heap, read https://doc.rust-lang.org/book/ch15-01-box.html, \
5043-
https://doc.rust-lang.org/rust-by-example/std/box.html, and \
5044-
https://doc.rust-lang.org/std/boxed/index.html",
5041+
"for more on the distinction between the stack and the heap, read \
5042+
https://doc.rust-lang.org/book/ch15-01-box.html, \
5043+
https://doc.rust-lang.org/rust-by-example/std/box.html, and \
5044+
https://doc.rust-lang.org/std/boxed/index.html",
5045+
);
5046+
}
5047+
}
5048+
5049+
/// When encountering an `impl Future` where `BoxFuture` is expected, suggest `Box::pin`.
5050+
fn suggest_calling_boxed_future_when_appropriate(
5051+
&self,
5052+
err: &mut DiagnosticBuilder<'_>,
5053+
expr: &hir::Expr<'_>,
5054+
expected: Ty<'tcx>,
5055+
found: Ty<'tcx>,
5056+
) {
5057+
// Handle #68197.
5058+
5059+
if self.tcx.hir().is_const_context(expr.hir_id) {
5060+
// Do not suggest `Box::new` in const context.
5061+
return;
5062+
}
5063+
let pin_did = self.tcx.lang_items().pin_type();
5064+
match expected.kind {
5065+
ty::Adt(def, _) if Some(def.did) != pin_did => return,
5066+
// This guards the `unwrap` and `mk_box` below.
5067+
_ if pin_did.is_none() || self.tcx.lang_items().owned_box().is_none() => return,
5068+
_ => {}
5069+
}
5070+
let boxed_found = self.tcx.mk_box(found);
5071+
let new_found = self.tcx.mk_lang_item(boxed_found, lang_items::PinTypeLangItem).unwrap();
5072+
if let (true, Ok(snippet)) = (
5073+
self.can_coerce(new_found, expected),
5074+
self.sess().source_map().span_to_snippet(expr.span),
5075+
) {
5076+
err.span_suggestion(
5077+
expr.span,
5078+
"you need to pin and box this expression",
5079+
format!("Box::pin({})", snippet),
5080+
Applicability::MachineApplicable,
50455081
);
50465082
}
50475083
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
// edition:2018
2+
// run-rustfix
3+
#![allow(dead_code)]
4+
use std::future::Future;
5+
use std::pin::Pin;
6+
7+
type BoxFuture<'a, T> = Pin<Box<dyn Future<Output = T> + Send + 'a>>;
8+
// ^^^^^^^^^ This would come from the `futures` crate in real code.
9+
10+
fn foo() -> BoxFuture<'static, i32> {
11+
Box::pin(async { //~ ERROR mismatched types
12+
42
13+
})
14+
}
15+
16+
fn main() {}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
// edition:2018
2+
// run-rustfix
3+
#![allow(dead_code)]
4+
use std::future::Future;
5+
use std::pin::Pin;
6+
7+
type BoxFuture<'a, T> = Pin<Box<dyn Future<Output = T> + Send + 'a>>;
8+
// ^^^^^^^^^ This would come from the `futures` crate in real code.
9+
10+
fn foo() -> BoxFuture<'static, i32> {
11+
async { //~ ERROR mismatched types
12+
42
13+
}
14+
}
15+
16+
fn main() {}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
error[E0308]: mismatched types
2+
--> $DIR/expected-boxed-future-isnt-pinned.rs:11:5
3+
|
4+
LL | fn foo() -> BoxFuture<'static, i32> {
5+
| ----------------------- expected `std::pin::Pin<std::boxed::Box<(dyn std::future::Future<Output = i32> + std::marker::Send + 'static)>>` because of return type
6+
LL | / async {
7+
LL | | 42
8+
LL | | }
9+
| |_____^ expected struct `std::pin::Pin`, found opaque type
10+
|
11+
::: $SRC_DIR/libstd/future.rs:LL:COL
12+
|
13+
LL | pub fn from_generator<T: Generator<Yield = ()>>(x: T) -> impl Future<Output = T::Return> {
14+
| ------------------------------- the found opaque type
15+
|
16+
= note: expected struct `std::pin::Pin<std::boxed::Box<(dyn std::future::Future<Output = i32> + std::marker::Send + 'static)>>`
17+
found opaque type `impl std::future::Future`
18+
help: you need to pin and box this expression
19+
|
20+
LL | Box::pin(async {
21+
LL | 42
22+
LL | })
23+
|
24+
25+
error: aborting due to previous error
26+
27+
For more information about this error, try `rustc --explain E0308`.

0 commit comments

Comments
 (0)