Change:
gives The in particular is confusing. This can be a pretty intimidating error message for someone new to async/await, when all they forgot was . I'm not sure if we can fix this without stabilizing so we can sprinkle some magic compiler dust on its error messages. Maybe there's something we can do, though. Maybe some intelligent use of type aliases in our error messages? cc
This can be handled without needing to stabilize the struct. It should act the same way that the primitive type cast suggestions do.
Some observations: There is no struct, it's a type-alias We could suggest invoking but that is a method defined only in the futures crate, which feels a bit awkward to me; I'd rather it were part of libstd We can* suggest as well ()
marking as OnDeck, since BoxFuture gets used quite often
I have a PR that suggests the right code for this: <img width="1269" alt="Screen Shot 2020-02-11 at 5 09 37 PM" src="https://user-"But if first you try : <img width="1271" alt="Screen Shot 2020-02-11 at 5 10 12 PM" src="https://user-"or : <img width="1303" alt="Screen Shot 2020-02-11 at 5 11 11 PM" src="https://user-"we will send you in a wild goose chase: <img width="946" alt="Screen Shot 2020-02-11 at 5 10 53 PM" src="https://user-"
Filed for the uncovered cases.

Discussion:
/// [`Pin<P>`]: ../pin/struct.Pin.html /// [`pin module`]: ../../std/pin/index.html #[stable(feature = "pin", since = "1.33.0")] <ins> #[rustc_on_unimplemented( on(_Self = "std::future::Future", note = "consider using `Box::pin`",), message = "`{Self}` cannot be unpinned" )] </ins> #[lang = "unpin"] pub auto trait Unpin {}

} } } <ins> if let ty::Dynamic(traits, _) = self_ty.kind { for t in *traits.skip_binder() { match t { ty::ExistentialPredicate::Trait(trait_ref) => { flags.push((sym::_Self, Some(self.tcx.def_path_str(trait_ref.def_id)))) } _ => {} } } } </ins> if let Ok(Some(command)) = OnUnimplementedDirective::of_item(self.tcx, trait_ref.def_id, def_id)

}) .collect::<Vec<_>>(); // Add the suggestion for the return type. <del> suggestions.push(( ret_ty.span, format!("Box<{}{}>", if has_dyn { "" } else { "dyn " }, snippet), )); </del> <ins> suggestions.push((ret_ty.span, format!("Box<dyn {}>", trait_obj))); </ins> err.multipart_suggestion( "return a boxed trait object instead", suggestions,

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); <ins> if self.suggest_calling_boxed_future_when_appropriate(err, expr, expected, expr_ty) { return; } </ins> self.suggest_boxing_when_appropriate(err, expr, expected, expr_ty); self.suggest_missing_await(err, expr, expected, expr_ty); }

Applicability::MachineApplicable, ); err.note( <del> "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", </del> <ins> "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", </ins> ); } } <ins> /// 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>, ) -> bool { // Handle #68197. if self.tcx.hir().is_const_context(expr.hir_id) { // Do not suggest `Box::new` in const context. return false; } let pin_did = self.tcx.lang_items().pin_type(); match expected.kind { 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 false, _ => {} } 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), ) { 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 } } </ins> /// A common error is to forget to add a semicolon at the end of a block, e.g., /// /// ```

let mut generator = static || { yield; }; <del> assert_unpin(generator); //~ ERROR std::marker::Unpin` is not satisfied </del> <ins> assert_unpin(generator); //~ ERROR E0277 </ins> }

<del> error[E0277]: the trait bound `[static generator@$DIR/static-not-unpin.rs:11:25: 13:6 _]: std::marker::Unpin` is not satisfied </del> <ins> error[E0277]: `[static generator@$DIR/static-not-unpin.rs:11:25: 13:6 _]` cannot be unpinned </ins> --> $DIR/static-not-unpin.rs:14:18 | LL | fn assert_unpin<T: Unpin>(_: T) {

<ins> // edition:2018 #![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. x //~ ERROR mismatched types } // FIXME: uncomment these once this commit is in Beta and we can rely on `rustc_on_unimplemented` //        having filtering for `Self` being a trait. // // fn bar<F: Future<Output=i32> + Send + 'static>(x: F) -> BoxFuture<'static, i32> { //     Box::new(x) // } // // fn baz<F: Future<Output=i32> + Send + 'static>(x: F) -> BoxFuture<'static, i32> { //     Pin::new(x) // } // // fn qux<F: Future<Output=i32> + Send + 'static>(x: F) -> BoxFuture<'static, i32> { //     Pin::new(Box::new(x)) // } fn main() {} </ins>

<ins> error[E0308]: mismatched types --> $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 LL |     // We could instead use an `async` block, but this way we have no std spans. LL |     x |     ^ |     | |     expected struct `std::pin::Pin`, found type parameter `F` |     help: you need to pin and box this expression: `Box::pin(x)` | = note:      expected struct `std::pin::Pin<std::boxed::Box<(dyn std::future::Future<Output = i32> + std::marker::Send + 'static)>>` 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 error: aborting due to previous error For more information about this error, try `rustc --explain E0308`. </ins>