1 use crate::infer::outlives::components::{compute_components_recursive, Component};
2 use crate::infer::outlives::env::RegionBoundPairs;
3 use crate::infer::region_constraints::VerifyIfEq;
4 use crate::infer::{GenericKind, VerifyBound};
5 use rustc_data_structures::captures::Captures;
6 use rustc_data_structures::sso::SsoHashSet;
7 use rustc_hir::def_id::DefId;
8 use rustc_middle::ty::subst::{GenericArg, Subst};
9 use rustc_middle::ty::{self, EarlyBinder, OutlivesPredicate, Ty, TyCtxt};
11 use smallvec::smallvec;
13 /// The `TypeOutlives` struct has the job of "lowering" a `T: 'a`
14 /// obligation into a series of `'a: 'b` constraints and "verifys", as
15 /// described on the module comment. The final constraints are emitted
16 /// via a "delegate" of type `D` -- this is usually the `infcx`, which
17 /// accrues them into the `region_obligations` code, but for NLL we
18 /// use something else.
19 pub struct VerifyBoundCx<'cx, 'tcx> {
21 region_bound_pairs: &'cx RegionBoundPairs<'tcx>,
22 /// During borrowck, if there are no outlives bounds on a generic
23 /// parameter `T`, we assume that `T: 'in_fn_body` holds.
25 /// Outside of borrowck the only way to prove `T: '?0` is by
26 /// setting `'?0` to `'empty`.
27 implicit_region_bound: Option<ty::Region<'tcx>>,
28 param_env: ty::ParamEnv<'tcx>,
31 impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> {
34 region_bound_pairs: &'cx RegionBoundPairs<'tcx>,
35 implicit_region_bound: Option<ty::Region<'tcx>>,
36 param_env: ty::ParamEnv<'tcx>,
38 Self { tcx, region_bound_pairs, implicit_region_bound, param_env }
41 /// Returns a "verify bound" that encodes what we know about
42 /// `generic` and the regions it outlives.
43 pub fn generic_bound(&self, generic: GenericKind<'tcx>) -> VerifyBound<'tcx> {
44 let mut visited = SsoHashSet::new();
46 GenericKind::Param(param_ty) => self.param_bound(param_ty),
47 GenericKind::Projection(projection_ty) => {
48 self.projection_bound(projection_ty, &mut visited)
53 fn param_bound(&self, param_ty: ty::ParamTy) -> VerifyBound<'tcx> {
54 debug!("param_bound(param_ty={:?})", param_ty);
56 // Start with anything like `T: 'a` we can scrape from the
57 // environment. If the environment contains something like
58 // `for<'a> T: 'a`, then we know that `T` outlives everything.
59 let declared_bounds_from_env = self.declared_generic_bounds_from_env(param_ty);
60 let mut param_bounds = vec![];
61 for declared_bound in declared_bounds_from_env {
62 let bound_region = declared_bound.map_bound(|outlives| outlives.1);
63 if let Some(region) = bound_region.no_bound_vars() {
64 // This is `T: 'a` for some free region `'a`.
65 param_bounds.push(VerifyBound::OutlivedBy(region));
67 // This is `for<'a> T: 'a`. This means that `T` outlives everything! All done here.
68 return VerifyBound::AllBounds(vec![]);
72 // Add in the default bound of fn body that applies to all in
73 // scope type parameters:
74 if let Some(r) = self.implicit_region_bound {
75 param_bounds.push(VerifyBound::OutlivedBy(r));
78 if param_bounds.is_empty() {
79 // We know that all types `T` outlive `'empty`, so if we
80 // can find no other bound, then check that the region
81 // being tested is `'empty`.
83 } else if param_bounds.len() == 1 {
84 // Micro-opt: no need to store the vector if it's just len 1
85 param_bounds.pop().unwrap()
87 // If we can find any other bound `R` such that `T: R`, then
88 // we don't need to check for `'empty`, because `R: 'empty`.
89 VerifyBound::AnyBound(param_bounds)
93 /// Given a projection like `T::Item`, searches the environment
94 /// for where-clauses like `T::Item: 'a`. Returns the set of
95 /// regions `'a` that it finds.
97 /// This is an "approximate" check -- it may not find all
98 /// applicable bounds, and not all the bounds it returns can be
99 /// relied upon. In particular, this check ignores region
100 /// identity. So, for example, if we have `<T as
101 /// Trait<'0>>::Item` where `'0` is a region variable, and the
102 /// user has `<T as Trait<'a>>::Item: 'b` in the environment, then
103 /// the clause from the environment only applies if `'0 = 'a`,
104 /// which we don't know yet. But we would still include `'b` in
106 pub fn projection_approx_declared_bounds_from_env(
108 projection_ty: ty::ProjectionTy<'tcx>,
109 ) -> Vec<ty::Binder<'tcx, ty::OutlivesPredicate<Ty<'tcx>, ty::Region<'tcx>>>> {
110 let projection_ty = GenericKind::Projection(projection_ty).to_ty(self.tcx);
111 let erased_projection_ty = self.tcx.erase_regions(projection_ty);
112 self.declared_generic_bounds_from_env_for_erased_ty(erased_projection_ty)
115 /// Searches the where-clauses in scope for regions that
116 /// `projection_ty` is known to outlive. Currently requires an
118 pub fn projection_declared_bounds_from_trait(
120 projection_ty: ty::ProjectionTy<'tcx>,
121 ) -> impl Iterator<Item = ty::Region<'tcx>> + 'cx + Captures<'tcx> {
122 self.declared_projection_bounds_from_trait(projection_ty)
125 pub fn projection_bound(
127 projection_ty: ty::ProjectionTy<'tcx>,
128 visited: &mut SsoHashSet<GenericArg<'tcx>>,
129 ) -> VerifyBound<'tcx> {
130 debug!("projection_bound(projection_ty={:?})", projection_ty);
132 let projection_ty_as_ty =
133 self.tcx.mk_projection(projection_ty.item_def_id, projection_ty.substs);
135 // Search the env for where clauses like `P: 'a`.
136 let env_bounds = self
137 .projection_approx_declared_bounds_from_env(projection_ty)
140 if let Some(ty::OutlivesPredicate(ty, r)) = binder.no_bound_vars() && ty == projection_ty_as_ty {
141 // Micro-optimize if this is an exact match (this
142 // occurs often when there are no region variables
144 VerifyBound::OutlivedBy(r)
146 let verify_if_eq_b = binder.map_bound(|ty::OutlivesPredicate(ty, bound)| VerifyIfEq { ty, bound });
147 VerifyBound::IfEq(verify_if_eq_b)
151 // Extend with bounds that we can find from the trait.
152 let trait_bounds = self
153 .projection_declared_bounds_from_trait(projection_ty)
154 .map(|r| VerifyBound::OutlivedBy(r));
156 // see the extensive comment in projection_must_outlive
157 let recursive_bound = {
158 let mut components = smallvec![];
159 let ty = self.tcx.mk_projection(projection_ty.item_def_id, projection_ty.substs);
160 compute_components_recursive(self.tcx, ty.into(), &mut components, visited);
161 self.bound_from_components(&components, visited)
164 VerifyBound::AnyBound(env_bounds.chain(trait_bounds).collect()).or(recursive_bound)
167 fn bound_from_components(
169 components: &[Component<'tcx>],
170 visited: &mut SsoHashSet<GenericArg<'tcx>>,
171 ) -> VerifyBound<'tcx> {
172 let mut bounds = components
174 .map(|component| self.bound_from_single_component(component, visited))
176 // Remove bounds that must hold, since they are not interesting.
180 match (bounds.next(), bounds.next()) {
181 (Some(first), None) => first,
183 VerifyBound::AllBounds(first.into_iter().chain(second).chain(bounds).collect())
188 fn bound_from_single_component(
190 component: &Component<'tcx>,
191 visited: &mut SsoHashSet<GenericArg<'tcx>>,
192 ) -> VerifyBound<'tcx> {
194 Component::Region(lt) => VerifyBound::OutlivedBy(lt),
195 Component::Param(param_ty) => self.param_bound(param_ty),
196 Component::Projection(projection_ty) => self.projection_bound(projection_ty, visited),
197 Component::EscapingProjection(ref components) => {
198 self.bound_from_components(components, visited)
200 Component::UnresolvedInferenceVariable(v) => {
201 // ignore this, we presume it will yield an error
202 // later, since if a type variable is not resolved by
203 // this point it never will be
204 self.tcx.sess.delay_span_bug(
205 rustc_span::DUMMY_SP,
206 &format!("unresolved inference variable in outlives: {:?}", v),
208 // add a bound that never holds
209 VerifyBound::AnyBound(vec![])
214 /// Searches the environment for where-clauses like `G: 'a` where
215 /// `G` is either some type parameter `T` or a projection like
216 /// `T::Item`. Returns a vector of the `'a` bounds it can find.
218 /// This is a conservative check -- it may not find all applicable
219 /// bounds, but all the bounds it returns can be relied upon.
220 fn declared_generic_bounds_from_env(
222 param_ty: ty::ParamTy,
223 ) -> Vec<ty::Binder<'tcx, ty::OutlivesPredicate<Ty<'tcx>, ty::Region<'tcx>>>> {
224 let generic_ty = param_ty.to_ty(self.tcx);
225 self.declared_generic_bounds_from_env_for_erased_ty(generic_ty)
228 /// Searches the environment to find all bounds that apply to `erased_ty`.
229 /// Obviously these must be approximate -- they are in fact both *over* and
230 /// and *under* approximated:
232 /// * Over-approximated because we erase regions, so
233 /// * Under-approximated because we look for syntactic equality and so for complex types
234 /// like `<T as Foo<fn(&u32, &u32)>>::Item` or whatever we may fail to figure out
235 /// all the subtleties.
237 /// In some cases, such as when `erased_ty` represents a `ty::Param`, however,
238 /// the result is precise.
239 fn declared_generic_bounds_from_env_for_erased_ty(
242 ) -> Vec<ty::Binder<'tcx, ty::OutlivesPredicate<Ty<'tcx>, ty::Region<'tcx>>>> {
245 // To start, collect bounds from user environment. Note that
246 // parameter environments are already elaborated, so we don't
247 // have to worry about that.
248 let c_b = self.param_env.caller_bounds();
249 let param_bounds = self.collect_outlives_from_predicate_list(erased_ty, c_b.into_iter());
251 // Next, collect regions we scraped from the well-formedness
252 // constraints in the fn signature. To do that, we walk the list
253 // of known relations from the fn ctxt.
255 // This is crucial because otherwise code like this fails:
257 // fn foo<'a, A>(x: &'a A) { x.bar() }
259 // The problem is that the type of `x` is `&'a A`. To be
260 // well-formed, then, A must outlive `'a`, but we don't know that
261 // this holds from first principles.
262 let from_region_bound_pairs =
263 self.region_bound_pairs.iter().filter_map(|&OutlivesPredicate(p, r)| {
265 "declared_generic_bounds_from_env_for_erased_ty: region_bound_pair = {:?}",
268 let p_ty = p.to_ty(tcx);
269 let erased_p_ty = self.tcx.erase_regions(p_ty);
270 (erased_p_ty == erased_ty)
271 .then_some(ty::Binder::dummy(ty::OutlivesPredicate(p.to_ty(tcx), r)))
275 .chain(from_region_bound_pairs)
278 "declared_generic_bounds_from_env_for_erased_ty: result predicate = {:?}",
285 /// Given a projection like `<T as Foo<'x>>::Bar`, returns any bounds
286 /// declared in the trait definition. For example, if the trait were
294 /// then this function would return `'x`. This is subject to the
295 /// limitations around higher-ranked bounds described in
296 /// `region_bounds_declared_on_associated_item`.
297 fn declared_projection_bounds_from_trait(
299 projection_ty: ty::ProjectionTy<'tcx>,
300 ) -> impl Iterator<Item = ty::Region<'tcx>> + 'cx + Captures<'tcx> {
301 debug!("projection_bounds(projection_ty={:?})", projection_ty);
303 self.region_bounds_declared_on_associated_item(projection_ty.item_def_id)
304 .map(move |r| EarlyBinder(r).subst(tcx, projection_ty.substs))
307 /// Given the `DefId` of an associated item, returns any region
308 /// bounds attached to that associated item from the trait definition.
318 /// If we were given the `DefId` of `Foo::Bar`, we would return
319 /// `'a`. You could then apply the substitutions from the
320 /// projection to convert this into your namespace. This also
321 /// works if the user writes `where <Self as Foo<'a>>::Bar: 'a` on
322 /// the trait. In fact, it works by searching for just such a
325 /// It will not, however, work for higher-ranked bounds like:
327 /// ```compile_fail,E0311
328 /// trait Foo<'a, 'b>
329 /// where for<'x> <Self as Foo<'x, 'b>>::Bar: 'x
335 /// This is for simplicity, and because we are not really smart
336 /// enough to cope with such bounds anywhere.
337 fn region_bounds_declared_on_associated_item(
339 assoc_item_def_id: DefId,
340 ) -> impl Iterator<Item = ty::Region<'tcx>> {
342 let bounds = tcx.item_bounds(assoc_item_def_id);
345 .filter_map(|p| p.to_opt_type_outlives())
346 .filter_map(|p| p.no_bound_vars())
350 /// Searches through a predicate list for a predicate `T: 'a`.
352 /// Careful: does not elaborate predicates, and just uses `==`
353 /// when comparing `ty` for equality, so `ty` must be something
354 /// that does not involve inference variables and where you
355 /// otherwise want a precise match.
356 fn collect_outlives_from_predicate_list(
359 predicates: impl Iterator<Item = ty::Predicate<'tcx>>,
360 ) -> impl Iterator<Item = ty::Binder<'tcx, ty::OutlivesPredicate<Ty<'tcx>, ty::Region<'tcx>>>>
363 let param_env = self.param_env;
364 predicates.filter_map(|p| p.to_opt_type_outlives()).filter(move |outlives_predicate| {
365 super::test_type_match::can_match_erased_ty(