1use rustc_data_structures::fx::FxIndexSet;
2use rustc_hir::def::DefKind;
3use rustc_hir::def_id::{DefId, LocalDefId};
4use rustc_middle::bug;
5use rustc_middle::ty::{
6self, Flags, ImplTraitInTraitData, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable,
7TypeVisitableExt, TypeVisitor,
8};
910use crate::infer::outlives::test_type_match;
11use crate::infer::region_constraints::VerifyIfEq;
12use crate::regions::{region_known_to_outlive, ty_known_to_outlive};
1314/// For a given alias type, this returns the set of (identity) generic args that
15/// are relevant for liveness, that can be inferred from outlives bounds on the
16/// alias itself, and the explicit and implicit outlives clauses of the alias.
17/// Callers should instantiate the returned args with the concrete args of the alias.
18///
19/// There are three cases to consider:
20/// 1. If there are *no* outlives bounds, then we return None.
21/// 2. If there is a `'static` outlives bound, then we know that all args are
22/// irrelevant, so we return an empty list.
23/// 3. If there are *any* outlives bounds, then we find any args that are known
24/// to outlive those bounds, since those are the args whose regions the
25/// underlying type could capture.
26x;#[tracing::instrument(level = "debug", skip(tcx), ret)]27pub(crate) fn live_args_for_alias_from_outlives_bounds<'tcx>(
28 tcx: TyCtxt<'tcx>,
29 kind: ty::AliasTyKind<'tcx>,
30) -> Option<ty::EarlyBinder<'tcx, Vec<ty::GenericArg<'tcx>>>> {
31let def_id = match kind {
32 ty::AliasTyKind::Projection { def_id }
33 | ty::AliasTyKind::Inherent { def_id }
34 | ty::AliasTyKind::Opaque { def_id }
35 | ty::AliasTyKind::Free { def_id } => def_id,
36 };
37let self_identity_args = ty::GenericArgs::identity_for_item(tcx, def_id);
3839// We first want to collect the outlives bounds of the alias.
40let bounds = tcx.item_bounds(def_id).instantiate_identity().skip_norm_wip();
41tracing::debug!(?bounds);
42let alias_ty = Ty::new_alias(
43 tcx,
44 ty::IsRigid::No,
45 ty::AliasTy::new_from_args(tcx, kind, self_identity_args),
46 );
47let outlives_regions: Vec<_> = bounds
48 .iter()
49 .filter_map(|clause| {
50let outlives = clause.as_type_outlives_clause()?;
51if let Some(outlives) = outlives.no_bound_vars()
52 && outlives.0 == alias_ty
53 {
54Some(outlives.1)
55 } else {
56 test_type_match::extract_verify_if_eq(
57 tcx,
58&outlives.map_bound(|ty::OutlivesClause(ty, bound)| VerifyIfEq { ty, bound }),
59// FIXME(#155345): Region handling should generally only
60 // deal with rigid aliases, making sure we do so correctly
61 // everywhere is effort, so we're just using `No` everywhere
62 // for now. This should change soon.
63alias_ty,
64 )
65 }
66 })
67 .collect();
68tracing::debug!(?outlives_regions);
6970// If there are no outlives bounds, then all (non-bivariant) args are potentially live.
71if outlives_regions.is_empty() {
72return None;
73 }
7475// If any of the outlives bounds are `'static`, then we know the alias
76 // doesn't capture *any* regions, so we can skip visiting any regions at all.
77 //
78 // I was originally a bit concerned about something like `'a: 'static`, and
79 // whether or not we need to mark `'a` as live. I don't think that we do.
80 //
81 // To dig in a bit: Think about the function using this alias. For the alias
82 // to be well-formed, then it must be proven that the arg (`'a` in this case)
83 // outlives `'static`. Well, if that is proven *once*, then it must be true
84 // across the entire function (because `'static` is free).
85 //
86 // I think this similarly applies to any other free region, like `'a: 'b`
87 // where `'b` is *also* free. Though, we of course can't know *here* which
88 // regions are going to be instantiated with free regions.
89if outlives_regions.contains(&tcx.lifetimes.re_static) {
90tracing::debug!("alias has a 'static outlives bound, so skipping visiting any regions");
91return Some(ty::EarlyBinder::bind(tcx, vec![]));
92 }
9394// Okay, so we know we have some outlives bounds, and that none of them are `'static`.
95 // Now, we need to find all other potentially-live args, those that outlive
96 // an outlives-bound region. `args_known_to_outlive_alias_params` does this
97 // for us, and in the case of opaques only includes *captured* regions, too.
9899let args_known_to_outlive =
100 tcx.args_known_to_outlive_alias_params(def_id).as_ref().skip_binder();
101tracing::debug!(?args_known_to_outlive);
102let mut live_args: Option<FxIndexSet<ty::GenericArg<'tcx>>> = None;
103for outlives_region in outlives_regions {
104let Some(outlives_params) =
105 args_known_to_outlive.iter().find(|(r, _)| *r == outlives_region)
106else {
107continue;
108 };
109let new_live_args = outlives_params.1.iter().copied().collect();
110match &mut live_args {
111None => live_args = Some(new_live_args),
112Some(prev) => *prev = prev.intersection(&new_live_args).copied().collect(),
113 };
114 }
115 live_args.map(|c| ty::EarlyBinder::bind(tcx, c.into_iter().collect()))
116}
117118/// For each region param of this alias compute the identity args that are known
119/// to outlive it, given only the alias's declared where-clauses.
120///
121/// Note: for opaques (including synthetic associated types from RPITITs),
122/// the outlives relationships are identified in the context of the *parent*,
123/// since bounds and well-formed types are not lowered.
124// FIXME: this likely should return a `BitSet` instead of a `Vec<Vec<>>`
125x;#[tracing::instrument(level = "debug", skip(tcx), ret)]126pub(crate) fn args_known_to_outlive_alias_params<'tcx>(
127 tcx: TyCtxt<'tcx>,
128 def_id: LocalDefId,
129) -> ty::EarlyBinder<'tcx, Vec<(ty::Region<'tcx>, Vec<ty::GenericArg<'tcx>>)>> {
130match tcx.def_kind(def_id) {
131 DefKind::OpaqueTy => args_known_to_outlive_opaque_params(tcx, def_id),
132 DefKind::AssocTy
133if let Some(ImplTraitInTraitData::Trait { fn_def_id: _, opaque_def_id }) =
134 tcx.opt_rpitit_info(def_id.to_def_id()) =>
135 {
136 args_known_to_outlive_opaque_params(tcx, opaque_def_id.expect_local())
137 }
138 DefKind::AssocTy | DefKind::TyAlias => args_known_to_outlive_non_opaque_params(tcx, def_id),
139 kind => {
140bug!("improper def_kind {kind:?} passed to `live_args_for_alias_from_outlives_bounds`")
141 }
142 }
143}
144145/// For each *captured* region of this alias, compute the *captured* identity
146/// args that are known to outlive it, given the definition of the opaque type
147/// in the the *parent* context.
148///
149/// Some examples:
150/// ```ignore (illustrative)
151/// // Returns `[('a, ['a]), ('b, ['b])]`
152/// fn foo<'a, 'b>() -> impl Sized + use<'a, 'b> {}
153///
154/// // Returns `[('a, ['a]), ('b, ['b])]`
155/// fn foo<'a: 'a, 'b>() -> impl Sized + use<'a, 'b> {}
156///
157/// // Returns `[('a, ['a])]`
158/// fn foo<'a, 'b>() -> impl Sized + use<'a> {}
159///
160/// // Returns `[('a, ['a, 'b]), ('b, ['b])]`
161/// fn foo<'a, 'b: 'a>() -> impl Sized + use<'a, 'b> {}
162///
163/// // Returns `[('a, ['a, 'b]), ('b, ['b])]`
164/// fn foo<'a, 'b>(_: &'a &'b ()) -> impl Sized + use<'a, 'b> {}
165/// ```
166///
167/// Importantly:
168/// - *All* captured regions are considered (not just those in outlives bounds)
169/// - It doesn't matter if the captured region is early-bound or late-bound
170x;#[tracing::instrument(level = "debug", skip(tcx), ret)]171pub(crate) fn args_known_to_outlive_opaque_params<'tcx>(
172 tcx: TyCtxt<'tcx>,
173 def_id: LocalDefId,
174) -> ty::EarlyBinder<'tcx, Vec<(ty::Region<'tcx>, Vec<ty::GenericArg<'tcx>>)>> {
175let self_identity_args = ty::GenericArgs::identity_for_item(tcx, def_id);
176177let mut result = Vec::new();
178179// For implied bounds, we need the set of WF types from the parents.
180 // - For functions, this is all the input and output types.
181 // - For type alias, there are no implied bounds, so this is empty.
182let (parent_def_id, wf_tys) = match tcx.opaque_ty_origin(def_id) {
183 rustc_hir::OpaqueTyOrigin::FnReturn { parent, .. }
184 | rustc_hir::OpaqueTyOrigin::AsyncFn { parent, .. }
185 | rustc_hir::OpaqueTyOrigin::TyAlias { parent, .. } => {
186let wf_tys = FxIndexSet::from_iter(
187 tcx.assumed_wf_types(parent.expect_local()).iter().map(|(ty, _)| *ty),
188 );
189 (parent, wf_tys)
190 }
191 };
192let parent_param_env = tcx.param_env(parent_def_id);
193tracing::debug!(?parent_param_env);
194195// Map the outlives regions to the parent regions.
196 // If we have `fn foo<'a>() -> impl Sized + 'a`, then this gets lowered as
197 // ```ignore (illustrative)
198 // opaque foo_opaque<'a0>: Sized + 'a0;
199 // fn foo<'a>() -> foo::<'a>::foo_opaque<'a> { ... }
200 // ```
201 // This maps `'a0` to `'a`, because that is what will be used to get the
202 // explicit and implied outlives relations.
203 //
204 // I suppose, an alternative way to do this would be iterate through all the
205 // *parent* regions and then find those that are captured. This should be
206 // basically equivalent (except with the added frustration of needing to
207 // build a `Region` from the opaque region's `LocalDefId`).
208let generics = tcx.generics_of(def_id);
209let mut parent_outlives_regions = Vec::with_capacity(generics.own_params.len());
210for opaque_arg in self_identity_args[generics.parent_count..].iter() {
211let Some(opaque_region) = opaque_arg.as_region() else {
212continue;
213 };
214let region_def_id = match opaque_region.kind() {
215 ty::ReEarlyParam(ebr) => generics.param_at(ebr.index as usize, tcx).def_id,
216_ => panic!("unexpected region `{opaque_region}` in opaque bounds"),
217 };
218let parent_region =
219 tcx.map_opaque_lifetime_to_parent_lifetime(region_def_id.expect_local());
220tracing::debug!(?region_def_id, ?parent_region);
221 parent_outlives_regions.push((parent_region, opaque_region));
222 }
223tracing::debug!(?parent_outlives_regions);
224225// For every captured region, we want to consider outlived args from two sources:
226 // 1) *Types*: These come from *parent* generics (and are not duplicated to the opaque)
227 // 2) *Captured Regions*
228 //
229 // In both cases, we need to check known outlives for the *parent* region, because that's where the param_env and wf_tys are.
230for (parent_outlived_region, opaque_outlived_region) in parent_outlives_regions.iter() {
231let mut opaque_outlives_args = Vec::with_capacity(self_identity_args.len());
232for parent_outlives_arg in self_identity_args[..generics.parent_count].iter() {
233let type_outlives = match parent_outlives_arg.kind() {
234// Consts don't have any non-static regions
235ty::GenericArgKind::Const(_) => continue,
236// Lifetimes should be captured
237ty::GenericArgKind::Lifetime(_) => continue,
238 ty::GenericArgKind::Type(t) => ty_known_to_outlive(
239 tcx,
240 def_id,
241 parent_param_env,
242&wf_tys,
243 t,
244*parent_outlived_region,
245 ),
246 };
247if !type_outlives {
248continue;
249 }
250251// Types aren't captured, so don't need to map to the opaque
252opaque_outlives_args.push(*parent_outlives_arg);
253 }
254255for &(parent_outlives_region, opaque_region) in parent_outlives_regions.iter() {
256let region_outlives = parent_outlives_region == *parent_outlived_region
257 || region_known_to_outlive(
258 tcx,
259 def_id,
260 parent_param_env,
261&wf_tys,
262 parent_outlives_region,
263*parent_outlived_region,
264 );
265if !region_outlives {
266continue;
267 }
268269 opaque_outlives_args.push(opaque_region.into());
270 }
271272 result.push((*opaque_outlived_region, opaque_outlives_args));
273 }
274275 ty::EarlyBinder::bind(tcx, result)
276}
277278x;#[tracing::instrument(level = "debug", skip(tcx), ret)]279pub(crate) fn args_known_to_outlive_non_opaque_params<'tcx>(
280 tcx: TyCtxt<'tcx>,
281 def_id: LocalDefId,
282) -> ty::EarlyBinder<'tcx, Vec<(ty::Region<'tcx>, Vec<ty::GenericArg<'tcx>>)>> {
283let self_identity_args = ty::GenericArgs::identity_for_item(tcx, def_id);
284let param_env = tcx.param_env(def_id);
285tracing::debug!(?param_env);
286let wf_tys = tcx.assumed_wf_types(def_id).iter().map(|(ty, _)| *ty).collect::<FxIndexSet<_>>();
287let mut result = Vec::new();
288for outlived_arg in self_identity_args.iter() {
289let Some(outlived_region) = outlived_arg.as_region() else {
290continue;
291 };
292let outliving_args = self_identity_args
293 .iter()
294 .filter(|arg| match arg.kind() {
295 ty::GenericArgKind::Lifetime(r) => {
296 region_known_to_outlive(tcx, def_id, param_env, &wf_tys, r, outlived_region)
297 }
298 ty::GenericArgKind::Type(t) => {
299 ty_known_to_outlive(tcx, def_id, param_env, &wf_tys, t, outlived_region)
300 }
301 ty::GenericArgKind::Const(_) => false,
302 })
303 .collect();
304 result.push((outlived_region, outliving_args));
305 }
306 ty::EarlyBinder::bind(tcx, result)
307}
308309/// For a param-env clause `for<'v..> <T as Trait>::Assoc<..>: 'bound` that
310/// applies to `ty` (an alias with `alias_def_id`), returns the set of (identity) args
311/// that the underlying type could possibly capture, as restricted by this clause.
312///
313/// As an example, let's imagine we had the following associated type definition:
314/// ```ignore (illustrative)
315/// type Assoc<'a, 'b, 'c: 'a> = (&'a &'c (), &'b ());
316/// ```
317///
318/// the following clause:
319/// ```ignore (illustrative)
320/// for<'x, 'y> T::Assoc<'x, 'x, 'y>: 'x
321/// ```
322///
323/// We know from the clause alone that *given some substitution of `T:Assoc`*,
324/// we know that it can capture either the first or the second region. However,
325/// the bounds on the associated type itself additionally imply that the
326/// third region can *also* be captured, because it outlives the first.
327///
328/// Now, let's assume we had this clause:
329/// ```ignore (illustrative)
330/// for<'x, 'y> T::Assoc<'x, 'y, 'x>: 'x
331/// ```
332///
333/// Here, we know that `'a` and `'c` could be captured, but there is no outlives
334/// relationship to `'b` for either of those, so the underlying type can't
335/// capture any arg containing `'b`.
336///
337/// Note: because higher-ranked bounds don't have implications, there will be
338/// some cases (like `for<'x, 'y, 'z> T::Assoc<'x, 'y, 'z>: 'x`) that won't
339/// be satisfiable today, but the logic here should hold whenever there *is*.
340///
341/// Returns `None` if the clause doesn't apply to `ty` or gives us no information.
342x;#[tracing::instrument(level = "debug", skip(tcx), ret)]343fn live_args_for_outlives_clause<'tcx>(
344 tcx: TyCtxt<'tcx>,
345 alias_def_id: DefId,
346 ty: Ty<'tcx>,
347 outlives: ty::Binder<'tcx, ty::TypeOutlivesClause<'tcx>>,
348) -> Option<FxIndexSet<ty::EarlyBinder<'tcx, ty::GenericArg<'tcx>>>> {
349// N.B. it's okay to skip the binder here (and in the rest of the function),
350 // because all variables under binders do not escape
351let ty::Alias(_, ty::AliasTy { kind: clause_alias_kind, args: clause_args, .. }) =
352*outlives.skip_binder().0.kind()
353else {
354return None;
355 };
356let clause_def_id = match clause_alias_kind {
357 ty::AliasTyKind::Projection { def_id }
358 | ty::AliasTyKind::Inherent { def_id }
359 | ty::AliasTyKind::Opaque { def_id }
360 | ty::AliasTyKind::Free { def_id } => def_id,
361 };
362if clause_def_id != alias_def_id {
363return None;
364 }
365366// Here, we're just using this to check if the clause *could apply* to `ty`,
367 // but importantly we don't want to use the returned region, because that is
368 // the "last visited" region in `ty` that matches the outlves bound. Actually,
369 // we want *all* the identity regions in `ty` that match the outlives bound.
370test_type_match::extract_verify_if_eq(
371 tcx,
372&outlives.map_bound(|ty::OutlivesClause(ty, bound)| VerifyIfEq { ty, bound }),
373 ty,
374 )?;
375376let outlived_region = outlives.skip_binder().1;
377let clause_identity_args = ty::GenericArgs::identity_for_item(tcx, alias_def_id);
378match outlived_region.kind() {
379// The underlying type must outlive `'static`, so it can't capture any of the args at all.
380 //
381 // Of course, you may ask: "what if the function has a `'a: 'static` bound?" See the corresponding
382 // comment in `live_args_for_alias_from_outlives_bounds` for why we don't need to worry about that.
383ty::ReStatic => Some(FxIndexSet::default()),
384 ty::ReBound(_, br) => {
385// The bound is one of the clause's higher-ranked vars. Find the arg
386 // positions it occupies, then (at the alias's identity level) find
387 // all args that are known to outlive one of those positions given
388 // the alias's declared bounds -- only those can be captured by the
389 // underlying type.
390let mut outlived_regions = Vec::new();
391for (clause_arg, identity_arg) in clause_args.iter().zip(clause_identity_args.iter()) {
392match clause_arg.kind() {
393 ty::GenericArgKind::Lifetime(r) => {
394if let ty::ReBound(_, arg_br) = r.kind()
395 && arg_br.var == br.var
396 {
397 outlived_regions.push(identity_arg.expect_region());
398 }
399 }
400 ty::GenericArgKind::Type(_) | ty::GenericArgKind::Const(_) => {
401// A bound var inside a type or const arg (e.g.
402 // `for<'a> <F as FnOnce<(&'a mut i32,)>>::Output: 'a`)
403 // can't be reasoned about at the identity-param level,
404 // so conservatively treat the clause as giving no
405 // restriction at all.
406if clause_arg.has_escaping_bound_vars() {
407return None;
408 }
409 }
410 }
411 }
412if outlived_regions.is_empty() {
413// The bound var doesn't appear in the args at all, so the clause
414 // requires the underlying type to outlive *every* region, which
415 // is equivalent to a `'static` bound.
416return Some(FxIndexSet::default());
417 }
418419// The underlying type can capture any arg that's known to outlive one
420 // of the bound var's positions (they're all instantiated to the same
421 // region at any use site this clause applies to).
422let args_known_to_outlive = tcx.args_known_to_outlive_alias_params(alias_def_id);
423tracing::debug!(?outlived_regions, ?args_known_to_outlive);
424let mut capturable_args = FxIndexSet::default();
425for &outlived_region in &outlived_regions {
426// There's a bit of a dance here around `Earlybinder::skip_binder`
427 // and then later a `Earlybinder::bind`. This is because there's
428 // no real good way today to move the `EarlyBinder` inward
429 // declaratively without cloning the entire thing.
430let (_, outliving_args) = args_known_to_outlive
431 .as_ref()
432 .skip_binder()
433 .iter()
434 .find(|(region, _)| *region == outlived_region)
435 .unwrap();
436 capturable_args
437 .extend(outliving_args.iter().copied().map(|a| ty::EarlyBinder::bind(tcx, a)));
438 }
439Some(capturable_args)
440 }
441// A free region (e.g. `for<a> T::Assoc<'a, 'x>: 'x`, where `'x` is free).
442 // This is effectively the same as `for<'a, 'b> T::Assoc<'a, 'b>: 'b`,
443 // but that only is sound if we either know that the second substituted
444 // lifetime equals `'x` or if we *constrain* that lifetime to be `'x`.
445 //
446 // In either case, something like this doesn't work today:
447 // ```ignore (illustrative)
448 // fn bar<'a, 'b>(a: &'a mut (), b: &'b ()) -> <Foo as MyTrait>::Assoc<'a, 'b> { b }
449 // fn foo<'x>()
450 // where
451 // for<'h> <Foo as MyTrait>::Assoc<'h, 'x>: 'x,
452 // {
453 // let a = &mut ();
454 // let b: &'x () = &();
455 // let val1 = rpit(a, b);
456 // let val2 = rpit(a, b);
457 // drop(val1);
458 // drop(val32);
459 // }
460 // ```
461 // So, we conservatively treat this as giving no restriction on which args can be captured.
462ty::ReEarlyParam(..) => None,
463// Don't know that we actually hit this (maybe `ReError`), go ahead and be conservative.
464_ => None,
465 }
466}
467468/// Visits free regions in the type that are relevant for liveness computation.
469/// These regions are passed to `OP`.
470///
471/// Specifically, we visit all of the regions of types recursively, except if
472/// the type is an alias, we look at the outlives bounds in the param-env and
473/// the alias's item bounds. Each such bound restricts which of the alias's
474/// args the underlying type could have captured, so only those (capturable)
475/// args are visited. If there are no applicable bounds, we walk through the
476/// alias's (non-bivariant) args structurally.
477pub struct FreeRegionsVisitor<'tcx, OP: FnMut(ty::Region<'tcx>)> {
478pub tcx: TyCtxt<'tcx>,
479pub param_env: ty::ParamEnv<'tcx>,
480pub op: OP,
481}
482483impl<'tcx, OP> TypeVisitor<TyCtxt<'tcx>> for FreeRegionsVisitor<'tcx, OP>
484where
485OP: FnMut(ty::Region<'tcx>),
486{
487fn visit_region(&mut self, r: ty::Region<'tcx>) {
488match r.kind() {
489// ignore bound regions, keep visiting
490ty::ReBound(_, _) => {}
491_ => (self.op)(r),
492 }
493 }
494495#[allow(clippy :: suspicious_else_formatting)]
{
let __tracing_attr_span;
let __tracing_attr_guard;
if ::tracing::Level::DEBUG <= ::tracing::level_filters::STATIC_MAX_LEVEL
&&
::tracing::Level::DEBUG <=
::tracing::level_filters::LevelFilter::current() ||
{ false } {
__tracing_attr_span =
{
use ::tracing::__macro_support::Callsite as _;
static __CALLSITE: ::tracing::callsite::DefaultCallsite =
{
static META: ::tracing::Metadata<'static> =
{
::tracing_core::metadata::Metadata::new("visit_ty",
"rustc_trait_selection::traits::outlives_for_liveness",
::tracing::Level::DEBUG,
::tracing_core::__macro_support::Option::Some("compiler/rustc_trait_selection/src/traits/outlives_for_liveness.rs"),
::tracing_core::__macro_support::Option::Some(495u32),
::tracing_core::__macro_support::Option::Some("rustc_trait_selection::traits::outlives_for_liveness"),
::tracing_core::field::FieldSet::new(&[{
const NAME:
::tracing::__macro_support::FieldName<{
::tracing::__macro_support::FieldName::len("ty")
}> =
::tracing::__macro_support::FieldName::new("ty");
NAME.as_str()
}], ::tracing_core::callsite::Identifier(&__CALLSITE)),
::tracing::metadata::Kind::SPAN)
};
::tracing::callsite::DefaultCallsite::new(&META)
};
let mut interest = ::tracing::subscriber::Interest::never();
if ::tracing::Level::DEBUG <=
::tracing::level_filters::STATIC_MAX_LEVEL &&
::tracing::Level::DEBUG <=
::tracing::level_filters::LevelFilter::current() &&
{ interest = __CALLSITE.interest(); !interest.is_never() }
&&
::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
interest) {
let meta = __CALLSITE.metadata();
::tracing::Span::new(meta,
&{
#[allow(unused_imports)]
use ::tracing::field::{debug, display, Value};
meta.fields().value_set_all(&[(::tracing::__macro_support::Option::Some(&::tracing::field::debug(&ty)
as &dyn ::tracing::field::Value))])
})
} else {
let span =
::tracing::__macro_support::__disabled_span(__CALLSITE.metadata());
{};
span
}
};
__tracing_attr_guard = __tracing_attr_span.enter();
}
#[warn(clippy :: suspicious_else_formatting)]
{
#[allow(unknown_lints, unreachable_code, clippy ::
diverging_sub_expression, clippy :: empty_loop, clippy ::
let_unit_value, clippy :: let_with_type_underscore, clippy ::
needless_return, clippy :: unreachable)]
if false {
let __tracing_attr_fake_return: () = loop {};
return __tracing_attr_fake_return;
}
{
if !ty.flags().intersects(ty::TypeFlags::HAS_FREE_REGIONS) {
return;
}
match *ty.kind() {
ty::Alias(_, ty::AliasTy { kind, args, .. }) => {
let tcx = self.tcx;
let param_env = self.param_env;
let def_id =
match kind {
ty::AliasTyKind::Projection { def_id } |
ty::AliasTyKind::Inherent { def_id } |
ty::AliasTyKind::Opaque { def_id } | ty::AliasTyKind::Free {
def_id } => def_id,
};
let mut capturable:
Option<FxIndexSet<ty::EarlyBinder<'tcx,
ty::GenericArg<'tcx>>>> = None;
let mut restrict =
|capturable_args:
FxIndexSet<ty::EarlyBinder<'tcx, ty::GenericArg<'tcx>>>|
{
match &mut capturable {
None => capturable = Some(capturable_args),
Some(prev) => {
*prev =
prev.intersection(&capturable_args).copied().collect()
}
};
};
if let Some(live_args) =
tcx.live_args_for_alias_from_outlives_bounds(kind) {
restrict(live_args.as_ref().skip_binder().iter().copied().map(|a|
ty::EarlyBinder::bind(tcx, a)).collect());
}
for clause in param_env.caller_bounds() {
let Some(outlives) =
clause.as_type_outlives_clause() else { continue; };
if let Some(capturable_args) =
live_args_for_outlives_clause(tcx, def_id, ty, outlives) {
restrict(capturable_args);
}
}
{
use ::tracing::__macro_support::Callsite as _;
static __CALLSITE: ::tracing::callsite::DefaultCallsite =
{
static META: ::tracing::Metadata<'static> =
{
::tracing_core::metadata::Metadata::new("event compiler/rustc_trait_selection/src/traits/outlives_for_liveness.rs:565",
"rustc_trait_selection::traits::outlives_for_liveness",
::tracing::Level::DEBUG,
::tracing_core::__macro_support::Option::Some("compiler/rustc_trait_selection/src/traits/outlives_for_liveness.rs"),
::tracing_core::__macro_support::Option::Some(565u32),
::tracing_core::__macro_support::Option::Some("rustc_trait_selection::traits::outlives_for_liveness"),
::tracing_core::field::FieldSet::new(&[{
const NAME:
::tracing::__macro_support::FieldName<{
::tracing::__macro_support::FieldName::len("capturable")
}> =
::tracing::__macro_support::FieldName::new("capturable");
NAME.as_str()
}], ::tracing_core::callsite::Identifier(&__CALLSITE)),
::tracing::metadata::Kind::EVENT)
};
::tracing::callsite::DefaultCallsite::new(&META)
};
let enabled =
::tracing::Level::DEBUG <=
::tracing::level_filters::STATIC_MAX_LEVEL &&
::tracing::Level::DEBUG <=
::tracing::level_filters::LevelFilter::current() &&
{
let interest = __CALLSITE.interest();
!interest.is_never() &&
::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
interest)
};
if enabled {
(|value_set: ::tracing::field::ValueSet|
{
let meta = __CALLSITE.metadata();
::tracing::Event::dispatch(meta, &value_set);
;
})({
#[allow(unused_imports)]
use ::tracing::field::{debug, display, Value};
__CALLSITE.metadata().fields().value_set_all(&[(::tracing::__macro_support::Option::Some(&::tracing::field::debug(&capturable)
as &dyn ::tracing::field::Value))])
});
} else { ; }
};
match capturable {
Some(capturable_args) => {
for arg in capturable_args {
let arg = arg.instantiate(tcx, args).skip_norm_wip();
arg.visit_with(self);
}
}
None => {
let variances = tcx.opt_alias_variances(kind);
for (idx, s) in args.iter().enumerate() {
if variances.map(|variances| variances[idx]) !=
Some(ty::Bivariant) {
s.visit_with(self);
}
}
}
}
}
_ => ty.super_visit_with(self),
}
}
}
}#[tracing::instrument(skip(self), level = "debug")]496fn visit_ty(&mut self, ty: Ty<'tcx>) {
497// We're only interested in types involving regions
498if !ty.flags().intersects(ty::TypeFlags::HAS_FREE_REGIONS) {
499return;
500 }
501502match *ty.kind() {
503// We can prove that an alias is live two ways:
504 // 1. All the components are live.
505 // 2. There is a known outlives bound or where-clause, and that
506 // region is live.
507 //
508 // We search through the item bounds and where clauses for
509 // either `'static` or a unique outlives region, and if one is
510 // found, we just need to prove that that region is still live.
511 // If one is not found, then we continue to walk through the alias.
512ty::Alias(_, ty::AliasTy { kind, args, .. }) => {
513let tcx = self.tcx;
514let param_env = self.param_env;
515516// For aliases other than opaques, we have to consider two
517 // sources of information to identity potentially-live args:
518 // - Bounds on alias item itself
519 // - Outlives clauses on the current function that apply to the alias
520 //
521 // Each source of information *restricts* the set of potentially-live
522 // args independently: only the args that can be live for *every*
523 // source of information can be actually live, so we take the intersection.
524let def_id = match kind {
525 ty::AliasTyKind::Projection { def_id }
526 | ty::AliasTyKind::Inherent { def_id }
527 | ty::AliasTyKind::Opaque { def_id }
528 | ty::AliasTyKind::Free { def_id } => def_id,
529 };
530let mut capturable: Option<
531 FxIndexSet<ty::EarlyBinder<'tcx, ty::GenericArg<'tcx>>>,
532 > = None;
533let mut restrict =
534 |capturable_args: FxIndexSet<ty::EarlyBinder<'tcx, ty::GenericArg<'tcx>>>| {
535match &mut capturable {
536None => capturable = Some(capturable_args),
537Some(prev) => {
538*prev = prev.intersection(&capturable_args).copied().collect()
539 }
540 };
541 };
542543if let Some(live_args) = tcx.live_args_for_alias_from_outlives_bounds(kind) {
544 restrict(
545 live_args
546 .as_ref()
547 .skip_binder()
548 .iter()
549 .copied()
550 .map(|a| ty::EarlyBinder::bind(tcx, a))
551 .collect(),
552 );
553 }
554555for clause in param_env.caller_bounds() {
556let Some(outlives) = clause.as_type_outlives_clause() else {
557continue;
558 };
559if let Some(capturable_args) =
560 live_args_for_outlives_clause(tcx, def_id, ty, outlives)
561 {
562 restrict(capturable_args);
563 }
564 }
565tracing::debug!(?capturable);
566567match capturable {
568Some(capturable_args) => {
569for arg in capturable_args {
570let arg = arg.instantiate(tcx, args).skip_norm_wip();
571 arg.visit_with(self);
572 }
573 }
574None => {
575// Skip lifetime parameters that are not captured, since they do
576 // not need to be live.
577let variances = tcx.opt_alias_variances(kind);
578for (idx, s) in args.iter().enumerate() {
579if variances.map(|variances| variances[idx]) != Some(ty::Bivariant) {
580 s.visit_with(self);
581 }
582 }
583 }
584 }
585 }
586587_ => ty.super_visit_with(self),
588 }
589 }
590}