Skip to content

Commit 7f50e7c

Browse files
committed
extract the writeback code for anon types into InferCtxt
No functional change.
1 parent 8e64ba8 commit 7f50e7c

File tree

2 files changed

+225
-132
lines changed

2 files changed

+225
-132
lines changed

src/librustc/infer/anon_types/mod.rs

Lines changed: 102 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,12 +11,13 @@
1111
use hir::def_id::DefId;
1212
use infer::{self, InferCtxt, InferOk, TypeVariableOrigin};
1313
use infer::outlives::free_region_map::FreeRegionRelations;
14+
use rustc_data_structures::fx::FxHashMap;
1415
use syntax::ast;
1516
use traits::{self, PredicateObligation};
1617
use ty::{self, Ty};
1718
use ty::fold::{BottomUpFolder, TypeFoldable};
1819
use ty::outlives::Component;
19-
use ty::subst::Substs;
20+
use ty::subst::{Kind, Substs};
2021
use util::nodemap::DefIdMap;
2122

2223
pub type AnonTypeMap<'tcx> = DefIdMap<AnonTypeDecl<'tcx>>;
@@ -375,6 +376,106 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
375376
}
376377
}
377378
}
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+
}
378479
}
379480

380481
struct Instantiator<'a, 'gcx: 'tcx, 'tcx: 'a> {

0 commit comments

Comments
 (0)