1 use rustc_data_structures
::fx
::FxHashSet
;
3 use rustc_hir
::lang_items
;
4 use rustc_middle
::ty
::{self, Region, RegionVid, TypeFoldable}
;
5 use rustc_trait_selection
::traits
::auto_trait
::{self, AutoTraitResult}
;
11 #[derive(Eq, PartialEq, Hash, Copy, Clone, Debug)]
12 enum RegionTarget
<'tcx
> {
17 #[derive(Default, Debug, Clone)]
18 struct RegionDeps
<'tcx
> {
19 larger
: FxHashSet
<RegionTarget
<'tcx
>>,
20 smaller
: FxHashSet
<RegionTarget
<'tcx
>>,
23 pub struct AutoTraitFinder
<'a
, 'tcx
> {
24 pub cx
: &'a core
::DocContext
<'tcx
>,
25 pub f
: auto_trait
::AutoTraitFinder
<'tcx
>,
28 impl<'a
, 'tcx
> AutoTraitFinder
<'a
, 'tcx
> {
29 pub fn new(cx
: &'a core
::DocContext
<'tcx
>) -> Self {
30 let f
= auto_trait
::AutoTraitFinder
::new(cx
.tcx
);
32 AutoTraitFinder { cx, f }
35 // FIXME(eddyb) figure out a better way to pass information about
36 // parametrization of `ty` than `param_env_def_id`.
37 pub fn get_auto_trait_impls(&self, ty
: Ty
<'tcx
>, param_env_def_id
: DefId
) -> Vec
<Item
> {
38 let param_env
= self.cx
.tcx
.param_env(param_env_def_id
);
40 debug
!("get_auto_trait_impls({:?})", ty
);
41 let auto_traits
= self.cx
.auto_traits
.iter().cloned();
43 .filter_map(|trait_def_id
| {
44 let trait_ref
= ty
::TraitRef
{
46 substs
: self.cx
.tcx
.mk_substs_trait(ty
, &[]),
48 if !self.cx
.generated_synthetics
.borrow_mut().insert((ty
, trait_def_id
)) {
49 debug
!("get_auto_trait_impl_for({:?}): already generated, aborting", trait_ref
);
54 self.f
.find_auto_trait_generics(ty
, param_env
, trait_def_id
, |infcx
, info
| {
55 let region_data
= info
.region_data
;
60 .generics_of(param_env_def_id
)
63 .filter_map(|param
| match param
.kind
{
64 ty
::GenericParamDefKind
::Lifetime
=> Some(param
.name
.to_string()),
67 .map(|name
| (name
.clone(), Lifetime(name
)))
69 let lifetime_predicates
= self.handle_lifetimes(®ion_data
, &names_map
);
70 let new_generics
= self.param_env_to_generics(
79 "find_auto_trait_generics(param_env_def_id={:?}, trait_def_id={:?}): \
81 param_env_def_id
, trait_def_id
, new_generics
88 let new_generics
= match result
{
89 AutoTraitResult
::PositiveImpl(new_generics
) => {
93 AutoTraitResult
::NegativeImpl
=> {
94 polarity
= Some(ImplPolarity
::Negative
);
96 // For negative impls, we use the generic params, but *not* the predicates,
97 // from the original type. Otherwise, the displayed impl appears to be a
98 // conditional negative impl, when it's really unconditional.
100 // For example, consider the struct Foo<T: Copy>(*mut T). Using
101 // the original predicates in our impl would cause us to generate
102 // `impl !Send for Foo<T: Copy>`, which makes it appear that Foo
103 // implements Send where T is not copy.
105 // Instead, we generate `impl !Send for Foo<T>`, which better
106 // expresses the fact that `Foo<T>` never implements `Send`,
107 // regardless of the choice of `T`.
109 self.cx
.tcx
.generics_of(param_env_def_id
),
110 ty
::GenericPredicates
::default(),
115 Generics { params, where_predicates: Vec::new() }
117 AutoTraitResult
::ExplicitImpl
=> return None
,
121 source
: Span
::empty(),
123 attrs
: Default
::default(),
124 visibility
: Inherited
,
125 def_id
: self.cx
.next_def_id(param_env_def_id
.krate
),
128 inner
: ImplItem(Impl
{
129 unsafety
: hir
::Unsafety
::Normal
,
130 generics
: new_generics
,
131 provided_trait_methods
: Default
::default(),
132 trait_
: Some(trait_ref
.clean(self.cx
).get_trait_type().unwrap()),
133 for_
: ty
.clean(self.cx
),
147 names_map
: &FxHashMap
<String
, Lifetime
>,
149 self.region_name(region
)
151 names_map
.get(&name
).unwrap_or_else(|| {
152 panic
!("Missing lifetime with name {:?} for {:?}", name
, region
)
155 .unwrap_or(&Lifetime
::statik())
159 fn region_name(&self, region
: Region
<'_
>) -> Option
<String
> {
161 &ty
::ReEarlyBound(r
) => Some(r
.name
.to_string()),
166 // This method calculates two things: Lifetime constraints of the form 'a: 'b,
167 // and region constraints of the form ReVar: 'a
169 // This is essentially a simplified version of lexical_region_resolve. However,
170 // handle_lifetimes determines what *needs be* true in order for an impl to hold.
171 // lexical_region_resolve, along with much of the rest of the compiler, is concerned
172 // with determining if a given set up constraints/predicates *are* met, given some
173 // starting conditions (e.g., user-provided code). For this reason, it's easier
174 // to perform the calculations we need on our own, rather than trying to make
175 // existing inference/solver code do what we want.
176 fn handle_lifetimes
<'cx
>(
178 regions
: &RegionConstraintData
<'cx
>,
179 names_map
: &FxHashMap
<String
, Lifetime
>,
180 ) -> Vec
<WherePredicate
> {
181 // Our goal is to 'flatten' the list of constraints by eliminating
182 // all intermediate RegionVids. At the end, all constraints should
183 // be between Regions (aka region variables). This gives us the information
184 // we need to create the Generics.
185 let mut finished
: FxHashMap
<_
, Vec
<_
>> = Default
::default();
187 let mut vid_map
: FxHashMap
<RegionTarget
<'_
>, RegionDeps
<'_
>> = Default
::default();
189 // Flattening is done in two parts. First, we insert all of the constraints
190 // into a map. Each RegionTarget (either a RegionVid or a Region) maps
191 // to its smaller and larger regions. Note that 'larger' regions correspond
192 // to sub-regions in Rust code (e.g., in 'a: 'b, 'a is the larger region).
193 for constraint
in regions
.constraints
.keys() {
195 &Constraint
::VarSubVar(r1
, r2
) => {
197 let deps1
= vid_map
.entry(RegionTarget
::RegionVid(r1
)).or_default();
198 deps1
.larger
.insert(RegionTarget
::RegionVid(r2
));
201 let deps2
= vid_map
.entry(RegionTarget
::RegionVid(r2
)).or_default();
202 deps2
.smaller
.insert(RegionTarget
::RegionVid(r1
));
204 &Constraint
::RegSubVar(region
, vid
) => {
205 let deps
= vid_map
.entry(RegionTarget
::RegionVid(vid
)).or_default();
206 deps
.smaller
.insert(RegionTarget
::Region(region
));
208 &Constraint
::VarSubReg(vid
, region
) => {
209 let deps
= vid_map
.entry(RegionTarget
::RegionVid(vid
)).or_default();
210 deps
.larger
.insert(RegionTarget
::Region(region
));
212 &Constraint
::RegSubReg(r1
, r2
) => {
213 // The constraint is already in the form that we want, so we're done with it
214 // Desired order is 'larger, smaller', so flip then
215 if self.region_name(r1
) != self.region_name(r2
) {
217 .entry(self.region_name(r2
).expect("no region_name found"))
225 // Here, we 'flatten' the map one element at a time.
226 // All of the element's sub and super regions are connected
227 // to each other. For example, if we have a graph that looks like this:
229 // (A, B) - C - (D, E)
230 // Where (A, B) are subregions, and (D,E) are super-regions
232 // then after deleting 'C', the graph will look like this:
233 // ... - A - (D, E ...)
234 // ... - B - (D, E, ...)
235 // (A, B, ...) - D - ...
236 // (A, B, ...) - E - ...
238 // where '...' signifies the existing sub and super regions of an entry
239 // When two adjacent ty::Regions are encountered, we've computed a final
240 // constraint, and add it to our list. Since we make sure to never re-add
241 // deleted items, this process will always finish.
242 while !vid_map
.is_empty() {
243 let target
= *vid_map
.keys().next().expect("Keys somehow empty");
244 let deps
= vid_map
.remove(&target
).expect("Entry somehow missing");
246 for smaller
in deps
.smaller
.iter() {
247 for larger
in deps
.larger
.iter() {
248 match (smaller
, larger
) {
249 (&RegionTarget
::Region(r1
), &RegionTarget
::Region(r2
)) => {
250 if self.region_name(r1
) != self.region_name(r2
) {
252 .entry(self.region_name(r2
).expect("no region name found"))
254 .push(r1
) // Larger, smaller
257 (&RegionTarget
::RegionVid(_
), &RegionTarget
::Region(_
)) => {
258 if let Entry
::Occupied(v
) = vid_map
.entry(*smaller
) {
259 let smaller_deps
= v
.into_mut();
260 smaller_deps
.larger
.insert(*larger
);
261 smaller_deps
.larger
.remove(&target
);
264 (&RegionTarget
::Region(_
), &RegionTarget
::RegionVid(_
)) => {
265 if let Entry
::Occupied(v
) = vid_map
.entry(*larger
) {
266 let deps
= v
.into_mut();
267 deps
.smaller
.insert(*smaller
);
268 deps
.smaller
.remove(&target
);
271 (&RegionTarget
::RegionVid(_
), &RegionTarget
::RegionVid(_
)) => {
272 if let Entry
::Occupied(v
) = vid_map
.entry(*smaller
) {
273 let smaller_deps
= v
.into_mut();
274 smaller_deps
.larger
.insert(*larger
);
275 smaller_deps
.larger
.remove(&target
);
278 if let Entry
::Occupied(v
) = vid_map
.entry(*larger
) {
279 let larger_deps
= v
.into_mut();
280 larger_deps
.smaller
.insert(*smaller
);
281 larger_deps
.smaller
.remove(&target
);
289 let lifetime_predicates
= names_map
291 .flat_map(|(name
, lifetime
)| {
292 let empty
= Vec
::new();
293 let bounds
: FxHashSet
<GenericBound
> = finished
297 .map(|region
| GenericBound
::Outlives(self.get_lifetime(region
, names_map
)))
300 if bounds
.is_empty() {
303 Some(WherePredicate
::RegionPredicate
{
304 lifetime
: lifetime
.clone(),
305 bounds
: bounds
.into_iter().collect(),
313 fn extract_for_generics(
316 pred
: ty
::Predicate
<'tcx
>,
317 ) -> FxHashSet
<GenericParamDef
> {
318 let regions
= match pred
{
319 ty
::Predicate
::Trait(poly_trait_pred
, _
) => {
320 tcx
.collect_referenced_late_bound_regions(&poly_trait_pred
)
322 ty
::Predicate
::Projection(poly_proj_pred
) => {
323 tcx
.collect_referenced_late_bound_regions(&poly_proj_pred
)
325 _
=> return FxHashSet
::default(),
332 // We only care about named late bound regions, as we need to add them
333 // to the 'for<>' section
334 ty
::BrNamed(_
, name
) => Some(GenericParamDef
{
335 name
: name
.to_string(),
336 kind
: GenericParamDefKind
::Lifetime
,
344 fn make_final_bounds(
346 ty_to_bounds
: FxHashMap
<Type
, FxHashSet
<GenericBound
>>,
347 ty_to_fn
: FxHashMap
<Type
, (Option
<PolyTrait
>, Option
<Type
>)>,
348 lifetime_to_bounds
: FxHashMap
<Lifetime
, FxHashSet
<GenericBound
>>,
349 ) -> Vec
<WherePredicate
> {
352 .flat_map(|(ty
, mut bounds
)| {
353 if let Some(data
) = ty_to_fn
.get(&ty
) {
354 let (poly_trait
, output
) =
355 (data
.0.as_ref().expect("as_ref failed").clone(), data
.1.as_ref().cloned());
356 let new_ty
= match &poly_trait
.trait_
{
357 &Type
::ResolvedPath
{
363 let mut new_path
= path
.clone();
365 new_path
.segments
.pop().expect("segments were empty");
367 let (old_input
, old_output
) = match last_segment
.args
{
368 GenericArgs
::AngleBracketed { args, .. }
=> {
371 .filter_map(|arg
| match arg
{
372 GenericArg
::Type(ty
) => Some(ty
.clone()),
378 GenericArgs
::Parenthesized { inputs, output, .. }
=> {
383 if old_output
.is_some() && old_output
!= output
{
385 "Output mismatch for {:?} {:?} {:?}",
386 ty
, old_output
, data
.1
391 GenericArgs
::Parenthesized { inputs: old_input, output }
;
395 .push(PathSegment { name: last_segment.name, args: new_params }
);
399 param_names
: param_names
.clone(),
401 is_generic
: *is_generic
,
404 _
=> panic
!("Unexpected data: {:?}, {:?}", ty
, data
),
406 bounds
.insert(GenericBound
::TraitBound(
407 PolyTrait { trait_: new_ty, generic_params: poly_trait.generic_params }
,
408 hir
::TraitBoundModifier
::None
,
411 if bounds
.is_empty() {
415 let mut bounds_vec
= bounds
.into_iter().collect();
416 self.sort_where_bounds(&mut bounds_vec
);
418 Some(WherePredicate
::BoundPredicate { ty, bounds: bounds_vec }
)
421 lifetime_to_bounds
.into_iter().filter(|&(_
, ref bounds
)| !bounds
.is_empty()).map(
422 |(lifetime
, bounds
)| {
423 let mut bounds_vec
= bounds
.into_iter().collect();
424 self.sort_where_bounds(&mut bounds_vec
);
425 WherePredicate
::RegionPredicate { lifetime, bounds: bounds_vec }
432 // Converts the calculated ParamEnv and lifetime information to a clean::Generics, suitable for
433 // display on the docs page. Cleaning the Predicates produces sub-optimal WherePredicate's,
434 // so we fix them up:
436 // * Multiple bounds for the same type are coalesced into one: e.g., 'T: Copy', 'T: Debug'
437 // becomes 'T: Copy + Debug'
438 // * Fn bounds are handled specially - instead of leaving it as 'T: Fn(), <T as Fn::Output> =
439 // K', we use the dedicated syntax 'T: Fn() -> K'
440 // * We explcitly add a '?Sized' bound if we didn't find any 'Sized' predicates for a type
441 fn param_env_to_generics(
444 param_env_def_id
: DefId
,
445 param_env
: ty
::ParamEnv
<'tcx
>,
446 mut existing_predicates
: Vec
<WherePredicate
>,
447 vid_to_region
: FxHashMap
<ty
::RegionVid
, ty
::Region
<'tcx
>>,
450 "param_env_to_generics(param_env_def_id={:?}, param_env={:?}, \
451 existing_predicates={:?})",
452 param_env_def_id
, param_env
, existing_predicates
455 // The `Sized` trait must be handled specially, since we only display it when
456 // it is *not* required (i.e., '?Sized')
457 let sized_trait
= self.cx
.tcx
.require_lang_item(lang_items
::SizedTraitLangItem
, None
);
459 let mut replacer
= RegionReplacer { vid_to_region: &vid_to_region, tcx }
;
461 let orig_bounds
: FxHashSet
<_
> =
462 self.cx
.tcx
.param_env(param_env_def_id
).caller_bounds
.iter().collect();
463 let clean_where_predicates
= param_env
467 !orig_bounds
.contains(p
)
469 ty
::Predicate
::Trait(pred
, _
) => pred
.def_id() == sized_trait
,
474 let replaced
= p
.fold_with(&mut replacer
);
475 (replaced
, replaced
.clean(self.cx
))
478 let mut generic_params
=
479 (tcx
.generics_of(param_env_def_id
), tcx
.explicit_predicates_of(param_env_def_id
))
483 let mut has_sized
= FxHashSet
::default();
484 let mut ty_to_bounds
: FxHashMap
<_
, FxHashSet
<_
>> = Default
::default();
485 let mut lifetime_to_bounds
: FxHashMap
<_
, FxHashSet
<_
>> = Default
::default();
486 let mut ty_to_traits
: FxHashMap
<Type
, FxHashSet
<Type
>> = Default
::default();
488 let mut ty_to_fn
: FxHashMap
<Type
, (Option
<PolyTrait
>, Option
<Type
>)> = Default
::default();
490 for (orig_p
, p
) in clean_where_predicates
{
496 WherePredicate
::BoundPredicate { ty, mut bounds }
=> {
497 // Writing a projection trait bound of the form
498 // <T as Trait>::Name : ?Sized
499 // is illegal, because ?Sized bounds can only
500 // be written in the (here, nonexistent) definition
502 // Therefore, we make sure that we never add a ?Sized
503 // bound for projections
504 if let Type
::QPath { .. }
= ty
{
505 has_sized
.insert(ty
.clone());
508 if bounds
.is_empty() {
512 let mut for_generics
= self.extract_for_generics(tcx
, orig_p
);
514 assert
!(bounds
.len() == 1);
515 let mut b
= bounds
.pop().expect("bounds were empty");
517 if b
.is_sized_bound(self.cx
) {
518 has_sized
.insert(ty
.clone());
524 .map(|bounds
| bounds
.contains(&strip_type(t
.clone())))
528 // If we've already added a projection bound for the same type, don't add
529 // this, as it would be a duplicate
531 // Handle any 'Fn/FnOnce/FnMut' bounds specially,
532 // as we want to combine them with any 'Output' qpaths
535 let is_fn
= match &mut b
{
536 &mut GenericBound
::TraitBound(ref mut p
, _
) => {
537 // Insert regions into the for_generics hash map first, to ensure
538 // that we don't end up with duplicate bounds (e.g., for<'b, 'b>)
539 for_generics
.extend(p
.generic_params
.clone());
540 p
.generic_params
= for_generics
.into_iter().collect();
541 self.is_fn_ty(tcx
, &p
.trait_
)
546 let poly_trait
= b
.get_poly_trait().expect("Cannot get poly trait");
551 .and_modify(|e
| *e
= (Some(poly_trait
.clone()), e
.1.clone()))
552 .or_insert(((Some(poly_trait
.clone())), None
));
554 ty_to_bounds
.entry(ty
.clone()).or_default();
556 ty_to_bounds
.entry(ty
.clone()).or_default().insert(b
.clone());
560 WherePredicate
::RegionPredicate { lifetime, bounds }
=> {
561 lifetime_to_bounds
.entry(lifetime
).or_default().extend(bounds
);
563 WherePredicate
::EqPredicate { lhs, rhs }
=> {
565 Type
::QPath { name: ref left_name, ref self_type, ref trait_ }
=> {
566 let ty
= &*self_type
;
569 path
: ref trait_path
,
574 let mut new_trait_path
= trait_path
.clone();
576 if self.is_fn_ty(tcx
, trait_
) && left_name
== FN_OUTPUT_NAME
{
579 .and_modify(|e
| *e
= (e
.0.clone(), Some(rhs
.clone())))
580 .or_insert((None
, Some(rhs
)));
584 let args
= &mut new_trait_path
587 .expect("segments were empty")
591 // Convert somethiung like '<T as Iterator::Item> = u8'
592 // to 'T: Iterator<Item=u8>'
593 GenericArgs
::AngleBracketed
{
596 bindings
.push(TypeBinding
{
597 name
: left_name
.clone(),
598 kind
: TypeBindingKind
::Equality { ty: rhs }
,
601 GenericArgs
::Parenthesized { .. }
=> {
602 existing_predicates
.push(WherePredicate
::EqPredicate
{
606 continue; // If something other than a Fn ends up
607 // with parenthesis, leave it alone
611 let bounds
= ty_to_bounds
.entry(*ty
.clone()).or_default();
613 bounds
.insert(GenericBound
::TraitBound(
615 trait_
: Type
::ResolvedPath
{
616 path
: new_trait_path
,
617 param_names
: param_names
.clone(),
619 is_generic
: *is_generic
,
621 generic_params
: Vec
::new(),
623 hir
::TraitBoundModifier
::None
,
626 // Remove any existing 'plain' bound (e.g., 'T: Iterator`) so
627 // that we don't see a
628 // duplicate bound like `T: Iterator + Iterator<Item=u8>`
630 bounds
.remove(&GenericBound
::TraitBound(
632 trait_
: *trait_
.clone(),
633 generic_params
: Vec
::new(),
635 hir
::TraitBoundModifier
::None
,
637 // Avoid creating any new duplicate bounds later in the outer
642 .insert(*trait_
.clone());
645 "Unexpected trait {:?} for {:?}",
646 trait_
, param_env_def_id
,
650 _
=> panic
!("Unexpected LHS {:?} for {:?}", lhs
, param_env_def_id
),
656 let final_bounds
= self.make_final_bounds(ty_to_bounds
, ty_to_fn
, lifetime_to_bounds
);
658 existing_predicates
.extend(final_bounds
);
660 for param
in generic_params
.iter_mut() {
662 GenericParamDefKind
::Type { ref mut default, ref mut bounds, .. }
=> {
663 // We never want something like `impl<T=Foo>`.
665 let generic_ty
= Type
::Generic(param
.name
.clone());
666 if !has_sized
.contains(&generic_ty
) {
667 bounds
.insert(0, GenericBound
::maybe_sized(self.cx
));
670 GenericParamDefKind
::Lifetime
=> {}
671 GenericParamDefKind
::Const { .. }
=> {}
675 self.sort_where_predicates(&mut existing_predicates
);
677 Generics { params: generic_params, where_predicates: existing_predicates }
680 // Ensure that the predicates are in a consistent order. The precise
681 // ordering doesn't actually matter, but it's important that
682 // a given set of predicates always appears in the same order -
683 // both for visual consistency between 'rustdoc' runs, and to
684 // make writing tests much easier
686 fn sort_where_predicates(&self, mut predicates
: &mut Vec
<WherePredicate
>) {
687 // We should never have identical bounds - and if we do,
688 // they're visually identical as well. Therefore, using
689 // an unstable sort is fine.
690 self.unstable_debug_sort(&mut predicates
);
693 // Ensure that the bounds are in a consistent order. The precise
694 // ordering doesn't actually matter, but it's important that
695 // a given set of bounds always appears in the same order -
696 // both for visual consistency between 'rustdoc' runs, and to
697 // make writing tests much easier
699 fn sort_where_bounds(&self, mut bounds
: &mut Vec
<GenericBound
>) {
700 // We should never have identical bounds - and if we do,
701 // they're visually identical as well. Therefore, using
702 // an unstable sort is fine.
703 self.unstable_debug_sort(&mut bounds
);
706 // This might look horrendously hacky, but it's actually not that bad.
708 // For performance reasons, we use several different FxHashMaps
709 // in the process of computing the final set of where predicates.
710 // However, the iteration order of a HashMap is completely unspecified.
711 // In fact, the iteration of an FxHashMap can even vary between platforms,
712 // since FxHasher has different behavior for 32-bit and 64-bit platforms.
714 // Obviously, it's extremely undesirable for documentation rendering
715 // to be depndent on the platform it's run on. Apart from being confusing
716 // to end users, it makes writing tests much more difficult, as predicates
717 // can appear in any order in the final result.
719 // To solve this problem, we sort WherePredicates and GenericBounds
720 // by their Debug string. The thing to keep in mind is that we don't really
721 // care what the final order is - we're synthesizing an impl or bound
722 // ourselves, so any order can be considered equally valid. By sorting the
723 // predicates and bounds, however, we ensure that for a given codebase, all
724 // auto-trait impls always render in exactly the same way.
726 // Using the Debug implementation for sorting prevents us from needing to
727 // write quite a bit of almost entirely useless code (e.g., how should two
728 // Types be sorted relative to each other). It also allows us to solve the
729 // problem for both WherePredicates and GenericBounds at the same time. This
730 // approach is probably somewhat slower, but the small number of items
731 // involved (impls rarely have more than a few bounds) means that it
732 // shouldn't matter in practice.
733 fn unstable_debug_sort
<T
: Debug
>(&self, vec
: &mut Vec
<T
>) {
734 vec
.sort_by_cached_key(|x
| format
!("{:?}", x
))
737 fn is_fn_ty(&self, tcx
: TyCtxt
<'_
>, ty
: &Type
) -> bool
{
739 &&Type
::ResolvedPath { ref did, .. }
=> {
740 *did
== tcx
.require_lang_item(lang_items
::FnTraitLangItem
, None
)
741 || *did
== tcx
.require_lang_item(lang_items
::FnMutTraitLangItem
, None
)
742 || *did
== tcx
.require_lang_item(lang_items
::FnOnceTraitLangItem
, None
)
749 // Replaces all ReVars in a type with ty::Region's, using the provided map
750 struct RegionReplacer
<'a
, 'tcx
> {
751 vid_to_region
: &'a FxHashMap
<ty
::RegionVid
, ty
::Region
<'tcx
>>,
755 impl<'a
, 'tcx
> TypeFolder
<'tcx
> for RegionReplacer
<'a
, 'tcx
> {
756 fn tcx
<'b
>(&'b
self) -> TyCtxt
<'tcx
> {
760 fn fold_region(&mut self, r
: ty
::Region
<'tcx
>) -> ty
::Region
<'tcx
> {
762 &ty
::ReVar(vid
) => self.vid_to_region
.get(&vid
).cloned(),
765 .unwrap_or_else(|| r
.super_fold_with(self))