]> git.lizzy.rs Git - rust.git/blob - compiler/rustc_typeck/src/outlives/mod.rs
Rollup merge of #87354 - Wind-River:2021_master, r=kennytm
[rust.git] / compiler / rustc_typeck / src / outlives / mod.rs
1 use hir::Node;
2 use rustc_hir as hir;
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;
8 use rustc_span::Span;
9
10 mod explicit;
11 mod implicit_infer;
12 /// Code to write unit test for outlives.
13 pub mod test;
14 mod utils;
15
16 pub fn provide(providers: &mut Providers) {
17     *providers = Providers { inferred_outlives_of, inferred_outlives_crate, ..*providers };
18 }
19
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());
22
23     if matches!(tcx.def_kind(item_def_id), hir::def::DefKind::AnonConst) && tcx.lazy_normalization()
24     {
25         if let Some(_) = tcx.hir().opt_const_param_default_param_hir_id(id) {
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)
29             //
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`
35             //
36             // In the above code we want the anon const to have predicates in its param env for `'b: 'a`
37             let item_id = tcx.hir().get_parent_item(id);
38             let item_def_id = tcx.hir().local_def_id(item_id).to_def_id();
39             // In the above code example we would be calling `inferred_outlives_of(Foo)` here
40             return tcx.inferred_outlives_of(item_def_id);
41         }
42     }
43
44     match tcx.hir().get(id) {
45         Node::Item(item) => match item.kind {
46             hir::ItemKind::Struct(..) | hir::ItemKind::Enum(..) | hir::ItemKind::Union(..) => {
47                 let crate_map = tcx.inferred_outlives_crate(());
48
49                 let predicates = crate_map.predicates.get(&item_def_id).copied().unwrap_or(&[]);
50
51                 if tcx.has_attr(item_def_id, sym::rustc_outlives) {
52                     let mut pred: Vec<String> = predicates
53                         .iter()
54                         .map(|(out_pred, _)| match out_pred.kind().skip_binder() {
55                             ty::PredicateKind::RegionOutlives(p) => p.to_string(),
56                             ty::PredicateKind::TypeOutlives(p) => p.to_string(),
57                             err => bug!("unexpected predicate {:?}", err),
58                         })
59                         .collect();
60                     pred.sort();
61
62                     let span = tcx.def_span(item_def_id);
63                     let mut err = tcx.sess.struct_span_err(span, "rustc_outlives");
64                     for p in &pred {
65                         err.note(p);
66                     }
67                     err.emit();
68                 }
69
70                 debug!("inferred_outlives_of({:?}) = {:?}", item_def_id, predicates);
71
72                 predicates
73             }
74
75             _ => &[],
76         },
77
78         _ => &[],
79     }
80 }
81
82 fn inferred_outlives_crate(tcx: TyCtxt<'_>, (): ()) -> CratePredicatesMap<'_> {
83     // Compute a map from each struct/enum/union S to the **explicit**
84     // outlives predicates (`T: 'a`, `'a: 'b`) that the user wrote.
85     // Typically there won't be many of these, except in older code where
86     // they were mandatory. Nonetheless, we have to ensure that every such
87     // predicate is satisfied, so they form a kind of base set of requirements
88     // for the type.
89
90     // Compute the inferred predicates
91     let mut exp_map = explicit::ExplicitPredicatesMap::new();
92
93     let global_inferred_outlives = implicit_infer::infer_predicates(tcx, &mut exp_map);
94
95     // Convert the inferred predicates into the "collected" form the
96     // global data structure expects.
97     //
98     // FIXME -- consider correcting impedance mismatch in some way,
99     // probably by updating the global data structure.
100     let predicates = global_inferred_outlives
101         .iter()
102         .map(|(&def_id, set)| {
103             let predicates = &*tcx.arena.alloc_from_iter(set.iter().filter_map(
104                 |(ty::OutlivesPredicate(kind1, region2), &span)| {
105                     match kind1.unpack() {
106                         GenericArgKind::Type(ty1) => Some((
107                             ty::PredicateKind::TypeOutlives(ty::OutlivesPredicate(ty1, region2))
108                                 .to_predicate(tcx),
109                             span,
110                         )),
111                         GenericArgKind::Lifetime(region1) => Some((
112                             ty::PredicateKind::RegionOutlives(ty::OutlivesPredicate(
113                                 region1, region2,
114                             ))
115                             .to_predicate(tcx),
116                             span,
117                         )),
118                         GenericArgKind::Const(_) => {
119                             // Generic consts don't impose any constraints.
120                             None
121                         }
122                     }
123                 },
124             ));
125             (def_id, predicates)
126         })
127         .collect();
128
129     ty::CratePredicatesMap { predicates }
130 }