Auto merge of #12982 - jridgewell:into_future, r=Veykril

Implement IntoFuture type inference

One of my projects is using [IntoFuture](https://doc.rust-lang.org/std/future/trait.IntoFuture.html) to make our async code a little less verbose. However, rust-analyzer can't infer the output type of an await expression if the value uses `IntoFuture` to convert into another type. So we're getting `{unknown}` types everywhere since switching.

`foo.await` itself [desugars](e4417cf020/compiler/rustc_ast_lowering/src/expr.rs (L644-L658)) into a `match into_future(foo) {}`, with every `Future` impl getting a [default](e4417cf020/library/core/src/future/into_future.rs (L131-L139)) `IntoFuture` implementation. I'm not sure if we want to disable the old `future_trait` paths, since this only recently [stabilize](https://github.com/rust-lang/rust/pull/98718).
This commit is contained in:
bors 2022-08-18 07:37:47 +00:00
commit 1da9156b0d
11 changed files with 178 additions and 35 deletions

View file

@ -2778,20 +2778,32 @@ impl Type {
self.ty.is_unknown()
}
/// Checks that particular type `ty` implements `std::future::Future`.
/// Checks that particular type `ty` implements `std::future::IntoFuture` or
/// `std::future::Future`.
/// This function is used in `.await` syntax completion.
pub fn impls_future(&self, db: &dyn HirDatabase) -> bool {
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 {
pub fn impls_into_future(&self, db: &dyn HirDatabase) -> bool {
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`.