]> git.proxmox.com Git - rustc.git/blame - compiler/rustc_hir_analysis/src/outlives/utils.rs
New upstream version 1.76.0+dfsg1
[rustc.git] / compiler / rustc_hir_analysis / src / outlives / utils.rs
CommitLineData
c295e0f8 1use rustc_infer::infer::outlives::components::{push_outlives_components, Component};
5099ac24 2use rustc_middle::ty::{self, Region, Ty, TyCtxt};
add651ee 3use rustc_middle::ty::{GenericArg, GenericArgKind};
dfeec247 4use rustc_span::Span;
a1dfa0c6 5use smallvec::smallvec;
e74abb32 6use std::collections::BTreeMap;
94b46f34
XL
7
8/// Tracks the `T: 'a` or `'a: 'a` predicates that we have inferred
9/// must be added to the struct header.
064997fb 10pub(crate) type RequiredPredicates<'tcx> =
e74abb32 11 BTreeMap<ty::OutlivesPredicate<GenericArg<'tcx>, ty::Region<'tcx>>, Span>;
94b46f34
XL
12
13/// Given a requirement `T: 'a` or `'b: 'a`, deduce the
14/// outlives_component and add it to `required_predicates`
064997fb 15pub(crate) fn insert_outlives_predicate<'tcx>(
dc9dc135 16 tcx: TyCtxt<'tcx>,
e74abb32 17 kind: GenericArg<'tcx>,
94b46f34 18 outlived_region: Region<'tcx>,
e74abb32 19 span: Span,
94b46f34
XL
20 required_predicates: &mut RequiredPredicates<'tcx>,
21) {
22 // If the `'a` region is bound within the field type itself, we
23 // don't want to propagate this constraint to the header.
923072b8 24 if !is_free_region(outlived_region) {
94b46f34
XL
25 return;
26 }
27
28 match kind.unpack() {
e74abb32 29 GenericArgKind::Type(ty) => {
94b46f34
XL
30 // `T: 'outlived_region` for some type `T`
31 // But T could be a lot of things:
32 // e.g., if `T = &'b u32`, then `'b: 'outlived_region` is
33 // what we want to add.
34 //
35 // Or if within `struct Foo<U>` you had `T = Vec<U>`, then
36 // we would want to add `U: 'outlived_region`
a1dfa0c6 37 let mut components = smallvec![];
c295e0f8 38 push_outlives_components(tcx, ty, &mut components);
a1dfa0c6 39 for component in components {
94b46f34
XL
40 match component {
41 Component::Region(r) => {
42 // This would arise from something like:
43 //
44 // ```
45 // struct Foo<'a, 'b> {
46 // x: &'a &'b u32
47 // }
48 // ```
49 //
50 // Here `outlived_region = 'a` and `kind = &'b
9c376795 51 // u32`. Decomposing `&'b u32` into
94b46f34
XL
52 // components would yield `'b`, and we add the
53 // where clause that `'b: 'a`.
54 insert_outlives_predicate(
55 tcx,
56 r.into(),
57 outlived_region,
e74abb32 58 span,
94b46f34
XL
59 required_predicates,
60 );
61 }
62
63 Component::Param(param_ty) => {
64 // param_ty: ty::ParamTy
65 // This would arise from something like:
66 //
67 // ```
68 // struct Foo<'a, U> {
69 // x: &'a Vec<U>
70 // }
71 // ```
72 //
73 // Here `outlived_region = 'a` and `kind =
9c376795 74 // Vec<U>`. Decomposing `Vec<U>` into
94b46f34
XL
75 // components would yield `U`, and we add the
76 // where clause that `U: 'a`.
77 let ty: Ty<'tcx> = param_ty.to_ty(tcx);
78 required_predicates
e74abb32
XL
79 .entry(ty::OutlivesPredicate(ty.into(), outlived_region))
80 .or_insert(span);
94b46f34
XL
81 }
82
4b012472
FG
83 Component::Placeholder(_) => {
84 span_bug!(span, "Should not deduce placeholder outlives component");
85 }
86
9c376795
FG
87 Component::Alias(alias_ty) => {
88 // This would either arise from something like:
94b46f34
XL
89 //
90 // ```
91 // struct Foo<'a, T: Iterator> {
92 // x: &'a <T as Iterator>::Item
93 // }
94 // ```
95 //
9c376795 96 // or:
2b03887a
FG
97 //
98 // ```rust
99 // type Opaque<T> = impl Sized;
100 // fn defining<T>() -> Opaque<T> {}
101 // struct Ss<'a, T>(&'a Opaque<T>);
102 // ```
103 //
9c376795
FG
104 // Here we want to add an explicit `where <T as Iterator>::Item: 'a`
105 // or `Opaque<T>: 'a` depending on the alias kind.
106 let ty = alias_ty.to_ty(tcx);
2b03887a
FG
107 required_predicates
108 .entry(ty::OutlivesPredicate(ty.into(), outlived_region))
109 .or_insert(span);
110 }
111
9c376795 112 Component::EscapingAlias(_) => {
94b46f34 113 // As above, but the projection involves
9c376795 114 // late-bound regions. Therefore, the WF
94b46f34
XL
115 // requirement is not checked in type definition
116 // but at fn call site, so ignore it.
117 //
118 // ```
119 // struct Foo<'a, T: Iterator> {
120 // x: for<'b> fn(<&'b T as Iterator>::Item)
121 // // ^^^^^^^^^^^^^^^^^^^^^^^^^
122 // }
123 // ```
124 //
125 // Since `'b` is not in scope on `Foo`, can't
126 // do anything here, ignore it.
127 }
128
129 Component::UnresolvedInferenceVariable(_) => bug!("not using infcx"),
130 }
131 }
132 }
133
e74abb32 134 GenericArgKind::Lifetime(r) => {
923072b8 135 if !is_free_region(r) {
94b46f34
XL
136 return;
137 }
dfeec247 138 required_predicates.entry(ty::OutlivesPredicate(kind, outlived_region)).or_insert(span);
94b46f34 139 }
532ac7d7 140
e74abb32 141 GenericArgKind::Const(_) => {
532ac7d7
XL
142 // Generic consts don't impose any constraints.
143 }
94b46f34
XL
144 }
145}
146
923072b8 147fn is_free_region(region: Region<'_>) -> bool {
94b46f34 148 // First, screen for regions that might appear in a type header.
5099ac24 149 match *region {
8faf50e0 150 // These correspond to `T: 'a` relationships:
94b46f34
XL
151 //
152 // struct Foo<'a, T> {
4b012472 153 // field: &'a T, // this would generate a ReEarlyParam referencing `'a`
94b46f34
XL
154 // }
155 //
156 // We care about these, so fall through.
4b012472 157 ty::ReEarlyParam(_) => true,
8faf50e0
XL
158
159 // These correspond to `T: 'static` relationships which can be
923072b8 160 // rather surprising.
8faf50e0
XL
161 //
162 // struct Foo<'a, T> {
163 // field: &'static T, // this would generate a ReStatic
164 // }
923072b8 165 ty::ReStatic => false,
94b46f34
XL
166
167 // Late-bound regions can appear in `fn` types:
168 //
169 // struct Foo<T> {
170 // field: for<'b> fn(&'b T) // e.g., 'b here
171 // }
172 //
173 // The type above might generate a `T: 'b` bound, but we can
4b012472
FG
174 // ignore it. We can't name this lifetime pn the struct header anyway.
175 ty::ReBound(..) => false,
94b46f34 176
9ffffee4
FG
177 ty::ReError(_) => false,
178
94b46f34 179 // These regions don't appear in types from type declarations:
4b012472 180 ty::ReErased | ty::ReVar(..) | ty::RePlaceholder(..) | ty::ReLateParam(..) => {
94b46f34
XL
181 bug!("unexpected region in outlives inference: {:?}", region);
182 }
183 }
184}