Skip to content

Commit

Permalink
fix: Fix return type of async closures.
Browse files Browse the repository at this point in the history
  • Loading branch information
zachs18 committed Aug 7, 2022
1 parent d9e462f commit 20d3b5a
Show file tree
Hide file tree
Showing 3 changed files with 33 additions and 3 deletions.
1 change: 1 addition & 0 deletions crates/hir-def/src/body/lower.rs
Original file line number Diff line number Diff line change
Expand Up @@ -466,6 +466,7 @@ impl ExprCollector<'_> {
arg_types: arg_types.into(),
ret_type,
body,
is_async: e.async_token().is_some(),
},
syntax_ptr,
)
Expand Down
1 change: 1 addition & 0 deletions crates/hir-def/src/expr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -196,6 +196,7 @@ pub enum Expr {
arg_types: Box<[Option<Interned<TypeRef>>]>,
ret_type: Option<Interned<TypeRef>>,
body: ExprId,
is_async: bool,
},
Tuple {
exprs: Box<[ExprId]>,
Expand Down
34 changes: 31 additions & 3 deletions crates/hir-ty/src/infer/expr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -218,7 +218,7 @@ impl<'a> InferenceContext<'a> {
self.diverges = Diverges::Maybe;
TyBuilder::unit()
}
Expr::Closure { body, args, ret_type, arg_types } => {
Expr::Closure { body, args, ret_type, arg_types, is_async } => {
assert_eq!(args.len(), arg_types.len());

let mut sig_tys = Vec::new();
Expand Down Expand Up @@ -262,18 +262,46 @@ impl<'a> InferenceContext<'a> {
);

// 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_pat(*arg_pat, &arg_ty, BindingMode::default());
}

let prev_diverges = mem::replace(&mut self.diverges, Diverges::Maybe);
let prev_ret_ty = mem::replace(&mut self.return_ty, ret_ty.clone());

self.infer_expr_coerce(*body, &Expectation::has_type(ret_ty));
let inner_ty = self.infer_expr_coerce(*body, &Expectation::has_type(ret_ty));


let inner_ty = if *is_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, inner_ty))
.intern(Interner)
} else {
inner_ty
};

self.diverges = prev_diverges;
self.return_ty = prev_ret_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);

let closure_ty =
TyKind::Closure(closure_id, Substitution::from1(Interner, sig_ty.clone()))
.intern(Interner);

closure_ty
}
Expr::Call { callee, args, .. } => {
Expand Down

0 comments on commit 20d3b5a

Please sign in to comment.