1 use rustc::ty::outlives::Component;
2 use rustc::ty::subst::{GenericArg, GenericArgKind};
3 use rustc::ty::{self, Region, RegionKind, Ty, TyCtxt};
4 use smallvec::smallvec;
5 use std::collections::BTreeSet;
7 /// Tracks the `T: 'a` or `'a: 'a` predicates that we have inferred
8 /// must be added to the struct header.
9 pub type RequiredPredicates<'tcx> =
10 BTreeSet<ty::OutlivesPredicate<GenericArg<'tcx>, ty::Region<'tcx>>>;
12 /// Given a requirement `T: 'a` or `'b: 'a`, deduce the
13 /// outlives_component and add it to `required_predicates`
14 pub fn insert_outlives_predicate<'tcx>(
16 kind: GenericArg<'tcx>,
17 outlived_region: Region<'tcx>,
18 required_predicates: &mut RequiredPredicates<'tcx>,
20 // If the `'a` region is bound within the field type itself, we
21 // don't want to propagate this constraint to the header.
22 if !is_free_region(tcx, outlived_region) {
27 GenericArgKind::Type(ty) => {
28 // `T: 'outlived_region` for some type `T`
29 // But T could be a lot of things:
30 // e.g., if `T = &'b u32`, then `'b: 'outlived_region` is
31 // what we want to add.
33 // Or if within `struct Foo<U>` you had `T = Vec<U>`, then
34 // we would want to add `U: 'outlived_region`
35 let mut components = smallvec![];
36 tcx.push_outlives_components(ty, &mut components);
37 for component in components {
39 Component::Region(r) => {
40 // This would arise from something like:
43 // struct Foo<'a, 'b> {
48 // Here `outlived_region = 'a` and `kind = &'b
49 // u32`. Decomposing `&'b u32` into
50 // components would yield `'b`, and we add the
51 // where clause that `'b: 'a`.
52 insert_outlives_predicate(
60 Component::Param(param_ty) => {
61 // param_ty: ty::ParamTy
62 // This would arise from something like:
65 // struct Foo<'a, U> {
70 // Here `outlived_region = 'a` and `kind =
71 // Vec<U>`. Decomposing `Vec<U>` into
72 // components would yield `U`, and we add the
73 // where clause that `U: 'a`.
74 let ty: Ty<'tcx> = param_ty.to_ty(tcx);
76 .insert(ty::OutlivesPredicate(ty.into(), outlived_region));
79 Component::Projection(proj_ty) => {
80 // This would arise from something like:
83 // struct Foo<'a, T: Iterator> {
84 // x: &'a <T as Iterator>::Item
88 // Here we want to add an explicit `where <T as Iterator>::Item: 'a`.
89 let ty: Ty<'tcx> = tcx.mk_projection(proj_ty.item_def_id, proj_ty.substs);
91 .insert(ty::OutlivesPredicate(ty.into(), outlived_region));
94 Component::EscapingProjection(_) => {
95 // As above, but the projection involves
96 // late-bound regions. Therefore, the WF
97 // requirement is not checked in type definition
98 // but at fn call site, so ignore it.
101 // struct Foo<'a, T: Iterator> {
102 // x: for<'b> fn(<&'b T as Iterator>::Item)
103 // // ^^^^^^^^^^^^^^^^^^^^^^^^^
107 // Since `'b` is not in scope on `Foo`, can't
108 // do anything here, ignore it.
111 Component::UnresolvedInferenceVariable(_) => bug!("not using infcx"),
116 GenericArgKind::Lifetime(r) => {
117 if !is_free_region(tcx, r) {
120 required_predicates.insert(ty::OutlivesPredicate(kind, outlived_region));
123 GenericArgKind::Const(_) => {
124 // Generic consts don't impose any constraints.
129 fn is_free_region(tcx: TyCtxt<'_>, region: Region<'_>) -> bool {
130 // First, screen for regions that might appear in a type header.
132 // These correspond to `T: 'a` relationships:
134 // struct Foo<'a, T> {
135 // field: &'a T, // this would generate a ReEarlyBound referencing `'a`
138 // We care about these, so fall through.
139 RegionKind::ReEarlyBound(_) => true,
141 // These correspond to `T: 'static` relationships which can be
142 // rather surprising. We are therefore putting this behind a
145 // struct Foo<'a, T> {
146 // field: &'static T, // this would generate a ReStatic
148 RegionKind::ReStatic => {
150 .features_untracked()
151 .infer_static_outlives_requirements
154 // Late-bound regions can appear in `fn` types:
157 // field: for<'b> fn(&'b T) // e.g., 'b here
160 // The type above might generate a `T: 'b` bound, but we can
161 // ignore it. We can't put it on the struct header anyway.
162 RegionKind::ReLateBound(..) => false,
164 // This can appear in `where Self: ` bounds (#64855):
166 // struct Bar<T>(<Self as Foo>::Type) where Self: ;
167 // struct Baz<'a>(&'a Self) where Self: ;
168 RegionKind::ReEmpty => false,
170 // These regions don't appear in types from type declarations:
172 | RegionKind::ReClosureBound(..)
173 | RegionKind::ReScope(..)
174 | RegionKind::ReVar(..)
175 | RegionKind::RePlaceholder(..)
176 | RegionKind::ReFree(..) => {
177 bug!("unexpected region in outlives inference: {:?}", region);