Unnamed repository; edit this file 'description' to name the repository.
fix: Fix return type of async closures.
(rebased onto 6dfd8ae)
Zachary S 2023-03-15
parent 1787c14 · commit 6746a08
-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 83ce9b6acb..fedaf39559 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 f8b159797e..610b7d8008 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 bbea608c55..19fa6b2541 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 535189ff02..8113b0bd53 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());