1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130
use hir::Node;
use rustc_hir as hir;
use rustc_hir::def_id::LocalDefId;
use rustc_middle::query::Providers;
use rustc_middle::ty::GenericArgKind;
use rustc_middle::ty::{self, CratePredicatesMap, ToPredicate, TyCtxt};
use rustc_span::symbol::sym;
use rustc_span::Span;
mod explicit;
mod implicit_infer;
/// Code to write unit test for outlives.
pub mod test;
mod utils;
pub fn provide(providers: &mut Providers) {
*providers = Providers { inferred_outlives_of, inferred_outlives_crate, ..*providers };
}
fn inferred_outlives_of(tcx: TyCtxt<'_>, item_def_id: LocalDefId) -> &[(ty::Clause<'_>, Span)] {
let id = tcx.hir().local_def_id_to_hir_id(item_def_id);
if matches!(tcx.def_kind(item_def_id), hir::def::DefKind::AnonConst)
&& tcx.features().generic_const_exprs
{
if tcx.hir().opt_const_param_default_param_def_id(id).is_some() {
// In `generics_of` we set the generics' parent to be our parent's parent which means that
// we lose out on the predicates of our actual parent if we dont return those predicates here.
// (See comment in `generics_of` for more information on why the parent shenanigans is necessary)
//
// struct Foo<'a, 'b, const N: usize = { ... }>(&'a &'b ());
// ^^^ ^^^^^^^ the def id we are calling
// ^^^ inferred_outlives_of on
// parent item we dont have set as the
// parent of generics returned by `generics_of`
//
// In the above code we want the anon const to have predicates in its param env for `'b: 'a`
let item_def_id = tcx.hir().get_parent_item(id);
// In the above code example we would be calling `inferred_outlives_of(Foo)` here
return tcx.inferred_outlives_of(item_def_id);
}
}
match tcx.hir().get(id) {
Node::Item(item) => match item.kind {
hir::ItemKind::Struct(..) | hir::ItemKind::Enum(..) | hir::ItemKind::Union(..) => {
let crate_map = tcx.inferred_outlives_crate(());
let predicates =
crate_map.predicates.get(&item_def_id.to_def_id()).copied().unwrap_or(&[]);
if tcx.has_attr(item_def_id, sym::rustc_outlives) {
let mut pred: Vec<String> = predicates
.iter()
.map(|(out_pred, _)| match out_pred.kind().skip_binder() {
ty::ClauseKind::RegionOutlives(p) => p.to_string(),
ty::ClauseKind::TypeOutlives(p) => p.to_string(),
err => bug!("unexpected clause {:?}", err),
})
.collect();
pred.sort();
let span = tcx.def_span(item_def_id);
let mut err = tcx.sess.struct_span_err(span, "rustc_outlives");
for p in pred {
err.note(p);
}
err.emit();
}
debug!("inferred_outlives_of({:?}) = {:?}", item_def_id, predicates);
predicates
}
_ => &[],
},
_ => &[],
}
}
fn inferred_outlives_crate(tcx: TyCtxt<'_>, (): ()) -> CratePredicatesMap<'_> {
// Compute a map from each struct/enum/union S to the **explicit**
// outlives predicates (`T: 'a`, `'a: 'b`) that the user wrote.
// Typically there won't be many of these, except in older code where
// they were mandatory. Nonetheless, we have to ensure that every such
// predicate is satisfied, so they form a kind of base set of requirements
// for the type.
// Compute the inferred predicates
let global_inferred_outlives = implicit_infer::infer_predicates(tcx);
// Convert the inferred predicates into the "collected" form the
// global data structure expects.
//
// FIXME -- consider correcting impedance mismatch in some way,
// probably by updating the global data structure.
let predicates = global_inferred_outlives
.iter()
.map(|(&def_id, set)| {
let predicates =
&*tcx.arena.alloc_from_iter(set.as_ref().skip_binder().iter().filter_map(
|(ty::OutlivesPredicate(kind1, region2), &span)| {
match kind1.unpack() {
GenericArgKind::Type(ty1) => Some((
ty::ClauseKind::TypeOutlives(ty::OutlivesPredicate(ty1, *region2))
.to_predicate(tcx),
span,
)),
GenericArgKind::Lifetime(region1) => Some((
ty::ClauseKind::RegionOutlives(ty::OutlivesPredicate(
region1, *region2,
))
.to_predicate(tcx),
span,
)),
GenericArgKind::Const(_) => {
// Generic consts don't impose any constraints.
None
}
}
},
));
(def_id, predicates)
})
.collect();
ty::CratePredicatesMap { predicates }
}