about summary refs log tree commit diff
diff options
context:
space:
mode:
authorJustin Ridgewell <justin@ridgewell.name>2022-08-08 20:20:45 -0400
committerJustin Ridgewell <justin@ridgewell.name>2022-08-08 21:05:56 -0400
commit5810c8188a2cfc36a8026ae068c985aa9a2f5f2b (patch)
tree56113cf9b774be9bbfe17dcb8e70bad28ad606e5
parent3792720086faccb3ee085558ad082c979785f437 (diff)
downloadrust-5810c8188a2cfc36a8026ae068c985aa9a2f5f2b.tar.gz
rust-5810c8188a2cfc36a8026ae068c985aa9a2f5f2b.zip
Implement IntoFuture type inference
-rw-r--r--crates/hir-expand/src/mod_path.rs1
-rw-r--r--crates/hir-expand/src/name.rs2
-rw-r--r--crates/hir-ty/src/infer.rs5
-rw-r--r--crates/hir-ty/src/tests/traits.rs25
-rw-r--r--crates/hir/src/lib.rs2
-rw-r--r--crates/hir/src/source_analyzer.rs2
-rw-r--r--crates/ide-assists/src/utils/suggest_name.rs1
-rw-r--r--crates/ide-completion/src/completions/keyword.rs44
-rw-r--r--crates/test-utils/src/minicore.rs15
9 files changed, 75 insertions, 22 deletions
diff --git a/crates/hir-expand/src/mod_path.rs b/crates/hir-expand/src/mod_path.rs
index fea09521e87..9ddafe01810 100644
--- a/crates/hir-expand/src/mod_path.rs
+++ b/crates/hir-expand/src/mod_path.rs
@@ -257,6 +257,7 @@ macro_rules! __known_path {
     (core::ops::RangeToInclusive) => {};
     (core::ops::RangeInclusive) => {};
     (core::future::Future) => {};
+    (core::future::IntoFuture) => {};
     (core::ops::Try) => {};
     ($path:path) => {
         compile_error!("Please register your known path in the path module")
diff --git a/crates/hir-expand/src/name.rs b/crates/hir-expand/src/name.rs
index 47d191822d8..757db79db4d 100644
--- a/crates/hir-expand/src/name.rs
+++ b/crates/hir-expand/src/name.rs
@@ -258,6 +258,7 @@ pub mod known {
         Try,
         Ok,
         Future,
+        IntoFuture,
         Result,
         Option,
         Output,
@@ -391,6 +392,7 @@ pub mod known {
         future_trait,
         index,
         index_mut,
+        into_future,
         mul_assign,
         mul,
         neg,
diff --git a/crates/hir-ty/src/infer.rs b/crates/hir-ty/src/infer.rs
index 46eeea0e6fc..95a7229e879 100644
--- a/crates/hir-ty/src/infer.rs
+++ b/crates/hir-ty/src/infer.rs
@@ -875,7 +875,10 @@ impl<'a> InferenceContext<'a> {
     }
 
     fn resolve_future_future_output(&self) -> Option<TypeAliasId> {
-        let trait_ = self.resolve_lang_item(name![future_trait])?.as_trait()?;
+        let trait_ = self
+            .resolver
+            .resolve_known_trait(self.db.upcast(), &path![core::future::IntoFuture])
+            .or_else(|| self.resolve_lang_item(name![future_trait])?.as_trait())?;
         self.db.trait_data(trait_).associated_type_by_name(&name![Output])
     }
 
diff --git a/crates/hir-ty/src/tests/traits.rs b/crates/hir-ty/src/tests/traits.rs
index 75802a5eb4d..730ebe2357d 100644
--- a/crates/hir-ty/src/tests/traits.rs
+++ b/crates/hir-ty/src/tests/traits.rs
@@ -138,6 +138,31 @@ fn not_send() -> Box<dyn Future<Output = ()> + 'static> {
 }
 
 #[test]
+fn into_future_trait() {
+    check_types(
+        r#"
+//- minicore: future
+struct Futurable;
+impl core::future::IntoFuture for Futurable {
+    type Output = u64;
+    type IntoFuture = IntFuture;
+}
+
+struct IntFuture;
+impl core::future::Future for IntFuture {
+    type Output = u64;
+}
+
+fn test() {
+    let r = Futurable;
+    let v = r.await;
+    v;
+} //^ u64
+"#,
+    );
+}
+
+#[test]
 fn infer_try() {
     check_types(
         r#"
diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs
index 8f984210e11..800ea58ba29 100644
--- a/crates/hir/src/lib.rs
+++ b/crates/hir/src/lib.rs
@@ -2780,6 +2780,8 @@ impl Type {
     /// Checks that particular type `ty` implements `std::future::Future`.
     /// This function is used in `.await` syntax completion.
     pub fn impls_future(&self, db: &dyn HirDatabase) -> bool {
+        // FIXME: This should be checking for IntoFuture trait, but I don't know how to find the
+        // right TraitId in this crate.
         let std_future_trait = db
             .lang_item(self.env.krate, SmolStr::new_inline("future_trait"))
             .and_then(|it| it.as_trait());
diff --git a/crates/hir/src/source_analyzer.rs b/crates/hir/src/source_analyzer.rs
index f5e2e443070..756772cf84e 100644
--- a/crates/hir/src/source_analyzer.rs
+++ b/crates/hir/src/source_analyzer.rs
@@ -269,6 +269,8 @@ impl SourceAnalyzer {
         db: &dyn HirDatabase,
         await_expr: &ast::AwaitExpr,
     ) -> Option<FunctionId> {
+        // FIXME This should be pointing to the poll of IntoFuture::Output's Future impl, but I
+        // don't know how to resolve the Output type so that we can query for its poll method.
         let ty = self.ty_of_expr(db, &await_expr.expr()?.into())?;
 
         let op_fn = db
diff --git a/crates/ide-assists/src/utils/suggest_name.rs b/crates/ide-assists/src/utils/suggest_name.rs
index 779cdbc93c5..68d59daef48 100644
--- a/crates/ide-assists/src/utils/suggest_name.rs
+++ b/crates/ide-assists/src/utils/suggest_name.rs
@@ -55,6 +55,7 @@ const USELESS_METHODS: &[&str] = &[
     "iter",
     "into_iter",
     "iter_mut",
+    "into_future",
 ];
 
 pub(crate) fn for_generic_parameter(ty: &ast::ImplTraitType) -> SmolStr {
diff --git a/crates/ide-completion/src/completions/keyword.rs b/crates/ide-completion/src/completions/keyword.rs
index 3989a451bde..032b23725f8 100644
--- a/crates/ide-completion/src/completions/keyword.rs
+++ b/crates/ide-completion/src/completions/keyword.rs
@@ -75,16 +75,17 @@ impl Future for A {}
 fn foo(a: A) { a.$0 }
 "#,
             expect![[r#"
-                kw await expr.await
-                sn box   Box::new(expr)
-                sn call  function(expr)
-                sn dbg   dbg!(expr)
-                sn dbgr  dbg!(&expr)
-                sn let   let
-                sn letm  let mut
-                sn match match expr {}
-                sn ref   &expr
-                sn refm  &mut expr
+                kw await                  expr.await
+                me into_future() (as IntoFuture) fn(self) -> <Self as IntoFuture>::IntoFuture
+                sn box                    Box::new(expr)
+                sn call                   function(expr)
+                sn dbg                    dbg!(expr)
+                sn dbgr                   dbg!(&expr)
+                sn let                    let
+                sn letm                   let mut
+                sn match                  match expr {}
+                sn ref                    &expr
+                sn refm                   &mut expr
             "#]],
         );
 
@@ -98,18 +99,19 @@ fn foo() {
 }
 "#,
             expect![[r#"
-                kw await expr.await
-                sn box   Box::new(expr)
-                sn call  function(expr)
-                sn dbg   dbg!(expr)
-                sn dbgr  dbg!(&expr)
-                sn let   let
-                sn letm  let mut
-                sn match match expr {}
-                sn ref   &expr
-                sn refm  &mut expr
+                kw await                  expr.await
+                me into_future() (use core::future::IntoFuture) fn(self) -> <Self as IntoFuture>::IntoFuture
+                sn box                    Box::new(expr)
+                sn call                   function(expr)
+                sn dbg                    dbg!(expr)
+                sn dbgr                   dbg!(&expr)
+                sn let                    let
+                sn letm                   let mut
+                sn match                  match expr {}
+                sn ref                    &expr
+                sn refm                   &mut expr
             "#]],
-        )
+        );
     }
 
     #[test]
diff --git a/crates/test-utils/src/minicore.rs b/crates/test-utils/src/minicore.rs
index f48d1ec66aa..6df29db4745 100644
--- a/crates/test-utils/src/minicore.rs
+++ b/crates/test-utils/src/minicore.rs
@@ -471,6 +471,21 @@ pub mod future {
         #[lang = "poll"]
         fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output>;
     }
+
+    pub trait IntoFuture {
+        type Output;
+        type IntoFuture: Future<Output = Self::Output>;
+        #[lang = "into_future"]
+        fn into_future(self) -> Self::IntoFuture;
+    }
+
+    impl<F: Future> IntoFuture for F {
+        type Output = F::Output;
+        type IntoFuture = F;
+        fn into_future(self) -> F {
+            self
+        }
+    }
 }
 pub mod task {
     pub enum Poll<T> {