|
11 | 11 | use hir::def_id::DefId;
|
12 | 12 | use infer::{self, InferCtxt, InferOk, TypeVariableOrigin};
|
13 | 13 | use infer::outlives::free_region_map::FreeRegionRelations;
|
| 14 | +use rustc_data_structures::fx::FxHashMap; |
14 | 15 | use syntax::ast;
|
15 | 16 | use traits::{self, PredicateObligation};
|
16 | 17 | use ty::{self, Ty};
|
17 | 18 | use ty::fold::{BottomUpFolder, TypeFoldable};
|
18 | 19 | use ty::outlives::Component;
|
19 |
| -use ty::subst::Substs; |
| 20 | +use ty::subst::{Kind, Substs}; |
20 | 21 | use util::nodemap::DefIdMap;
|
21 | 22 |
|
22 | 23 | pub type AnonTypeMap<'tcx> = DefIdMap<AnonTypeDecl<'tcx>>;
|
@@ -375,6 +376,106 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
|
375 | 376 | }
|
376 | 377 | }
|
377 | 378 | }
|
| 379 | + |
| 380 | + /// Given the fully resolved, instantiated type for an anonymous |
| 381 | + /// type, i.e., the value of an inference variable like C1 or C2 |
| 382 | + /// (*), computes the "definition type" for an abstract type |
| 383 | + /// definition -- that is, the inferred value of `Foo1<'x>` or |
| 384 | + /// `Foo2<'x>` that we would conceptually use in its definition: |
| 385 | + /// |
| 386 | + /// abstract type Foo1<'x>: Bar<'x> = AAA; <-- this type AAA |
| 387 | + /// abstract type Foo2<'x>: Bar<'x> = BBB; <-- or this type BBB |
| 388 | + /// fn foo<'a, 'b>(..) -> (Foo1<'a>, Foo2<'b>) { .. } |
| 389 | + /// |
| 390 | + /// Note that these values are defined in terms of a distinct set of |
| 391 | + /// generic parameters (`'x` instead of `'a`) from C1 or C2. The main |
| 392 | + /// purpose of this function is to do that translation. |
| 393 | + /// |
| 394 | + /// (*) C1 and C2 were introduced in the comments on |
| 395 | + /// `constrain_anon_types`. Read that comment for more context. |
| 396 | + /// |
| 397 | + /// # Parameters |
| 398 | + /// |
| 399 | + /// - `def_id`, the `impl Trait` type |
| 400 | + /// - `anon_defn`, the anonymous definition created in `instantiate_anon_types` |
| 401 | + /// - `instantiated_ty`, the inferred type C1 -- fully resolved, lifted version of |
| 402 | + /// `anon_defn.concrete_ty` |
| 403 | + pub fn infer_anon_definition_from_instantiation( |
| 404 | + &self, |
| 405 | + def_id: DefId, |
| 406 | + anon_defn: &AnonTypeDecl<'tcx>, |
| 407 | + instantiated_ty: Ty<'gcx>, |
| 408 | + ) -> Ty<'gcx> { |
| 409 | + debug!( |
| 410 | + "infer_anon_definition_from_instantiation(instantiated_ty={:?})", |
| 411 | + instantiated_ty |
| 412 | + ); |
| 413 | + |
| 414 | + let gcx = self.tcx.global_tcx(); |
| 415 | + |
| 416 | + // Use substs to build up a reverse map from regions to their |
| 417 | + // identity mappings. This is necessary because of `impl |
| 418 | + // Trait` lifetimes are computed by replacing existing |
| 419 | + // lifetimes with 'static and remapping only those used in the |
| 420 | + // `impl Trait` return type, resulting in the parameters |
| 421 | + // shifting. |
| 422 | + let id_substs = Substs::identity_for_item(gcx, def_id); |
| 423 | + let map: FxHashMap<Kind<'tcx>, Kind<'gcx>> = anon_defn |
| 424 | + .substs |
| 425 | + .iter() |
| 426 | + .enumerate() |
| 427 | + .map(|(index, subst)| (*subst, id_substs[index])) |
| 428 | + .collect(); |
| 429 | + |
| 430 | + // Convert the type from the function into a type valid outside |
| 431 | + // the function, by replacing invalid regions with 'static, |
| 432 | + // after producing an error for each of them. |
| 433 | + let definition_ty = gcx.fold_regions(&instantiated_ty, &mut false, |r, _| { |
| 434 | + match *r { |
| 435 | + // 'static and early-bound regions are valid. |
| 436 | + ty::ReStatic | ty::ReEmpty => r, |
| 437 | + |
| 438 | + // All other regions, we map them appropriately to their adjusted |
| 439 | + // indices, erroring if we find any lifetimes that were not mapped |
| 440 | + // into the new set. |
| 441 | + _ => if let Some(r1) = map.get(&Kind::from(r)).and_then(|k| k.as_region()) { |
| 442 | + r1 |
| 443 | + } else { |
| 444 | + // No mapping was found. This means that |
| 445 | + // it is either a disallowed lifetime, |
| 446 | + // which will be caught by regionck, or it |
| 447 | + // is a region in a non-upvar closure |
| 448 | + // generic, which is explicitly |
| 449 | + // allowed. If that surprises you, read |
| 450 | + // on. |
| 451 | + // |
| 452 | + // The case of closure is a somewhat |
| 453 | + // subtle (read: hacky) consideration. The |
| 454 | + // problem is that our closure types |
| 455 | + // currently include all the lifetime |
| 456 | + // parameters declared on the enclosing |
| 457 | + // function, even if they are unused by |
| 458 | + // the closure itself. We can't readily |
| 459 | + // filter them out, so here we replace |
| 460 | + // those values with `'empty`. This can't |
| 461 | + // really make a difference to the rest of |
| 462 | + // the compiler; those regions are ignored |
| 463 | + // for the outlives relation, and hence |
| 464 | + // don't affect trait selection or auto |
| 465 | + // traits, and they are erased during |
| 466 | + // trans. |
| 467 | + gcx.types.re_empty |
| 468 | + }, |
| 469 | + } |
| 470 | + }); |
| 471 | + |
| 472 | + debug!( |
| 473 | + "infer_anon_definition_from_instantiation: definition_ty={:?}", |
| 474 | + definition_ty |
| 475 | + ); |
| 476 | + |
| 477 | + definition_ty |
| 478 | + } |
378 | 479 | }
|
379 | 480 |
|
380 | 481 | struct Instantiator<'a, 'gcx: 'tcx, 'tcx: 'a> {
|
|
0 commit comments