fix: Fix return type of async closures.

(rebased onto 6dfd8ae)
This commit is contained in:
Zachary S 2022-08-06 21:11:02 -05:00 committed by Lukas Wirth
parent 1787c14e72
commit 6746a08b44
4 changed files with 81 additions and 31 deletions

View File

@ -499,6 +499,8 @@ fn maybe_collect_expr(&mut self, expr: ast::Expr) -> Option<ExprId> {
Movability::Movable Movability::Movable
}; };
ClosureKind::Generator(movability) ClosureKind::Generator(movability)
} else if e.async_token().is_some() {
ClosureKind::Async
} else { } else {
ClosureKind::Closure ClosureKind::Closure
}; };

View File

@ -375,10 +375,21 @@ fn print_expr(&mut self, expr: ExprId) {
} }
} }
w!(self, "|"); w!(self, "|");
if let Some(ret_ty) = ret_type { 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, " -> "); w!(self, " -> ");
self.print_type_ref(ret_ty); self.print_type_ref(ret_ty);
} }
(None, ClosureKind::Async) => {
w!(self, " -> impl Future<Output = {{unknown}}>"); // FIXME(zachs18): {unknown} or ()?
}
(None, _) => {}
}
self.whitespace(); self.whitespace();
self.print_expr(*body); self.print_expr(*body);
} }

View File

@ -245,6 +245,7 @@ pub enum Expr {
pub enum ClosureKind { pub enum ClosureKind {
Closure, Closure,
Generator(Movability), Generator(Movability),
Async,
} }
#[derive(Debug, Clone, Copy, PartialEq, Eq)] #[derive(Debug, Clone, Copy, PartialEq, Eq)]

View File

@ -286,7 +286,8 @@ fn infer_expr_inner(&mut self, tgt_expr: ExprId, expected: &Expectation) -> Ty {
}) })
.intern(Interner); .intern(Interner);
let (ty, resume_yield_tys) = if matches!(closure_kind, ClosureKind::Generator(_)) { let (closure_id, ty, resume_yield_tys) = match closure_kind {
ClosureKind::Generator(_) => {
// FIXME: report error when there are more than 1 parameter. // FIXME: report error when there are more than 1 parameter.
let resume_ty = match sig_tys.first() { let resume_ty = match sig_tys.first() {
// When `sig_tys.len() == 1` the first type is the return type, not the // When `sig_tys.len() == 1` the first type is the return type, not the
@ -305,14 +306,18 @@ fn infer_expr_inner(&mut self, tgt_expr: ExprId, expected: &Expectation) -> Ty {
let generator_id = self.db.intern_generator((self.owner, tgt_expr)).into(); let generator_id = self.db.intern_generator((self.owner, tgt_expr)).into();
let generator_ty = TyKind::Generator(generator_id, subst).intern(Interner); let generator_ty = TyKind::Generator(generator_id, subst).intern(Interner);
(generator_ty, Some((resume_ty, yield_ty))) (None, generator_ty, Some((resume_ty, yield_ty)))
} else { }
ClosureKind::Async | ClosureKind::Closure => {
let closure_id = self.db.intern_closure((self.owner, tgt_expr)).into(); let closure_id = self.db.intern_closure((self.owner, tgt_expr)).into();
let closure_ty = let closure_ty = TyKind::Closure(
TyKind::Closure(closure_id, Substitution::from1(Interner, sig_ty.clone())) closure_id,
Substitution::from1(Interner, sig_ty.clone()),
)
.intern(Interner); .intern(Interner);
(closure_ty, None) (Some(closure_id), closure_ty, None)
}
}; };
// Eagerly try to relate the closure type with the expected // 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); self.deduce_closure_type_from_expectations(tgt_expr, &ty, &sig_ty, expected);
// Now go through the argument patterns // 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); 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 = let prev_resume_yield_tys =
mem::replace(&mut self.resume_yield_tys, resume_yield_tys); mem::replace(&mut self.resume_yield_tys, resume_yield_tys);
let (breaks, ()) =
self.with_breakable_ctx(BreakableKind::Border, None, None, |this| { self.with_breakable_ctx(BreakableKind::Border, None, None, |this| {
this.infer_return(*body); 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.diverges = prev_diverges;
self.return_ty = prev_ret_ty; self.return_ty = prev_ret_ty;
self.return_coercion = prev_ret_coercion; self.return_coercion = prev_ret_coercion;
self.resume_yield_tys = prev_resume_yield_tys; 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, .. } => { Expr::Call { callee, args, .. } => {
let callee_ty = self.infer_expr(*callee, &Expectation::none()); let callee_ty = self.infer_expr(*callee, &Expectation::none());