})
}
- /// Setup lifetime capture for and impl-trait.
- /// The captures will be added to `captures`.
- fn while_capturing_lifetimes<T>(
- &mut self,
- parent_def_id: LocalDefId,
- captures: &mut FxHashMap<LocalDefId, (Span, NodeId, ParamName, LifetimeRes)>,
- f: impl FnOnce(&mut Self) -> T,
- ) -> T {
- let lifetime_stash = std::mem::replace(
- &mut self.captured_lifetimes,
- Some(LifetimeCaptureContext {
- parent_def_id,
- captures: std::mem::take(captures),
- binders_to_ignore: Default::default(),
- }),
- );
-
- let ret = f(self);
-
- let ctxt = std::mem::replace(&mut self.captured_lifetimes, lifetime_stash).unwrap();
- *captures = ctxt.captures;
-
- ret
- }
-
/// Register a binder to be ignored for lifetime capture.
#[tracing::instrument(level = "debug", skip(self, f))]
#[inline]
TyKind::ImplTrait(def_node_id, ref bounds) => {
let span = t.span;
match itctx {
- ImplTraitContext::ReturnPositionOpaqueTy { origin } => self
- .lower_opaque_impl_trait(span, origin, def_node_id, |this| {
- this.lower_param_bounds(bounds, itctx)
- }),
+ ImplTraitContext::ReturnPositionOpaqueTy { origin } => {
+ self.lower_opaque_impl_trait(span, origin, def_node_id, bounds, itctx)
+ }
ImplTraitContext::TypeAliasesOpaqueTy => {
let nested_itctx = ImplTraitContext::TypeAliasesOpaqueTy;
self.lower_opaque_impl_trait(
span,
hir::OpaqueTyOrigin::TyAlias,
def_node_id,
- |this| this.lower_param_bounds(bounds, nested_itctx),
+ bounds,
+ nested_itctx,
)
}
ImplTraitContext::Universal => {
hir::Ty { kind, span: self.lower_span(t.span), hir_id: self.lower_node_id(t.id) }
}
- #[tracing::instrument(level = "debug", skip(self, lower_bounds))]
+ #[tracing::instrument(level = "debug", skip(self))]
fn lower_opaque_impl_trait(
&mut self,
span: Span,
origin: hir::OpaqueTyOrigin,
opaque_ty_node_id: NodeId,
- lower_bounds: impl FnOnce(&mut Self) -> hir::GenericBounds<'hir>,
+ bounds: &GenericBounds,
+ itctx: ImplTraitContext,
) -> hir::TyKind<'hir> {
// Make sure we know that some funky desugaring has been going on here.
// This is a first: there is code in other places like for loop
let mut collected_lifetimes = FxHashMap::default();
self.with_hir_id_owner(opaque_ty_node_id, |lctx| {
let hir_bounds = if origin == hir::OpaqueTyOrigin::TyAlias {
- lower_bounds(lctx)
+ lctx.lower_param_bounds(bounds, itctx)
} else {
- lctx.while_capturing_lifetimes(
- opaque_ty_def_id,
- &mut collected_lifetimes,
- lower_bounds,
- )
+ debug!(?lctx.captured_lifetimes);
+
+ let lifetime_stash = std::mem::replace(
+ &mut lctx.captured_lifetimes,
+ Some(LifetimeCaptureContext {
+ parent_def_id: opaque_ty_def_id,
+ captures: std::mem::take(&mut collected_lifetimes),
+ binders_to_ignore: Default::default(),
+ }),
+ );
+
+ let (lifetimes_in_bounds, binders_to_ignore) = ast::lifetimes_in_bounds(bounds);
+ debug!(?lifetimes_in_bounds);
+ debug!(?binders_to_ignore);
+
+ lctx.create_and_capture_lifetime_defs(&lifetimes_in_bounds, &binders_to_ignore);
+
+ let ret = lctx.lower_param_bounds(bounds, itctx);
+
+ let ctxt = std::mem::replace(&mut lctx.captured_lifetimes, lifetime_stash).unwrap();
+
+ collected_lifetimes = ctxt.captures;
+
+ ret
};
debug!(?collected_lifetimes);
hir::OwnerNode::Item(self.arena.alloc(opaque_ty_item))
}
+ fn create_and_capture_lifetime_defs(
+ &mut self,
+ lifetimes_in_bounds: &[&Lifetime],
+ binders_to_ignore: &FxHashMap<NodeId, Vec<NodeId>>,
+ ) {
+ for lifetime in lifetimes_in_bounds {
+ let ident = lifetime.ident;
+ let span = ident.span;
+
+ let res = self.resolver.get_lifetime_res(lifetime.id).unwrap_or(LifetimeRes::Error);
+ debug!(?res);
+
+ if let Some(mut captured_lifetimes) = self.captured_lifetimes.take() {
+ match res {
+ LifetimeRes::Param { param, binder } => {
+ if !binders_to_ignore
+ .get(&lifetime.id)
+ .unwrap_or(&Vec::new())
+ .contains(&binder)
+ {
+ match captured_lifetimes.captures.entry(param) {
+ Entry::Occupied(_) => {}
+ Entry::Vacant(v) => {
+ let node_id = self.next_node_id();
+ let name = ParamName::Plain(ident);
+
+ self.create_def(
+ captured_lifetimes.parent_def_id,
+ node_id,
+ DefPathData::LifetimeNs(name.ident().name),
+ );
+
+ v.insert((span, node_id, name, res));
+ }
+ }
+ }
+ }
+
+ LifetimeRes::Fresh { param, binder } => {
+ debug_assert_eq!(ident.name, kw::UnderscoreLifetime);
+ if !binders_to_ignore
+ .get(&lifetime.id)
+ .unwrap_or(&Vec::new())
+ .contains(&binder)
+ {
+ let param = self.local_def_id(param);
+ match captured_lifetimes.captures.entry(param) {
+ Entry::Occupied(_) => {}
+ Entry::Vacant(v) => {
+ let node_id = self.next_node_id();
+
+ let name = ParamName::Fresh;
+
+ self.create_def(
+ captured_lifetimes.parent_def_id,
+ node_id,
+ DefPathData::LifetimeNs(kw::UnderscoreLifetime),
+ );
+
+ v.insert((span, node_id, name, res));
+ }
+ }
+ }
+ }
+
+ LifetimeRes::Infer | LifetimeRes::Static | LifetimeRes::Error => {}
+
+ res => panic!(
+ "Unexpected lifetime resolution {:?} for {:?} at {:?}",
+ res, lifetime.ident, lifetime.ident.span
+ ),
+ }
+
+ self.captured_lifetimes = Some(captured_lifetimes);
+ }
+ }
+ }
+
fn lower_fn_params_to_names(&mut self, decl: &FnDecl) -> &'hir [Ident] {
// Skip the `...` (`CVarArgs`) trailing arguments from the AST,
// as they are not explicit in HIR/Ty function signatures.
//
// type OpaqueTy<generics_from_parent_fn> = impl Future<Output = T>;
//
- // `inputs`: lowered types of parameters to the function (used to collect lifetimes)
// `output`: unlowered output type (`T` in `-> T`)
// `fn_def_id`: `DefId` of the parent function (used to create child impl trait definition)
// `opaque_ty_node_id`: `NodeId` of the opaque `impl Trait` type that should be created
- // `elided_lt_replacement`: replacement for elided lifetimes in the return type
#[tracing::instrument(level = "debug", skip(self))]
fn lower_async_fn_ret_ty(
&mut self,
debug!(?captures);
self.with_hir_id_owner(opaque_ty_node_id, |this| {
- let future_bound =
- this.while_capturing_lifetimes(opaque_ty_def_id, &mut captures, |this| {
- // We have to be careful to get elision right here. The
- // idea is that we create a lifetime parameter for each
- // lifetime in the return type. So, given a return type
- // like `async fn foo(..) -> &[&u32]`, we lower to `impl
- // Future<Output = &'1 [ &'2 u32 ]>`.
- //
- // Then, we will create `fn foo(..) -> Foo<'_, '_>`, and
- // hence the elision takes place at the fn site.
- this.lower_async_fn_output_type_to_future_bound(output, fn_def_id, span)
- });
- debug!("lower_async_fn_ret_ty: future_bound={:#?}", future_bound);
- debug!("lower_async_fn_ret_ty: captures={:#?}", captures);
+ let lifetime_stash = std::mem::replace(
+ &mut this.captured_lifetimes,
+ Some(LifetimeCaptureContext {
+ parent_def_id: opaque_ty_def_id,
+ captures: std::mem::take(&mut captures),
+ binders_to_ignore: Default::default(),
+ }),
+ );
+
+ let (lifetimes_in_bounds, binders_to_ignore) = ast::lifetimes_in_ret_ty(output);
+ debug!(?lifetimes_in_bounds);
+ debug!(?binders_to_ignore);
+
+ this.create_and_capture_lifetime_defs(&lifetimes_in_bounds, &binders_to_ignore);
+
+ // We have to be careful to get elision right here. The
+ // idea is that we create a lifetime parameter for each
+ // lifetime in the return type. So, given a return type
+ // like `async fn foo(..) -> &[&u32]`, we lower to `impl
+ // Future<Output = &'1 [ &'2 u32 ]>`.
+ //
+ // Then, we will create `fn foo(..) -> Foo<'_, '_>`, and
+ // hence the elision takes place at the fn site.
+ let ret = this.lower_async_fn_output_type_to_future_bound(output, fn_def_id, span);
+
+ let ctxt = std::mem::replace(&mut this.captured_lifetimes, lifetime_stash).unwrap();
+
+ captures = ctxt.captures;
+
+ let future_bound = ret;
let generic_params =
this.arena.alloc_from_iter(captures.iter().map(|(_, &(span, p_id, p_name, _))| {
res: LifetimeRes,
) -> hir::Lifetime {
debug!(?self.captured_lifetimes);
+
let name = match res {
LifetimeRes::Param { mut param, binder } => {
let p_name = ParamName::Plain(ident);
Entry::Occupied(o) => param = self.local_def_id(o.get().1),
Entry::Vacant(v) => {
let p_id = self.next_node_id();
+
let p_def_id = self.create_def(
captured_lifetimes.parent_def_id,
p_id,
self.captured_lifetimes = Some(captured_lifetimes);
}
+
hir::LifetimeName::Param(param, p_name)
}
LifetimeRes::Fresh { param, binder } => {
debug_assert_eq!(ident.name, kw::UnderscoreLifetime);
+
let mut param = self.local_def_id(param);
if let Some(mut captured_lifetimes) = self.captured_lifetimes.take() {
if !captured_lifetimes.binders_to_ignore.contains(&binder) {
Entry::Occupied(o) => param = self.local_def_id(o.get().1),
Entry::Vacant(v) => {
let p_id = self.next_node_id();
+
let p_def_id = self.create_def(
captured_lifetimes.parent_def_id,
p_id,
}
hir::LifetimeName::Param(param, ParamName::Fresh)
}
- LifetimeRes::Anonymous { binder, elided } => {
- let mut l_name = None;
- if let Some(mut captured_lifetimes) = self.captured_lifetimes.take() {
- if !captured_lifetimes.binders_to_ignore.contains(&binder) {
- let p_id = self.next_node_id();
- let p_def_id = self.create_def(
- captured_lifetimes.parent_def_id,
- p_id,
- DefPathData::LifetimeNs(kw::UnderscoreLifetime),
- );
- captured_lifetimes
- .captures
- .insert(p_def_id, (span, p_id, ParamName::Fresh, res));
- l_name = Some(hir::LifetimeName::Param(p_def_id, ParamName::Fresh));
- }
- self.captured_lifetimes = Some(captured_lifetimes);
- };
- l_name.unwrap_or(if elided {
- hir::LifetimeName::Implicit
- } else {
- hir::LifetimeName::Underscore
- })
- }
+ LifetimeRes::Infer => hir::LifetimeName::Infer,
LifetimeRes::Static => hir::LifetimeName::Static,
LifetimeRes::Error => hir::LifetimeName::Error,
res => panic!("Unexpected lifetime resolution {:?} for {:?} at {:?}", res, ident, span),
// Add a definition for the in-band `Param`.
let def_id = self.local_def_id(node_id);
- let hir_bounds = self.lower_param_bounds(bounds, ImplTraitContext::Universal);
// Set the name to `impl Bound1 + Bound2`.
let param = hir::GenericParam {
hir_id: self.lower_node_id(node_id),
ident,
node_id,
&GenericParamKind::Type { default: None },
- hir_bounds,
+ bounds,
+ ImplTraitContext::Universal,
hir::PredicateOrigin::ImplTrait,
);