about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--crates/hir-def/src/body/lower.rs2
-rw-r--r--crates/hir-def/src/body/pretty.rs17
-rw-r--r--crates/hir-def/src/expr.rs1
-rw-r--r--crates/hir-ty/src/infer/expr.rs94
4 files changed, 82 insertions, 32 deletions
diff --git a/crates/hir-def/src/body/lower.rs b/crates/hir-def/src/body/lower.rs
index 83ce9b6acbb..fedaf395598 100644
--- a/crates/hir-def/src/body/lower.rs
+++ b/crates/hir-def/src/body/lower.rs
@@ -499,6 +499,8 @@ impl ExprCollector<'_> {
                         Movability::Movable
                     };
                     ClosureKind::Generator(movability)
+                } else if e.async_token().is_some() {
+                    ClosureKind::Async
                 } else {
                     ClosureKind::Closure
                 };
diff --git a/crates/hir-def/src/body/pretty.rs b/crates/hir-def/src/body/pretty.rs
index f8b159797e4..610b7d8008d 100644
--- a/crates/hir-def/src/body/pretty.rs
+++ b/crates/hir-def/src/body/pretty.rs
@@ -375,9 +375,20 @@ impl<'a> Printer<'a> {
                     }
                 }
                 w!(self, "|");
-                if let Some(ret_ty) = ret_type {
-                    w!(self, " -> ");
-                    self.print_type_ref(ret_ty);
+                match (ret_type, closure_kind) {
+                    (Some(ret_ty), ClosureKind::Async) => {
+                        w!(self, " -> impl Future<Output = ");
+                        self.print_type_ref(ret_ty);
+                        w!(self, ">");
+                    }
+                    (Some(ret_ty), _) => {
+                        w!(self, " -> ");
+                        self.print_type_ref(ret_ty);
+                    }
+                    (None, ClosureKind::Async) => {
+                        w!(self, " -> impl Future<Output = {{unknown}}>"); // FIXME(zachs18): {unknown} or ()?
+                    }
+                    (None, _) => {}
                 }
                 self.whitespace();
                 self.print_expr(*body);
diff --git a/crates/hir-def/src/expr.rs b/crates/hir-def/src/expr.rs
index bbea608c55e..19fa6b25419 100644
--- a/crates/hir-def/src/expr.rs
+++ b/crates/hir-def/src/expr.rs
@@ -245,6 +245,7 @@ pub enum Expr {
 pub enum ClosureKind {
     Closure,
     Generator(Movability),
+    Async,
 }
 
 #[derive(Debug, Clone, Copy, PartialEq, Eq)]
diff --git a/crates/hir-ty/src/infer/expr.rs b/crates/hir-ty/src/infer/expr.rs
index 535189ff028..8113b0bd537 100644
--- a/crates/hir-ty/src/infer/expr.rs
+++ b/crates/hir-ty/src/infer/expr.rs
@@ -286,33 +286,38 @@ impl<'a> InferenceContext<'a> {
                 })
                 .intern(Interner);
 
-                let (ty, resume_yield_tys) = if matches!(closure_kind, ClosureKind::Generator(_)) {
-                    // FIXME: report error when there are more than 1 parameter.
-                    let resume_ty = match sig_tys.first() {
-                        // When `sig_tys.len() == 1` the first type is the return type, not the
-                        // first parameter type.
-                        Some(ty) if sig_tys.len() > 1 => ty.clone(),
-                        _ => self.result.standard_types.unit.clone(),
-                    };
-                    let yield_ty = self.table.new_type_var();
-
-                    let subst = TyBuilder::subst_for_generator(self.db, self.owner)
-                        .push(resume_ty.clone())
-                        .push(yield_ty.clone())
-                        .push(ret_ty.clone())
-                        .build();
+                let (closure_id, ty, resume_yield_tys) = match closure_kind {
+                    ClosureKind::Generator(_) => {
+                        // FIXME: report error when there are more than 1 parameter.
+                        let resume_ty = match sig_tys.first() {
+                            // When `sig_tys.len() == 1` the first type is the return type, not the
+                            // first parameter type.
+                            Some(ty) if sig_tys.len() > 1 => ty.clone(),
+                            _ => self.result.standard_types.unit.clone(),
+                        };
+                        let yield_ty = self.table.new_type_var();
+
+                        let subst = TyBuilder::subst_for_generator(self.db, self.owner)
+                            .push(resume_ty.clone())
+                            .push(yield_ty.clone())
+                            .push(ret_ty.clone())
+                            .build();
 
-                    let generator_id = self.db.intern_generator((self.owner, tgt_expr)).into();
-                    let generator_ty = TyKind::Generator(generator_id, subst).intern(Interner);
+                        let generator_id = self.db.intern_generator((self.owner, tgt_expr)).into();
+                        let generator_ty = TyKind::Generator(generator_id, subst).intern(Interner);
 
-                    (generator_ty, Some((resume_ty, yield_ty)))
-                } else {
-                    let closure_id = self.db.intern_closure((self.owner, tgt_expr)).into();
-                    let closure_ty =
-                        TyKind::Closure(closure_id, Substitution::from1(Interner, sig_ty.clone()))
-                            .intern(Interner);
+                        (None, generator_ty, Some((resume_ty, yield_ty)))
+                    }
+                    ClosureKind::Async | ClosureKind::Closure => {
+                        let closure_id = self.db.intern_closure((self.owner, tgt_expr)).into();
+                        let closure_ty = TyKind::Closure(
+                            closure_id,
+                            Substitution::from1(Interner, sig_ty.clone()),
+                        )
+                        .intern(Interner);
 
-                    (closure_ty, None)
+                        (Some(closure_id), closure_ty, None)
+                    }
                 };
 
                 // Eagerly try to relate the closure type with the expected
@@ -321,7 +326,7 @@ impl<'a> InferenceContext<'a> {
                 self.deduce_closure_type_from_expectations(tgt_expr, &ty, &sig_ty, expected);
 
                 // Now go through the argument patterns
-                for (arg_pat, arg_ty) in args.iter().zip(sig_tys) {
+                for (arg_pat, arg_ty) in args.iter().zip(&sig_tys) {
                     self.infer_top_pat(*arg_pat, &arg_ty);
                 }
 
@@ -333,16 +338,47 @@ impl<'a> InferenceContext<'a> {
                 let prev_resume_yield_tys =
                     mem::replace(&mut self.resume_yield_tys, resume_yield_tys);
 
-                self.with_breakable_ctx(BreakableKind::Border, None, None, |this| {
-                    this.infer_return(*body);
-                });
+                let (breaks, ()) =
+                    self.with_breakable_ctx(BreakableKind::Border, None, None, |this| {
+                        this.infer_return(*body);
+                    });
+
+                let inner_ty = if matches!(closure_kind, ClosureKind::Async) {
+                    // Use the first type parameter as the output type of future.
+                    // existential type AsyncBlockImplTrait<InnerType>: Future<Output = InnerType>
+                    let impl_trait_id =
+                        crate::ImplTraitId::AsyncBlockTypeImplTrait(self.owner, *body);
+                    let opaque_ty_id = self.db.intern_impl_trait_id(impl_trait_id).into();
+                    TyKind::OpaqueType(opaque_ty_id, Substitution::from1(Interner, ret_ty.clone()))
+                        .intern(Interner)
+                } else {
+                    ret_ty.clone()
+                };
 
                 self.diverges = prev_diverges;
                 self.return_ty = prev_ret_ty;
                 self.return_coercion = prev_ret_coercion;
                 self.resume_yield_tys = prev_resume_yield_tys;
 
-                ty
+                sig_tys.pop();
+                sig_tys.push(inner_ty);
+
+                let sig_ty = TyKind::Function(FnPointer {
+                    num_binders: 0,
+                    sig: FnSig { abi: (), safety: chalk_ir::Safety::Safe, variadic: false },
+                    substitution: FnSubst(
+                        Substitution::from_iter(Interner, sig_tys.clone()).shifted_in(Interner),
+                    ),
+                })
+                .intern(Interner);
+
+                match closure_id {
+                    Some(closure_id) => {
+                        TyKind::Closure(closure_id, Substitution::from1(Interner, sig_ty.clone()))
+                            .intern(Interner)
+                    }
+                    None => ty,
+                }
             }
             Expr::Call { callee, args, .. } => {
                 let callee_ty = self.infer_expr(*callee, &Expectation::none());