@@ -1471,27 +1471,68 @@ impl Type {
1471
1471
result
1472
1472
}
1473
1473
1474
- /// Check if two types are "potentially the same".
1474
+ pub(crate) fn is_borrowed_ref(&self) -> bool {
1475
+ matches!(self, Type::BorrowedRef { .. })
1476
+ }
1477
+
1478
+ /// Check if two types are "the same" for documentation purposes.
1479
+ ///
1475
1480
/// This is different from `Eq`, because it knows that things like
1476
1481
/// `Placeholder` are possible matches for everything.
1477
- pub(crate) fn is_same(&self, other: &Self, cache: &Cache) -> bool {
1478
- match (self, other) {
1482
+ ///
1483
+ /// This relation is not commutative when generics are involved:
1484
+ ///
1485
+ /// ```ignore(private)
1486
+ /// # // see types/tests.rs:is_same_generic for the real test
1487
+ /// use rustdoc::format::cache::Cache;
1488
+ /// use rustdoc::clean::types::{Type, PrimitiveType};
1489
+ /// let cache = Cache::new(false);
1490
+ /// let generic = Type::Generic(rustc_span::symbol::sym::Any);
1491
+ /// let unit = Type::Primitive(PrimitiveType::Unit);
1492
+ /// assert!(!generic.is_same(&unit, &cache));
1493
+ /// assert!(unit.is_same(&generic, &cache));
1494
+ /// ```
1495
+ ///
1496
+ /// An owned type is also the same as its borrowed variants (this is commutative),
1497
+ /// but `&T` is not the same as `&mut T`.
1498
+ pub(crate) fn is_doc_subtype_of(&self, other: &Self, cache: &Cache) -> bool {
1499
+ // Strip the references so that it can compare the actual types, unless both are references.
1500
+ // If both are references, leave them alone and compare the mutabilities later.
1501
+ let (self_cleared, other_cleared) = if !self.is_borrowed_ref() || !other.is_borrowed_ref() {
1502
+ (self.without_borrowed_ref(), other.without_borrowed_ref())
1503
+ } else {
1504
+ (self, other)
1505
+ };
1506
+ match (self_cleared, other_cleared) {
1479
1507
// Recursive cases.
1480
1508
(Type::Tuple(a), Type::Tuple(b)) => {
1481
- a.len() == b.len() && a.iter().zip(b).all(|(a, b)| a.is_same (b, cache))
1509
+ a.len() == b.len() && a.iter().zip(b).all(|(a, b)| a.is_doc_subtype_of (b, cache))
1482
1510
}
1483
- (Type::Slice(a), Type::Slice(b)) => a.is_same (b, cache),
1484
- (Type::Array(a, al), Type::Array(b, bl)) => al == bl && a.is_same (b, cache),
1511
+ (Type::Slice(a), Type::Slice(b)) => a.is_doc_subtype_of (b, cache),
1512
+ (Type::Array(a, al), Type::Array(b, bl)) => al == bl && a.is_doc_subtype_of (b, cache),
1485
1513
(Type::RawPointer(mutability, type_), Type::RawPointer(b_mutability, b_type_)) => {
1486
- mutability == b_mutability && type_.is_same (b_type_, cache)
1514
+ mutability == b_mutability && type_.is_doc_subtype_of (b_type_, cache)
1487
1515
}
1488
1516
(
1489
1517
Type::BorrowedRef { mutability, type_, .. },
1490
1518
Type::BorrowedRef { mutability: b_mutability, type_: b_type_, .. },
1491
- ) => mutability == b_mutability && type_.is_same (b_type_, cache),
1492
- // Placeholders and generics are equal to all other types.
1519
+ ) => mutability == b_mutability && type_.is_doc_subtype_of (b_type_, cache),
1520
+ // Placeholders are equal to all other types.
1493
1521
(Type::Infer, _) | (_, Type::Infer) => true,
1494
- (Type::Generic(_), _) | (_, Type::Generic(_)) => true,
1522
+ // Generics match everything on the right, but not on the left.
1523
+ // If both sides are generic, this returns true.
1524
+ (_, Type::Generic(_)) => true,
1525
+ (Type::Generic(_), _) => false,
1526
+ // Paths account for both the path itself and its generics.
1527
+ (Type::Path { path: a }, Type::Path { path: b }) => {
1528
+ a.def_id() == b.def_id()
1529
+ && a.generics()
1530
+ .zip(b.generics())
1531
+ .map(|(ag, bg)| {
1532
+ ag.iter().zip(bg.iter()).all(|(at, bt)| at.is_doc_subtype_of(bt, cache))
1533
+ })
1534
+ .unwrap_or(true)
1535
+ }
1495
1536
// Other cases, such as primitives, just use recursion.
1496
1537
(a, b) => a
1497
1538
.def_id(cache)
0 commit comments