Unnamed repository; edit this file 'description' to name the repository.
Implement IntoFuture type inference
Justin Ridgewell 2022-08-09
parent 3792720 · commit 5810c81
-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 fea09521e8..9ddafe0181 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 47d191822d..757db79db4 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 46eeea0e6f..95a7229e87 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 75802a5eb4..730ebe2357 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 8f984210e1..800ea58ba2 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 f5e2e44307..756772cf84 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 779cdbc93c..68d59daef4 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 3989a451bd..032b23725f 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 f48d1ec66a..6df29db474 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> {