3 use rustc_hir::def_id::DefId;
4 use rustc_middle::ty::query::Providers;
5 use rustc_middle::ty::subst::GenericArgKind;
6 use rustc_middle::ty::{self, CratePredicatesMap, ToPredicate, TyCtxt};
7 use rustc_span::symbol::sym;
12 /// Code to write unit test for outlives.
16 pub fn provide(providers: &mut Providers) {
17 *providers = Providers { inferred_outlives_of, inferred_outlives_crate, ..*providers };
20 fn inferred_outlives_of(tcx: TyCtxt<'_>, item_def_id: DefId) -> &[(ty::Predicate<'_>, Span)] {
21 let id = tcx.hir().local_def_id_to_hir_id(item_def_id.expect_local());
23 if matches!(tcx.def_kind(item_def_id), hir::def::DefKind::AnonConst) && tcx.lazy_normalization()
25 if tcx.hir().opt_const_param_default_param_hir_id(id).is_some() {
26 // In `generics_of` we set the generics' parent to be our parent's parent which means that
27 // we lose out on the predicates of our actual parent if we dont return those predicates here.
28 // (See comment in `generics_of` for more information on why the parent shenanigans is necessary)
30 // struct Foo<'a, 'b, const N: usize = { ... }>(&'a &'b ());
31 // ^^^ ^^^^^^^ the def id we are calling
32 // ^^^ inferred_outlives_of on
33 // parent item we dont have set as the
34 // parent of generics returned by `generics_of`
36 // In the above code we want the anon const to have predicates in its param env for `'b: 'a`
37 let item_def_id = tcx.hir().get_parent_item(id);
38 // In the above code example we would be calling `inferred_outlives_of(Foo)` here
39 return tcx.inferred_outlives_of(item_def_id);
43 match tcx.hir().get(id) {
44 Node::Item(item) => match item.kind {
45 hir::ItemKind::Struct(..) | hir::ItemKind::Enum(..) | hir::ItemKind::Union(..) => {
46 let crate_map = tcx.inferred_outlives_crate(());
48 let predicates = crate_map.predicates.get(&item_def_id).copied().unwrap_or(&[]);
50 if tcx.has_attr(item_def_id, sym::rustc_outlives) {
51 let mut pred: Vec<String> = predicates
53 .map(|(out_pred, _)| match out_pred.kind().skip_binder() {
54 ty::PredicateKind::RegionOutlives(p) => p.to_string(),
55 ty::PredicateKind::TypeOutlives(p) => p.to_string(),
56 err => bug!("unexpected predicate {:?}", err),
61 let span = tcx.def_span(item_def_id);
62 let mut err = tcx.sess.struct_span_err(span, "rustc_outlives");
69 debug!("inferred_outlives_of({:?}) = {:?}", item_def_id, predicates);
81 fn inferred_outlives_crate(tcx: TyCtxt<'_>, (): ()) -> CratePredicatesMap<'_> {
82 // Compute a map from each struct/enum/union S to the **explicit**
83 // outlives predicates (`T: 'a`, `'a: 'b`) that the user wrote.
84 // Typically there won't be many of these, except in older code where
85 // they were mandatory. Nonetheless, we have to ensure that every such
86 // predicate is satisfied, so they form a kind of base set of requirements
89 // Compute the inferred predicates
90 let global_inferred_outlives = implicit_infer::infer_predicates(tcx);
92 // Convert the inferred predicates into the "collected" form the
93 // global data structure expects.
95 // FIXME -- consider correcting impedance mismatch in some way,
96 // probably by updating the global data structure.
97 let predicates = global_inferred_outlives
99 .map(|(&def_id, set)| {
100 let predicates = &*tcx.arena.alloc_from_iter(set.0.iter().filter_map(
101 |(ty::OutlivesPredicate(kind1, region2), &span)| {
102 match kind1.unpack() {
103 GenericArgKind::Type(ty1) => Some((
104 ty::Binder::dummy(ty::PredicateKind::TypeOutlives(
105 ty::OutlivesPredicate(ty1, *region2),
110 GenericArgKind::Lifetime(region1) => Some((
111 ty::Binder::dummy(ty::PredicateKind::RegionOutlives(
112 ty::OutlivesPredicate(region1, *region2),
117 GenericArgKind::Const(_) => {
118 // Generic consts don't impose any constraints.
128 ty::CratePredicatesMap { predicates }