Skip to content

Commit eb725bb

Browse files
committed
Auto merge of #49196 - Phlosioneer:49123-sort-where-conditions, r=QuietMisdreavus
Fix ordering of auto-generated trait bounds in rustdoc output While the order of the where clauses was deterministic, the ordering of bounds and lifetimes was not. This made the order flip- flop randomly when new traits and impls were added to libstd. This PR makes the ordering of bounds and lifetimes deterministic, and re-enables the test that was causing the issue. Fixes #49123
2 parents 75af15e + 7daf3f9 commit eb725bb

File tree

2 files changed

+67
-37
lines changed

2 files changed

+67
-37
lines changed

src/librustdoc/clean/auto_trait.rs

+67-35
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
// except according to those terms.
1010

1111
use rustc::ty::TypeFoldable;
12+
use std::fmt::Debug;
1213

1314
use super::*;
1415

@@ -1081,18 +1082,25 @@ impl<'a, 'tcx, 'rcx> AutoTraitFinder<'a, 'tcx, 'rcx> {
10811082
return None;
10821083
}
10831084

1085+
let mut bounds_vec = bounds.into_iter().collect();
1086+
self.sort_where_bounds(&mut bounds_vec);
1087+
10841088
Some(WherePredicate::BoundPredicate {
10851089
ty,
1086-
bounds: bounds.into_iter().collect(),
1090+
bounds: bounds_vec,
10871091
})
10881092
})
10891093
.chain(
10901094
lifetime_to_bounds
10911095
.into_iter()
10921096
.filter(|&(_, ref bounds)| !bounds.is_empty())
1093-
.map(|(lifetime, bounds)| WherePredicate::RegionPredicate {
1094-
lifetime,
1095-
bounds: bounds.into_iter().collect(),
1097+
.map(|(lifetime, bounds)| {
1098+
let mut bounds_vec = bounds.into_iter().collect();
1099+
self.sort_where_lifetimes(&mut bounds_vec);
1100+
WherePredicate::RegionPredicate {
1101+
lifetime,
1102+
bounds: bounds_vec,
1103+
}
10961104
}),
10971105
)
10981106
.collect()
@@ -1372,40 +1380,64 @@ impl<'a, 'tcx, 'rcx> AutoTraitFinder<'a, 'tcx, 'rcx> {
13721380
// a given set of predicates always appears in the same order -
13731381
// both for visual consistency between 'rustdoc' runs, and to
13741382
// make writing tests much easier
1375-
fn sort_where_predicates(&self, predicates: &mut Vec<WherePredicate>) {
1383+
#[inline]
1384+
fn sort_where_predicates(&self, mut predicates: &mut Vec<WherePredicate>) {
13761385
// We should never have identical bounds - and if we do,
13771386
// they're visually identical as well. Therefore, using
13781387
// an unstable sort is fine.
1379-
predicates.sort_unstable_by(|first, second| {
1380-
// This might look horrendously hacky, but it's actually not that bad.
1381-
//
1382-
// For performance reasons, we use several different FxHashMaps
1383-
// in the process of computing the final set of where predicates.
1384-
// However, the iteration order of a HashMap is completely unspecified.
1385-
// In fact, the iteration of an FxHashMap can even vary between platforms,
1386-
// since FxHasher has different behavior for 32-bit and 64-bit platforms.
1387-
//
1388-
// Obviously, it's extremely undesireable for documentation rendering
1389-
// to be depndent on the platform it's run on. Apart from being confusing
1390-
// to end users, it makes writing tests much more difficult, as predicates
1391-
// can appear in any order in the final result.
1392-
//
1393-
// To solve this problem, we sort WherePredicates by their Debug
1394-
// string. The thing to keep in mind is that we don't really
1395-
// care what the final order is - we're synthesizing an impl
1396-
// ourselves, so any order can be considered equally valid.
1397-
// By sorting the predicates, however, we ensure that for
1398-
// a given codebase, all auto-trait impls always render
1399-
// in exactly the same way.
1400-
//
1401-
// Using the Debug impementation for sorting prevents
1402-
// us from needing to write quite a bit of almost
1403-
// entirely useless code (e.g. how should two
1404-
// Types be sorted relative to each other).
1405-
// This approach is probably somewhat slower, but
1406-
// the small number of items involved (impls
1407-
// rarely have more than a few bounds) means
1408-
// that it shouldn't matter in practice.
1388+
self.unstable_debug_sort(&mut predicates);
1389+
}
1390+
1391+
// Ensure that the bounds are in a consistent order. The precise
1392+
// ordering doesn't actually matter, but it's important that
1393+
// a given set of bounds always appears in the same order -
1394+
// both for visual consistency between 'rustdoc' runs, and to
1395+
// make writing tests much easier
1396+
#[inline]
1397+
fn sort_where_bounds(&self, mut bounds: &mut Vec<TyParamBound>) {
1398+
// We should never have identical bounds - and if we do,
1399+
// they're visually identical as well. Therefore, using
1400+
// an unstable sort is fine.
1401+
self.unstable_debug_sort(&mut bounds);
1402+
}
1403+
1404+
#[inline]
1405+
fn sort_where_lifetimes(&self, mut bounds: &mut Vec<Lifetime>) {
1406+
// We should never have identical bounds - and if we do,
1407+
// they're visually identical as well. Therefore, using
1408+
// an unstable sort is fine.
1409+
self.unstable_debug_sort(&mut bounds);
1410+
}
1411+
1412+
// This might look horrendously hacky, but it's actually not that bad.
1413+
//
1414+
// For performance reasons, we use several different FxHashMaps
1415+
// in the process of computing the final set of where predicates.
1416+
// However, the iteration order of a HashMap is completely unspecified.
1417+
// In fact, the iteration of an FxHashMap can even vary between platforms,
1418+
// since FxHasher has different behavior for 32-bit and 64-bit platforms.
1419+
//
1420+
// Obviously, it's extremely undesireable for documentation rendering
1421+
// to be depndent on the platform it's run on. Apart from being confusing
1422+
// to end users, it makes writing tests much more difficult, as predicates
1423+
// can appear in any order in the final result.
1424+
//
1425+
// To solve this problem, we sort WherePredicates and TyParamBounds
1426+
// by their Debug string. The thing to keep in mind is that we don't really
1427+
// care what the final order is - we're synthesizing an impl or bound
1428+
// ourselves, so any order can be considered equally valid. By sorting the
1429+
// predicates and bounds, however, we ensure that for a given codebase, all
1430+
// auto-trait impls always render in exactly the same way.
1431+
//
1432+
// Using the Debug impementation for sorting prevents us from needing to
1433+
// write quite a bit of almost entirely useless code (e.g. how should two
1434+
// Types be sorted relative to each other). It also allows us to solve the
1435+
// problem for both WherePredicates and TyParamBounds at the same time. This
1436+
// approach is probably somewhat slower, but the small number of items
1437+
// involved (impls rarely have more than a few bounds) means that it
1438+
// shouldn't matter in practice.
1439+
fn unstable_debug_sort<T: Debug>(&self, vec: &mut Vec<T>) {
1440+
vec.sort_unstable_by(|first, second| {
14091441
format!("{:?}", first).cmp(&format!("{:?}", second))
14101442
});
14111443
}

src/test/rustdoc/synthetic_auto/no-redundancy.rs

-2
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,6 @@
88
// option. This file may not be copied, modified, or distributed
99
// except according to those terms.
1010

11-
// ignore-test
12-
1311
pub struct Inner<T> {
1412
field: T,
1513
}

0 commit comments

Comments
 (0)