|
| 1 | +use crate::infer::InferCtxt; |
| 2 | +use rustc_data_structures::sync::Lrc; |
1 | 3 | use rustc_data_structures::vec_map::VecMap;
|
2 | 4 | use rustc_hir as hir;
|
3 |
| -use rustc_middle::ty::{OpaqueTypeKey, Ty}; |
| 5 | +use rustc_middle::ty::subst::GenericArgKind; |
| 6 | +use rustc_middle::ty::{self, OpaqueTypeKey, Ty, TyCtxt, TypeFoldable, TypeVisitor}; |
4 | 7 | use rustc_span::Span;
|
5 | 8 |
|
| 9 | +use std::ops::ControlFlow; |
| 10 | + |
6 | 11 | pub type OpaqueTypeMap<'tcx> = VecMap<OpaqueTypeKey<'tcx>, OpaqueTypeDecl<'tcx>>;
|
7 | 12 |
|
8 | 13 | /// Information about the opaque types whose values we
|
@@ -45,3 +50,312 @@ pub struct OpaqueTypeDecl<'tcx> {
|
45 | 50 | /// The origin of the opaque type.
|
46 | 51 | pub origin: hir::OpaqueTyOrigin,
|
47 | 52 | }
|
| 53 | + |
| 54 | +impl<'a, 'tcx> InferCtxt<'a, 'tcx> { |
| 55 | + /// Given the map `opaque_types` containing the opaque |
| 56 | + /// `impl Trait` types whose underlying, hidden types are being |
| 57 | + /// inferred, this method adds constraints to the regions |
| 58 | + /// appearing in those underlying hidden types to ensure that they |
| 59 | + /// at least do not refer to random scopes within the current |
| 60 | + /// function. These constraints are not (quite) sufficient to |
| 61 | + /// guarantee that the regions are actually legal values; that |
| 62 | + /// final condition is imposed after region inference is done. |
| 63 | + /// |
| 64 | + /// # The Problem |
| 65 | + /// |
| 66 | + /// Let's work through an example to explain how it works. Assume |
| 67 | + /// the current function is as follows: |
| 68 | + /// |
| 69 | + /// ```text |
| 70 | + /// fn foo<'a, 'b>(..) -> (impl Bar<'a>, impl Bar<'b>) |
| 71 | + /// ``` |
| 72 | + /// |
| 73 | + /// Here, we have two `impl Trait` types whose values are being |
| 74 | + /// inferred (the `impl Bar<'a>` and the `impl |
| 75 | + /// Bar<'b>`). Conceptually, this is sugar for a setup where we |
| 76 | + /// define underlying opaque types (`Foo1`, `Foo2`) and then, in |
| 77 | + /// the return type of `foo`, we *reference* those definitions: |
| 78 | + /// |
| 79 | + /// ```text |
| 80 | + /// type Foo1<'x> = impl Bar<'x>; |
| 81 | + /// type Foo2<'x> = impl Bar<'x>; |
| 82 | + /// fn foo<'a, 'b>(..) -> (Foo1<'a>, Foo2<'b>) { .. } |
| 83 | + /// // ^^^^ ^^ |
| 84 | + /// // | | |
| 85 | + /// // | substs |
| 86 | + /// // def_id |
| 87 | + /// ``` |
| 88 | + /// |
| 89 | + /// As indicating in the comments above, each of those references |
| 90 | + /// is (in the compiler) basically a substitution (`substs`) |
| 91 | + /// applied to the type of a suitable `def_id` (which identifies |
| 92 | + /// `Foo1` or `Foo2`). |
| 93 | + /// |
| 94 | + /// Now, at this point in compilation, what we have done is to |
| 95 | + /// replace each of the references (`Foo1<'a>`, `Foo2<'b>`) with |
| 96 | + /// fresh inference variables C1 and C2. We wish to use the values |
| 97 | + /// of these variables to infer the underlying types of `Foo1` and |
| 98 | + /// `Foo2`. That is, this gives rise to higher-order (pattern) unification |
| 99 | + /// constraints like: |
| 100 | + /// |
| 101 | + /// ```text |
| 102 | + /// for<'a> (Foo1<'a> = C1) |
| 103 | + /// for<'b> (Foo1<'b> = C2) |
| 104 | + /// ``` |
| 105 | + /// |
| 106 | + /// For these equation to be satisfiable, the types `C1` and `C2` |
| 107 | + /// can only refer to a limited set of regions. For example, `C1` |
| 108 | + /// can only refer to `'static` and `'a`, and `C2` can only refer |
| 109 | + /// to `'static` and `'b`. The job of this function is to impose that |
| 110 | + /// constraint. |
| 111 | + /// |
| 112 | + /// Up to this point, C1 and C2 are basically just random type |
| 113 | + /// inference variables, and hence they may contain arbitrary |
| 114 | + /// regions. In fact, it is fairly likely that they do! Consider |
| 115 | + /// this possible definition of `foo`: |
| 116 | + /// |
| 117 | + /// ```text |
| 118 | + /// fn foo<'a, 'b>(x: &'a i32, y: &'b i32) -> (impl Bar<'a>, impl Bar<'b>) { |
| 119 | + /// (&*x, &*y) |
| 120 | + /// } |
| 121 | + /// ``` |
| 122 | + /// |
| 123 | + /// Here, the values for the concrete types of the two impl |
| 124 | + /// traits will include inference variables: |
| 125 | + /// |
| 126 | + /// ```text |
| 127 | + /// &'0 i32 |
| 128 | + /// &'1 i32 |
| 129 | + /// ``` |
| 130 | + /// |
| 131 | + /// Ordinarily, the subtyping rules would ensure that these are |
| 132 | + /// sufficiently large. But since `impl Bar<'a>` isn't a specific |
| 133 | + /// type per se, we don't get such constraints by default. This |
| 134 | + /// is where this function comes into play. It adds extra |
| 135 | + /// constraints to ensure that all the regions which appear in the |
| 136 | + /// inferred type are regions that could validly appear. |
| 137 | + /// |
| 138 | + /// This is actually a bit of a tricky constraint in general. We |
| 139 | + /// want to say that each variable (e.g., `'0`) can only take on |
| 140 | + /// values that were supplied as arguments to the opaque type |
| 141 | + /// (e.g., `'a` for `Foo1<'a>`) or `'static`, which is always in |
| 142 | + /// scope. We don't have a constraint quite of this kind in the current |
| 143 | + /// region checker. |
| 144 | + /// |
| 145 | + /// # The Solution |
| 146 | + /// |
| 147 | + /// We generally prefer to make `<=` constraints, since they |
| 148 | + /// integrate best into the region solver. To do that, we find the |
| 149 | + /// "minimum" of all the arguments that appear in the substs: that |
| 150 | + /// is, some region which is less than all the others. In the case |
| 151 | + /// of `Foo1<'a>`, that would be `'a` (it's the only choice, after |
| 152 | + /// all). Then we apply that as a least bound to the variables |
| 153 | + /// (e.g., `'a <= '0`). |
| 154 | + /// |
| 155 | + /// In some cases, there is no minimum. Consider this example: |
| 156 | + /// |
| 157 | + /// ```text |
| 158 | + /// fn baz<'a, 'b>() -> impl Trait<'a, 'b> { ... } |
| 159 | + /// ``` |
| 160 | + /// |
| 161 | + /// Here we would report a more complex "in constraint", like `'r |
| 162 | + /// in ['a, 'b, 'static]` (where `'r` is some region appearing in |
| 163 | + /// the hidden type). |
| 164 | + /// |
| 165 | + /// # Constrain regions, not the hidden concrete type |
| 166 | + /// |
| 167 | + /// Note that generating constraints on each region `Rc` is *not* |
| 168 | + /// the same as generating an outlives constraint on `Tc` iself. |
| 169 | + /// For example, if we had a function like this: |
| 170 | + /// |
| 171 | + /// ```rust |
| 172 | + /// fn foo<'a, T>(x: &'a u32, y: T) -> impl Foo<'a> { |
| 173 | + /// (x, y) |
| 174 | + /// } |
| 175 | + /// |
| 176 | + /// // Equivalent to: |
| 177 | + /// type FooReturn<'a, T> = impl Foo<'a>; |
| 178 | + /// fn foo<'a, T>(..) -> FooReturn<'a, T> { .. } |
| 179 | + /// ``` |
| 180 | + /// |
| 181 | + /// then the hidden type `Tc` would be `(&'0 u32, T)` (where `'0` |
| 182 | + /// is an inference variable). If we generated a constraint that |
| 183 | + /// `Tc: 'a`, then this would incorrectly require that `T: 'a` -- |
| 184 | + /// but this is not necessary, because the opaque type we |
| 185 | + /// create will be allowed to reference `T`. So we only generate a |
| 186 | + /// constraint that `'0: 'a`. |
| 187 | + /// |
| 188 | + /// # The `free_region_relations` parameter |
| 189 | + /// |
| 190 | + /// The `free_region_relations` argument is used to find the |
| 191 | + /// "minimum" of the regions supplied to a given opaque type. |
| 192 | + /// It must be a relation that can answer whether `'a <= 'b`, |
| 193 | + /// where `'a` and `'b` are regions that appear in the "substs" |
| 194 | + /// for the opaque type references (the `<'a>` in `Foo1<'a>`). |
| 195 | + /// |
| 196 | + /// Note that we do not impose the constraints based on the |
| 197 | + /// generic regions from the `Foo1` definition (e.g., `'x`). This |
| 198 | + /// is because the constraints we are imposing here is basically |
| 199 | + /// the concern of the one generating the constraining type C1, |
| 200 | + /// which is the current function. It also means that we can |
| 201 | + /// take "implied bounds" into account in some cases: |
| 202 | + /// |
| 203 | + /// ```text |
| 204 | + /// trait SomeTrait<'a, 'b> { } |
| 205 | + /// fn foo<'a, 'b>(_: &'a &'b u32) -> impl SomeTrait<'a, 'b> { .. } |
| 206 | + /// ``` |
| 207 | + /// |
| 208 | + /// Here, the fact that `'b: 'a` is known only because of the |
| 209 | + /// implied bounds from the `&'a &'b u32` parameter, and is not |
| 210 | + /// "inherent" to the opaque type definition. |
| 211 | + /// |
| 212 | + /// # Parameters |
| 213 | + /// |
| 214 | + /// - `opaque_types` -- the map produced by `instantiate_opaque_types` |
| 215 | + /// - `free_region_relations` -- something that can be used to relate |
| 216 | + /// the free regions (`'a`) that appear in the impl trait. |
| 217 | + #[instrument(level = "debug", skip(self))] |
| 218 | + pub fn constrain_opaque_type( |
| 219 | + &self, |
| 220 | + opaque_type_key: OpaqueTypeKey<'tcx>, |
| 221 | + opaque_defn: &OpaqueTypeDecl<'tcx>, |
| 222 | + ) { |
| 223 | + let def_id = opaque_type_key.def_id; |
| 224 | + |
| 225 | + let tcx = self.tcx; |
| 226 | + |
| 227 | + let concrete_ty = self.resolve_vars_if_possible(opaque_defn.concrete_ty); |
| 228 | + |
| 229 | + debug!(?concrete_ty); |
| 230 | + |
| 231 | + let first_own_region = match opaque_defn.origin { |
| 232 | + hir::OpaqueTyOrigin::FnReturn | hir::OpaqueTyOrigin::AsyncFn => { |
| 233 | + // We lower |
| 234 | + // |
| 235 | + // fn foo<'l0..'ln>() -> impl Trait<'l0..'lm> |
| 236 | + // |
| 237 | + // into |
| 238 | + // |
| 239 | + // type foo::<'p0..'pn>::Foo<'q0..'qm> |
| 240 | + // fn foo<l0..'ln>() -> foo::<'static..'static>::Foo<'l0..'lm>. |
| 241 | + // |
| 242 | + // For these types we only iterate over `'l0..lm` below. |
| 243 | + tcx.generics_of(def_id).parent_count |
| 244 | + } |
| 245 | + // These opaque type inherit all lifetime parameters from their |
| 246 | + // parent, so we have to check them all. |
| 247 | + hir::OpaqueTyOrigin::TyAlias => 0, |
| 248 | + }; |
| 249 | + |
| 250 | + // For a case like `impl Foo<'a, 'b>`, we would generate a constraint |
| 251 | + // `'r in ['a, 'b, 'static]` for each region `'r` that appears in the |
| 252 | + // hidden type (i.e., it must be equal to `'a`, `'b`, or `'static`). |
| 253 | + // |
| 254 | + // `conflict1` and `conflict2` are the two region bounds that we |
| 255 | + // detected which were unrelated. They are used for diagnostics. |
| 256 | + |
| 257 | + // Create the set of choice regions: each region in the hidden |
| 258 | + // type can be equal to any of the region parameters of the |
| 259 | + // opaque type definition. |
| 260 | + let choice_regions: Lrc<Vec<ty::Region<'tcx>>> = Lrc::new( |
| 261 | + opaque_type_key.substs[first_own_region..] |
| 262 | + .iter() |
| 263 | + .filter_map(|arg| match arg.unpack() { |
| 264 | + GenericArgKind::Lifetime(r) => Some(r), |
| 265 | + GenericArgKind::Type(_) | GenericArgKind::Const(_) => None, |
| 266 | + }) |
| 267 | + .chain(std::iter::once(self.tcx.lifetimes.re_static)) |
| 268 | + .collect(), |
| 269 | + ); |
| 270 | + |
| 271 | + concrete_ty.visit_with(&mut ConstrainOpaqueTypeRegionVisitor { |
| 272 | + tcx: self.tcx, |
| 273 | + op: |r| { |
| 274 | + self.member_constraint( |
| 275 | + opaque_type_key.def_id, |
| 276 | + opaque_defn.definition_span, |
| 277 | + concrete_ty, |
| 278 | + r, |
| 279 | + &choice_regions, |
| 280 | + ) |
| 281 | + }, |
| 282 | + }); |
| 283 | + } |
| 284 | +} |
| 285 | + |
| 286 | +// Visitor that requires that (almost) all regions in the type visited outlive |
| 287 | +// `least_region`. We cannot use `push_outlives_components` because regions in |
| 288 | +// closure signatures are not included in their outlives components. We need to |
| 289 | +// ensure all regions outlive the given bound so that we don't end up with, |
| 290 | +// say, `ReVar` appearing in a return type and causing ICEs when other |
| 291 | +// functions end up with region constraints involving regions from other |
| 292 | +// functions. |
| 293 | +// |
| 294 | +// We also cannot use `for_each_free_region` because for closures it includes |
| 295 | +// the regions parameters from the enclosing item. |
| 296 | +// |
| 297 | +// We ignore any type parameters because impl trait values are assumed to |
| 298 | +// capture all the in-scope type parameters. |
| 299 | +struct ConstrainOpaqueTypeRegionVisitor<'tcx, OP> { |
| 300 | + tcx: TyCtxt<'tcx>, |
| 301 | + op: OP, |
| 302 | +} |
| 303 | + |
| 304 | +impl<'tcx, OP> TypeVisitor<'tcx> for ConstrainOpaqueTypeRegionVisitor<'tcx, OP> |
| 305 | +where |
| 306 | + OP: FnMut(ty::Region<'tcx>), |
| 307 | +{ |
| 308 | + fn tcx_for_anon_const_substs(&self) -> Option<TyCtxt<'tcx>> { |
| 309 | + Some(self.tcx) |
| 310 | + } |
| 311 | + |
| 312 | + fn visit_binder<T: TypeFoldable<'tcx>>( |
| 313 | + &mut self, |
| 314 | + t: &ty::Binder<'tcx, T>, |
| 315 | + ) -> ControlFlow<Self::BreakTy> { |
| 316 | + t.as_ref().skip_binder().visit_with(self); |
| 317 | + ControlFlow::CONTINUE |
| 318 | + } |
| 319 | + |
| 320 | + fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow<Self::BreakTy> { |
| 321 | + match *r { |
| 322 | + // ignore bound regions, keep visiting |
| 323 | + ty::ReLateBound(_, _) => ControlFlow::CONTINUE, |
| 324 | + _ => { |
| 325 | + (self.op)(r); |
| 326 | + ControlFlow::CONTINUE |
| 327 | + } |
| 328 | + } |
| 329 | + } |
| 330 | + |
| 331 | + fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow<Self::BreakTy> { |
| 332 | + // We're only interested in types involving regions |
| 333 | + if !ty.flags().intersects(ty::TypeFlags::HAS_POTENTIAL_FREE_REGIONS) { |
| 334 | + return ControlFlow::CONTINUE; |
| 335 | + } |
| 336 | + |
| 337 | + match ty.kind() { |
| 338 | + ty::Closure(_, ref substs) => { |
| 339 | + // Skip lifetime parameters of the enclosing item(s) |
| 340 | + |
| 341 | + substs.as_closure().tupled_upvars_ty().visit_with(self); |
| 342 | + substs.as_closure().sig_as_fn_ptr_ty().visit_with(self); |
| 343 | + } |
| 344 | + |
| 345 | + ty::Generator(_, ref substs, _) => { |
| 346 | + // Skip lifetime parameters of the enclosing item(s) |
| 347 | + // Also skip the witness type, because that has no free regions. |
| 348 | + |
| 349 | + substs.as_generator().tupled_upvars_ty().visit_with(self); |
| 350 | + substs.as_generator().return_ty().visit_with(self); |
| 351 | + substs.as_generator().yield_ty().visit_with(self); |
| 352 | + substs.as_generator().resume_ty().visit_with(self); |
| 353 | + } |
| 354 | + _ => { |
| 355 | + ty.super_visit_with(self); |
| 356 | + } |
| 357 | + } |
| 358 | + |
| 359 | + ControlFlow::CONTINUE |
| 360 | + } |
| 361 | +} |
0 commit comments