})
.collect::<Vec<_>>();
// Add the suggestion for the return type.
- suggestions.push((
- ret_ty.span,
- format!("Box<{}{}>", if has_dyn { "" } else { "dyn " }, snippet),
- ));
+ suggestions.push((ret_ty.span, format!("Box<dyn {}>", trait_obj)));
err.multipart_suggestion(
"return a boxed trait object instead",
suggestions,
self.suggest_compatible_variants(err, expr, expected, expr_ty);
self.suggest_ref_or_into(err, expr, expected, expr_ty);
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);
}
Applicability::MachineApplicable,
);
err.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",
+ "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",
+ );
+ }
+ }
+
+ /// When encountering an `impl Future` where `BoxFuture` is expected, suggest `Box::pin`.
+ fn suggest_calling_boxed_future_when_appropriate(
+ &self,
+ err: &mut DiagnosticBuilder<'_>,
+ expr: &hir::Expr<'_>,
+ expected: Ty<'tcx>,
+ found: Ty<'tcx>,
+ ) {
+ // Handle #68197.
+
+ if self.tcx.hir().is_const_context(expr.hir_id) {
+ // Do not suggest `Box::new` in const context.
+ return;
+ }
+ let pin_did = self.tcx.lang_items().pin_type();
+ match expected.kind {
+ ty::Adt(def, _) if Some(def.did) != pin_did => return,
+ // This guards the `unwrap` and `mk_box` below.
+ _ if pin_did.is_none() || self.tcx.lang_items().owned_box().is_none() => return,
+ _ => {}
+ }
+ let boxed_found = self.tcx.mk_box(found);
+ let new_found = self.tcx.mk_lang_item(boxed_found, lang_items::PinTypeLangItem).unwrap();
+ if let (true, Ok(snippet)) = (
+ 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,
);
}
}
--- /dev/null
+// 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() -> BoxFuture<'static, i32> {
+ Box::pin(async { //~ ERROR mismatched types
+ 42
+ })
+}
+
+fn main() {}
--- /dev/null
+// 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() -> BoxFuture<'static, i32> {
+ async { //~ ERROR mismatched types
+ 42
+ }
+}
+
+fn main() {}
--- /dev/null
+error[E0308]: mismatched types
+ --> $DIR/expected-boxed-future-isnt-pinned.rs:11:5
+ |
+LL | fn foo() -> 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 | / async {
+LL | | 42
+LL | | }
+ | |_____^ expected struct `std::pin::Pin`, found opaque type
+ |
+ ::: $SRC_DIR/libstd/future.rs:LL:COL
+ |
+LL | pub fn from_generator<T: Generator<Yield = ()>>(x: T) -> impl Future<Output = T::Return> {
+ | ------------------------------- the found opaque type
+ |
+ = note: expected struct `std::pin::Pin<std::boxed::Box<(dyn std::future::Future<Output = i32> + std::marker::Send + 'static)>>`
+ found opaque type `impl std::future::Future`
+help: you need to pin and box this expression
+ |
+LL | Box::pin(async {
+LL | 42
+LL | })
+ |
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0308`.