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 @@ fn maybe_collect_expr(&mut self, expr: ast::Expr) -> Option { 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 @@ fn print_expr(&mut self, expr: ExprId) { } } 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"); + } + (Some(ret_ty), _) => { + w!(self, " -> "); + self.print_type_ref(ret_ty); + } + (None, ClosureKind::Async) => { + w!(self, " -> impl Future"); // 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 @@ fn infer_expr_inner(&mut self, tgt_expr: ExprId, expected: &Expectation) -> Ty { }) .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 (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 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 @@ fn infer_expr_inner(&mut self, tgt_expr: ExprId, expected: &Expectation) -> Ty { 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 @@ fn infer_expr_inner(&mut self, tgt_expr: ExprId, expected: &Expectation) -> Ty { 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: Future + 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());