diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/libcore/marker.rs | 4 | ||||
| -rw-r--r-- | src/librustc/traits/error_reporting/on_unimplemented.rs | 10 | ||||
| -rw-r--r-- | src/librustc/traits/error_reporting/suggestions.rs | 5 | ||||
| -rw-r--r-- | src/librustc_typeck/check/demand.rs | 3 | ||||
| -rw-r--r-- | src/librustc_typeck/check/mod.rs | 54 | ||||
| -rw-r--r-- | src/test/ui/generator/static-not-unpin.rs | 2 | ||||
| -rw-r--r-- | src/test/ui/generator/static-not-unpin.stderr | 2 | ||||
| -rw-r--r-- | src/test/ui/suggestions/expected-boxed-future-isnt-pinned.rs | 29 | ||||
| -rw-r--r-- | src/test/ui/suggestions/expected-boxed-future-isnt-pinned.stderr | 20 |
9 files changed, 119 insertions, 10 deletions
diff --git a/src/libcore/marker.rs b/src/libcore/marker.rs index b4b595f330e..2800f11cc01 100644 --- a/src/libcore/marker.rs +++ b/src/libcore/marker.rs @@ -727,6 +727,10 @@ unsafe impl<T: ?Sized> Freeze for &mut T {} /// [`Pin<P>`]: ../pin/struct.Pin.html /// [`pin module`]: ../../std/pin/index.html #[stable(feature = "pin", since = "1.33.0")] +#[rustc_on_unimplemented( + on(_Self = "std::future::Future", note = "consider using `Box::pin`",), + message = "`{Self}` cannot be unpinned" +)] #[lang = "unpin"] pub auto trait Unpin {} diff --git a/src/librustc/traits/error_reporting/on_unimplemented.rs b/src/librustc/traits/error_reporting/on_unimplemented.rs index 2ba12baaf6d..ab2d74b1c8d 100644 --- a/src/librustc/traits/error_reporting/on_unimplemented.rs +++ b/src/librustc/traits/error_reporting/on_unimplemented.rs @@ -201,6 +201,16 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { } } } + 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)))) + } + _ => {} + } + } + } if let Ok(Some(command)) = OnUnimplementedDirective::of_item(self.tcx, trait_ref.def_id, def_id) diff --git a/src/librustc/traits/error_reporting/suggestions.rs b/src/librustc/traits/error_reporting/suggestions.rs index 60e55bd7bd9..82b73518d09 100644 --- a/src/librustc/traits/error_reporting/suggestions.rs +++ b/src/librustc/traits/error_reporting/suggestions.rs @@ -701,10 +701,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { }) .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, diff --git a/src/librustc_typeck/check/demand.rs b/src/librustc_typeck/check/demand.rs index 3c2e02fc79b..4a98095ec89 100644 --- a/src/librustc_typeck/check/demand.rs +++ b/src/librustc_typeck/check/demand.rs @@ -24,6 +24,9 @@ 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_missing_await(err, expr, expected, expr_ty); } diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 0bdf7ba1a56..fd0c994a6ea 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -5038,14 +5038,60 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { 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>, + ) -> 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 + } + } + /// A common error is to forget to add a semicolon at the end of a block, e.g., /// /// ``` diff --git a/src/test/ui/generator/static-not-unpin.rs b/src/test/ui/generator/static-not-unpin.rs index b271e982fb4..cfcb94737be 100644 --- a/src/test/ui/generator/static-not-unpin.rs +++ b/src/test/ui/generator/static-not-unpin.rs @@ -11,5 +11,5 @@ fn main() { let mut generator = static || { yield; }; - assert_unpin(generator); //~ ERROR std::marker::Unpin` is not satisfied + assert_unpin(generator); //~ ERROR E0277 } diff --git a/src/test/ui/generator/static-not-unpin.stderr b/src/test/ui/generator/static-not-unpin.stderr index f2b1078e2b5..6512d67319b 100644 --- a/src/test/ui/generator/static-not-unpin.stderr +++ b/src/test/ui/generator/static-not-unpin.stderr @@ -1,4 +1,4 @@ -error[E0277]: the trait bound `[static generator@$DIR/static-not-unpin.rs:11:25: 13:6 _]: std::marker::Unpin` is not satisfied +error[E0277]: `[static generator@$DIR/static-not-unpin.rs:11:25: 13:6 _]` cannot be unpinned --> $DIR/static-not-unpin.rs:14:18 | LL | fn assert_unpin<T: Unpin>(_: T) { diff --git a/src/test/ui/suggestions/expected-boxed-future-isnt-pinned.rs b/src/test/ui/suggestions/expected-boxed-future-isnt-pinned.rs new file mode 100644 index 00000000000..0a1686eac9d --- /dev/null +++ b/src/test/ui/suggestions/expected-boxed-future-isnt-pinned.rs @@ -0,0 +1,29 @@ +// 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() {} diff --git a/src/test/ui/suggestions/expected-boxed-future-isnt-pinned.stderr b/src/test/ui/suggestions/expected-boxed-future-isnt-pinned.stderr new file mode 100644 index 00000000000..48d941283b6 --- /dev/null +++ b/src/test/ui/suggestions/expected-boxed-future-isnt-pinned.stderr @@ -0,0 +1,20 @@ +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`. |
