|
9 | 9 | // except according to those terms.
|
10 | 10 |
|
11 | 11 | use hir::def_id::DefId;
|
12 |
| -use infer::{InferCtxt, InferOk, TypeVariableOrigin}; |
| 12 | +use infer::{self, InferCtxt, InferOk, TypeVariableOrigin}; |
| 13 | +use infer::outlives::free_region_map::FreeRegionRelations; |
13 | 14 | use syntax::ast;
|
14 | 15 | use traits::{self, PredicateObligation};
|
15 | 16 | use ty::{self, Ty};
|
16 | 17 | use ty::fold::{BottomUpFolder, TypeFoldable};
|
| 18 | +use ty::outlives::Component; |
17 | 19 | use ty::subst::Substs;
|
18 | 20 | use util::nodemap::DefIdMap;
|
19 | 21 |
|
@@ -115,6 +117,264 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
|
115 | 117 | obligations: instantiator.obligations,
|
116 | 118 | }
|
117 | 119 | }
|
| 120 | + |
| 121 | + /// Given the map `anon_types` containing the existential `impl |
| 122 | + /// Trait` types whose underlying, hidden types are being |
| 123 | + /// inferred, this method adds constraints to the regions |
| 124 | + /// appearing in those underlying hidden types to ensure that they |
| 125 | + /// at least do not refer to random scopes within the current |
| 126 | + /// function. These constraints are not (quite) sufficient to |
| 127 | + /// guarantee that the regions are actually legal values; that |
| 128 | + /// final condition is imposed after region inference is done. |
| 129 | + /// |
| 130 | + /// # The Problem |
| 131 | + /// |
| 132 | + /// Let's work through an example to explain how it works. Assume |
| 133 | + /// the current function is as follows: |
| 134 | + /// |
| 135 | + /// fn foo<'a, 'b>(..) -> (impl Bar<'a>, impl Bar<'b>) |
| 136 | + /// |
| 137 | + /// Here, we have two `impl Trait` types whose values are being |
| 138 | + /// inferred (the `impl Bar<'a>` and the `impl |
| 139 | + /// Bar<'b>`). Conceptually, this is sugar for a setup where we |
| 140 | + /// define underlying abstract types (`Foo1`, `Foo2`) and then, in |
| 141 | + /// the return type of `foo`, we *reference* those definitions: |
| 142 | + /// |
| 143 | + /// abstract type Foo1<'x>: Bar<'x>; |
| 144 | + /// abstract type Foo2<'x>: Bar<'x>; |
| 145 | + /// fn foo<'a, 'b>(..) -> (Foo1<'a>, Foo2<'b>) { .. } |
| 146 | + /// // ^^^^ ^^ |
| 147 | + /// // | | |
| 148 | + /// // | substs |
| 149 | + /// // def_id |
| 150 | + /// |
| 151 | + /// As indicating in the comments above, each of those references |
| 152 | + /// is (in the compiler) basically a substitution (`substs`) |
| 153 | + /// applied to the type of a suitable `def_id` (which identifies |
| 154 | + /// `Foo1` or `Foo2`). |
| 155 | + /// |
| 156 | + /// Now, at this point in compilation, what we have done is to |
| 157 | + /// replace each of the references (`Foo1<'a>`, `Foo2<'b>`) with |
| 158 | + /// fresh inference variables C1 and C2. We wish to use the values |
| 159 | + /// of these variables to infer the underlying types of `Foo1` and |
| 160 | + /// `Foo2`. That is, this gives rise to higher-order (pattern) unification |
| 161 | + /// constraints like: |
| 162 | + /// |
| 163 | + /// for<'a> (Foo1<'a> = C1) |
| 164 | + /// for<'b> (Foo1<'b> = C2) |
| 165 | + /// |
| 166 | + /// For these equation to be satisfiable, the types `C1` and `C2` |
| 167 | + /// can only refer to a limited set of regions. For example, `C1` |
| 168 | + /// can only refer to `'static` and `'a`, and `C2` can only refer |
| 169 | + /// to `'static` and `'b`. The job of this function is to impose that |
| 170 | + /// constraint. |
| 171 | + /// |
| 172 | + /// Up to this point, C1 and C2 are basically just random type |
| 173 | + /// inference variables, and hence they may contain arbitrary |
| 174 | + /// regions. In fact, it is fairly likely that they do! Consider |
| 175 | + /// this possible definition of `foo`: |
| 176 | + /// |
| 177 | + /// fn foo<'a, 'b>(x: &'a i32, y: &'b i32) -> (impl Bar<'a>, impl Bar<'b>) { |
| 178 | + /// (&*x, &*y) |
| 179 | + /// } |
| 180 | + /// |
| 181 | + /// Here, the values for the concrete types of the two impl |
| 182 | + /// traits will include inference variables: |
| 183 | + /// |
| 184 | + /// &'0 i32 |
| 185 | + /// &'1 i32 |
| 186 | + /// |
| 187 | + /// Ordinarily, the subtyping rules would ensure that these are |
| 188 | + /// sufficiently large. But since `impl Bar<'a>` isn't a specific |
| 189 | + /// type per se, we don't get such constraints by default. This |
| 190 | + /// is where this function comes into play. It adds extra |
| 191 | + /// constraints to ensure that all the regions which appear in the |
| 192 | + /// inferred type are regions that could validly appear. |
| 193 | + /// |
| 194 | + /// This is actually a bit of a tricky constraint in general. We |
| 195 | + /// want to say that each variable (e.g., `'0``) can only take on |
| 196 | + /// values that were supplied as arguments to the abstract type |
| 197 | + /// (e.g., `'a` for `Foo1<'a>`) or `'static`, which is always in |
| 198 | + /// scope. We don't have a constraint quite of this kind in the current |
| 199 | + /// region checker. |
| 200 | + /// |
| 201 | + /// # The Solution |
| 202 | + /// |
| 203 | + /// We make use of the constraint that we *do* have in the `<=` |
| 204 | + /// relation. To do that, we find the "minimum" of all the |
| 205 | + /// arguments that appear in the substs: that is, some region |
| 206 | + /// which is less than all the others. In the case of `Foo1<'a>`, |
| 207 | + /// that would be `'a` (it's the only choice, after all). Then we |
| 208 | + /// apply that as a least bound to the variables (e.g., `'a <= |
| 209 | + /// '0`). |
| 210 | + /// |
| 211 | + /// In some cases, there is no minimum. Consider this example: |
| 212 | + /// |
| 213 | + /// fn baz<'a, 'b>() -> impl Trait<'a, 'b> { ... } |
| 214 | + /// |
| 215 | + /// Here we would report an error, because `'a` and `'b` have no |
| 216 | + /// relation to one another. |
| 217 | + /// |
| 218 | + /// # The `free_region_relations` parameter |
| 219 | + /// |
| 220 | + /// The `free_region_relations` argument is used to find the |
| 221 | + /// "minimum" of the regions supplied to a given abstract type. |
| 222 | + /// It must be a relation that can answer whether `'a <= 'b`, |
| 223 | + /// where `'a` and `'b` are regions that appear in the "substs" |
| 224 | + /// for the abstract type references (the `<'a>` in `Foo1<'a>`). |
| 225 | + /// |
| 226 | + /// Note that we do not impose the constraints based on the |
| 227 | + /// generic regions from the `Foo1` definition (e.g., `'x`). This |
| 228 | + /// is because the constraints we are imposing here is basically |
| 229 | + /// the concern of the one generating the constraining type C1, |
| 230 | + /// which is the current function. It also means that we can |
| 231 | + /// take "implied bounds" into account in some cases: |
| 232 | + /// |
| 233 | + /// trait SomeTrait<'a, 'b> { } |
| 234 | + /// fn foo<'a, 'b>(_: &'a &'b u32) -> impl SomeTrait<'a, 'b> { .. } |
| 235 | + /// |
| 236 | + /// Here, the fact that `'b: 'a` is known only because of the |
| 237 | + /// implied bounds from the `&'a &'b u32` parameter, and is not |
| 238 | + /// "inherent" to the abstract type definition. |
| 239 | + /// |
| 240 | + /// # Parameters |
| 241 | + /// |
| 242 | + /// - `anon_types` -- the map produced by `instantiate_anon_types` |
| 243 | + /// - `free_region_relations` -- something that can be used to relate |
| 244 | + /// the free regions (`'a`) that appear in the impl trait. |
| 245 | + pub fn constrain_anon_types<FRR: FreeRegionRelations<'tcx>>( |
| 246 | + &self, |
| 247 | + anon_types: &AnonTypeMap<'tcx>, |
| 248 | + free_region_relations: &FRR, |
| 249 | + ) { |
| 250 | + debug!("constrain_anon_types()"); |
| 251 | + |
| 252 | + for (&def_id, anon_defn) in anon_types { |
| 253 | + self.constrain_anon_type(def_id, anon_defn, free_region_relations); |
| 254 | + } |
| 255 | + } |
| 256 | + |
| 257 | + fn constrain_anon_type<FRR: FreeRegionRelations<'tcx>>( |
| 258 | + &self, |
| 259 | + def_id: DefId, |
| 260 | + anon_defn: &AnonTypeDecl<'tcx>, |
| 261 | + free_region_relations: &FRR, |
| 262 | + ) { |
| 263 | + debug!("constrain_anon_type()"); |
| 264 | + debug!("constrain_anon_type: def_id={:?}", def_id); |
| 265 | + debug!("constrain_anon_type: anon_defn={:#?}", anon_defn); |
| 266 | + |
| 267 | + let concrete_ty = self.resolve_type_vars_if_possible(&anon_defn.concrete_ty); |
| 268 | + |
| 269 | + debug!("constrain_anon_type: concrete_ty={:?}", concrete_ty); |
| 270 | + |
| 271 | + let abstract_type_generics = self.tcx.generics_of(def_id); |
| 272 | + |
| 273 | + let span = self.tcx.def_span(def_id); |
| 274 | + |
| 275 | + // If there are required region bounds, we can just skip |
| 276 | + // ahead. There will already be a registered region |
| 277 | + // obligation related `concrete_ty` to those regions. |
| 278 | + if anon_defn.has_required_region_bounds { |
| 279 | + return; |
| 280 | + } |
| 281 | + |
| 282 | + // There were no `required_region_bounds`, |
| 283 | + // so we have to search for a `least_region`. |
| 284 | + // Go through all the regions used as arguments to the |
| 285 | + // abstract type. These are the parameters to the abstract |
| 286 | + // type; so in our example above, `substs` would contain |
| 287 | + // `['a]` for the first impl trait and `'b` for the |
| 288 | + // second. |
| 289 | + let mut least_region = None; |
| 290 | + for region_def in &abstract_type_generics.regions { |
| 291 | + // Find the index of this region in the list of substitutions. |
| 292 | + let index = region_def.index as usize; |
| 293 | + |
| 294 | + // Get the value supplied for this region from the substs. |
| 295 | + let subst_arg = anon_defn.substs[index].as_region().unwrap(); |
| 296 | + |
| 297 | + // Compute the least upper bound of it with the other regions. |
| 298 | + debug!("constrain_anon_types: least_region={:?}", least_region); |
| 299 | + debug!("constrain_anon_types: subst_arg={:?}", subst_arg); |
| 300 | + match least_region { |
| 301 | + None => least_region = Some(subst_arg), |
| 302 | + Some(lr) => { |
| 303 | + if free_region_relations.sub_free_regions(lr, subst_arg) { |
| 304 | + // keep the current least region |
| 305 | + } else if free_region_relations.sub_free_regions(subst_arg, lr) { |
| 306 | + // switch to `subst_arg` |
| 307 | + least_region = Some(subst_arg); |
| 308 | + } else { |
| 309 | + // There are two regions (`lr` and |
| 310 | + // `subst_arg`) which are not relatable. We can't |
| 311 | + // find a best choice. |
| 312 | + self.tcx |
| 313 | + .sess |
| 314 | + .struct_span_err(span, "ambiguous lifetime bound in `impl Trait`") |
| 315 | + .span_label( |
| 316 | + span, |
| 317 | + format!("neither `{}` nor `{}` outlives the other", lr, subst_arg), |
| 318 | + ) |
| 319 | + .emit(); |
| 320 | + |
| 321 | + least_region = Some(self.tcx.mk_region(ty::ReEmpty)); |
| 322 | + break; |
| 323 | + } |
| 324 | + } |
| 325 | + } |
| 326 | + } |
| 327 | + |
| 328 | + let least_region = least_region.unwrap_or(self.tcx.types.re_static); |
| 329 | + debug!("constrain_anon_types: least_region={:?}", least_region); |
| 330 | + |
| 331 | + // Require that the type `concrete_ty` outlives |
| 332 | + // `least_region`, modulo any type parameters that appear |
| 333 | + // in the type, which we ignore. This is because impl |
| 334 | + // trait values are assumed to capture all the in-scope |
| 335 | + // type parameters. This little loop here just invokes |
| 336 | + // `outlives` repeatedly, draining all the nested |
| 337 | + // obligations that result. |
| 338 | + let mut types = vec![concrete_ty]; |
| 339 | + let bound_region = |r| self.sub_regions(infer::CallReturn(span), least_region, r); |
| 340 | + while let Some(ty) = types.pop() { |
| 341 | + let mut components = self.tcx.outlives_components(ty); |
| 342 | + while let Some(component) = components.pop() { |
| 343 | + match component { |
| 344 | + Component::Region(r) => { |
| 345 | + bound_region(r); |
| 346 | + } |
| 347 | + |
| 348 | + Component::Param(_) => { |
| 349 | + // ignore type parameters like `T`, they are captured |
| 350 | + // implicitly by the `impl Trait` |
| 351 | + } |
| 352 | + |
| 353 | + Component::UnresolvedInferenceVariable(_) => { |
| 354 | + // we should get an error that more type |
| 355 | + // annotations are needed in this case |
| 356 | + self.tcx |
| 357 | + .sess |
| 358 | + .delay_span_bug(span, "unresolved inf var in anon"); |
| 359 | + } |
| 360 | + |
| 361 | + Component::Projection(ty::ProjectionTy { |
| 362 | + substs, |
| 363 | + item_def_id: _, |
| 364 | + }) => { |
| 365 | + for r in substs.regions() { |
| 366 | + bound_region(r); |
| 367 | + } |
| 368 | + types.extend(substs.types()); |
| 369 | + } |
| 370 | + |
| 371 | + Component::EscapingProjection(more_components) => { |
| 372 | + components.extend(more_components); |
| 373 | + } |
| 374 | + } |
| 375 | + } |
| 376 | + } |
| 377 | + } |
118 | 378 | }
|
119 | 379 |
|
120 | 380 | struct Instantiator<'a, 'gcx: 'tcx, 'tcx: 'a> {
|
|
0 commit comments