Skip to content

Commit 2c0b515

Browse files
committed
Use collect_in_band_defs for async lifetime captures.
1 parent 36c6c2c commit 2c0b515

File tree

2 files changed

+55
-54
lines changed

2 files changed

+55
-54
lines changed

compiler/rustc_ast_lowering/src/lib.rs

Lines changed: 44 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -649,15 +649,13 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
649649
&mut self,
650650
f: impl FnOnce(&mut Self) -> T,
651651
) -> (Vec<(Span, ParamName)>, T) {
652-
assert!(!self.is_collecting_in_band_lifetimes);
653-
assert!(self.lifetimes_to_define.is_empty());
654-
self.is_collecting_in_band_lifetimes = true;
652+
let was_collecting = std::mem::replace(&mut self.is_collecting_in_band_lifetimes, true);
653+
let len = self.lifetimes_to_define.len();
655654

656655
let res = f(self);
657656

658-
self.is_collecting_in_band_lifetimes = false;
659-
660-
let lifetimes_to_define = std::mem::take(&mut self.lifetimes_to_define);
657+
let lifetimes_to_define = self.lifetimes_to_define.split_off(len);
658+
self.is_collecting_in_band_lifetimes = was_collecting;
661659
(lifetimes_to_define, res)
662660
}
663661

@@ -1689,18 +1687,29 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
16891687
// this is because the elided lifetimes from the return type
16901688
// should be figured out using the ordinary elision rules, and
16911689
// this desugaring achieves that.
1690+
1691+
debug!("lower_async_fn_ret_ty: in_scope_lifetimes={:#?}", self.in_scope_lifetimes);
1692+
debug!("lower_async_fn_ret_ty: lifetimes_to_define={:#?}", self.lifetimes_to_define);
1693+
1694+
// Calculate all the lifetimes that should be captured
1695+
// by the opaque type. This should include all in-scope
1696+
// lifetime parameters, including those defined in-band.
16921697
//
1693-
// The variable `input_lifetimes_count` tracks the number of
1694-
// lifetime parameters to the opaque type *not counting* those
1695-
// lifetimes elided in the return type. This includes those
1696-
// that are explicitly declared (`in_scope_lifetimes`) and
1697-
// those elided lifetimes we found in the arguments (current
1698-
// content of `lifetimes_to_define`). Next, we will process
1699-
// the return type, which will cause `lifetimes_to_define` to
1700-
// grow.
1701-
let input_lifetimes_count = self.in_scope_lifetimes.len() + self.lifetimes_to_define.len();
1702-
1703-
let mut lifetime_params = Vec::new();
1698+
// `lifetime_params` is a vector of tuple (span, parameter name, lifetime name).
1699+
1700+
// Input lifetime like `'a` or `'1`:
1701+
let mut lifetime_params: Vec<_> = self
1702+
.in_scope_lifetimes
1703+
.iter()
1704+
.cloned()
1705+
.map(|name| (name.ident().span, name, hir::LifetimeName::Param(name)))
1706+
.chain(
1707+
self.lifetimes_to_define
1708+
.iter()
1709+
.map(|&(span, name)| (span, name, hir::LifetimeName::Param(name))),
1710+
)
1711+
.collect();
1712+
17041713
self.with_hir_id_owner(opaque_ty_node_id, |this| {
17051714
// We have to be careful to get elision right here. The
17061715
// idea is that we create a lifetime parameter for each
@@ -1710,34 +1719,26 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
17101719
//
17111720
// Then, we will create `fn foo(..) -> Foo<'_, '_>`, and
17121721
// hence the elision takes place at the fn site.
1713-
let future_bound = this
1714-
.with_anonymous_lifetime_mode(AnonymousLifetimeMode::CreateParameter, |this| {
1715-
this.lower_async_fn_output_type_to_future_bound(output, fn_def_id, span)
1722+
let (lifetimes_to_define, future_bound) =
1723+
this.with_anonymous_lifetime_mode(AnonymousLifetimeMode::CreateParameter, |this| {
1724+
this.collect_in_band_defs(|this| {
1725+
this.lower_async_fn_output_type_to_future_bound(output, fn_def_id, span)
1726+
})
17161727
});
1717-
17181728
debug!("lower_async_fn_ret_ty: future_bound={:#?}", future_bound);
1729+
debug!("lower_async_fn_ret_ty: lifetimes_to_define={:#?}", lifetimes_to_define);
17191730

1720-
// Calculate all the lifetimes that should be captured
1721-
// by the opaque type. This should include all in-scope
1722-
// lifetime parameters, including those defined in-band.
1723-
//
1724-
// Note: this must be done after lowering the output type,
1725-
// as the output type may introduce new in-band lifetimes.
1726-
lifetime_params = this
1727-
.in_scope_lifetimes
1728-
.iter()
1729-
.cloned()
1730-
.map(|name| (name.ident().span, name))
1731-
.chain(this.lifetimes_to_define.iter().cloned())
1732-
.collect();
1733-
1734-
debug!("lower_async_fn_ret_ty: in_scope_lifetimes={:#?}", this.in_scope_lifetimes);
1735-
debug!("lower_async_fn_ret_ty: lifetimes_to_define={:#?}", this.lifetimes_to_define);
1731+
lifetime_params.extend(
1732+
// Output lifetime like `'_`:
1733+
lifetimes_to_define
1734+
.into_iter()
1735+
.map(|(span, name)| (span, name, hir::LifetimeName::Implicit(false))),
1736+
);
17361737
debug!("lower_async_fn_ret_ty: lifetime_params={:#?}", lifetime_params);
17371738

17381739
let generic_params =
1739-
this.arena.alloc_from_iter(lifetime_params.iter().map(|(span, hir_name)| {
1740-
this.lifetime_to_generic_param(*span, *hir_name, opaque_ty_def_id)
1740+
this.arena.alloc_from_iter(lifetime_params.iter().map(|&(span, hir_name, _)| {
1741+
this.lifetime_to_generic_param(span, hir_name, opaque_ty_def_id)
17411742
}));
17421743

17431744
let opaque_ty_item = hir::OpaqueTy {
@@ -1771,25 +1772,14 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
17711772
//
17721773
// For the "output" lifetime parameters, we just want to
17731774
// generate `'_`.
1774-
let mut generic_args = Vec::with_capacity(lifetime_params.len());
1775-
generic_args.extend(lifetime_params[..input_lifetimes_count].iter().map(
1776-
|&(span, hir_name)| {
1777-
// Input lifetime like `'a` or `'1`:
1775+
let generic_args =
1776+
self.arena.alloc_from_iter(lifetime_params.into_iter().map(|(span, _, name)| {
17781777
GenericArg::Lifetime(hir::Lifetime {
17791778
hir_id: self.next_id(),
17801779
span: self.lower_span(span),
1781-
name: hir::LifetimeName::Param(hir_name),
1780+
name,
17821781
})
1783-
},
1784-
));
1785-
generic_args.extend(lifetime_params[input_lifetimes_count..].iter().map(|&(span, _)|
1786-
// Output lifetime like `'_`.
1787-
GenericArg::Lifetime(hir::Lifetime {
1788-
hir_id: self.next_id(),
1789-
span: self.lower_span(span),
1790-
name: hir::LifetimeName::Implicit(false),
1791-
})));
1792-
let generic_args = self.arena.alloc_from_iter(generic_args);
1782+
}));
17931783

17941784
// Create the `Foo<...>` reference itself. Note that the `type
17951785
// Foo = impl Trait` is, internally, created as a child of the

src/test/ui/async-await/generics-and-bounds.rs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22
// edition:2018
33
// compile-flags: --crate-type lib
44

5+
#![feature(in_band_lifetimes)]
6+
57
use std::future::Future;
68

79
pub async fn simple_generic<T>() {}
@@ -71,6 +73,10 @@ pub fn call_with_ref_block<'a>(f: &'a (impl Foo + 'a)) -> impl Future<Output = (
7173
async move { f.foo() }
7274
}
7375

76+
pub fn call_with_ref_block_in_band(f: &'a (impl Foo + 'a)) -> impl Future<Output = ()> + 'a {
77+
async move { f.foo() }
78+
}
79+
7480
pub fn async_block_with_same_generic_params_unifies() {
7581
let mut a = call_generic_bound_block(FooType);
7682
a = call_generic_bound_block(FooType);
@@ -85,4 +91,9 @@ pub fn async_block_with_same_generic_params_unifies() {
8591
let f_two = FooType;
8692
let mut d = call_with_ref_block(&f_one);
8793
d = call_with_ref_block(&f_two);
94+
95+
let f_one = FooType;
96+
let f_two = FooType;
97+
let mut d = call_with_ref_block_in_band(&f_one);
98+
d = call_with_ref_block_in_band(&f_two);
8899
}

0 commit comments

Comments
 (0)