Repository: rust-analyzer/rust-analyzer (rust)

Issue:
Implement async blocks
We don't currently handle async blocks correctly:
```rust
let x = async { 1 }.await;
```
Basically, we just ignore the `async` modifier at the moment. We need to:
 - add the information whether the block is `async` to [`Expr::Block`](https://github.com/rust-analyzer/rust-analyzer/blob/690a0b249eee6537953350be28a0ca11fa96b12a/crates/ra_hir_def/src/expr.rs#L52-L55) and set this during [lowering](https://github.com/rust-analyzer/rust-analyzer/blob/690a0b249eee6537953350be28a0ca11fa96b12a/crates/ra_hir_def/src/body/lower.rs#L467) (this might need some adaptation to ast_src.rs and maybe even the parser to get the async token)
 - adapt [`infer_block`](https://github.com/rust-analyzer/rust-analyzer/blob/690a0b249eee6537953350be28a0ca11fa96b12a/crates/ra_hir_ty/src/infer/expr.rs#L521) to wrap the result in an `impl Future` if the block is async. This requires impl trait support, which we don't have at the moment but should be ready in Chalk soon.

Pull request:
Implement async blocks
Fix #4018

@flodiebold already gave a generic guide in the issue. Here's some concern about implementation detail:
- Chalk doesn't support generator type yet.
- Adding generator type as a brand new type (ctor) can be complex and need to *re-introduced* builtin impls. (Like how we implement closures before native closure support of chalk, which is already removed in #5401 )
- The output type of async block should be known after type inference of the whole body.
  - We cannot directly get the type from source like return-positon-impl-trait. But we still need to provide trait bounds when chalk asking for `opaque_ty_data`.
  - During the inference, the output type of async block can be temporary unknown and participate the later inference.
    `let a = async { None }; let _: i32 = a.await.unwrap();`

So in this PR, the type of async blocks is inferred as an opaque type parameterized by the `Future::Output` type it should be, like what we do with closure type.
And it really works now.

Well, I still have some questions:
- The bounds `AsyncBlockImplType<T>: Future<Output = T>` is currently generated in `opaque_ty_data`. I'm not sure if we should put this code here.
- Type of async block is now rendered as `impl Future<Output = OutputType>`. Do we need to special display to hint that it's a async block? Note that closure type has its special format, instead of `impl Fn(..) -> ..` or function type.



Patch:
diff --git a/Cargo.lock b/Cargo.lock
index 9ebb15a96a..a6dc0dc4b9 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -129,9 +129,9 @@ checksum = "08c48aae112d48ed9f069b33538ea9e3e90aa263cfa3d1c24309612b1f7472de"
 
 [[package]]
 name = "cargo_metadata"
-version = "0.11.2"
+version = "0.11.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c990b1694d29f8e477f456db1b2fcd5dd1cd6e29d5be082df45213e8834eb39a"
+checksum = "89fec17b16f1ac67908af82e47d0a90a7afd0e1827b181cd77504323d3263d35"
 dependencies = [
  "semver",
  "serde",
@@ -252,12 +252,12 @@ dependencies = [
 
 [[package]]
 name = "crossbeam-channel"
-version = "0.4.4"
+version = "0.4.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b153fe7cbef478c567df0f972e02e6d736db11affe43dfc9c56a9374d1adfb87"
+checksum = "09ee0cc8804d5393478d743b035099520087a5186f3b93fa58cec08fa62407b6"
 dependencies = [
+ "cfg-if",
  "crossbeam-utils",
- "maybe-uninit",
 ]
 
 [[package]]
@@ -451,9 +451,12 @@ dependencies = [
 
 [[package]]
 name = "hashbrown"
-version = "0.9.0"
+version = "0.8.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "00d63df3d41950fb462ed38308eea019113ad1508da725bbedcd0fa5a85ef5f7"
+checksum = "e91b62f79061a0bc2e046024cb7ba44b08419ed238ecbd9adbd787434b9e8c25"
+dependencies = [
+ "autocfg",
+]
 
 [[package]]
 name = "heck"
@@ -632,9 +635,9 @@ dependencies = [
 
 [[package]]
 name = "indexmap"
-version = "1.6.0"
+version = "1.5.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "55e2e4c765aa53a0424761bf9f41aa7a6ac1efa87238f59560640e27fca028f2"
+checksum = "4e47a3566dd4fd4eec714ae6ceabdee0caec795be835c223d92c2d40f1e8cf1c"
 dependencies = [
  "autocfg",
  "hashbrown",
@@ -909,9 +912,9 @@ dependencies = [
 
 [[package]]
 name = "net2"
-version = "0.2.35"
+version = "0.2.34"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3ebc3ec692ed7c9a255596c67808dee269f64655d8baf7b4f0638e51ba1d6853"
+checksum = "2ba7c918ac76704fb42afcbbb43891e72731f3dcca3bef2a19786297baf14af7"
 dependencies = [
  "cfg-if",
  "libc",
@@ -1492,9 +1495,9 @@ version = "0.0.0"
 
 [[package]]
 name = "syn"
-version = "1.0.40"
+version = "1.0.39"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "963f7d3cc59b59b9325165add223142bbf1df27655d07789f109896d353d8350"
+checksum = "891d8d6567fe7c7f8835a3a98af4208f3846fba258c1bc3c31d6e506239f11f9"
 dependencies = [
  "proc-macro2",
  "quote",
diff --git a/crates/hir/src/code_model.rs b/crates/hir/src/code_model.rs
index c2fc819e76..7a9747fc71 100644
--- a/crates/hir/src/code_model.rs
+++ b/crates/hir/src/code_model.rs
@@ -1283,6 +1283,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 {
+        // No special case for the type of async block, since Chalk can figure it out.
+
         let krate = self.krate;
 
         let std_future_trait =
@@ -1600,6 +1602,11 @@ impl Type {
                                 cb(type_.derived(ty.clone()));
                             }
                         }
+                        TypeCtor::OpaqueType(..) => {
+                            if let Some(bounds) = ty.impl_trait_bounds(db) {
+                                walk_bounds(db, &type_.derived(ty.clone()), &bounds, cb);
+                            }
+                        }
                         _ => (),
                     }
 
diff --git a/crates/hir_def/src/body/lower.rs b/crates/hir_def/src/body/lower.rs
index 30ac12a12e..c5ebc2aa06 100644
--- a/crates/hir_def/src/body/lower.rs
+++ b/crates/hir_def/src/body/lower.rs
@@ -239,7 +239,10 @@ impl ExprCollector<'_> {
                     None => self.missing_expr(),
                 },
                 // FIXME: we need to record these effects somewhere...
-                ast::Effect::Async(_) => self.collect_block_opt(e.block_expr()),
+                ast::Effect::Async(_) => {
+                    let body = self.collect_block_opt(e.block_expr());
+                    self.alloc_expr(Expr::Async { body }, syntax_ptr)
+                }
             },
             ast::Expr::BlockExpr(e) => self.collect_block(e),
             ast::Expr::LoopExpr(e) => {
diff --git a/crates/hir_def/src/expr.rs b/crates/hir_def/src/expr.rs
index c94b3a36f5..e862c20800 100644
--- a/crates/hir_def/src/expr.rs
+++ b/crates/hir_def/src/expr.rs
@@ -111,6 +111,9 @@ pub enum Expr {
     TryBlock {
         body: ExprId,
     },
+    Async {
+        body: ExprId,
+    },
     Cast {
         expr: ExprId,
         type_ref: TypeRef,
@@ -250,7 +253,7 @@ impl Expr {
                     f(*expr);
                 }
             }
-            Expr::TryBlock { body } | Expr::Unsafe { body } => f(*body),
+            Expr::TryBlock { body } | Expr::Unsafe { body } | Expr::Async { body } => f(*body),
             Expr::Loop { body, .. } => f(*body),
             Expr::While { condition, body, .. } => {
                 f(*condition);
diff --git a/crates/hir_ty/src/display.rs b/crates/hir_ty/src/display.rs
index 64b68014d8..efb48c7ee4 100644
--- a/crates/hir_ty/src/display.rs
+++ b/crates/hir_ty/src/display.rs
@@ -381,19 +381,24 @@ impl HirDisplay for ApplicationTy {
                 }
             }
             TypeCtor::OpaqueType(opaque_ty_id) => {
-                let bounds = match opaque_ty_id {
+                match opaque_ty_id {
                     OpaqueTyId::ReturnTypeImplTrait(func, idx) => {
                         let datas =
                             f.db.return_type_impl_traits(func).expect("impl trait id without data");
                         let data = (*datas)
                             .as_ref()
                             .map(|rpit| rpit.impl_traits[idx as usize].bounds.clone());
-                        data.subst(&self.parameters)
+                        let bounds = data.subst(&self.parameters);
+                        write!(f, "impl ")?;
+                        write_bounds_like_dyn_trait(&bounds.value, f)?;
+                        // FIXME: it would maybe be good to distinguish this from the alias type (when debug printing), and to show the substitution
                     }
-                };
-                write!(f, "impl ")?;
-                write_bounds_like_dyn_trait(&bounds.value, f)?;
-                // FIXME: it would maybe be good to distinguish this from the alias type (when debug printing), and to show the substitution
+                    OpaqueTyId::AsyncBlockTypeImplTrait(..) => {
+                        write!(f, "impl Future<Output = ")?;
+                        self.parameters[0].hir_fmt(f)?;
+                        write!(f, ">")?;
+                    }
+                }
             }
             TypeCtor::Closure { .. } => {
                 let sig = self.parameters[0].callable_sig(f.db);
@@ -474,18 +479,21 @@ impl HirDisplay for Ty {
                 write_bounds_like_dyn_trait(predicates, f)?;
             }
             Ty::Opaque(opaque_ty) => {
-                let bounds = match opaque_ty.opaque_ty_id {
+                match opaque_ty.opaque_ty_id {
                     OpaqueTyId::ReturnTypeImplTrait(func, idx) => {
                         let datas =
                             f.db.return_type_impl_traits(func).expect("impl trait id without data");
                         let data = (*datas)
                             .as_ref()
                             .map(|rpit| rpit.impl_traits[idx as usize].bounds.clone());
-                        data.subst(&opaque_ty.parameters)
+                        let bounds = data.subst(&opaque_ty.parameters);
+                        write!(f, "impl ")?;
+                        write_bounds_like_dyn_trait(&bounds.value, f)?;
+                    }
+                    OpaqueTyId::AsyncBlockTypeImplTrait(..) => {
+                        write!(f, "{{async block}}")?;
                     }
                 };
-                write!(f, "impl ")?;
-                write_bounds_like_dyn_trait(&bounds.value, f)?;
             }
             Ty::Unknown => write!(f, "{{unknown}}")?,
             Ty::Infer(..) => write!(f, "_")?,
diff --git a/crates/hir_ty/src/infer/expr.rs b/crates/hir_ty/src/infer/expr.rs
index a2f849d021..0a141b9cb9 100644
--- a/crates/hir_ty/src/infer/expr.rs
+++ b/crates/hir_ty/src/infer/expr.rs
@@ -17,8 +17,8 @@ use crate::{
     autoderef, method_resolution, op,
     traits::{FnTrait, InEnvironment},
     utils::{generics, variant_data, Generics},
-    ApplicationTy, Binders, CallableDefId, InferTy, IntTy, Mutability, Obligation, Rawness, Substs,
-    TraitRef, Ty, TypeCtor,
+    ApplicationTy, Binders, CallableDefId, InferTy, IntTy, Mutability, Obligation, OpaqueTyId,
+    Rawness, Substs, TraitRef, Ty, TypeCtor,
 };
 
 use super::{
@@ -146,6 +146,13 @@ impl<'a> InferenceContext<'a> {
                 // FIXME should be std::result::Result<{inner}, _>
                 Ty::Unknown
             }
+            Expr::Async { body } => {
+                // Use the first type parameter as the output type of future.
+                // existenail type AsyncBlockImplTrait<InnerType>: Future<Output = InnerType>
+                let inner_ty = self.infer_expr(*body, &Expectation::none());
+                let opaque_ty_id = OpaqueTyId::AsyncBlockTypeImplTrait(self.owner, *body);
+                Ty::apply_one(TypeCtor::OpaqueType(opaque_ty_id), inner_ty)
+            }
             Expr::Loop { body, label } => {
                 self.breakables.push(BreakableContext {
                     may_break: false,
diff --git a/crates/hir_ty/src/lib.rs b/crates/hir_ty/src/lib.rs
index 1e748476ac..f16d1fc979 100644
--- a/crates/hir_ty/src/lib.rs
+++ b/crates/hir_ty/src/lib.rs
@@ -129,8 +129,9 @@ pub enum TypeCtor {
 
     /// This represents a placeholder for an opaque type in situations where we
     /// don't know the hidden type (i.e. currently almost always). This is
-    /// analogous to the `AssociatedType` type constructor. As with that one,
-    /// these are only produced by Chalk.
+    /// analogous to the `AssociatedType` type constructor.
+    /// It is also used as the type of async block, with one type parameter
+    /// representing the Future::Output type.
     OpaqueType(OpaqueTyId),
 
     /// The type of a specific closure.
@@ -173,6 +174,8 @@ impl TypeCtor {
                         let generic_params = generics(db.upcast(), func.into());
                         generic_params.len()
                     }
+                    // 1 param representing Future::Output type.
+                    OpaqueTyId::AsyncBlockTypeImplTrait(..) => 1,
                 }
             }
             TypeCtor::FnPtr { num_args, is_varargs: _ } => num_args as usize + 1,
@@ -205,6 +208,7 @@ impl TypeCtor {
                 OpaqueTyId::ReturnTypeImplTrait(func, _) => {
                     Some(func.lookup(db.upcast()).module(db.upcast()).krate)
                 }
+                OpaqueTyId::AsyncBlockTypeImplTrait(def, _) => Some(def.module(db.upcast()).krate),
             },
         }
     }
@@ -843,6 +847,29 @@ impl Ty {
 
     pub fn impl_trait_bounds(&self, db: &dyn HirDatabase) -> Option<Vec<GenericPredicate>> {
         match self {
+            Ty::Apply(ApplicationTy { ctor: TypeCtor::OpaqueType(opaque_ty_id), .. }) => {
+                match opaque_ty_id {
+                    OpaqueTyId::AsyncBlockTypeImplTrait(def, _expr) => {
+                        let krate = def.module(db.upcast()).krate;
+                        if let Some(future_trait) = db
+                            .lang_item(krate, "future_trait".into())
+                            .and_then(|item| item.as_trait())
+                        {
+                            // This is only used by type walking.
+                            // Parameters will be walked outside, and projection predicate is not used.
+                            // So just provide the Future trait.
+                            let impl_bound = GenericPredicate::Implemented(TraitRef {
+                                trait_: future_trait,
+                                substs: Substs::empty(),
+                            });
+                            Some(vec![impl_bound])
+                        } else {
+                            None
+                        }
+                    }
+                    OpaqueTyId::ReturnTypeImplTrait(..) => None,
+                }
+            }
             Ty::Opaque(opaque_ty) => {
                 let predicates = match opaque_ty.opaque_ty_id {
                     OpaqueTyId::ReturnTypeImplTrait(func, idx) => {
@@ -853,6 +880,8 @@ impl Ty {
                             data.subst(&opaque_ty.parameters)
                         })
                     }
+                    // It always has an parameter for Future::Output type.
+                    OpaqueTyId::AsyncBlockTypeImplTrait(..) => unreachable!(),
                 };
 
                 predicates.map(|it| it.value)
@@ -1065,6 +1094,7 @@ impl<T: TypeWalk> TypeWalk for Vec<T> {
 #[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)]
 pub enum OpaqueTyId {
     ReturnTypeImplTrait(hir_def::FunctionId, u16),
+    AsyncBlockTypeImplTrait(hir_def::DefWithBodyId, ExprId),
 }
 
 #[derive(Clone, PartialEq, Eq, Debug, Hash)]
diff --git a/crates/hir_ty/src/traits/chalk.rs b/crates/hir_ty/src/traits/chalk.rs
index 01b5717a3f..ff364789e0 100644
--- a/crates/hir_ty/src/traits/chalk.rs
+++ b/crates/hir_ty/src/traits/chalk.rs
@@ -11,6 +11,7 @@ use hir_def::{
     lang_item::{lang_attr, LangItemTarget},
     AssocContainerId, AssocItemId, HasModule, Lookup, TypeAliasId,
 };
+use hir_expand::name::name;
 
 use super::ChalkContext;
 use crate::{
@@ -18,7 +19,8 @@ use crate::{
     display::HirDisplay,
     method_resolution::{TyFingerprint, ALL_FLOAT_FPS, ALL_INT_FPS},
     utils::generics,
-    CallableDefId, DebruijnIndex, FnSig, GenericPredicate, Substs, Ty, TypeCtor,
+    BoundVar, CallableDefId, DebruijnIndex, FnSig, GenericPredicate, ProjectionPredicate,
+    ProjectionTy, Substs, TraitRef, Ty, TypeCtor,
 };
 use mapping::{
     convert_where_clauses, generic_predicate_to_inline_bound, make_binders, TypeAliasAsValue,
@@ -166,27 +168,88 @@ impl<'a> chalk_solve::RustIrDatabase<Interner> for ChalkContext<'a> {
     fn opaque_ty_data(&self, id: chalk_ir::OpaqueTyId<Interner>) -> Arc<OpaqueTyDatum> {
         let interned_id = crate::db::InternedOpaqueTyId::from(id);
         let full_id = self.db.lookup_intern_impl_trait_id(interned_id);
-        let (func, idx) = match full_id {
-            crate::OpaqueTyId::ReturnTypeImplTrait(func, idx) => (func, idx),
-        };
-        let datas =
-            self.db.return_type_impl_traits(func).expect("impl trait id without impl traits");
-        let data = &datas.value.impl_traits[idx as usize];
-        let bound = OpaqueTyDatumBound {
-            bounds: make_binders(
-                data.bounds
-                    .value
-                    .iter()
-                    .cloned()
-                    .filter(|b| !b.is_error())
-                    .map(|b| b.to_chalk(self.db))
-                    .collect(),
-                1,
-            ),
-            where_clauses: make_binders(vec![], 0),
+        let bound = match full_id {
+            crate::OpaqueTyId::ReturnTypeImplTrait(func, idx) => {
+                let datas = self
+                    .db
+                    .return_type_impl_traits(func)
+                    .expect("impl trait id without impl traits");
+                let data = &datas.value.impl_traits[idx as usize];
+                let bound = OpaqueTyDatumBound {
+                    bounds: make_binders(
+                        data.bounds
+                            .value
+                            .iter()
+                            .cloned()
+                            .filter(|b| !b.is_error())
+                            .map(|b| b.to_chalk(self.db))
+                            .collect(),
+                        1,
+                    ),
+                    where_clauses: make_binders(vec![], 0),
+                };
+                let num_vars = datas.num_binders;
+                make_binders(bound, num_vars)
+            }
+            crate::OpaqueTyId::AsyncBlockTypeImplTrait(..) => {
+                if let Some((future_trait, future_output)) = self
+                    .db
+                    .lang_item(self.krate, "future_trait".into())
+                    .and_then(|item| item.as_trait())
+                    .and_then(|trait_| {
+                        let alias =
+                            self.db.trait_data(trait_).associated_type_by_name(&name![Output])?;
+                        Some((trait_, alias))
+                    })
+                {
+                    // Making up `AsyncBlock<T>: Future<Output = T>`
+                    //
+                    // |--------------------OpaqueTyDatum-------------------|
+                    //        |-------------OpaqueTyDatumBound--------------|
+                    // for<T> <Self> [Future<Self>, Future::Output<Self> = T]
+                    //     ^1  ^0            ^0                    ^0      ^1
+                    let impl_bound = GenericPredicate::Implemented(TraitRef {
+                        trait_: future_trait,
+                        // Self type as the first parameter.
+                        substs: Substs::single(Ty::Bound(BoundVar {
+                            debruijn: DebruijnIndex::INNERMOST,
+                            index: 0,
+                        })),
+                    });
+                    let proj_bound = GenericPredicate::Projection(ProjectionPredicate {
+                        // The parameter of the opaque type.
+                        ty: Ty::Bound(BoundVar { debruijn: DebruijnIndex::ONE, index: 0 }),
+                        projection_ty: ProjectionTy {
+                            associated_ty: future_output,
+                            // Self type as the first parameter.
+                            parameters: Substs::single(Ty::Bound(BoundVar::new(
+                                DebruijnIndex::INNERMOST,
+                                0,
+                            ))),
+                        },
+                    });
+                    let bound = OpaqueTyDatumBound {
+                        bounds: make_binders(
+                            vec![impl_bound.to_chalk(self.db), proj_bound.to_chalk(self.db)],
+                            1,
+                        ),
+                        where_clauses: make_binders(vec![], 0),
+                    };
+                    // The opaque type has 1 parameter.
+                    make_binders(bound, 1)
+                } else {
+                    // If failed to find `Future::Output`, return empty bounds as fallback.
+                    let bound = OpaqueTyDatumBound {
+                        bounds: make_binders(vec![], 0),
+                        where_clauses: make_binders(vec![], 0),
+                    };
+                    // The opaque type has 1 parameter.
+                    make_binders(bound, 1)
+                }
+            }
         };
-        let num_vars = datas.num_binders;
-        Arc::new(OpaqueTyDatum { opaque_ty_id: id, bound: make_binders(bound, num_vars) })
+
+        Arc::new(OpaqueTyDatum { opaque_ty_id: id, bound })
     }
 
     fn hidden_opaque_type(&self, _id: chalk_ir::OpaqueTyId<Interner>) -> chalk_ir::Ty<Interner> {
@@ -244,17 +307,13 @@ impl<'a> chalk_solve::RustIrDatabase<Interner> for ChalkContext<'a> {
         let id = from_chalk(self.db, trait_id);
         self.db.trait_data(id).name.to_string()
     }
-    fn adt_name(&self, adt_id: chalk_ir::AdtId<Interner>) -> String {
-        let id = from_chalk(self.db, adt_id);
-        match id {
-            hir_def::AdtId::StructId(id) => self.db.struct_data(id).name.to_string(),
-            hir_def::AdtId::EnumId(id) => self.db.enum_data(id).name.to_string(),
-            hir_def::AdtId::UnionId(id) => self.db.union_data(id).name.to_string(),
-        }
+    // FIXME: lookup names
+    fn adt_name(&self, struct_id: chalk_ir::AdtId<Interner>) -> String {
+        let datum = self.db.struct_datum(self.krate, struct_id);
+        format!("{:?}", datum.name(&Interner))
     }
     fn assoc_type_name(&self, assoc_ty_id: chalk_ir::AssocTypeId<Interner>) -> String {
-        let id = self.db.associated_ty_data(assoc_ty_id).name;
-        self.db.type_alias_data(id).name.to_string()
+        format!("Assoc_{}", assoc_ty_id.0)
     }
     fn opaque_type_name(&self, opaque_ty_id: chalk_ir::OpaqueTyId<Interner>) -> String {
         format!("Opaque_{}", opaque_ty_id.0)
diff --git a/crates/hir_ty/src/traits/chalk/interner.rs b/crates/hir_ty/src/traits/chalk/interner.rs
index eb35db3ffc..fc0f9c2019 100644
--- a/crates/hir_ty/src/traits/chalk/interner.rs
+++ b/crates/hir_ty/src/traits/chalk/interner.rs
@@ -26,7 +26,7 @@ pub type OpaqueTyId = chalk_ir::OpaqueTyId<Interner>;
 pub type OpaqueTyDatum = chalk_solve::rust_ir::OpaqueTyDatum<Interner>;
 
 impl chalk_ir::interner::Interner for Interner {
-    type InternedType = Arc<chalk_ir::TyData<Self>>;
+    type InternedType = Box<chalk_ir::TyData<Self>>; // FIXME use Arc?
     type InternedLifetime = chalk_ir::LifetimeData<Self>;
     type InternedConst = Arc<chalk_ir::ConstData<Self>>;
     type InternedConcreteConst = ();
@@ -34,7 +34,7 @@ impl chalk_ir::interner::Interner for Interner {
     type InternedGoal = Arc<GoalData<Self>>;
     type InternedGoals = Vec<Goal<Self>>;
     type InternedSubstitution = Vec<GenericArg<Self>>;
-    type InternedProgramClause = Arc<chalk_ir::ProgramClauseData<Self>>;
+    type InternedProgramClause = chalk_ir::ProgramClauseData<Self>;
     type InternedProgramClauses = Arc<[chalk_ir::ProgramClause<Self>]>;
     type InternedQuantifiedWhereClauses = Vec<chalk_ir::QuantifiedWhereClause<Self>>;
     type InternedVariableKinds = Vec<chalk_ir::VariableKind<Self>>;
@@ -197,11 +197,11 @@ impl chalk_ir::interner::Interner for Interner {
         tls::with_current_program(|prog| Some(prog?.debug_quantified_where_clauses(clauses, fmt)))
     }
 
-    fn intern_ty(&self, ty: chalk_ir::TyData<Self>) -> Arc<chalk_ir::TyData<Self>> {
-        Arc::new(ty)
+    fn intern_ty(&self, ty: chalk_ir::TyData<Self>) -> Box<chalk_ir::TyData<Self>> {
+        Box::new(ty)
     }
 
-    fn ty_data<'a>(&self, ty: &'a Arc<chalk_ir::TyData<Self>>) -> &'a chalk_ir::TyData<Self> {
+    fn ty_data<'a>(&self, ty: &'a Box<chalk_ir::TyData<Self>>) -> &'a chalk_ir::TyData<Self> {
         ty
     }
 
@@ -230,7 +230,7 @@ impl chalk_ir::interner::Interner for Interner {
         constant
     }
 
-    fn const_eq(&self, _ty: &Arc<chalk_ir::TyData<Self>>, _c1: &(), _c2: &()) -> bool {
+    fn const_eq(&self, _ty: &Box<chalk_ir::TyData<Self>>, _c1: &(), _c2: &()) -> bool {
         true
     }
 
@@ -284,13 +284,13 @@ impl chalk_ir::interner::Interner for Interner {
     fn intern_program_clause(
         &self,
         data: chalk_ir::ProgramClauseData<Self>,
-    ) -> Arc<chalk_ir::ProgramClauseData<Self>> {
-        Arc::new(data)
+    ) -> chalk_ir::ProgramClauseData<Self> {
+        data
     }
 
     fn program_clause_data<'a>(
         &self,
-        clause: &'a Arc<chalk_ir::ProgramClauseData<Self>>,
+        clause: &'a chalk_ir::ProgramClauseData<Self>,
     ) -> &'a chalk_ir::ProgramClauseData<Self> {
         clause
     }
diff --git a/crates/hir_ty/src/traits/chalk/mapping.rs b/crates/hir_ty/src/traits/chalk/mapping.rs
index d6bacba1d3..fe62f3fa7c 100644
--- a/crates/hir_ty/src/traits/chalk/mapping.rs
+++ b/crates/hir_ty/src/traits/chalk/mapping.rs
@@ -464,18 +464,6 @@ impl ToChalk for hir_def::ImplId {
     }
 }
 
-impl ToChalk for hir_def::AdtId {
-    type Chalk = AdtId;
-
-    fn to_chalk(self, _db: &dyn HirDatabase) -> Self::Chalk {
-        chalk_ir::AdtId(self.into())
-    }
-
-    fn from_chalk(_db: &dyn HirDatabase, id: AdtId) -> Self {
-        id.0
-    }
-}
-
 impl ToChalk for CallableDefId {
     type Chalk = FnDefId;
 
diff --git a/crates/hir_ty/src/traits/chalk/tls.rs b/crates/hir_ty/src/traits/chalk/tls.rs
index db915625c2..cb6b0fe81f 100644
--- a/crates/hir_ty/src/traits/chalk/tls.rs
+++ b/crates/hir_ty/src/traits/chalk/tls.rs
@@ -73,6 +73,9 @@ impl DebugContext<'_> {
                 crate::OpaqueTyId::ReturnTypeImplTrait(func, idx) => {
                     write!(f, "{{impl trait {} of {:?}}}", idx, func)?;
                 }
+                crate::OpaqueTyId::AsyncBlockTypeImplTrait(def, idx) => {
+                    write!(f, "{{impl trait of async block {} of {:?}}}", idx.into_raw(), def)?;
+                }
             },
             TypeCtor::Closure { def, expr } => {
                 write!(f, "{{closure {:?} in ", expr.into_raw())?;
diff --git a/crates/ide/src/completion/complete_keyword.rs b/crates/ide/src/completion/complete_keyword.rs
index 53ba76e0e9..5645b41fa4 100644
--- a/crates/ide/src/completion/complete_keyword.rs
+++ b/crates/ide/src/completion/complete_keyword.rs
@@ -506,6 +506,28 @@ pub mod future {
     #[lang = "future_trait"]
     pub trait Future {}
 }
+"#,
+            expect![[r#"
+                kw await expr.await
+            "#]],
+        );
+
+        check(
+            r#"
+//- /main.rs
+use std::future::*;
+fn foo() {
+    let a = async {};
+    a.<|>
+}
+
+//- /std/lib.rs
+pub mod future {
+    #[lang = "future_trait"]
+    pub trait Future {
+        type Output;
+    }
+}
 "#,
             expect![[r#"
                 kw await expr.await
diff --git a/crates/ide/src/hover.rs b/crates/ide/src/hover.rs
index efec0184e2..37171cbef3 100644
--- a/crates/ide/src/hover.rs
+++ b/crates/ide/src/hover.rs
@@ -2646,6 +2646,70 @@ fn foo(ar<|>g: &impl Foo + Bar<S>) {}
         );
     }
 
+    #[test]
+    fn test_hover_async_block_impl_trait_has_goto_type_action() {
+        check_actions(
+            r#"
+struct S;
+fn foo() {
+    let fo<|>o = async { S };
+}
+
+#[prelude_import] use future::*;
+mod future {
+    #[lang = "future_trait"]
+    pub trait Future { type Output; }
+}
+"#,
+            expect![[r#"
+                [
+                    GoToType(
+                        [
+                            HoverGotoTypeData {
+                                mod_path: "test::future::Future",
+                                nav: NavigationTarget {
+                                    file_id: FileId(
+                                        1,
+                                    ),
+                                    full_range: 101..163,
+                                    focus_range: Some(
+                                        140..146,
+                                    ),
+                                    name: "Future",
+                                    kind: TRAIT,
+                                    container_name: None,
+                                    description: Some(
+                                        "pub trait Future",
+                                    ),
+                                    docs: None,
+                                },
+                            },
+                            HoverGotoTypeData {
+                                mod_path: "test::S",
+                                nav: NavigationTarget {
+                                    file_id: FileId(
+                                        1,
+                                    ),
+                                    full_range: 0..9,
+                                    focus_range: Some(
+                                        7..8,
+                                    ),
+                                    name: "S",
+                                    kind: STRUCT,
+                                    container_name: None,
+                                    description: Some(
+                                        "struct S",
+                                    ),
+                                    docs: None,
+                                },
+                            },
+                        ],
+                    ),
+                ]
+            "#]],
+        );
+    }
+
     #[test]
     fn test_hover_arg_generic_impl_trait_has_goto_type_action() {
         check_actions(


Test patch:
diff --git a/crates/hir_ty/src/tests/simple.rs b/crates/hir_ty/src/tests/simple.rs
index 48db23a341..5b07948f3d 100644
--- a/crates/hir_ty/src/tests/simple.rs
+++ b/crates/hir_ty/src/tests/simple.rs
@@ -1889,31 +1889,40 @@ fn fn_pointer_return() {
 fn effects_smoke_test() {
     check_infer(
         r#"
-        fn main() {
+        async fn main() {
             let x = unsafe { 92 };
             let y = async { async { () }.await };
             let z = try { () };
             let t = 'a: { 92 };
         }
+
+        #[prelude_import] use future::*;
+
+        mod future {
+            #[lang = "future_trait"]
+            pub trait Future { type Output; }
+        }
         "#,
         expect![[r#"
-            10..130 '{     ...2 }; }': ()
-            20..21 'x': i32
-            24..37 'unsafe { 92 }': i32
-            31..37 '{ 92 }': i32
-            33..35 '92': i32
-            47..48 'y': {unknown}
-            57..79 '{ asyn...wait }': {unknown}
-            59..77 'async ....await': {unknown}
-            65..71 '{ () }': ()
-            67..69 '()': ()
-            89..90 'z': {unknown}
-            93..103 'try { () }': {unknown}
-            97..103 '{ () }': ()
-            99..101 '()': ()
-            113..114 't': i32
-            121..127 '{ 92 }': i32
-            123..125 '92': i32
+            16..136 '{     ...2 }; }': ()
+            26..27 'x': i32
+            30..43 'unsafe { 92 }': i32
+            37..43 '{ 92 }': i32
+            39..41 '92': i32
+            53..54 'y': impl Future<Output = ()>
+            57..85 'async ...wait }': impl Future<Output = ()>
+            63..85 '{ asyn...wait }': ()
+            65..77 'async { () }': impl Future<Output = ()>
+            65..83 'async ....await': ()
+            71..77 '{ () }': ()
+            73..75 '()': ()
+            95..96 'z': {unknown}
+            99..109 'try { () }': {unknown}
+            103..109 '{ () }': ()
+            105..107 '()': ()
+            119..120 't': i32
+            127..133 '{ 92 }': i32
+            129..131 '92': i32
         "#]],
     )
 }
diff --git a/crates/hir_ty/src/tests/traits.rs b/crates/hir_ty/src/tests/traits.rs
index 1f1056962b..41d0975197 100644
--- a/crates/hir_ty/src/tests/traits.rs
+++ b/crates/hir_ty/src/tests/traits.rs
@@ -85,6 +85,46 @@ mod future {
     );
 }
 
+#[test]
+fn infer_async_block() {
+    check_types(
+        r#"
+//- /main.rs crate:main deps:core
+async fn test() {
+    let a = async { 42 };
+    a;
+//  ^ impl Future<Output = i32>
+    let x = a.await;
+    x;
+//  ^ i32
+    let b = async {}.await;
+    b;
+//  ^ ()
+    let c = async {
+        let y = Option::None;
+        y
+    //  ^ Option<u64>
+    };
+    let _: Option<u64> = c.await;
+    c;
+//  ^ impl Future<Output = Option<u64>>
+}
+
+enum Option<T> { None, Some(T) }
+
+//- /core.rs crate:core
+#[prelude_import] use future::*;
+mod future {
+    #[lang = "future_trait"]
+    trait Future {
+        type Output;
+    }
+}
+
+"#,
+    );
+}
+
 #[test]
 fn infer_try() {
     check_types(