Skip to content

Commit 8330f8e

Browse files
committed
Auto merge of rust-lang#12958 - zachs18:async_closure, r=Veykril
fix: Fix return type of async closures. May fix rust-lang#12957
2 parents c16f051 + 3bf07a5 commit 8330f8e

File tree

5 files changed

+114
-43
lines changed

5 files changed

+114
-43
lines changed

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

+2
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

+8-2
Original file line numberDiff line numberDiff line change
@@ -360,8 +360,14 @@ impl<'a> Printer<'a> {
360360
w!(self, "]");
361361
}
362362
Expr::Closure { args, arg_types, ret_type, body, closure_kind } => {
363-
if let ClosureKind::Generator(Movability::Static) = closure_kind {
364-
w!(self, "static ");
363+
match closure_kind {
364+
ClosureKind::Generator(Movability::Static) => {
365+
w!(self, "static ");
366+
}
367+
ClosureKind::Async => {
368+
w!(self, "async ");
369+
}
370+
_ => (),
365371
}
366372
w!(self, "|");
367373
for (i, (pat, ty)) in args.iter().zip(arg_types.iter()).enumerate() {

crates/hir-def/src/expr.rs

+1
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

+47-26
Original file line numberDiff line numberDiff line change
@@ -275,7 +275,23 @@ impl<'a> InferenceContext<'a> {
275275
Some(type_ref) => self.make_ty(type_ref),
276276
None => self.table.new_type_var(),
277277
};
278-
sig_tys.push(ret_ty.clone());
278+
if let ClosureKind::Async = closure_kind {
279+
// Use the first type parameter as the output type of future.
280+
// existential type AsyncBlockImplTrait<InnerType>: Future<Output = InnerType>
281+
let impl_trait_id =
282+
crate::ImplTraitId::AsyncBlockTypeImplTrait(self.owner, *body);
283+
let opaque_ty_id = self.db.intern_impl_trait_id(impl_trait_id).into();
284+
sig_tys.push(
285+
TyKind::OpaqueType(
286+
opaque_ty_id,
287+
Substitution::from1(Interner, ret_ty.clone()),
288+
)
289+
.intern(Interner),
290+
);
291+
} else {
292+
sig_tys.push(ret_ty.clone());
293+
}
294+
279295
let sig_ty = TyKind::Function(FnPointer {
280296
num_binders: 0,
281297
sig: FnSig { abi: (), safety: chalk_ir::Safety::Safe, variadic: false },
@@ -286,33 +302,38 @@ impl<'a> InferenceContext<'a> {
286302
})
287303
.intern(Interner);
288304

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();
305+
let (ty, resume_yield_tys) = match closure_kind {
306+
ClosureKind::Generator(_) => {
307+
// FIXME: report error when there are more than 1 parameter.
308+
let resume_ty = match sig_tys.first() {
309+
// When `sig_tys.len() == 1` the first type is the return type, not the
310+
// first parameter type.
311+
Some(ty) if sig_tys.len() > 1 => ty.clone(),
312+
_ => self.result.standard_types.unit.clone(),
313+
};
314+
let yield_ty = self.table.new_type_var();
315+
316+
let subst = TyBuilder::subst_for_generator(self.db, self.owner)
317+
.push(resume_ty.clone())
318+
.push(yield_ty.clone())
319+
.push(ret_ty.clone())
320+
.build();
304321

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

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);
325+
(generator_ty, Some((resume_ty, yield_ty)))
326+
}
327+
ClosureKind::Closure | ClosureKind::Async => {
328+
let closure_id = self.db.intern_closure((self.owner, tgt_expr)).into();
329+
let closure_ty = TyKind::Closure(
330+
closure_id,
331+
Substitution::from1(Interner, sig_ty.clone()),
332+
)
333+
.intern(Interner);
314334

315-
(closure_ty, None)
335+
(closure_ty, None)
336+
}
316337
};
317338

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

323344
// Now go through the argument patterns
324-
for (arg_pat, arg_ty) in args.iter().zip(sig_tys) {
345+
for (arg_pat, arg_ty) in args.iter().zip(&sig_tys) {
325346
self.infer_top_pat(*arg_pat, &arg_ty);
326347
}
327348

crates/hir-ty/src/tests/traits.rs

+56-15
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,46 @@ async fn test() {
8282
);
8383
}
8484

85+
#[test]
86+
fn infer_async_closure() {
87+
check_types(
88+
r#"
89+
//- minicore: future, option
90+
async fn test() {
91+
let f = async move |x: i32| x + 42;
92+
f;
93+
// ^ |i32| -> impl Future<Output = i32>
94+
let a = f(4);
95+
a;
96+
// ^ impl Future<Output = i32>
97+
let x = a.await;
98+
x;
99+
// ^ i32
100+
let f = async move || 42;
101+
f;
102+
// ^ || -> impl Future<Output = i32>
103+
let a = f();
104+
a;
105+
// ^ impl Future<Output = i32>
106+
let x = a.await;
107+
x;
108+
// ^ i32
109+
let b = ((async move || {})()).await;
110+
b;
111+
// ^ ()
112+
let c = async move || {
113+
let y = None;
114+
y
115+
// ^ Option<u64>
116+
};
117+
let _: Option<u64> = c().await;
118+
c;
119+
// ^ || -> impl Future<Output = Option<u64>>
120+
}
121+
"#,
122+
);
123+
}
124+
85125
#[test]
86126
fn auto_sized_async_block() {
87127
check_no_mismatches(
@@ -493,29 +533,30 @@ fn tuple_struct_with_fn() {
493533
r#"
494534
struct S(fn(u32) -> u64);
495535
fn test() -> u64 {
496-
let a = S(|i| 2*i);
536+
let a = S(|i| 2*i as u64);
497537
let b = a.0(4);
498538
a.0(2)
499539
}"#,
500540
expect![[r#"
501-
43..101 '{ ...0(2) }': u64
541+
43..108 '{ ...0(2) }': u64
502542
53..54 'a': S
503543
57..58 'S': S(fn(u32) -> u64) -> S
504-
57..67 'S(|i| 2*i)': S
505-
59..66 '|i| 2*i': |u32| -> u64
544+
57..74 'S(|i| ...s u64)': S
545+
59..73 '|i| 2*i as u64': |u32| -> u64
506546
60..61 'i': u32
507-
63..64 '2': u32
508-
63..66 '2*i': u32
547+
63..64 '2': u64
548+
63..73 '2*i as u64': u64
509549
65..66 'i': u32
510-
77..78 'b': u64
511-
81..82 'a': S
512-
81..84 'a.0': fn(u32) -> u64
513-
81..87 'a.0(4)': u64
514-
85..86 '4': u32
515-
93..94 'a': S
516-
93..96 'a.0': fn(u32) -> u64
517-
93..99 'a.0(2)': u64
518-
97..98 '2': u32
550+
65..73 'i as u64': u64
551+
84..85 'b': u64
552+
88..89 'a': S
553+
88..91 'a.0': fn(u32) -> u64
554+
88..94 'a.0(4)': u64
555+
92..93 '4': u32
556+
100..101 'a': S
557+
100..103 'a.0': fn(u32) -> u64
558+
100..106 'a.0(2)': u64
559+
104..105 '2': u32
519560
"#]],
520561
);
521562
}

0 commit comments

Comments
 (0)