Skip to content

Commit efeb398

Browse files
authored
Merge pull request rust-lang#20895 from ChayimFriedman2/async-block-no-opaque
fix: Lower async block/closures correctly
2 parents 1796ced + 3a47c64 commit efeb398

File tree

14 files changed

+405
-280
lines changed

14 files changed

+405
-280
lines changed

src/tools/rust-analyzer/crates/hir-ty/src/display.rs

Lines changed: 129 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,8 @@ use rustc_apfloat::{
3838
use rustc_ast_ir::FloatTy;
3939
use rustc_hash::FxHashSet;
4040
use rustc_type_ir::{
41-
AliasTyKind, BoundVarIndexKind, CoroutineArgsParts, RegionKind, Upcast,
41+
AliasTyKind, BoundVarIndexKind, CoroutineArgsParts, CoroutineClosureArgsParts, RegionKind,
42+
Upcast,
4243
inherent::{AdtDef, GenericArgs as _, IntoKind, SliceLike, Term as _, Ty as _, Tys as _},
4344
};
4445
use smallvec::SmallVec;
@@ -48,7 +49,7 @@ use triomphe::Arc;
4849

4950
use crate::{
5051
CallableDefId, FnAbi, ImplTraitId, MemoryMap, TraitEnvironment, consteval,
51-
db::{HirDatabase, InternedClosure},
52+
db::{HirDatabase, InternedClosure, InternedCoroutine},
5253
generics::generics,
5354
layout::Layout,
5455
mir::pad16,
@@ -1389,33 +1390,6 @@ impl<'db> HirDisplay<'db> for Ty<'db> {
13891390
SizedByDefault::Sized { anchor: krate },
13901391
)?;
13911392
}
1392-
ImplTraitId::AsyncBlockTypeImplTrait(body, ..) => {
1393-
let future_trait =
1394-
LangItem::Future.resolve_trait(db, body.module(db).krate());
1395-
let output = future_trait.and_then(|t| {
1396-
t.trait_items(db)
1397-
.associated_type_by_name(&Name::new_symbol_root(sym::Output))
1398-
});
1399-
write!(f, "impl ")?;
1400-
if let Some(t) = future_trait {
1401-
f.start_location_link(t.into());
1402-
}
1403-
write!(f, "Future")?;
1404-
if future_trait.is_some() {
1405-
f.end_location_link();
1406-
}
1407-
write!(f, "<")?;
1408-
if let Some(t) = output {
1409-
f.start_location_link(t.into());
1410-
}
1411-
write!(f, "Output")?;
1412-
if output.is_some() {
1413-
f.end_location_link();
1414-
}
1415-
write!(f, " = ")?;
1416-
alias_ty.args.type_at(0).hir_fmt(f)?;
1417-
write!(f, ">")?;
1418-
}
14191393
}
14201394
}
14211395
TyKind::Closure(id, substs) => {
@@ -1471,14 +1445,83 @@ impl<'db> HirDisplay<'db> for Ty<'db> {
14711445
}
14721446
if f.closure_style == ClosureStyle::RANotation || !sig.output().is_unit() {
14731447
write!(f, " -> ")?;
1474-
// FIXME: We display `AsyncFn` as `-> impl Future`, but this is hard to fix because
1475-
// we don't have a trait environment here, required to normalize `<Ret as Future>::Output`.
14761448
sig.output().hir_fmt(f)?;
14771449
}
14781450
} else {
14791451
write!(f, "{{closure}}")?;
14801452
}
14811453
}
1454+
TyKind::CoroutineClosure(id, args) => {
1455+
let id = id.0;
1456+
if f.display_kind.is_source_code() {
1457+
if !f.display_kind.allows_opaque() {
1458+
return Err(HirDisplayError::DisplaySourceCodeError(
1459+
DisplaySourceCodeError::OpaqueType,
1460+
));
1461+
} else if f.closure_style != ClosureStyle::ImplFn {
1462+
never!("Only `impl Fn` is valid for displaying closures in source code");
1463+
}
1464+
}
1465+
match f.closure_style {
1466+
ClosureStyle::Hide => return write!(f, "{TYPE_HINT_TRUNCATION}"),
1467+
ClosureStyle::ClosureWithId => {
1468+
return write!(
1469+
f,
1470+
"{{async closure#{:?}}}",
1471+
salsa::plumbing::AsId::as_id(&id).index()
1472+
);
1473+
}
1474+
ClosureStyle::ClosureWithSubst => {
1475+
write!(
1476+
f,
1477+
"{{async closure#{:?}}}",
1478+
salsa::plumbing::AsId::as_id(&id).index()
1479+
)?;
1480+
return hir_fmt_generics(f, args.as_slice(), None, None);
1481+
}
1482+
_ => (),
1483+
}
1484+
let CoroutineClosureArgsParts { closure_kind_ty, signature_parts_ty, .. } =
1485+
args.split_coroutine_closure_args();
1486+
let kind = closure_kind_ty.to_opt_closure_kind().unwrap();
1487+
let kind = match kind {
1488+
rustc_type_ir::ClosureKind::Fn => "AsyncFn",
1489+
rustc_type_ir::ClosureKind::FnMut => "AsyncFnMut",
1490+
rustc_type_ir::ClosureKind::FnOnce => "AsyncFnOnce",
1491+
};
1492+
let TyKind::FnPtr(coroutine_sig, _) = signature_parts_ty.kind() else {
1493+
unreachable!("invalid coroutine closure signature");
1494+
};
1495+
let coroutine_sig = coroutine_sig.skip_binder();
1496+
let coroutine_inputs = coroutine_sig.inputs();
1497+
let TyKind::Tuple(coroutine_inputs) = coroutine_inputs.as_slice()[1].kind() else {
1498+
unreachable!("invalid coroutine closure signature");
1499+
};
1500+
let TyKind::Tuple(coroutine_output) = coroutine_sig.output().kind() else {
1501+
unreachable!("invalid coroutine closure signature");
1502+
};
1503+
let coroutine_output = coroutine_output.as_slice()[1];
1504+
match f.closure_style {
1505+
ClosureStyle::ImplFn => write!(f, "impl {kind}(")?,
1506+
ClosureStyle::RANotation => write!(f, "async |")?,
1507+
_ => unreachable!(),
1508+
}
1509+
if coroutine_inputs.is_empty() {
1510+
} else if f.should_truncate() {
1511+
write!(f, "{TYPE_HINT_TRUNCATION}")?;
1512+
} else {
1513+
f.write_joined(coroutine_inputs, ", ")?;
1514+
};
1515+
match f.closure_style {
1516+
ClosureStyle::ImplFn => write!(f, ")")?,
1517+
ClosureStyle::RANotation => write!(f, "|")?,
1518+
_ => unreachable!(),
1519+
}
1520+
if f.closure_style == ClosureStyle::RANotation || !coroutine_output.is_unit() {
1521+
write!(f, " -> ")?;
1522+
coroutine_output.hir_fmt(f)?;
1523+
}
1524+
}
14821525
TyKind::Placeholder(_) => write!(f, "{{placeholder}}")?,
14831526
TyKind::Param(param) => {
14841527
// FIXME: We should not access `param.id`, it should be removed, and we should know the
@@ -1567,28 +1610,69 @@ impl<'db> HirDisplay<'db> for Ty<'db> {
15671610
}
15681611
}
15691612
TyKind::Infer(..) => write!(f, "_")?,
1570-
TyKind::Coroutine(_, subst) => {
1571-
if f.display_kind.is_source_code() {
1572-
return Err(HirDisplayError::DisplaySourceCodeError(
1573-
DisplaySourceCodeError::Coroutine,
1574-
));
1575-
}
1613+
TyKind::Coroutine(coroutine_id, subst) => {
1614+
let InternedCoroutine(owner, expr_id) = coroutine_id.0.loc(db);
15761615
let CoroutineArgsParts { resume_ty, yield_ty, return_ty, .. } =
15771616
subst.split_coroutine_args();
1578-
write!(f, "|")?;
1579-
resume_ty.hir_fmt(f)?;
1580-
write!(f, "|")?;
1617+
let body = db.body(owner);
1618+
let expr = &body[expr_id];
1619+
match expr {
1620+
hir_def::hir::Expr::Closure {
1621+
closure_kind: hir_def::hir::ClosureKind::Async,
1622+
..
1623+
}
1624+
| hir_def::hir::Expr::Async { .. } => {
1625+
let future_trait =
1626+
LangItem::Future.resolve_trait(db, owner.module(db).krate());
1627+
let output = future_trait.and_then(|t| {
1628+
t.trait_items(db)
1629+
.associated_type_by_name(&Name::new_symbol_root(sym::Output))
1630+
});
1631+
write!(f, "impl ")?;
1632+
if let Some(t) = future_trait {
1633+
f.start_location_link(t.into());
1634+
}
1635+
write!(f, "Future")?;
1636+
if future_trait.is_some() {
1637+
f.end_location_link();
1638+
}
1639+
write!(f, "<")?;
1640+
if let Some(t) = output {
1641+
f.start_location_link(t.into());
1642+
}
1643+
write!(f, "Output")?;
1644+
if output.is_some() {
1645+
f.end_location_link();
1646+
}
1647+
write!(f, " = ")?;
1648+
return_ty.hir_fmt(f)?;
1649+
write!(f, ">")?;
1650+
}
1651+
hir_def::hir::Expr::Closure {
1652+
closure_kind: hir_def::hir::ClosureKind::Coroutine(..),
1653+
..
1654+
} => {
1655+
if f.display_kind.is_source_code() {
1656+
return Err(HirDisplayError::DisplaySourceCodeError(
1657+
DisplaySourceCodeError::Coroutine,
1658+
));
1659+
}
1660+
write!(f, "|")?;
1661+
resume_ty.hir_fmt(f)?;
1662+
write!(f, "|")?;
15811663

1582-
write!(f, " yields ")?;
1583-
yield_ty.hir_fmt(f)?;
1664+
write!(f, " yields ")?;
1665+
yield_ty.hir_fmt(f)?;
15841666

1585-
write!(f, " -> ")?;
1586-
return_ty.hir_fmt(f)?;
1667+
write!(f, " -> ")?;
1668+
return_ty.hir_fmt(f)?;
1669+
}
1670+
_ => panic!("invalid expr for coroutine: {expr:?}"),
1671+
}
15871672
}
15881673
TyKind::CoroutineWitness(..) => write!(f, "{{coroutine witness}}")?,
15891674
TyKind::Pat(_, _) => write!(f, "{{pat}}")?,
15901675
TyKind::UnsafeBinder(_) => write!(f, "{{unsafe binder}}")?,
1591-
TyKind::CoroutineClosure(_, _) => write!(f, "{{coroutine closure}}")?,
15921676
TyKind::Alias(_, _) => write!(f, "{{alias}}")?,
15931677
}
15941678
Ok(())

src/tools/rust-analyzer/crates/hir-ty/src/infer.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1243,7 +1243,6 @@ impl<'body, 'db> InferenceContext<'body, 'db> {
12431243
}
12441244
(self.db.type_alias_impl_traits(def), idx)
12451245
}
1246-
_ => unreachable!(),
12471246
};
12481247
let Some(impl_traits) = impl_traits else {
12491248
return ty;

src/tools/rust-analyzer/crates/hir-ty/src/infer/closure.rs

Lines changed: 68 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,9 @@ use hir_def::{
1111
type_ref::TypeRefId,
1212
};
1313
use rustc_type_ir::{
14-
ClosureArgs, ClosureArgsParts, CoroutineArgs, CoroutineArgsParts, Interner, TypeSuperVisitable,
15-
TypeVisitable, TypeVisitableExt, TypeVisitor,
14+
ClosureArgs, ClosureArgsParts, CoroutineArgs, CoroutineArgsParts, CoroutineClosureArgs,
15+
CoroutineClosureArgsParts, Interner, TypeSuperVisitable, TypeVisitable, TypeVisitableExt,
16+
TypeVisitor,
1617
inherent::{BoundExistentialPredicates, GenericArgs as _, IntoKind, SliceLike, Ty as _},
1718
};
1819
use tracing::debug;
@@ -22,8 +23,9 @@ use crate::{
2223
db::{InternedClosure, InternedCoroutine},
2324
infer::{BreakableKind, Diverges, coerce::CoerceMany},
2425
next_solver::{
25-
AliasTy, Binder, ClauseKind, DbInterner, ErrorGuaranteed, FnSig, GenericArgs, PolyFnSig,
26-
PolyProjectionPredicate, Predicate, PredicateKind, SolverDefId, Ty, TyKind,
26+
AliasTy, Binder, BoundRegionKind, BoundVarKind, BoundVarKinds, ClauseKind, DbInterner,
27+
ErrorGuaranteed, FnSig, GenericArgs, PolyFnSig, PolyProjectionPredicate, Predicate,
28+
PredicateKind, SolverDefId, Ty, TyKind,
2729
abi::Safety,
2830
infer::{
2931
BoundRegionConversionTime, InferOk, InferResult,
@@ -72,6 +74,8 @@ impl<'db> InferenceContext<'_, 'db> {
7274
let sig_ty = Ty::new_fn_ptr(interner, bound_sig);
7375

7476
let parent_args = GenericArgs::identity_for_item(interner, self.generic_def.into());
77+
// FIXME: Make this an infer var and infer it later.
78+
let tupled_upvars_ty = self.types.unit;
7579
let (id, ty, resume_yield_tys) = match closure_kind {
7680
ClosureKind::Coroutine(_) => {
7781
let yield_ty = self.table.next_ty_var();
@@ -80,11 +84,11 @@ impl<'db> InferenceContext<'_, 'db> {
8084
// FIXME: Infer the upvars later.
8185
let parts = CoroutineArgsParts {
8286
parent_args,
83-
kind_ty: Ty::new_unit(interner),
87+
kind_ty: self.types.unit,
8488
resume_ty,
8589
yield_ty,
8690
return_ty: body_ret_ty,
87-
tupled_upvars_ty: Ty::new_unit(interner),
91+
tupled_upvars_ty,
8892
};
8993

9094
let coroutine_id =
@@ -97,9 +101,7 @@ impl<'db> InferenceContext<'_, 'db> {
97101

98102
(None, coroutine_ty, Some((resume_ty, yield_ty)))
99103
}
100-
// FIXME(next-solver): `ClosureKind::Async` should really be a separate arm that creates a `CoroutineClosure`.
101-
// But for now we treat it as a closure.
102-
ClosureKind::Closure | ClosureKind::Async => {
104+
ClosureKind::Closure => {
103105
let closure_id = self.db.intern_closure(InternedClosure(self.owner, tgt_expr));
104106
match expected_kind {
105107
Some(kind) => {
@@ -117,15 +119,15 @@ impl<'db> InferenceContext<'_, 'db> {
117119
}
118120
None => {}
119121
};
120-
// FIXME: Infer the kind and the upvars later when needed.
122+
// FIXME: Infer the kind later if needed.
121123
let parts = ClosureArgsParts {
122124
parent_args,
123125
closure_kind_ty: Ty::from_closure_kind(
124126
interner,
125127
expected_kind.unwrap_or(rustc_type_ir::ClosureKind::Fn),
126128
),
127129
closure_sig_as_fn_ptr_ty: sig_ty,
128-
tupled_upvars_ty: Ty::new_unit(interner),
130+
tupled_upvars_ty,
129131
};
130132
let closure_ty = Ty::new_closure(
131133
interner,
@@ -136,6 +138,61 @@ impl<'db> InferenceContext<'_, 'db> {
136138
self.add_current_closure_dependency(closure_id);
137139
(Some(closure_id), closure_ty, None)
138140
}
141+
ClosureKind::Async => {
142+
// async closures always return the type ascribed after the `->` (if present),
143+
// and yield `()`.
144+
let bound_return_ty = bound_sig.skip_binder().output();
145+
let bound_yield_ty = self.types.unit;
146+
// rustc uses a special lang item type for the resume ty. I don't believe this can cause us problems.
147+
let resume_ty = self.types.unit;
148+
149+
// FIXME: Infer the kind later if needed.
150+
let closure_kind_ty = Ty::from_closure_kind(
151+
interner,
152+
expected_kind.unwrap_or(rustc_type_ir::ClosureKind::Fn),
153+
);
154+
155+
// FIXME: Infer captures later.
156+
// `for<'env> fn() -> ()`, for no captures.
157+
let coroutine_captures_by_ref_ty = Ty::new_fn_ptr(
158+
interner,
159+
Binder::bind_with_vars(
160+
interner.mk_fn_sig([], self.types.unit, false, Safety::Safe, FnAbi::Rust),
161+
BoundVarKinds::new_from_iter(
162+
interner,
163+
[BoundVarKind::Region(BoundRegionKind::ClosureEnv)],
164+
),
165+
),
166+
);
167+
let closure_args = CoroutineClosureArgs::new(
168+
interner,
169+
CoroutineClosureArgsParts {
170+
parent_args,
171+
closure_kind_ty,
172+
signature_parts_ty: Ty::new_fn_ptr(
173+
interner,
174+
bound_sig.map_bound(|sig| {
175+
interner.mk_fn_sig(
176+
[
177+
resume_ty,
178+
Ty::new_tup_from_iter(interner, sig.inputs().iter()),
179+
],
180+
Ty::new_tup(interner, &[bound_yield_ty, bound_return_ty]),
181+
sig.c_variadic,
182+
sig.safety,
183+
sig.abi,
184+
)
185+
}),
186+
),
187+
tupled_upvars_ty,
188+
coroutine_captures_by_ref_ty,
189+
},
190+
);
191+
192+
let coroutine_id =
193+
self.db.intern_coroutine(InternedCoroutine(self.owner, tgt_expr)).into();
194+
(None, Ty::new_coroutine_closure(interner, coroutine_id, closure_args.args), None)
195+
}
139196
};
140197

141198
// Now go through the argument patterns

0 commit comments

Comments
 (0)