Consolidate opaque ty and async fn lowering code
This commit is contained in:
parent
fbc11e9690
commit
57a96893f6
@ -512,11 +512,6 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
self.resolver.node_id_to_def_id.get(&node).map(|local_def_id| *local_def_id)
|
||||
}
|
||||
|
||||
fn orig_local_def_id(&self, node: NodeId) -> LocalDefId {
|
||||
self.orig_opt_local_def_id(node)
|
||||
.unwrap_or_else(|| panic!("no entry for node id: `{node:?}`"))
|
||||
}
|
||||
|
||||
/// Given the id of some node in the AST, finds the `LocalDefId` associated with it by the name
|
||||
/// resolver (if any), after applying any remapping from `get_remapped_def_id`.
|
||||
///
|
||||
@ -1521,6 +1516,45 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
// frequently opened issues show.
|
||||
let opaque_ty_span = self.mark_span_with_reason(DesugaringKind::OpaqueTy, span, None);
|
||||
|
||||
let captured_lifetimes_to_duplicate = match origin {
|
||||
hir::OpaqueTyOrigin::TyAlias { .. } => {
|
||||
// in a TAIT like `type Foo<'a> = impl Foo<'a>`, we don't duplicate any
|
||||
// lifetimes, since we don't have the issue that any are late-bound.
|
||||
Vec::new()
|
||||
}
|
||||
hir::OpaqueTyOrigin::FnReturn(..) => {
|
||||
// in fn return position, like the `fn test<'a>() -> impl Debug + 'a`
|
||||
// example, we only need to duplicate lifetimes that appear in the
|
||||
// bounds, since those are the only ones that are captured by the opaque.
|
||||
lifetime_collector::lifetimes_in_bounds(&self.resolver, bounds)
|
||||
}
|
||||
hir::OpaqueTyOrigin::AsyncFn(..) => {
|
||||
unreachable!("should be using `lower_async_fn_ret_ty`")
|
||||
}
|
||||
};
|
||||
debug!(?captured_lifetimes_to_duplicate);
|
||||
|
||||
self.lower_opaque_inner(
|
||||
opaque_ty_node_id,
|
||||
origin,
|
||||
in_trait,
|
||||
captured_lifetimes_to_duplicate,
|
||||
span,
|
||||
opaque_ty_span,
|
||||
|this| this.lower_param_bounds(bounds, itctx),
|
||||
)
|
||||
}
|
||||
|
||||
fn lower_opaque_inner(
|
||||
&mut self,
|
||||
opaque_ty_node_id: NodeId,
|
||||
origin: hir::OpaqueTyOrigin,
|
||||
in_trait: bool,
|
||||
captured_lifetimes_to_duplicate: Vec<Lifetime>,
|
||||
span: Span,
|
||||
opaque_ty_span: Span,
|
||||
lower_item_bounds: impl FnOnce(&mut Self) -> &'hir [hir::GenericBound<'hir>],
|
||||
) -> hir::TyKind<'hir> {
|
||||
let opaque_ty_def_id = self.create_def(
|
||||
self.current_hir_id_owner.def_id,
|
||||
opaque_ty_node_id,
|
||||
@ -1529,201 +1563,39 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
);
|
||||
debug!(?opaque_ty_def_id);
|
||||
|
||||
// If this came from a TAIT (as opposed to a function that returns an RPIT), we only want
|
||||
// to capture the lifetimes that appear in the bounds. So visit the bounds to find out
|
||||
// exactly which ones those are.
|
||||
let lifetimes_to_remap = match origin {
|
||||
hir::OpaqueTyOrigin::TyAlias { .. } => {
|
||||
// in a TAIT like `type Foo<'a> = impl Foo<'a>`, we don't keep all the lifetime parameters
|
||||
Vec::new()
|
||||
}
|
||||
hir::OpaqueTyOrigin::AsyncFn(..) | hir::OpaqueTyOrigin::FnReturn(..) => {
|
||||
// in fn return position, like the `fn test<'a>() -> impl Debug + 'a` example,
|
||||
// we only keep the lifetimes that appear in the `impl Debug` itself:
|
||||
lifetime_collector::lifetimes_in_bounds(&self.resolver, bounds)
|
||||
}
|
||||
};
|
||||
debug!(?lifetimes_to_remap);
|
||||
// Map from captured (old) lifetime to synthetic (new) lifetime.
|
||||
// Used to resolve lifetimes in the bounds of the opaque.
|
||||
let mut captured_to_synthesized_mapping = FxHashMap::default();
|
||||
// List of (early-bound) synthetic lifetimes that are owned by the opaque.
|
||||
// This is used to create the `hir::Generics` owned by the opaque.
|
||||
let mut synthesized_lifetime_definitions = vec![];
|
||||
// Pairs of lifetime arg (that resolves to the captured lifetime)
|
||||
// and the def-id of the (early-bound) synthetic lifetime definition.
|
||||
// This is used both to create generics for the `TyKind::OpaqueDef` that
|
||||
// we return, and also as a captured lifetime mapping for RPITITs.
|
||||
let mut synthesized_lifetime_args = vec![];
|
||||
|
||||
let mut new_remapping = FxHashMap::default();
|
||||
|
||||
// Contains the new lifetime definitions created for the TAIT (if any).
|
||||
// If this opaque type is only capturing a subset of the lifetimes (those that appear in
|
||||
// bounds), then create the new lifetime parameters required and create a mapping from the
|
||||
// old `'a` (on the function) to the new `'a` (on the opaque type).
|
||||
let collected_lifetimes =
|
||||
self.create_lifetime_defs(opaque_ty_def_id, &lifetimes_to_remap, &mut new_remapping);
|
||||
debug!(?collected_lifetimes);
|
||||
debug!(?new_remapping);
|
||||
|
||||
// This creates HIR lifetime arguments as `hir::GenericArg`, in the given example `type
|
||||
// TestReturn<'a, T, 'x> = impl Debug + 'x`, it creates a collection containing `&['x]`.
|
||||
let collected_lifetime_mapping: Vec<_> = collected_lifetimes
|
||||
.iter()
|
||||
.map(|(node_id, lifetime)| {
|
||||
let id = self.next_node_id();
|
||||
let lifetime = self.new_named_lifetime(lifetime.id, id, lifetime.ident);
|
||||
let def_id = self.local_def_id(*node_id);
|
||||
(lifetime, def_id)
|
||||
})
|
||||
.collect();
|
||||
debug!(?collected_lifetime_mapping);
|
||||
|
||||
self.with_hir_id_owner(opaque_ty_node_id, |lctx| {
|
||||
// Install the remapping from old to new (if any):
|
||||
lctx.with_remapping(new_remapping, |lctx| {
|
||||
// This creates HIR lifetime definitions as `hir::GenericParam`, in the given
|
||||
// example `type TestReturn<'a, T, 'x> = impl Debug + 'x`, it creates a collection
|
||||
// containing `&['x]`.
|
||||
let lifetime_defs = lctx.arena.alloc_from_iter(collected_lifetimes.iter().map(
|
||||
|&(new_node_id, lifetime)| {
|
||||
let hir_id = lctx.lower_node_id(new_node_id);
|
||||
debug_assert_ne!(lctx.opt_local_def_id(new_node_id), None);
|
||||
|
||||
let (name, kind) = if lifetime.ident.name == kw::UnderscoreLifetime {
|
||||
(hir::ParamName::Fresh, hir::LifetimeParamKind::Elided)
|
||||
} else {
|
||||
(
|
||||
hir::ParamName::Plain(lifetime.ident),
|
||||
hir::LifetimeParamKind::Explicit,
|
||||
)
|
||||
};
|
||||
|
||||
hir::GenericParam {
|
||||
hir_id,
|
||||
def_id: lctx.local_def_id(new_node_id),
|
||||
name,
|
||||
span: lifetime.ident.span,
|
||||
pure_wrt_drop: false,
|
||||
kind: hir::GenericParamKind::Lifetime { kind },
|
||||
colon_span: None,
|
||||
source: hir::GenericParamSource::Generics,
|
||||
}
|
||||
},
|
||||
));
|
||||
debug!(?lifetime_defs);
|
||||
|
||||
// Then when we lower the param bounds, references to 'a are remapped to 'a1, so we
|
||||
// get back Debug + 'a1, which is suitable for use on the TAIT.
|
||||
let hir_bounds = lctx.lower_param_bounds(bounds, itctx);
|
||||
debug!(?hir_bounds);
|
||||
|
||||
let lifetime_mapping = if in_trait {
|
||||
Some(
|
||||
&*self.arena.alloc_from_iter(
|
||||
collected_lifetime_mapping
|
||||
.iter()
|
||||
.map(|(lifetime, def_id)| (**lifetime, *def_id)),
|
||||
),
|
||||
)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
let opaque_ty_item = hir::OpaqueTy {
|
||||
generics: self.arena.alloc(hir::Generics {
|
||||
params: lifetime_defs,
|
||||
predicates: &[],
|
||||
has_where_clause_predicates: false,
|
||||
where_clause_span: lctx.lower_span(span),
|
||||
span: lctx.lower_span(span),
|
||||
}),
|
||||
bounds: hir_bounds,
|
||||
origin,
|
||||
lifetime_mapping,
|
||||
in_trait,
|
||||
};
|
||||
debug!(?opaque_ty_item);
|
||||
|
||||
lctx.generate_opaque_type(opaque_ty_def_id, opaque_ty_item, span, opaque_ty_span)
|
||||
})
|
||||
});
|
||||
|
||||
// `impl Trait` now just becomes `Foo<'a, 'b, ..>`.
|
||||
hir::TyKind::OpaqueDef(
|
||||
hir::ItemId { owner_id: hir::OwnerId { def_id: opaque_ty_def_id } },
|
||||
self.arena.alloc_from_iter(
|
||||
collected_lifetime_mapping
|
||||
.iter()
|
||||
.map(|(lifetime, _)| hir::GenericArg::Lifetime(*lifetime)),
|
||||
),
|
||||
in_trait,
|
||||
)
|
||||
}
|
||||
|
||||
/// Registers a new opaque type with the proper `NodeId`s and
|
||||
/// returns the lowered node-ID for the opaque type.
|
||||
fn generate_opaque_type(
|
||||
&mut self,
|
||||
opaque_ty_id: LocalDefId,
|
||||
opaque_ty_item: hir::OpaqueTy<'hir>,
|
||||
span: Span,
|
||||
opaque_ty_span: Span,
|
||||
) -> hir::OwnerNode<'hir> {
|
||||
let opaque_ty_item_kind = hir::ItemKind::OpaqueTy(self.arena.alloc(opaque_ty_item));
|
||||
// Generate an `type Foo = impl Trait;` declaration.
|
||||
trace!("registering opaque type with id {:#?}", opaque_ty_id);
|
||||
let opaque_ty_item = hir::Item {
|
||||
owner_id: hir::OwnerId { def_id: opaque_ty_id },
|
||||
ident: Ident::empty(),
|
||||
kind: opaque_ty_item_kind,
|
||||
vis_span: self.lower_span(span.shrink_to_lo()),
|
||||
span: self.lower_span(opaque_ty_span),
|
||||
};
|
||||
hir::OwnerNode::Item(self.arena.alloc(opaque_ty_item))
|
||||
}
|
||||
|
||||
/// Given a `parent_def_id`, a list of `lifetimes_in_bounds` and a `remapping` hash to be
|
||||
/// filled, this function creates new definitions for `Param` and `Fresh` lifetimes, inserts the
|
||||
/// new definition, adds it to the remapping with the definition of the given lifetime and
|
||||
/// returns a list of lifetimes to be lowered afterwards.
|
||||
fn create_lifetime_defs(
|
||||
&mut self,
|
||||
parent_def_id: LocalDefId,
|
||||
lifetimes_in_bounds: &[Lifetime],
|
||||
remapping: &mut FxHashMap<LocalDefId, LocalDefId>,
|
||||
) -> Vec<(NodeId, Lifetime)> {
|
||||
let mut result = Vec::new();
|
||||
|
||||
for lifetime in lifetimes_in_bounds {
|
||||
for lifetime in captured_lifetimes_to_duplicate {
|
||||
let res = self.resolver.get_lifetime_res(lifetime.id).unwrap_or(LifetimeRes::Error);
|
||||
debug!(?res);
|
||||
|
||||
match res {
|
||||
LifetimeRes::Param { param: old_def_id, binder: _ } => {
|
||||
if remapping.get(&old_def_id).is_none() {
|
||||
let node_id = self.next_node_id();
|
||||
|
||||
let new_def_id = self.create_def(
|
||||
parent_def_id,
|
||||
node_id,
|
||||
DefPathData::LifetimeNs(lifetime.ident.name),
|
||||
lifetime.ident.span,
|
||||
);
|
||||
remapping.insert(old_def_id, new_def_id);
|
||||
|
||||
result.push((node_id, *lifetime));
|
||||
}
|
||||
}
|
||||
let old_def_id = match res {
|
||||
LifetimeRes::Param { param: old_def_id, binder: _ } => old_def_id,
|
||||
|
||||
LifetimeRes::Fresh { param, binder: _ } => {
|
||||
debug_assert_eq!(lifetime.ident.name, kw::UnderscoreLifetime);
|
||||
if let Some(old_def_id) = self.orig_opt_local_def_id(param) && remapping.get(&old_def_id).is_none() {
|
||||
let node_id = self.next_node_id();
|
||||
|
||||
let new_def_id = self.create_def(
|
||||
parent_def_id,
|
||||
node_id,
|
||||
DefPathData::LifetimeNs(kw::UnderscoreLifetime),
|
||||
lifetime.ident.span,
|
||||
);
|
||||
remapping.insert(old_def_id, new_def_id);
|
||||
|
||||
result.push((node_id, *lifetime));
|
||||
if let Some(old_def_id) = self.orig_opt_local_def_id(param) {
|
||||
old_def_id
|
||||
} else {
|
||||
self.tcx
|
||||
.sess
|
||||
.delay_span_bug(lifetime.ident.span, "no def-id for fresh lifetime");
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
LifetimeRes::Static | LifetimeRes::Error => {}
|
||||
// Opaques do not capture `'static`
|
||||
LifetimeRes::Static | LifetimeRes::Error => {
|
||||
continue;
|
||||
}
|
||||
|
||||
res => {
|
||||
let bug_msg = format!(
|
||||
@ -1732,10 +1604,113 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
);
|
||||
span_bug!(lifetime.ident.span, "{}", bug_msg);
|
||||
}
|
||||
};
|
||||
|
||||
if captured_to_synthesized_mapping.get(&old_def_id).is_none() {
|
||||
// Create a new lifetime parameter local to the opaque.
|
||||
let duplicated_lifetime_node_id = self.next_node_id();
|
||||
let duplicated_lifetime_def_id = self.create_def(
|
||||
opaque_ty_def_id,
|
||||
duplicated_lifetime_node_id,
|
||||
DefPathData::LifetimeNs(lifetime.ident.name),
|
||||
lifetime.ident.span,
|
||||
);
|
||||
captured_to_synthesized_mapping.insert(old_def_id, duplicated_lifetime_def_id);
|
||||
// FIXME: Instead of doing this, we could move this whole loop
|
||||
// into the `with_hir_id_owner`, then just directly construct
|
||||
// the `hir::GenericParam` here.
|
||||
synthesized_lifetime_definitions.push((
|
||||
duplicated_lifetime_node_id,
|
||||
duplicated_lifetime_def_id,
|
||||
lifetime.ident,
|
||||
));
|
||||
|
||||
// Now make an arg that we can use for the substs of the opaque tykind.
|
||||
let id = self.next_node_id();
|
||||
let lifetime_arg = self.new_named_lifetime_with_res(id, lifetime.ident, res);
|
||||
let duplicated_lifetime_def_id = self.local_def_id(duplicated_lifetime_node_id);
|
||||
synthesized_lifetime_args.push((lifetime_arg, duplicated_lifetime_def_id))
|
||||
}
|
||||
}
|
||||
|
||||
result
|
||||
self.with_hir_id_owner(opaque_ty_node_id, |this| {
|
||||
// Install the remapping from old to new (if any). This makes sure that
|
||||
// any lifetimes that would have resolved to the def-id of captured
|
||||
// lifetimes are remapped to the new *synthetic* lifetimes of the opaque.
|
||||
let bounds = this
|
||||
.with_remapping(captured_to_synthesized_mapping, |this| lower_item_bounds(this));
|
||||
|
||||
let generic_params = this.arena.alloc_from_iter(
|
||||
synthesized_lifetime_definitions.iter().map(|&(new_node_id, new_def_id, ident)| {
|
||||
let hir_id = this.lower_node_id(new_node_id);
|
||||
let (name, kind) = if ident.name == kw::UnderscoreLifetime {
|
||||
(hir::ParamName::Fresh, hir::LifetimeParamKind::Elided)
|
||||
} else {
|
||||
(hir::ParamName::Plain(ident), hir::LifetimeParamKind::Explicit)
|
||||
};
|
||||
|
||||
hir::GenericParam {
|
||||
hir_id,
|
||||
def_id: new_def_id,
|
||||
name,
|
||||
span: ident.span,
|
||||
pure_wrt_drop: false,
|
||||
kind: hir::GenericParamKind::Lifetime { kind },
|
||||
colon_span: None,
|
||||
source: hir::GenericParamSource::Generics,
|
||||
}
|
||||
}),
|
||||
);
|
||||
debug!("lower_async_fn_ret_ty: generic_params={:#?}", generic_params);
|
||||
|
||||
let lifetime_mapping = if in_trait {
|
||||
Some(&*self.arena.alloc_slice(&synthesized_lifetime_args))
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
let opaque_ty_item = hir::OpaqueTy {
|
||||
generics: this.arena.alloc(hir::Generics {
|
||||
params: generic_params,
|
||||
predicates: &[],
|
||||
has_where_clause_predicates: false,
|
||||
where_clause_span: this.lower_span(span),
|
||||
span: this.lower_span(span),
|
||||
}),
|
||||
bounds,
|
||||
origin,
|
||||
lifetime_mapping,
|
||||
in_trait,
|
||||
};
|
||||
|
||||
// Generate an `type Foo = impl Trait;` declaration.
|
||||
trace!("registering opaque type with id {:#?}", opaque_ty_def_id);
|
||||
let opaque_ty_item = hir::Item {
|
||||
owner_id: hir::OwnerId { def_id: opaque_ty_def_id },
|
||||
ident: Ident::empty(),
|
||||
kind: hir::ItemKind::OpaqueTy(this.arena.alloc(opaque_ty_item)),
|
||||
vis_span: this.lower_span(span.shrink_to_lo()),
|
||||
span: this.lower_span(opaque_ty_span),
|
||||
};
|
||||
|
||||
hir::OwnerNode::Item(this.arena.alloc(opaque_ty_item))
|
||||
});
|
||||
|
||||
let generic_args = self.arena.alloc_from_iter(
|
||||
synthesized_lifetime_args
|
||||
.iter()
|
||||
.map(|(lifetime, _)| hir::GenericArg::Lifetime(*lifetime)),
|
||||
);
|
||||
|
||||
// Create the `Foo<...>` reference itself. Note that the `type
|
||||
// Foo = impl Trait` is, internally, created as a child of the
|
||||
// async fn, so the *type parameters* are inherited. It's
|
||||
// only the lifetime parameters that we must supply.
|
||||
hir::TyKind::OpaqueDef(
|
||||
hir::ItemId { owner_id: hir::OwnerId { def_id: opaque_ty_def_id } },
|
||||
generic_args,
|
||||
in_trait,
|
||||
)
|
||||
}
|
||||
|
||||
fn lower_fn_params_to_names(&mut self, decl: &FnDecl) -> &'hir [Ident] {
|
||||
@ -1813,9 +1788,10 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
}
|
||||
}
|
||||
|
||||
let fn_def_id = self.local_def_id(fn_node_id);
|
||||
self.lower_async_fn_ret_ty(
|
||||
&decl.output,
|
||||
fn_node_id,
|
||||
fn_def_id,
|
||||
ret_id,
|
||||
matches!(kind, FnDeclKind::Trait),
|
||||
)
|
||||
@ -1892,151 +1868,28 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
fn lower_async_fn_ret_ty(
|
||||
&mut self,
|
||||
output: &FnRetTy,
|
||||
fn_node_id: NodeId,
|
||||
fn_def_id: LocalDefId,
|
||||
opaque_ty_node_id: NodeId,
|
||||
in_trait: bool,
|
||||
) -> hir::FnRetTy<'hir> {
|
||||
let span = output.span();
|
||||
|
||||
let span = self.lower_span(output.span());
|
||||
let opaque_ty_span = self.mark_span_with_reason(DesugaringKind::Async, span, None);
|
||||
|
||||
let fn_def_id = self.local_def_id(fn_node_id);
|
||||
|
||||
let opaque_ty_def_id =
|
||||
self.create_def(fn_def_id, opaque_ty_node_id, DefPathData::ImplTrait, opaque_ty_span);
|
||||
|
||||
// When we create the opaque type for this async fn, it is going to have
|
||||
// to capture all the lifetimes involved in the signature (including in the
|
||||
// return type). This is done by introducing lifetime parameters for:
|
||||
//
|
||||
// - all the explicitly declared lifetimes from the impl and function itself;
|
||||
// - all the elided lifetimes in the fn arguments;
|
||||
// - all the elided lifetimes in the return type.
|
||||
//
|
||||
// So for example in this snippet:
|
||||
//
|
||||
// ```rust
|
||||
// impl<'a> Foo<'a> {
|
||||
// async fn bar<'b>(&self, x: &'b Vec<f64>, y: &str) -> &u32 {
|
||||
// // ^ '0 ^ '1 ^ '2
|
||||
// // elided lifetimes used below
|
||||
// }
|
||||
// }
|
||||
// ```
|
||||
//
|
||||
// we would create an opaque type like:
|
||||
//
|
||||
// ```
|
||||
// type Bar<'a, 'b, '0, '1, '2> = impl Future<Output = &'2 u32>;
|
||||
// ```
|
||||
//
|
||||
// and we would then desugar `bar` to the equivalent of:
|
||||
//
|
||||
// ```rust
|
||||
// impl<'a> Foo<'a> {
|
||||
// fn bar<'b, '0, '1>(&'0 self, x: &'b Vec<f64>, y: &'1 str) -> Bar<'a, 'b, '0, '1, '_>
|
||||
// }
|
||||
// ```
|
||||
//
|
||||
// Note that the final parameter to `Bar` is `'_`, not `'2` --
|
||||
// this is because the elided lifetimes from the return type
|
||||
// should be figured out using the ordinary elision rules, and
|
||||
// this desugaring achieves that.
|
||||
|
||||
// Calculate all the lifetimes that should be captured
|
||||
// by the opaque type. This should include all in-scope
|
||||
// lifetime parameters, including those defined in-band.
|
||||
|
||||
// Contains the new lifetime definitions created for the TAIT (if any) generated for the
|
||||
// return type.
|
||||
let mut collected_lifetimes = Vec::new();
|
||||
let mut new_remapping = FxHashMap::default();
|
||||
|
||||
let extra_lifetime_params = self.resolver.take_extra_lifetime_params(opaque_ty_node_id);
|
||||
debug!(?extra_lifetime_params);
|
||||
for (ident, outer_node_id, outer_res) in extra_lifetime_params {
|
||||
let outer_def_id = self.orig_local_def_id(outer_node_id);
|
||||
let inner_node_id = self.next_node_id();
|
||||
|
||||
// Add a definition for the in scope lifetime def.
|
||||
let inner_def_id = self.create_def(
|
||||
opaque_ty_def_id,
|
||||
inner_node_id,
|
||||
DefPathData::LifetimeNs(ident.name),
|
||||
ident.span,
|
||||
);
|
||||
new_remapping.insert(outer_def_id, inner_def_id);
|
||||
|
||||
let inner_res = match outer_res {
|
||||
// Input lifetime like `'a`:
|
||||
LifetimeRes::Param { param, .. } => {
|
||||
LifetimeRes::Param { param, binder: fn_node_id }
|
||||
}
|
||||
// Input lifetime like `'1`:
|
||||
LifetimeRes::Fresh { param, .. } => {
|
||||
LifetimeRes::Fresh { param, binder: fn_node_id }
|
||||
}
|
||||
LifetimeRes::Static | LifetimeRes::Error => continue,
|
||||
res => {
|
||||
panic!(
|
||||
"Unexpected lifetime resolution {:?} for {:?} at {:?}",
|
||||
res, ident, ident.span
|
||||
)
|
||||
}
|
||||
};
|
||||
|
||||
let lifetime = Lifetime { id: outer_node_id, ident };
|
||||
collected_lifetimes.push((inner_node_id, lifetime, Some(inner_res)));
|
||||
}
|
||||
debug!(?collected_lifetimes);
|
||||
|
||||
// We only want to capture the lifetimes that appear in the bounds. So visit the bounds to
|
||||
// find out exactly which ones those are.
|
||||
// in fn return position, like the `fn test<'a>() -> impl Debug + 'a` example,
|
||||
// we only keep the lifetimes that appear in the `impl Debug` itself:
|
||||
let lifetimes_to_remap = lifetime_collector::lifetimes_in_ret_ty(&self.resolver, output);
|
||||
debug!(?lifetimes_to_remap);
|
||||
|
||||
// If this opaque type is only capturing a subset of the lifetimes (those that appear in
|
||||
// bounds), then create the new lifetime parameters required and create a mapping from the
|
||||
// old `'a` (on the function) to the new `'a` (on the opaque type).
|
||||
collected_lifetimes.extend(
|
||||
self.create_lifetime_defs(opaque_ty_def_id, &lifetimes_to_remap, &mut new_remapping)
|
||||
.into_iter()
|
||||
.map(|(new_node_id, lifetime)| (new_node_id, lifetime, None)),
|
||||
);
|
||||
debug!(?collected_lifetimes);
|
||||
debug!(?new_remapping);
|
||||
|
||||
// This creates pairs of HIR lifetimes and def_ids. In the given example `type
|
||||
// TestReturn<'a, T, 'x> = impl Debug + 'x`, it creates a collection containing the
|
||||
// new lifetime of the RPIT 'x and the def_id of the lifetime 'x corresponding to
|
||||
// `TestReturn`.
|
||||
let collected_lifetime_mapping: Vec<_> = collected_lifetimes
|
||||
.iter()
|
||||
.map(|(node_id, lifetime, res)| {
|
||||
let id = self.next_node_id();
|
||||
let res = res.unwrap_or(
|
||||
self.resolver.get_lifetime_res(lifetime.id).unwrap_or(LifetimeRes::Error),
|
||||
);
|
||||
let lifetime = self.new_named_lifetime_with_res(id, lifetime.ident, res);
|
||||
let def_id = self.local_def_id(*node_id);
|
||||
(lifetime, def_id)
|
||||
})
|
||||
let captured_lifetimes: Vec<_> = self
|
||||
.resolver
|
||||
.take_extra_lifetime_params(opaque_ty_node_id)
|
||||
.into_iter()
|
||||
.map(|(ident, id, _)| Lifetime { id, ident })
|
||||
.collect();
|
||||
debug!(?collected_lifetime_mapping);
|
||||
|
||||
self.with_hir_id_owner(opaque_ty_node_id, |this| {
|
||||
// Install the remapping from old to new (if any):
|
||||
this.with_remapping(new_remapping, |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.
|
||||
let opaque_ty_ref = self.lower_opaque_inner(
|
||||
opaque_ty_node_id,
|
||||
hir::OpaqueTyOrigin::AsyncFn(fn_def_id),
|
||||
in_trait,
|
||||
captured_lifetimes,
|
||||
span,
|
||||
opaque_ty_span,
|
||||
|this| {
|
||||
let future_bound = this.lower_async_fn_output_type_to_future_bound(
|
||||
output,
|
||||
span,
|
||||
@ -2052,96 +1905,10 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
let generic_params = this.arena.alloc_from_iter(collected_lifetimes.iter().map(
|
||||
|&(new_node_id, lifetime, _)| {
|
||||
let hir_id = this.lower_node_id(new_node_id);
|
||||
debug_assert_ne!(this.opt_local_def_id(new_node_id), None);
|
||||
|
||||
let (name, kind) = if lifetime.ident.name == kw::UnderscoreLifetime {
|
||||
(hir::ParamName::Fresh, hir::LifetimeParamKind::Elided)
|
||||
} else {
|
||||
(
|
||||
hir::ParamName::Plain(lifetime.ident),
|
||||
hir::LifetimeParamKind::Explicit,
|
||||
)
|
||||
};
|
||||
|
||||
hir::GenericParam {
|
||||
hir_id,
|
||||
def_id: this.local_def_id(new_node_id),
|
||||
name,
|
||||
span: lifetime.ident.span,
|
||||
pure_wrt_drop: false,
|
||||
kind: hir::GenericParamKind::Lifetime { kind },
|
||||
colon_span: None,
|
||||
source: hir::GenericParamSource::Generics,
|
||||
}
|
||||
},
|
||||
));
|
||||
debug!("lower_async_fn_ret_ty: generic_params={:#?}", generic_params);
|
||||
|
||||
let lifetime_mapping = if in_trait {
|
||||
Some(
|
||||
&*self.arena.alloc_from_iter(
|
||||
collected_lifetime_mapping
|
||||
.iter()
|
||||
.map(|(lifetime, def_id)| (**lifetime, *def_id)),
|
||||
),
|
||||
)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
let opaque_ty_item = hir::OpaqueTy {
|
||||
generics: this.arena.alloc(hir::Generics {
|
||||
params: generic_params,
|
||||
predicates: &[],
|
||||
has_where_clause_predicates: false,
|
||||
where_clause_span: this.lower_span(span),
|
||||
span: this.lower_span(span),
|
||||
}),
|
||||
bounds: arena_vec![this; future_bound],
|
||||
origin: hir::OpaqueTyOrigin::AsyncFn(fn_def_id),
|
||||
lifetime_mapping,
|
||||
in_trait,
|
||||
};
|
||||
|
||||
trace!("exist ty from async fn def id: {:#?}", opaque_ty_def_id);
|
||||
this.generate_opaque_type(opaque_ty_def_id, opaque_ty_item, span, opaque_ty_span)
|
||||
})
|
||||
});
|
||||
|
||||
// As documented above, we need to create the lifetime
|
||||
// arguments to our opaque type. Continuing with our example,
|
||||
// we're creating the type arguments for the return type:
|
||||
//
|
||||
// ```
|
||||
// Bar<'a, 'b, '0, '1, '_>
|
||||
// ```
|
||||
//
|
||||
// For the "input" lifetime parameters, we wish to create
|
||||
// references to the parameters themselves, including the
|
||||
// "implicit" ones created from parameter types (`'a`, `'b`,
|
||||
// '`0`, `'1`).
|
||||
//
|
||||
// For the "output" lifetime parameters, we just want to
|
||||
// generate `'_`.
|
||||
let generic_args = self.arena.alloc_from_iter(
|
||||
collected_lifetime_mapping
|
||||
.iter()
|
||||
.map(|(lifetime, _)| hir::GenericArg::Lifetime(*lifetime)),
|
||||
arena_vec![this; future_bound]
|
||||
},
|
||||
);
|
||||
|
||||
// Create the `Foo<...>` reference itself. Note that the `type
|
||||
// Foo = impl Trait` is, internally, created as a child of the
|
||||
// async fn, so the *type parameters* are inherited. It's
|
||||
// only the lifetime parameters that we must supply.
|
||||
let opaque_ty_ref = hir::TyKind::OpaqueDef(
|
||||
hir::ItemId { owner_id: hir::OwnerId { def_id: opaque_ty_def_id } },
|
||||
generic_args,
|
||||
in_trait,
|
||||
);
|
||||
let opaque_ty = self.ty(opaque_ty_span, opaque_ty_ref);
|
||||
hir::FnRetTy::Return(self.arena.alloc(opaque_ty))
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
use super::ResolverAstLoweringExt;
|
||||
use rustc_ast::visit::{self, BoundKind, LifetimeCtxt, Visitor};
|
||||
use rustc_ast::{FnRetTy, GenericBounds, Lifetime, NodeId, PathSegment, PolyTraitRef, Ty, TyKind};
|
||||
use rustc_ast::{GenericBounds, Lifetime, NodeId, PathSegment, PolyTraitRef, Ty, TyKind};
|
||||
use rustc_hir::def::LifetimeRes;
|
||||
use rustc_middle::span_bug;
|
||||
use rustc_middle::ty::ResolverAstLowering;
|
||||
@ -94,12 +94,6 @@ impl<'ast> Visitor<'ast> for LifetimeCollectVisitor<'ast> {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn lifetimes_in_ret_ty(resolver: &ResolverAstLowering, ret_ty: &FnRetTy) -> Vec<Lifetime> {
|
||||
let mut visitor = LifetimeCollectVisitor::new(resolver);
|
||||
visitor.visit_fn_ret_ty(ret_ty);
|
||||
visitor.collected_lifetimes
|
||||
}
|
||||
|
||||
pub fn lifetimes_in_bounds(
|
||||
resolver: &ResolverAstLowering,
|
||||
bounds: &GenericBounds,
|
||||
|
@ -2675,7 +2675,7 @@ pub struct OpaqueTy<'hir> {
|
||||
///
|
||||
/// This mapping associated a captured lifetime (first parameter) with the new
|
||||
/// early-bound lifetime that was generated for the opaque.
|
||||
pub lifetime_mapping: Option<&'hir [(Lifetime, LocalDefId)]>,
|
||||
pub lifetime_mapping: Option<&'hir [(&'hir Lifetime, LocalDefId)]>,
|
||||
/// Whether the opaque is a return-position impl trait (or async future)
|
||||
/// originating from a trait method. This makes it so that the opaque is
|
||||
/// lowered as an associated type.
|
||||
|
@ -82,7 +82,7 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen
|
||||
tcx,
|
||||
def_id,
|
||||
lifetime_mapping.iter().map(|(lifetime, def_id)| {
|
||||
(*lifetime, (*def_id, lifetime.ident.name, lifetime.ident.span))
|
||||
(**lifetime, (*def_id, lifetime.ident.name, lifetime.ident.span))
|
||||
}),
|
||||
tcx.generics_of(def_id.to_def_id()),
|
||||
&mut predicates,
|
||||
|
@ -1694,6 +1694,7 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
|
||||
// Leave the responsibility to create the `LocalDefId` to lowering.
|
||||
let param = self.r.next_node_id();
|
||||
let res = LifetimeRes::Fresh { param, binder };
|
||||
self.record_lifetime_param(param, res);
|
||||
|
||||
// Record the created lifetime parameter so lowering can pick it up and add it to HIR.
|
||||
self.r
|
||||
|
Loading…
x
Reference in New Issue
Block a user