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