From c39b04ea851b821359534b540c0babb97de24122 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Tue, 11 Feb 2020 17:19:05 -0800 Subject: [PATCH 1/5] When expecting `BoxFuture` and using `async {}`, suggest `Box::pin` --- .../traits/error_reporting/suggestions.rs | 5 +-- src/librustc_typeck/check/demand.rs | 1 + src/librustc_typeck/check/mod.rs | 44 +++++++++++++++++-- .../expected-boxed-future-isnt-pinned.fixed | 16 +++++++ .../expected-boxed-future-isnt-pinned.rs | 16 +++++++ .../expected-boxed-future-isnt-pinned.stderr | 27 ++++++++++++ 6 files changed, 101 insertions(+), 8 deletions(-) create mode 100644 src/test/ui/suggestions/expected-boxed-future-isnt-pinned.fixed create mode 100644 src/test/ui/suggestions/expected-boxed-future-isnt-pinned.rs create mode 100644 src/test/ui/suggestions/expected-boxed-future-isnt-pinned.stderr diff --git a/src/librustc/traits/error_reporting/suggestions.rs b/src/librustc/traits/error_reporting/suggestions.rs index 60e55bd7bd9ad..82b73518d09a8 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::>(); // 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", 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 3c2e02fc79b3a..ac5214ca756b2 100644 --- a/src/librustc_typeck/check/demand.rs +++ b/src/librustc_typeck/check/demand.rs @@ -25,6 +25,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { 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); } diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index be2052dce3c0b..03c1f97246df9 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -5038,10 +5038,46 @@ 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>, + ) { + // 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, ); } } diff --git a/src/test/ui/suggestions/expected-boxed-future-isnt-pinned.fixed b/src/test/ui/suggestions/expected-boxed-future-isnt-pinned.fixed new file mode 100644 index 0000000000000..bddfd3ac9ccf0 --- /dev/null +++ b/src/test/ui/suggestions/expected-boxed-future-isnt-pinned.fixed @@ -0,0 +1,16 @@ +// edition:2018 +// run-rustfix +#![allow(dead_code)] +use std::future::Future; +use std::pin::Pin; + +type BoxFuture<'a, T> = Pin + 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() {} 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 0000000000000..51818d6ae8f69 --- /dev/null +++ b/src/test/ui/suggestions/expected-boxed-future-isnt-pinned.rs @@ -0,0 +1,16 @@ +// edition:2018 +// run-rustfix +#![allow(dead_code)] +use std::future::Future; +use std::pin::Pin; + +type BoxFuture<'a, T> = Pin + Send + 'a>>; +// ^^^^^^^^^ This would come from the `futures` crate in real code. + +fn foo() -> BoxFuture<'static, i32> { + async { //~ ERROR mismatched types + 42 + } +} + +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 0000000000000..5e6f5c13b7a60 --- /dev/null +++ b/src/test/ui/suggestions/expected-boxed-future-isnt-pinned.stderr @@ -0,0 +1,27 @@ +error[E0308]: mismatched types + --> $DIR/expected-boxed-future-isnt-pinned.rs:11:5 + | +LL | fn foo() -> BoxFuture<'static, i32> { + | ----------------------- expected `std::pin::Pin + 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>(x: T) -> impl Future { + | ------------------------------- the found opaque type + | + = note: expected struct `std::pin::Pin + 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`. From a852fb74131af7473bafb03d0f3994a0e9f597d5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Tue, 11 Feb 2020 17:35:04 -0800 Subject: [PATCH 2/5] Remove std lib `Span` from expected boxed future test --- .../expected-boxed-future-isnt-pinned.fixed | 7 ++-- .../expected-boxed-future-isnt-pinned.rs | 7 ++-- .../expected-boxed-future-isnt-pinned.stderr | 33 ++++++++----------- 3 files changed, 19 insertions(+), 28 deletions(-) diff --git a/src/test/ui/suggestions/expected-boxed-future-isnt-pinned.fixed b/src/test/ui/suggestions/expected-boxed-future-isnt-pinned.fixed index bddfd3ac9ccf0..9c68de7bacec6 100644 --- a/src/test/ui/suggestions/expected-boxed-future-isnt-pinned.fixed +++ b/src/test/ui/suggestions/expected-boxed-future-isnt-pinned.fixed @@ -7,10 +7,9 @@ use std::pin::Pin; type BoxFuture<'a, T> = Pin + 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 foo + Send + 'static>(x: F) -> BoxFuture<'static, i32> { + // We could instead use an `async` block, but this way we have no std spans. + Box::pin(x) //~ ERROR mismatched types } fn main() {} diff --git a/src/test/ui/suggestions/expected-boxed-future-isnt-pinned.rs b/src/test/ui/suggestions/expected-boxed-future-isnt-pinned.rs index 51818d6ae8f69..0b5200fc25ca0 100644 --- a/src/test/ui/suggestions/expected-boxed-future-isnt-pinned.rs +++ b/src/test/ui/suggestions/expected-boxed-future-isnt-pinned.rs @@ -7,10 +7,9 @@ use std::pin::Pin; type BoxFuture<'a, T> = Pin + Send + 'a>>; // ^^^^^^^^^ This would come from the `futures` crate in real code. -fn foo() -> BoxFuture<'static, i32> { - async { //~ ERROR mismatched types - 42 - } +fn foo + 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 } 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 index 5e6f5c13b7a60..5e54fc246a20f 100644 --- a/src/test/ui/suggestions/expected-boxed-future-isnt-pinned.stderr +++ b/src/test/ui/suggestions/expected-boxed-future-isnt-pinned.stderr @@ -1,26 +1,19 @@ error[E0308]: mismatched types - --> $DIR/expected-boxed-future-isnt-pinned.rs:11:5 + --> $DIR/expected-boxed-future-isnt-pinned.rs:12:5 | -LL | fn foo() -> BoxFuture<'static, i32> { - | ----------------------- expected `std::pin::Pin + 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>(x: T) -> impl Future { - | ------------------------------- the found opaque type - | - = note: expected struct `std::pin::Pin + 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 | }) +LL | fn foo + Send + 'static>(x: F) -> BoxFuture<'static, i32> { + | - this type parameter ----------------------- expected `std::pin::Pin + 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::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 From 80cdb0af7dd27471e1e4a4362e2473a9331a5fdd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Wed, 12 Feb 2020 11:11:55 -0800 Subject: [PATCH 3/5] Account for `Box::new(impl Future)` and emit help `use Box::pin` --- src/librustc_typeck/check/demand.rs | 4 +- src/librustc_typeck/check/mod.rs | 30 +++++++---- .../expected-boxed-future-isnt-pinned.fixed | 15 ------ .../expected-boxed-future-isnt-pinned.rs | 13 ++++- .../expected-boxed-future-isnt-pinned.stderr | 52 +++++++++++++++++-- 5 files changed, 84 insertions(+), 30 deletions(-) delete mode 100644 src/test/ui/suggestions/expected-boxed-future-isnt-pinned.fixed diff --git a/src/librustc_typeck/check/demand.rs b/src/librustc_typeck/check/demand.rs index ac5214ca756b2..4a98095ec89c6 100644 --- a/src/librustc_typeck/check/demand.rs +++ b/src/librustc_typeck/check/demand.rs @@ -24,8 +24,10 @@ 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_calling_boxed_future_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 03c1f97246df9..6d37526df2c22 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -5053,18 +5053,18 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { 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; + return false; } let pin_did = self.tcx.lang_items().pin_type(); match expected.kind { - ty::Adt(def, _) if Some(def.did) != pin_did => return, + 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, + _ if pin_did.is_none() || self.tcx.lang_items().owned_box().is_none() => return false, _ => {} } let boxed_found = self.tcx.mk_box(found); @@ -5073,12 +5073,22 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { 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, - ); + 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 } } diff --git a/src/test/ui/suggestions/expected-boxed-future-isnt-pinned.fixed b/src/test/ui/suggestions/expected-boxed-future-isnt-pinned.fixed deleted file mode 100644 index 9c68de7bacec6..0000000000000 --- a/src/test/ui/suggestions/expected-boxed-future-isnt-pinned.fixed +++ /dev/null @@ -1,15 +0,0 @@ -// edition:2018 -// run-rustfix -#![allow(dead_code)] -use std::future::Future; -use std::pin::Pin; - -type BoxFuture<'a, T> = Pin + Send + 'a>>; -// ^^^^^^^^^ This would come from the `futures` crate in real code. - -fn foo + Send + 'static>(x: F) -> BoxFuture<'static, i32> { - // We could instead use an `async` block, but this way we have no std spans. - Box::pin(x) //~ ERROR mismatched types -} - -fn main() {} diff --git a/src/test/ui/suggestions/expected-boxed-future-isnt-pinned.rs b/src/test/ui/suggestions/expected-boxed-future-isnt-pinned.rs index 0b5200fc25ca0..fd40776539035 100644 --- a/src/test/ui/suggestions/expected-boxed-future-isnt-pinned.rs +++ b/src/test/ui/suggestions/expected-boxed-future-isnt-pinned.rs @@ -1,5 +1,4 @@ // edition:2018 -// run-rustfix #![allow(dead_code)] use std::future::Future; use std::pin::Pin; @@ -11,5 +10,17 @@ fn foo + 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 } +fn bar + Send + 'static>(x: F) -> BoxFuture<'static, i32> { + Box::new(x) //~ ERROR mismatched types + //~^ HELP use `Box::pin` +} +fn baz + Send + 'static>(x: F) -> BoxFuture<'static, i32> { + Pin::new(x) //~ ERROR mismatched types + //~^ ERROR the trait bound +} +fn qux + Send + 'static>(x: F) -> BoxFuture<'static, i32> { + Pin::new(Box::new(x)) //~ ERROR mismatched types + //~^ ERROR the trait bound +} 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 index 5e54fc246a20f..cf5ef1362db3f 100644 --- a/src/test/ui/suggestions/expected-boxed-future-isnt-pinned.stderr +++ b/src/test/ui/suggestions/expected-boxed-future-isnt-pinned.stderr @@ -1,5 +1,5 @@ error[E0308]: mismatched types - --> $DIR/expected-boxed-future-isnt-pinned.rs:12:5 + --> $DIR/expected-boxed-future-isnt-pinned.rs:11:5 | LL | fn foo + Send + 'static>(x: F) -> BoxFuture<'static, i32> { | - this type parameter ----------------------- expected `std::pin::Pin + std::marker::Send + 'static)>>` because of return type @@ -15,6 +15,52 @@ LL | x = 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 +error[E0308]: mismatched types + --> $DIR/expected-boxed-future-isnt-pinned.rs:14:5 + | +LL | fn bar + Send + 'static>(x: F) -> BoxFuture<'static, i32> { + | ----------------------- expected `std::pin::Pin + std::marker::Send + 'static)>>` because of return type +LL | Box::new(x) + | ^^^^^^^^^^^ expected struct `std::pin::Pin`, found struct `std::boxed::Box` + | + = note: expected struct `std::pin::Pin + std::marker::Send + 'static)>>` + found struct `std::boxed::Box` + = help: use `Box::pin` + +error[E0308]: mismatched types + --> $DIR/expected-boxed-future-isnt-pinned.rs:18:14 + | +LL | fn baz + Send + 'static>(x: F) -> BoxFuture<'static, i32> { + | - this type parameter +LL | Pin::new(x) + | ^ + | | + | expected struct `std::boxed::Box`, found type parameter `F` + | help: store this in the heap by calling `Box::new`: `Box::new(x)` + | + = note: expected struct `std::boxed::Box + std::marker::Send>` + 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 + = 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 + +error[E0277]: the trait bound `dyn std::future::Future + std::marker::Send: std::marker::Unpin` is not satisfied + --> $DIR/expected-boxed-future-isnt-pinned.rs:18:5 + | +LL | Pin::new(x) + | ^^^^^^^^ the trait `std::marker::Unpin` is not implemented for `dyn std::future::Future + std::marker::Send` + | + = note: required by `std::pin::Pin::

::new` + +error[E0277]: the trait bound `dyn std::future::Future + std::marker::Send: std::marker::Unpin` is not satisfied + --> $DIR/expected-boxed-future-isnt-pinned.rs:22:5 + | +LL | Pin::new(Box::new(x)) + | ^^^^^^^^ the trait `std::marker::Unpin` is not implemented for `dyn std::future::Future + std::marker::Send` + | + = note: required by `std::pin::Pin::

::new` + +error: aborting due to 5 previous errors -For more information about this error, try `rustc --explain E0308`. +Some errors have detailed explanations: E0277, E0308. +For more information about an error, try `rustc --explain E0277`. From c376fc001772200e2de8d7a610a5b67dcf642432 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Wed, 12 Feb 2020 11:51:07 -0800 Subject: [PATCH 4/5] Account for `Pin::new(_)` and `Pin::new(Box::new(_))` when `Box::pin(_)` would be applicable --- src/libcore/marker.rs | 7 +++++++ src/test/ui/generator/static-not-unpin.rs | 2 +- src/test/ui/generator/static-not-unpin.stderr | 2 +- .../expected-boxed-future-isnt-pinned.rs | 9 +++++---- .../expected-boxed-future-isnt-pinned.stderr | 14 ++++++++------ 5 files changed, 22 insertions(+), 12 deletions(-) diff --git a/src/libcore/marker.rs b/src/libcore/marker.rs index b4b595f330e22..5c35041249f36 100644 --- a/src/libcore/marker.rs +++ b/src/libcore/marker.rs @@ -727,6 +727,13 @@ unsafe impl Freeze for &mut T {} /// [`Pin

`]: ../pin/struct.Pin.html /// [`pin module`]: ../../std/pin/index.html #[stable(feature = "pin", since = "1.33.0")] +#[rustc_on_unimplemented( + on( + _Self = "dyn std::future::Future + std::marker::Send", + note = "consider using `Box::pin`", + ), + message = "`{Self}` cannot be unpinned" +)] #[lang = "unpin"] pub auto trait Unpin {} diff --git a/src/test/ui/generator/static-not-unpin.rs b/src/test/ui/generator/static-not-unpin.rs index b271e982fb420..cfcb94737be6f 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 f2b1078e2b532..6512d67319b0b 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) { diff --git a/src/test/ui/suggestions/expected-boxed-future-isnt-pinned.rs b/src/test/ui/suggestions/expected-boxed-future-isnt-pinned.rs index fd40776539035..eda579f7fb49e 100644 --- a/src/test/ui/suggestions/expected-boxed-future-isnt-pinned.rs +++ b/src/test/ui/suggestions/expected-boxed-future-isnt-pinned.rs @@ -10,17 +10,18 @@ fn foo + 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 } + fn bar + Send + 'static>(x: F) -> BoxFuture<'static, i32> { Box::new(x) //~ ERROR mismatched types - //~^ HELP use `Box::pin` } + fn baz + Send + 'static>(x: F) -> BoxFuture<'static, i32> { Pin::new(x) //~ ERROR mismatched types - //~^ ERROR the trait bound + //~^ ERROR E0277 } + fn qux + Send + 'static>(x: F) -> BoxFuture<'static, i32> { - Pin::new(Box::new(x)) //~ ERROR mismatched types - //~^ ERROR the trait bound + Pin::new(Box::new(x)) //~ ERROR E0277 } 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 index cf5ef1362db3f..783b118d2f9a2 100644 --- a/src/test/ui/suggestions/expected-boxed-future-isnt-pinned.stderr +++ b/src/test/ui/suggestions/expected-boxed-future-isnt-pinned.stderr @@ -16,7 +16,7 @@ LL | x = note: for more information, visit https://doc.rust-lang.org/book/ch10-02-traits.html#traits-as-parameters error[E0308]: mismatched types - --> $DIR/expected-boxed-future-isnt-pinned.rs:14:5 + --> $DIR/expected-boxed-future-isnt-pinned.rs:15:5 | LL | fn bar + Send + 'static>(x: F) -> BoxFuture<'static, i32> { | ----------------------- expected `std::pin::Pin + std::marker::Send + 'static)>>` because of return type @@ -28,7 +28,7 @@ LL | Box::new(x) = help: use `Box::pin` error[E0308]: mismatched types - --> $DIR/expected-boxed-future-isnt-pinned.rs:18:14 + --> $DIR/expected-boxed-future-isnt-pinned.rs:19:14 | LL | fn baz + Send + 'static>(x: F) -> BoxFuture<'static, i32> { | - this type parameter @@ -44,20 +44,22 @@ LL | Pin::new(x) = note: for more information, visit https://doc.rust-lang.org/book/ch10-02-traits.html#traits-as-parameters = 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 -error[E0277]: the trait bound `dyn std::future::Future + std::marker::Send: std::marker::Unpin` is not satisfied - --> $DIR/expected-boxed-future-isnt-pinned.rs:18:5 +error[E0277]: `dyn std::future::Future + std::marker::Send` cannot be unpinned + --> $DIR/expected-boxed-future-isnt-pinned.rs:19:5 | LL | Pin::new(x) | ^^^^^^^^ the trait `std::marker::Unpin` is not implemented for `dyn std::future::Future + std::marker::Send` | + = note: consider using `Box::pin` = note: required by `std::pin::Pin::

::new` -error[E0277]: the trait bound `dyn std::future::Future + std::marker::Send: std::marker::Unpin` is not satisfied - --> $DIR/expected-boxed-future-isnt-pinned.rs:22:5 +error[E0277]: `dyn std::future::Future + std::marker::Send` cannot be unpinned + --> $DIR/expected-boxed-future-isnt-pinned.rs:24:5 | LL | Pin::new(Box::new(x)) | ^^^^^^^^ the trait `std::marker::Unpin` is not implemented for `dyn std::future::Future + std::marker::Send` | + = note: consider using `Box::pin` = note: required by `std::pin::Pin::

::new` error: aborting due to 5 previous errors From 248f5a4046ab5a90189f37c305c759b7cde8acb3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Wed, 12 Feb 2020 16:50:28 -0800 Subject: [PATCH 5/5] Add trait `Self` filtering to `rustc_on_unimplemented` --- src/libcore/marker.rs | 5 +- .../error_reporting/on_unimplemented.rs | 10 ++++ .../expected-boxed-future-isnt-pinned.rs | 26 +++++----- .../expected-boxed-future-isnt-pinned.stderr | 52 +------------------ 4 files changed, 27 insertions(+), 66 deletions(-) diff --git a/src/libcore/marker.rs b/src/libcore/marker.rs index 5c35041249f36..2800f11cc01b1 100644 --- a/src/libcore/marker.rs +++ b/src/libcore/marker.rs @@ -728,10 +728,7 @@ unsafe impl Freeze for &mut T {} /// [`pin module`]: ../../std/pin/index.html #[stable(feature = "pin", since = "1.33.0")] #[rustc_on_unimplemented( - on( - _Self = "dyn std::future::Future + std::marker::Send", - note = "consider using `Box::pin`", - ), + on(_Self = "std::future::Future", note = "consider using `Box::pin`",), message = "`{Self}` cannot be unpinned" )] #[lang = "unpin"] diff --git a/src/librustc/traits/error_reporting/on_unimplemented.rs b/src/librustc/traits/error_reporting/on_unimplemented.rs index 2ba12baaf6d6e..ab2d74b1c8deb 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/test/ui/suggestions/expected-boxed-future-isnt-pinned.rs b/src/test/ui/suggestions/expected-boxed-future-isnt-pinned.rs index eda579f7fb49e..0a1686eac9d34 100644 --- a/src/test/ui/suggestions/expected-boxed-future-isnt-pinned.rs +++ b/src/test/ui/suggestions/expected-boxed-future-isnt-pinned.rs @@ -11,17 +11,19 @@ fn foo + Send + 'static>(x: F) -> BoxFuture<'static, i32> x //~ ERROR mismatched types } -fn bar + Send + 'static>(x: F) -> BoxFuture<'static, i32> { - Box::new(x) //~ ERROR mismatched types -} - -fn baz + Send + 'static>(x: F) -> BoxFuture<'static, i32> { - Pin::new(x) //~ ERROR mismatched types - //~^ ERROR E0277 -} - -fn qux + Send + 'static>(x: F) -> BoxFuture<'static, i32> { - Pin::new(Box::new(x)) //~ ERROR E0277 -} +// 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 + Send + 'static>(x: F) -> BoxFuture<'static, i32> { +// Box::new(x) +// } +// +// fn baz + Send + 'static>(x: F) -> BoxFuture<'static, i32> { +// Pin::new(x) +// } +// +// fn qux + 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 index 783b118d2f9a2..48d941283b62d 100644 --- a/src/test/ui/suggestions/expected-boxed-future-isnt-pinned.stderr +++ b/src/test/ui/suggestions/expected-boxed-future-isnt-pinned.stderr @@ -15,54 +15,6 @@ LL | x = 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[E0308]: mismatched types - --> $DIR/expected-boxed-future-isnt-pinned.rs:15:5 - | -LL | fn bar + Send + 'static>(x: F) -> BoxFuture<'static, i32> { - | ----------------------- expected `std::pin::Pin + std::marker::Send + 'static)>>` because of return type -LL | Box::new(x) - | ^^^^^^^^^^^ expected struct `std::pin::Pin`, found struct `std::boxed::Box` - | - = note: expected struct `std::pin::Pin + std::marker::Send + 'static)>>` - found struct `std::boxed::Box` - = help: use `Box::pin` - -error[E0308]: mismatched types - --> $DIR/expected-boxed-future-isnt-pinned.rs:19:14 - | -LL | fn baz + Send + 'static>(x: F) -> BoxFuture<'static, i32> { - | - this type parameter -LL | Pin::new(x) - | ^ - | | - | expected struct `std::boxed::Box`, found type parameter `F` - | help: store this in the heap by calling `Box::new`: `Box::new(x)` - | - = note: expected struct `std::boxed::Box + std::marker::Send>` - 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 - = 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 - -error[E0277]: `dyn std::future::Future + std::marker::Send` cannot be unpinned - --> $DIR/expected-boxed-future-isnt-pinned.rs:19:5 - | -LL | Pin::new(x) - | ^^^^^^^^ the trait `std::marker::Unpin` is not implemented for `dyn std::future::Future + std::marker::Send` - | - = note: consider using `Box::pin` - = note: required by `std::pin::Pin::

::new` - -error[E0277]: `dyn std::future::Future + std::marker::Send` cannot be unpinned - --> $DIR/expected-boxed-future-isnt-pinned.rs:24:5 - | -LL | Pin::new(Box::new(x)) - | ^^^^^^^^ the trait `std::marker::Unpin` is not implemented for `dyn std::future::Future + std::marker::Send` - | - = note: consider using `Box::pin` - = note: required by `std::pin::Pin::

::new` - -error: aborting due to 5 previous errors +error: aborting due to previous error -Some errors have detailed explanations: E0277, E0308. -For more information about an error, try `rustc --explain E0277`. +For more information about this error, try `rustc --explain E0308`.