]> git.lizzy.rs Git - rust.git/blob - compiler/rustc_typeck/src/outlives/mod.rs
c0920895b66d617f06050b6e057c71db7f02c4d4
[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::{CrateNum, DefId, LOCAL_CRATE};
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     match tcx.hir().get(id) {
24         Node::Item(item) => match item.kind {
25             hir::ItemKind::Struct(..) | hir::ItemKind::Enum(..) | hir::ItemKind::Union(..) => {
26                 let crate_map = tcx.inferred_outlives_crate(LOCAL_CRATE);
27
28                 let predicates = crate_map.predicates.get(&item_def_id).copied().unwrap_or(&[]);
29
30                 if tcx.has_attr(item_def_id, sym::rustc_outlives) {
31                     let mut pred: Vec<String> = predicates
32                         .iter()
33                         .map(|(out_pred, _)| {
34                             let binder = out_pred.kind();
35                             match binder.skip_binder() {
36                                 ty::PredicateAtom::RegionOutlives(p) => p.to_string(),
37                                 ty::PredicateAtom::TypeOutlives(p) => p.to_string(),
38                                 err => bug!("unexpected predicate {:?}", err),
39                             }
40                         })
41                         .collect();
42                     pred.sort();
43
44                     let span = tcx.def_span(item_def_id);
45                     let mut err = tcx.sess.struct_span_err(span, "rustc_outlives");
46                     for p in &pred {
47                         err.note(p);
48                     }
49                     err.emit();
50                 }
51
52                 debug!("inferred_outlives_of({:?}) = {:?}", item_def_id, predicates);
53
54                 predicates
55             }
56
57             _ => &[],
58         },
59
60         _ => &[],
61     }
62 }
63
64 fn inferred_outlives_crate(tcx: TyCtxt<'_>, crate_num: CrateNum) -> CratePredicatesMap<'_> {
65     assert_eq!(crate_num, LOCAL_CRATE);
66
67     // Compute a map from each struct/enum/union S to the **explicit**
68     // outlives predicates (`T: 'a`, `'a: 'b`) that the user wrote.
69     // Typically there won't be many of these, except in older code where
70     // they were mandatory. Nonetheless, we have to ensure that every such
71     // predicate is satisfied, so they form a kind of base set of requirements
72     // for the type.
73
74     // Compute the inferred predicates
75     let mut exp_map = explicit::ExplicitPredicatesMap::new();
76
77     let global_inferred_outlives = implicit_infer::infer_predicates(tcx, &mut exp_map);
78
79     // Convert the inferred predicates into the "collected" form the
80     // global data structure expects.
81     //
82     // FIXME -- consider correcting impedance mismatch in some way,
83     // probably by updating the global data structure.
84     let predicates = global_inferred_outlives
85         .iter()
86         .map(|(&def_id, set)| {
87             let predicates = &*tcx.arena.alloc_from_iter(set.iter().filter_map(
88                 |(ty::OutlivesPredicate(kind1, region2), &span)| {
89                     match kind1.unpack() {
90                         GenericArgKind::Type(ty1) => Some((
91                             ty::PredicateAtom::TypeOutlives(ty::OutlivesPredicate(ty1, region2))
92                                 .to_predicate(tcx),
93                             span,
94                         )),
95                         GenericArgKind::Lifetime(region1) => Some((
96                             ty::PredicateAtom::RegionOutlives(ty::OutlivesPredicate(
97                                 region1, region2,
98                             ))
99                             .to_predicate(tcx),
100                             span,
101                         )),
102                         GenericArgKind::Const(_) => {
103                             // Generic consts don't impose any constraints.
104                             None
105                         }
106                     }
107                 },
108             ));
109             (def_id, predicates)
110         })
111         .collect();
112
113     ty::CratePredicatesMap { predicates }
114 }