summaryrefslogtreecommitdiffstats
path: root/compiler/rustc_typeck/src/outlives/mod.rs
blob: e50c267659e3f3b5a754e80966f59d2ea23eb75c (plain)
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
use hir::Node;
use rustc_hir as hir;
use rustc_hir::def_id::DefId;
use rustc_middle::ty::query::Providers;
use rustc_middle::ty::subst::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: DefId) -> &[(ty::Predicate<'_>, Span)] {
    let id = tcx.hir().local_def_id_to_hir_id(item_def_id.expect_local());

    if matches!(tcx.def_kind(item_def_id), hir::def::DefKind::AnonConst) && tcx.lazy_normalization()
    {
        if tcx.hir().opt_const_param_default_param_hir_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).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::PredicateKind::RegionOutlives(p) => p.to_string(),
                            ty::PredicateKind::TypeOutlives(p) => p.to_string(),
                            err => bug!("unexpected predicate {:?}", 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.0.iter().filter_map(
                |(ty::OutlivesPredicate(kind1, region2), &span)| {
                    match kind1.unpack() {
                        GenericArgKind::Type(ty1) => Some((
                            ty::Binder::dummy(ty::PredicateKind::TypeOutlives(
                                ty::OutlivesPredicate(ty1, *region2),
                            ))
                            .to_predicate(tcx),
                            span,
                        )),
                        GenericArgKind::Lifetime(region1) => Some((
                            ty::Binder::dummy(ty::PredicateKind::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 }
}