about summary refs log tree commit diff
diff options
context:
space:
mode:
authorJustin Ridgewell <justin@ridgewell.name>2022-08-09 16:25:25 -0400
committerJustin Ridgewell <justin@ridgewell.name>2022-08-09 16:39:14 -0400
commitdc3219bb11f032e2e6f1d16deab2b5eabe9463d7 (patch)
treecff9427420bc3b139891e71dfa2885b062b9c587
parent5810c8188a2cfc36a8026ae068c985aa9a2f5f2b (diff)
downloadrust-dc3219bb11f032e2e6f1d16deab2b5eabe9463d7.tar.gz
rust-dc3219bb11f032e2e6f1d16deab2b5eabe9463d7.zip
Suggest `.await` when type impls IntoFuture
-rw-r--r--crates/hir/src/lib.rs23
-rw-r--r--crates/ide-completion/src/completions/keyword.rs26
2 files changed, 42 insertions, 7 deletions
diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs
index 800ea58ba29..7f16634afe1 100644
--- a/crates/hir/src/lib.rs
+++ b/crates/hir/src/lib.rs
@@ -2780,19 +2780,28 @@ 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());
-        let std_future_trait = match std_future_trait {
+        let trait_ = db
+            .lang_item(self.env.krate, SmolStr::new_inline("into_future"))
+            .and_then(|it| {
+                let into_future_fn = it.as_function()?;
+                let assoc_item = as_assoc_item(db, AssocItem::Function, into_future_fn)?;
+                let into_future_trait = assoc_item.containing_trait_or_trait_impl(db)?;
+                Some(into_future_trait.id)
+            })
+            .or_else(|| {
+                let future_trait =
+                    db.lang_item(self.env.krate, SmolStr::new_inline("future_trait"))?;
+                future_trait.as_trait()
+            });
+
+        let trait_ = match trait_ {
             Some(it) => it,
             None => return false,
         };
 
         let canonical_ty =
             Canonical { value: self.ty.clone(), binders: CanonicalVarKinds::empty(Interner) };
-        method_resolution::implements_trait(&canonical_ty, db, self.env.clone(), std_future_trait)
+        method_resolution::implements_trait(&canonical_ty, db, self.env.clone(), trait_)
     }
 
     /// Checks that particular type `ty` implements `std::ops::FnOnce`.
diff --git a/crates/ide-completion/src/completions/keyword.rs b/crates/ide-completion/src/completions/keyword.rs
index 032b23725f8..1d03c8cc5ca 100644
--- a/crates/ide-completion/src/completions/keyword.rs
+++ b/crates/ide-completion/src/completions/keyword.rs
@@ -115,6 +115,32 @@ fn foo() {
     }
 
     #[test]
+    fn test_completion_await_impls_into_future() {
+        check(
+            r#"
+//- minicore: future
+use core::future::*;
+struct A {}
+impl IntoFuture for A {}
+fn foo(a: A) { a.$0 }
+"#,
+            expect![[r#"
+                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
+            "#]],
+        );
+    }
+
+    #[test]
     fn let_semi() {
         cov_mark::check!(let_semi);
         check_edit(