Skip to content

Commit 6746a08

Browse files
zachs18Veykril
authored andcommitted
fix: Fix return type of async closures.
(rebased onto 6dfd8ae)
1 parent 1787c14 commit 6746a08

File tree

4 files changed

+82
-32
lines changed

4 files changed

+82
-32
lines changed

crates/hir-def/src/body/lower.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -499,6 +499,8 @@ impl ExprCollector<'_> {
499499
Movability::Movable
500500
};
501501
ClosureKind::Generator(movability)
502+
} else if e.async_token().is_some() {
503+
ClosureKind::Async
502504
} else {
503505
ClosureKind::Closure
504506
};

crates/hir-def/src/body/pretty.rs

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -375,9 +375,20 @@ impl<'a> Printer<'a> {
375375
}
376376
}
377377
w!(self, "|");
378-
if let Some(ret_ty) = ret_type {
379-
w!(self, " -> ");
380-
self.print_type_ref(ret_ty);
378+
match (ret_type, closure_kind) {
379+
(Some(ret_ty), ClosureKind::Async) => {
380+
w!(self, " -> impl Future<Output = ");
381+
self.print_type_ref(ret_ty);
382+
w!(self, ">");
383+
}
384+
(Some(ret_ty), _) => {
385+
w!(self, " -> ");
386+
self.print_type_ref(ret_ty);
387+
}
388+
(None, ClosureKind::Async) => {
389+
w!(self, " -> impl Future<Output = {{unknown}}>"); // FIXME(zachs18): {unknown} or ()?
390+
}
391+
(None, _) => {}
381392
}
382393
self.whitespace();
383394
self.print_expr(*body);

crates/hir-def/src/expr.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -245,6 +245,7 @@ pub enum Expr {
245245
pub enum ClosureKind {
246246
Closure,
247247
Generator(Movability),
248+
Async,
248249
}
249250

250251
#[derive(Debug, Clone, Copy, PartialEq, Eq)]

crates/hir-ty/src/infer/expr.rs

Lines changed: 65 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -286,33 +286,38 @@ impl<'a> InferenceContext<'a> {
286286
})
287287
.intern(Interner);
288288

289-
let (ty, resume_yield_tys) = if matches!(closure_kind, ClosureKind::Generator(_)) {
290-
// FIXME: report error when there are more than 1 parameter.
291-
let resume_ty = match sig_tys.first() {
292-
// When `sig_tys.len() == 1` the first type is the return type, not the
293-
// first parameter type.
294-
Some(ty) if sig_tys.len() > 1 => ty.clone(),
295-
_ => self.result.standard_types.unit.clone(),
296-
};
297-
let yield_ty = self.table.new_type_var();
298-
299-
let subst = TyBuilder::subst_for_generator(self.db, self.owner)
300-
.push(resume_ty.clone())
301-
.push(yield_ty.clone())
302-
.push(ret_ty.clone())
303-
.build();
289+
let (closure_id, ty, resume_yield_tys) = match closure_kind {
290+
ClosureKind::Generator(_) => {
291+
// FIXME: report error when there are more than 1 parameter.
292+
let resume_ty = match sig_tys.first() {
293+
// When `sig_tys.len() == 1` the first type is the return type, not the
294+
// first parameter type.
295+
Some(ty) if sig_tys.len() > 1 => ty.clone(),
296+
_ => self.result.standard_types.unit.clone(),
297+
};
298+
let yield_ty = self.table.new_type_var();
299+
300+
let subst = TyBuilder::subst_for_generator(self.db, self.owner)
301+
.push(resume_ty.clone())
302+
.push(yield_ty.clone())
303+
.push(ret_ty.clone())
304+
.build();
304305

305-
let generator_id = self.db.intern_generator((self.owner, tgt_expr)).into();
306-
let generator_ty = TyKind::Generator(generator_id, subst).intern(Interner);
306+
let generator_id = self.db.intern_generator((self.owner, tgt_expr)).into();
307+
let generator_ty = TyKind::Generator(generator_id, subst).intern(Interner);
307308

308-
(generator_ty, Some((resume_ty, yield_ty)))
309-
} else {
310-
let closure_id = self.db.intern_closure((self.owner, tgt_expr)).into();
311-
let closure_ty =
312-
TyKind::Closure(closure_id, Substitution::from1(Interner, sig_ty.clone()))
313-
.intern(Interner);
309+
(None, generator_ty, Some((resume_ty, yield_ty)))
310+
}
311+
ClosureKind::Async | ClosureKind::Closure => {
312+
let closure_id = self.db.intern_closure((self.owner, tgt_expr)).into();
313+
let closure_ty = TyKind::Closure(
314+
closure_id,
315+
Substitution::from1(Interner, sig_ty.clone()),
316+
)
317+
.intern(Interner);
314318

315-
(closure_ty, None)
319+
(Some(closure_id), closure_ty, None)
320+
}
316321
};
317322

318323
// Eagerly try to relate the closure type with the expected
@@ -321,7 +326,7 @@ impl<'a> InferenceContext<'a> {
321326
self.deduce_closure_type_from_expectations(tgt_expr, &ty, &sig_ty, expected);
322327

323328
// Now go through the argument patterns
324-
for (arg_pat, arg_ty) in args.iter().zip(sig_tys) {
329+
for (arg_pat, arg_ty) in args.iter().zip(&sig_tys) {
325330
self.infer_top_pat(*arg_pat, &arg_ty);
326331
}
327332

@@ -333,16 +338,47 @@ impl<'a> InferenceContext<'a> {
333338
let prev_resume_yield_tys =
334339
mem::replace(&mut self.resume_yield_tys, resume_yield_tys);
335340

336-
self.with_breakable_ctx(BreakableKind::Border, None, None, |this| {
337-
this.infer_return(*body);
338-
});
341+
let (breaks, ()) =
342+
self.with_breakable_ctx(BreakableKind::Border, None, None, |this| {
343+
this.infer_return(*body);
344+
});
345+
346+
let inner_ty = if matches!(closure_kind, ClosureKind::Async) {
347+
// Use the first type parameter as the output type of future.
348+
// existential type AsyncBlockImplTrait<InnerType>: Future<Output = InnerType>
349+
let impl_trait_id =
350+
crate::ImplTraitId::AsyncBlockTypeImplTrait(self.owner, *body);
351+
let opaque_ty_id = self.db.intern_impl_trait_id(impl_trait_id).into();
352+
TyKind::OpaqueType(opaque_ty_id, Substitution::from1(Interner, ret_ty.clone()))
353+
.intern(Interner)
354+
} else {
355+
ret_ty.clone()
356+
};
339357

340358
self.diverges = prev_diverges;
341359
self.return_ty = prev_ret_ty;
342360
self.return_coercion = prev_ret_coercion;
343361
self.resume_yield_tys = prev_resume_yield_tys;
344362

345-
ty
363+
sig_tys.pop();
364+
sig_tys.push(inner_ty);
365+
366+
let sig_ty = TyKind::Function(FnPointer {
367+
num_binders: 0,
368+
sig: FnSig { abi: (), safety: chalk_ir::Safety::Safe, variadic: false },
369+
substitution: FnSubst(
370+
Substitution::from_iter(Interner, sig_tys.clone()).shifted_in(Interner),
371+
),
372+
})
373+
.intern(Interner);
374+
375+
match closure_id {
376+
Some(closure_id) => {
377+
TyKind::Closure(closure_id, Substitution::from1(Interner, sig_ty.clone()))
378+
.intern(Interner)
379+
}
380+
None => ty,
381+
}
346382
}
347383
Expr::Call { callee, args, .. } => {
348384
let callee_ty = self.infer_expr(*callee, &Expectation::none());

0 commit comments

Comments
 (0)