]> git.lizzy.rs Git - rust.git/commitdiff
When expecting `BoxFuture` and using `async {}`, suggest `Box::pin`
authorEsteban Küber <esteban@kuber.com.ar>
Wed, 12 Feb 2020 01:19:05 +0000 (17:19 -0800)
committerEsteban Küber <esteban@kuber.com.ar>
Wed, 12 Feb 2020 23:13:04 +0000 (15:13 -0800)
src/librustc/traits/error_reporting/suggestions.rs
src/librustc_typeck/check/demand.rs
src/librustc_typeck/check/mod.rs
src/test/ui/suggestions/expected-boxed-future-isnt-pinned.fixed [new file with mode: 0644]
src/test/ui/suggestions/expected-boxed-future-isnt-pinned.rs [new file with mode: 0644]
src/test/ui/suggestions/expected-boxed-future-isnt-pinned.stderr [new file with mode: 0644]

index 60e55bd7bd9ad709512d90e672fbd518cfd785ba..82b73518d09a86d4e84ee6aa5b5f322df38b322d 100644 (file)
@@ -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,
index 3c2e02fc79b3ae81fc87ebafc035cfe3dba133cf..ac5214ca756b258a25bc5459e73f1747cd0d14b2 100644 (file)
@@ -25,6 +25,7 @@ pub fn emit_coerce_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);
     }
 
index be2052dce3c0b9f3232237f11fca5d3ebda0591c..03c1f97246df91cc1d78356a2a09d63975808112 100644 (file)
@@ -5038,10 +5038,46 @@ fn suggest_boxing_when_appropriate(
                 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 (file)
index 0000000..bddfd3a
--- /dev/null
@@ -0,0 +1,16 @@
+// 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() {}
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 (file)
index 0000000..51818d6
--- /dev/null
@@ -0,0 +1,16 @@
+// 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() {}
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 (file)
index 0000000..5e6f5c1
--- /dev/null
@@ -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::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`.