1 use rustc_data_structures
::fx
::FxHashSet
;
3 use rustc_hir
::lang_items
::LangItem
;
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 crate struct AutoTraitFinder
<'a
, 'tcx
> {
24 crate cx
: &'a
mut core
::DocContext
<'tcx
>,
27 impl<'a
, 'tcx
> AutoTraitFinder
<'a
, 'tcx
> {
28 crate fn new(cx
: &'a
mut core
::DocContext
<'tcx
>) -> Self {
29 AutoTraitFinder { cx }
32 fn generate_for_trait(
36 param_env
: ty
::ParamEnv
<'tcx
>,
38 f
: &auto_trait
::AutoTraitFinder
<'tcx
>,
39 // If this is set, show only negative trait implementations, not positive ones.
40 discard_positive_impl
: bool
,
42 let tcx
= self.cx
.tcx
;
43 let trait_ref
= ty
::TraitRef { def_id: trait_def_id, substs: tcx.mk_substs_trait(ty, &[]) }
;
44 if !self.cx
.generated_synthetics
.insert((ty
, trait_def_id
)) {
45 debug
!("get_auto_trait_impl_for({:?}): already generated, aborting", trait_ref
);
49 let result
= f
.find_auto_trait_generics(ty
, param_env
, trait_def_id
, |info
| {
50 let region_data
= info
.region_data
;
53 .generics_of(item_def_id
)
56 .filter_map(|param
| match param
.kind
{
57 ty
::GenericParamDefKind
::Lifetime
=> Some(param
.name
),
60 .map(|name
| (name
, Lifetime(name
)))
62 let lifetime_predicates
= Self::handle_lifetimes(®ion_data
, &names_map
);
63 let new_generics
= self.param_env_to_generics(
71 "find_auto_trait_generics(item_def_id={:?}, trait_def_id={:?}): \
73 item_def_id
, trait_def_id
, new_generics
80 let new_generics
= match result
{
81 AutoTraitResult
::PositiveImpl(new_generics
) => {
82 polarity
= ty
::ImplPolarity
::Positive
;
83 if discard_positive_impl
{
88 AutoTraitResult
::NegativeImpl
=> {
89 polarity
= ty
::ImplPolarity
::Negative
;
91 // For negative impls, we use the generic params, but *not* the predicates,
92 // from the original type. Otherwise, the displayed impl appears to be a
93 // conditional negative impl, when it's really unconditional.
95 // For example, consider the struct Foo<T: Copy>(*mut T). Using
96 // the original predicates in our impl would cause us to generate
97 // `impl !Send for Foo<T: Copy>`, which makes it appear that Foo
98 // implements Send where T is not copy.
100 // Instead, we generate `impl !Send for Foo<T>`, which better
101 // expresses the fact that `Foo<T>` never implements `Send`,
102 // regardless of the choice of `T`.
103 let params
= (tcx
.generics_of(item_def_id
), ty
::GenericPredicates
::default())
107 Generics { params, where_predicates: Vec::new() }
109 AutoTraitResult
::ExplicitImpl
=> return None
,
114 attrs
: Default
::default(),
115 visibility
: Inherited
,
116 def_id
: ItemId
::Auto { trait_: trait_def_id, for_: item_def_id }
,
117 kind
: box ImplItem(Impl
{
118 unsafety
: hir
::Unsafety
::Normal
,
119 generics
: new_generics
,
120 trait_
: Some(trait_ref
.clean(self.cx
)),
121 for_
: ty
.clean(self.cx
),
124 kind
: ImplKind
::Auto
,
130 crate fn get_auto_trait_impls(&mut self, item_def_id
: DefId
) -> Vec
<Item
> {
131 let tcx
= self.cx
.tcx
;
132 let param_env
= tcx
.param_env(item_def_id
);
133 let ty
= tcx
.type_of(item_def_id
);
134 let f
= auto_trait
::AutoTraitFinder
::new(tcx
);
136 debug
!("get_auto_trait_impls({:?})", ty
);
137 let auto_traits
: Vec
<_
> = self.cx
.auto_traits
.iter().copied().collect();
138 let mut auto_traits
: Vec
<Item
> = auto_traits
140 .filter_map(|trait_def_id
| {
141 self.generate_for_trait(ty
, trait_def_id
, param_env
, item_def_id
, &f
, false)
144 // We are only interested in case the type *doesn't* implement the Sized trait.
145 if !ty
.is_sized(tcx
.at(rustc_span
::DUMMY_SP
), param_env
) {
146 // In case `#![no_core]` is used, `sized_trait` returns nothing.
147 if let Some(item
) = tcx
.lang_items().sized_trait().and_then(|sized_trait_did
| {
148 self.generate_for_trait(ty
, sized_trait_did
, param_env
, item_def_id
, &f
, true)
150 auto_traits
.push(item
);
156 fn get_lifetime(region
: Region
<'_
>, names_map
: &FxHashMap
<Symbol
, Lifetime
>) -> Lifetime
{
159 names_map
.get(&name
).unwrap_or_else(|| {
160 panic
!("Missing lifetime with name {:?} for {:?}", name
.as_str(), region
)
163 .unwrap_or(&Lifetime
::statik())
167 /// This method calculates two things: Lifetime constraints of the form `'a: 'b`,
168 /// and region constraints of the form `RegionVid: 'a`
170 /// This is essentially a simplified version of lexical_region_resolve. However,
171 /// handle_lifetimes determines what *needs be* true in order for an impl to hold.
172 /// lexical_region_resolve, along with much of the rest of the compiler, is concerned
173 /// with determining if a given set up constraints/predicates *are* met, given some
174 /// starting conditions (e.g., user-provided code). For this reason, it's easier
175 /// to perform the calculations we need on our own, rather than trying to make
176 /// existing inference/solver code do what we want.
177 fn handle_lifetimes
<'cx
>(
178 regions
: &RegionConstraintData
<'cx
>,
179 names_map
: &FxHashMap
<Symbol
, 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 region_name(r1
) != region_name(r2
) {
217 .entry(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 region_name(r1
) != region_name(r2
) {
252 .entry(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(&self, pred
: ty
::Predicate
<'tcx
>) -> FxHashSet
<GenericParamDef
> {
314 let bound_predicate
= pred
.kind();
315 let tcx
= self.cx
.tcx
;
316 let regions
= match bound_predicate
.skip_binder() {
317 ty
::PredicateKind
::Trait(poly_trait_pred
) => {
318 tcx
.collect_referenced_late_bound_regions(&bound_predicate
.rebind(poly_trait_pred
))
320 ty
::PredicateKind
::Projection(poly_proj_pred
) => {
321 tcx
.collect_referenced_late_bound_regions(&bound_predicate
.rebind(poly_proj_pred
))
323 _
=> return FxHashSet
::default(),
330 // We only care about named late bound regions, as we need to add them
331 // to the 'for<>' section
332 ty
::BrNamed(_
, name
) => Some(GenericParamDef
{
334 kind
: GenericParamDefKind
::Lifetime { outlives: vec![] }
,
342 fn make_final_bounds(
344 ty_to_bounds
: FxHashMap
<Type
, FxHashSet
<GenericBound
>>,
345 ty_to_fn
: FxHashMap
<Type
, (Option
<PolyTrait
>, Option
<Type
>)>,
346 lifetime_to_bounds
: FxHashMap
<Lifetime
, FxHashSet
<GenericBound
>>,
347 ) -> Vec
<WherePredicate
> {
350 .flat_map(|(ty
, mut bounds
)| {
351 if let Some(data
) = ty_to_fn
.get(&ty
) {
352 let (poly_trait
, output
) =
353 (data
.0.as_ref().unwrap().clone(), data
.1.as_ref().cloned().map(Box
::new
));
354 let mut new_path
= poly_trait
.trait_
.clone();
355 let last_segment
= new_path
.segments
.pop().expect("segments were empty");
357 let (old_input
, old_output
) = match last_segment
.args
{
358 GenericArgs
::AngleBracketed { args, .. }
=> {
361 .filter_map(|arg
| match arg
{
362 GenericArg
::Type(ty
) => Some(ty
.clone()),
368 GenericArgs
::Parenthesized { inputs, output }
=> (inputs
, output
),
371 if old_output
.is_some() && old_output
!= output
{
372 panic
!("Output mismatch for {:?} {:?} {:?}", ty
, old_output
, data
.1);
375 let new_params
= GenericArgs
::Parenthesized { inputs: old_input, output }
;
379 .push(PathSegment { name: last_segment.name, args: new_params }
);
381 bounds
.insert(GenericBound
::TraitBound(
382 PolyTrait { trait_: new_path, generic_params: poly_trait.generic_params }
,
383 hir
::TraitBoundModifier
::None
,
386 if bounds
.is_empty() {
390 let mut bounds_vec
= bounds
.into_iter().collect();
391 self.sort_where_bounds(&mut bounds_vec
);
393 Some(WherePredicate
::BoundPredicate
{
396 bound_params
: Vec
::new(),
400 lifetime_to_bounds
.into_iter().filter(|&(_
, ref bounds
)| !bounds
.is_empty()).map(
401 |(lifetime
, bounds
)| {
402 let mut bounds_vec
= bounds
.into_iter().collect();
403 self.sort_where_bounds(&mut bounds_vec
);
404 WherePredicate
::RegionPredicate { lifetime, bounds: bounds_vec }
411 /// Converts the calculated `ParamEnv` and lifetime information to a [`clean::Generics`](Generics), suitable for
412 /// display on the docs page. Cleaning the `Predicates` produces sub-optimal [`WherePredicate`]s,
413 /// so we fix them up:
415 /// * Multiple bounds for the same type are coalesced into one: e.g., `T: Copy`, `T: Debug`
416 /// becomes `T: Copy + Debug`
417 /// * `Fn` bounds are handled specially - instead of leaving it as `T: Fn(), <T as Fn::Output> =
418 /// K`, we use the dedicated syntax `T: Fn() -> K`
419 /// * We explicitly add a `?Sized` bound if we didn't find any `Sized` predicates for a type
420 fn param_env_to_generics(
423 param_env
: ty
::ParamEnv
<'tcx
>,
424 mut existing_predicates
: Vec
<WherePredicate
>,
425 vid_to_region
: FxHashMap
<ty
::RegionVid
, ty
::Region
<'tcx
>>,
428 "param_env_to_generics(item_def_id={:?}, param_env={:?}, \
429 existing_predicates={:?})",
430 item_def_id
, param_env
, existing_predicates
433 let tcx
= self.cx
.tcx
;
435 // The `Sized` trait must be handled specially, since we only display it when
436 // it is *not* required (i.e., '?Sized')
437 let sized_trait
= tcx
.require_lang_item(LangItem
::Sized
, None
);
439 let mut replacer
= RegionReplacer { vid_to_region: &vid_to_region, tcx }
;
441 let orig_bounds
: FxHashSet
<_
> = tcx
.param_env(item_def_id
).caller_bounds().iter().collect();
442 let clean_where_predicates
= param_env
446 !orig_bounds
.contains(p
)
447 || match p
.kind().skip_binder() {
448 ty
::PredicateKind
::Trait(pred
) => pred
.def_id() == sized_trait
,
452 .map(|p
| p
.fold_with(&mut replacer
));
454 let mut generic_params
=
455 (tcx
.generics_of(item_def_id
), tcx
.explicit_predicates_of(item_def_id
))
459 debug
!("param_env_to_generics({:?}): generic_params={:?}", item_def_id
, generic_params
);
461 let mut has_sized
= FxHashSet
::default();
462 let mut ty_to_bounds
: FxHashMap
<_
, FxHashSet
<_
>> = Default
::default();
463 let mut lifetime_to_bounds
: FxHashMap
<_
, FxHashSet
<_
>> = Default
::default();
464 let mut ty_to_traits
: FxHashMap
<Type
, FxHashSet
<Path
>> = Default
::default();
466 let mut ty_to_fn
: FxHashMap
<Type
, (Option
<PolyTrait
>, Option
<Type
>)> = Default
::default();
468 for p
in clean_where_predicates
{
469 let (orig_p
, p
) = (p
, p
.clean(self.cx
));
475 WherePredicate
::BoundPredicate { ty, mut bounds, .. }
=> {
476 // Writing a projection trait bound of the form
477 // <T as Trait>::Name : ?Sized
478 // is illegal, because ?Sized bounds can only
479 // be written in the (here, nonexistent) definition
481 // Therefore, we make sure that we never add a ?Sized
482 // bound for projections
483 if let Type
::QPath { .. }
= ty
{
484 has_sized
.insert(ty
.clone());
487 if bounds
.is_empty() {
491 let mut for_generics
= self.extract_for_generics(orig_p
);
493 assert
!(bounds
.len() == 1);
494 let mut b
= bounds
.pop().expect("bounds were empty");
496 if b
.is_sized_bound(self.cx
) {
497 has_sized
.insert(ty
.clone());
503 .map(|bounds
| bounds
.contains(&strip_path_generics(trait_
.clone())))
507 // If we've already added a projection bound for the same type, don't add
508 // this, as it would be a duplicate
510 // Handle any 'Fn/FnOnce/FnMut' bounds specially,
511 // as we want to combine them with any 'Output' qpaths
514 let is_fn
= match b
{
515 GenericBound
::TraitBound(ref mut p
, _
) => {
516 // Insert regions into the for_generics hash map first, to ensure
517 // that we don't end up with duplicate bounds (e.g., for<'b, 'b>)
518 for_generics
.extend(p
.generic_params
.clone());
519 p
.generic_params
= for_generics
.into_iter().collect();
520 self.is_fn_trait(&p
.trait_
)
525 let poly_trait
= b
.get_poly_trait().expect("Cannot get poly trait");
530 .and_modify(|e
| *e
= (Some(poly_trait
.clone()), e
.1.clone()))
531 .or_insert(((Some(poly_trait
.clone())), None
));
533 ty_to_bounds
.entry(ty
.clone()).or_default();
535 ty_to_bounds
.entry(ty
.clone()).or_default().insert(b
.clone());
539 WherePredicate
::RegionPredicate { lifetime, bounds }
=> {
540 lifetime_to_bounds
.entry(lifetime
).or_default().extend(bounds
);
542 WherePredicate
::EqPredicate { lhs, rhs }
=> {
544 Type
::QPath { name: left_name, ref self_type, ref trait_, .. }
=> {
545 let ty
= &*self_type
;
546 let mut new_trait
= trait_
.clone();
548 if self.is_fn_trait(trait_
) && left_name
== sym
::Output
{
551 .and_modify(|e
| *e
= (e
.0.clone(), Some(rhs
.clone())))
552 .or_insert((None
, Some(rhs
)));
556 let args
= &mut new_trait
559 .expect("segments were empty")
563 // Convert something like '<T as Iterator::Item> = u8'
564 // to 'T: Iterator<Item=u8>'
565 GenericArgs
::AngleBracketed { ref mut bindings, .. }
=> {
566 bindings
.push(TypeBinding
{
568 kind
: TypeBindingKind
::Equality { ty: rhs }
,
571 GenericArgs
::Parenthesized { .. }
=> {
572 existing_predicates
.push(WherePredicate
::EqPredicate
{
576 continue; // If something other than a Fn ends up
577 // with parentheses, leave it alone
581 let bounds
= ty_to_bounds
.entry(*ty
.clone()).or_default();
583 bounds
.insert(GenericBound
::TraitBound(
584 PolyTrait { trait_: new_trait, generic_params: Vec::new() }
,
585 hir
::TraitBoundModifier
::None
,
588 // Remove any existing 'plain' bound (e.g., 'T: Iterator`) so
589 // that we don't see a
590 // duplicate bound like `T: Iterator + Iterator<Item=u8>`
592 bounds
.remove(&GenericBound
::TraitBound(
593 PolyTrait { trait_: trait_.clone(), generic_params: Vec::new() }
,
594 hir
::TraitBoundModifier
::None
,
596 // Avoid creating any new duplicate bounds later in the outer
598 ty_to_traits
.entry(*ty
.clone()).or_default().insert(trait_
.clone());
600 _
=> panic
!("Unexpected LHS {:?} for {:?}", lhs
, item_def_id
),
606 let final_bounds
= self.make_final_bounds(ty_to_bounds
, ty_to_fn
, lifetime_to_bounds
);
608 existing_predicates
.extend(final_bounds
);
610 for param
in generic_params
.iter_mut() {
612 GenericParamDefKind
::Type { ref mut default, ref mut bounds, .. }
=> {
613 // We never want something like `impl<T=Foo>`.
615 let generic_ty
= Type
::Generic(param
.name
);
616 if !has_sized
.contains(&generic_ty
) {
617 bounds
.insert(0, GenericBound
::maybe_sized(self.cx
));
620 GenericParamDefKind
::Lifetime { .. }
=> {}
621 GenericParamDefKind
::Const { ref mut default, .. }
=> {
622 // We never want something like `impl<const N: usize = 10>`
628 self.sort_where_predicates(&mut existing_predicates
);
630 Generics { params: generic_params, where_predicates: existing_predicates }
633 /// Ensure that the predicates are in a consistent order. The precise
634 /// ordering doesn't actually matter, but it's important that
635 /// a given set of predicates always appears in the same order -
636 /// both for visual consistency between 'rustdoc' runs, and to
637 /// make writing tests much easier
639 fn sort_where_predicates(&self, mut predicates
: &mut Vec
<WherePredicate
>) {
640 // We should never have identical bounds - and if we do,
641 // they're visually identical as well. Therefore, using
642 // an unstable sort is fine.
643 self.unstable_debug_sort(&mut predicates
);
646 /// Ensure that the bounds are in a consistent order. The precise
647 /// ordering doesn't actually matter, but it's important that
648 /// a given set of bounds always appears in the same order -
649 /// both for visual consistency between 'rustdoc' runs, and to
650 /// make writing tests much easier
652 fn sort_where_bounds(&self, mut bounds
: &mut Vec
<GenericBound
>) {
653 // We should never have identical bounds - and if we do,
654 // they're visually identical as well. Therefore, using
655 // an unstable sort is fine.
656 self.unstable_debug_sort(&mut bounds
);
659 /// This might look horrendously hacky, but it's actually not that bad.
661 /// For performance reasons, we use several different FxHashMaps
662 /// in the process of computing the final set of where predicates.
663 /// However, the iteration order of a HashMap is completely unspecified.
664 /// In fact, the iteration of an FxHashMap can even vary between platforms,
665 /// since FxHasher has different behavior for 32-bit and 64-bit platforms.
667 /// Obviously, it's extremely undesirable for documentation rendering
668 /// to be dependent on the platform it's run on. Apart from being confusing
669 /// to end users, it makes writing tests much more difficult, as predicates
670 /// can appear in any order in the final result.
672 /// To solve this problem, we sort WherePredicates and GenericBounds
673 /// by their Debug string. The thing to keep in mind is that we don't really
674 /// care what the final order is - we're synthesizing an impl or bound
675 /// ourselves, so any order can be considered equally valid. By sorting the
676 /// predicates and bounds, however, we ensure that for a given codebase, all
677 /// auto-trait impls always render in exactly the same way.
679 /// Using the Debug implementation for sorting prevents us from needing to
680 /// write quite a bit of almost entirely useless code (e.g., how should two
681 /// Types be sorted relative to each other). It also allows us to solve the
682 /// problem for both WherePredicates and GenericBounds at the same time. This
683 /// approach is probably somewhat slower, but the small number of items
684 /// involved (impls rarely have more than a few bounds) means that it
685 /// shouldn't matter in practice.
686 fn unstable_debug_sort
<T
: Debug
>(&self, vec
: &mut Vec
<T
>) {
687 vec
.sort_by_cached_key(|x
| format
!("{:?}", x
))
690 fn is_fn_trait(&self, path
: &Path
) -> bool
{
691 let tcx
= self.cx
.tcx
;
692 let did
= path
.def_id();
693 did
== tcx
.require_lang_item(LangItem
::Fn
, None
)
694 || did
== tcx
.require_lang_item(LangItem
::FnMut
, None
)
695 || did
== tcx
.require_lang_item(LangItem
::FnOnce
, None
)
699 fn region_name(region
: Region
<'_
>) -> Option
<Symbol
> {
701 ty
::ReEarlyBound(r
) => Some(r
.name
),
706 /// Replaces all [`ty::RegionVid`]s in a type with [`ty::Region`]s, using the provided map.
707 struct RegionReplacer
<'a
, 'tcx
> {
708 vid_to_region
: &'a FxHashMap
<ty
::RegionVid
, ty
::Region
<'tcx
>>,
712 impl<'a
, 'tcx
> TypeFolder
<'tcx
> for RegionReplacer
<'a
, 'tcx
> {
713 fn tcx
<'b
>(&'b
self) -> TyCtxt
<'tcx
> {
717 fn fold_region(&mut self, r
: ty
::Region
<'tcx
>) -> ty
::Region
<'tcx
> {
719 ty
::ReVar(vid
) => self.vid_to_region
.get(&vid
).cloned(),
722 .unwrap_or_else(|| r
.super_fold_with(self))