diff options
| author | Matthias Krüger <matthias.krueger@famsik.de> | 2023-03-22 22:44:39 +0100 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2023-03-22 22:44:39 +0100 |
| commit | 0392e2996e828fe5f435b3f13037f8af7ad4563b (patch) | |
| tree | 75ef6b25f6b03ec6c6668ffa4dbfe7851affd04f | |
| parent | a266f11990d9544ee408e213e1eec8cc9eb032b7 (diff) | |
| parent | 7f76084933b69ae856bc872c3eecdc2378a21f4b (diff) | |
| download | rust-0392e2996e828fe5f435b3f13037f8af7ad4563b.tar.gz rust-0392e2996e828fe5f435b3f13037f8af7ad4563b.zip | |
Rollup merge of #108954 - notriddle:notriddle/notable-trait-generic, r=camelid
rustdoc: handle generics better when matching notable traits This commit makes the `clean::Type::is_same` non-commutative (renaming it `is_doc_subtype_of`), so that a generic `impl` matches a concrete return, but a generic return does not match a concrete `impl`. It makes slice and vector Write for `u8` not match on every generic return value. Fixes #100322 Fixes #55082 Preview: * https://notriddle.com/rustdoc-demo-html-3/notable-trait-generic/std/vec/struct.Vec.html#method.new * https://notriddle.com/rustdoc-demo-html-3/notable-trait-generic/std/vec/struct.Vec.html#method.from-12 * https://notriddle.com/rustdoc-demo-html-3/notable-trait-generic/std/iter/trait.Iterator.html#method.intersperse_with * https://notriddle.com/rustdoc-demo-html-3/notable-trait-generic/std/string/struct.String.html#method.as_bytes
| -rw-r--r-- | src/librustdoc/clean/types.rs | 61 | ||||
| -rw-r--r-- | src/librustdoc/clean/types/tests.rs | 11 | ||||
| -rw-r--r-- | src/librustdoc/html/render/mod.rs | 4 | ||||
| -rw-r--r-- | tests/rustdoc/notable-trait/doc-notable_trait-mut_t_is_not_an_iterator.rs (renamed from tests/rustdoc/doc-notable_trait-mut_t_is_not_an_iterator.rs) | 0 | ||||
| -rw-r--r-- | tests/rustdoc/notable-trait/doc-notable_trait-mut_t_is_not_ref_t.rs (renamed from tests/rustdoc/doc-notable_trait-mut_t_is_not_ref_t.rs) | 0 | ||||
| -rw-r--r-- | tests/rustdoc/notable-trait/doc-notable_trait-slice.bare_fn_matches.html (renamed from tests/rustdoc/doc-notable_trait-slice.bare_fn_matches.html) | 0 | ||||
| -rw-r--r-- | tests/rustdoc/notable-trait/doc-notable_trait-slice.rs (renamed from tests/rustdoc/doc-notable_trait-slice.rs) | 6 | ||||
| -rw-r--r-- | tests/rustdoc/notable-trait/doc-notable_trait.bare-fn.html (renamed from tests/rustdoc/doc-notable_trait.bare-fn.html) | 0 | ||||
| -rw-r--r-- | tests/rustdoc/notable-trait/doc-notable_trait.rs (renamed from tests/rustdoc/doc-notable_trait.rs) | 0 | ||||
| -rw-r--r-- | tests/rustdoc/notable-trait/doc-notable_trait.some-struct-new.html (renamed from tests/rustdoc/doc-notable_trait.some-struct-new.html) | 0 | ||||
| -rw-r--r-- | tests/rustdoc/notable-trait/doc-notable_trait.wrap-me.html (renamed from tests/rustdoc/doc-notable_trait.wrap-me.html) | 0 | ||||
| -rw-r--r-- | tests/rustdoc/notable-trait/doc-notable_trait_box_is_not_an_iterator.rs (renamed from tests/rustdoc/doc-notable_trait_box_is_not_an_iterator.rs) | 0 | ||||
| -rw-r--r-- | tests/rustdoc/notable-trait/notable-trait-generics.rs | 35 | ||||
| -rw-r--r-- | tests/rustdoc/notable-trait/spotlight-from-dependency.odd.html (renamed from tests/rustdoc/spotlight-from-dependency.odd.html) | 0 | ||||
| -rw-r--r-- | tests/rustdoc/notable-trait/spotlight-from-dependency.rs (renamed from tests/rustdoc/spotlight-from-dependency.rs) | 0 |
15 files changed, 105 insertions, 12 deletions
diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index 6d8380c5fcc..7dbb3f76a0a 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -1471,27 +1471,68 @@ impl Type { result } - /// Check if two types are "potentially the same". + pub(crate) fn is_borrowed_ref(&self) -> bool { + matches!(self, Type::BorrowedRef { .. }) + } + + /// Check if two types are "the same" for documentation purposes. + /// /// This is different from `Eq`, because it knows that things like /// `Placeholder` are possible matches for everything. - pub(crate) fn is_same(&self, other: &Self, cache: &Cache) -> bool { - match (self, other) { + /// + /// This relation is not commutative when generics are involved: + /// + /// ```ignore(private) + /// # // see types/tests.rs:is_same_generic for the real test + /// use rustdoc::format::cache::Cache; + /// use rustdoc::clean::types::{Type, PrimitiveType}; + /// let cache = Cache::new(false); + /// let generic = Type::Generic(rustc_span::symbol::sym::Any); + /// let unit = Type::Primitive(PrimitiveType::Unit); + /// assert!(!generic.is_same(&unit, &cache)); + /// assert!(unit.is_same(&generic, &cache)); + /// ``` + /// + /// An owned type is also the same as its borrowed variants (this is commutative), + /// but `&T` is not the same as `&mut T`. + pub(crate) fn is_doc_subtype_of(&self, other: &Self, cache: &Cache) -> bool { + // Strip the references so that it can compare the actual types, unless both are references. + // If both are references, leave them alone and compare the mutabilities later. + let (self_cleared, other_cleared) = if !self.is_borrowed_ref() || !other.is_borrowed_ref() { + (self.without_borrowed_ref(), other.without_borrowed_ref()) + } else { + (self, other) + }; + match (self_cleared, other_cleared) { // Recursive cases. (Type::Tuple(a), Type::Tuple(b)) => { - a.len() == b.len() && a.iter().zip(b).all(|(a, b)| a.is_same(b, cache)) + a.len() == b.len() && a.iter().zip(b).all(|(a, b)| a.is_doc_subtype_of(b, cache)) } - (Type::Slice(a), Type::Slice(b)) => a.is_same(b, cache), - (Type::Array(a, al), Type::Array(b, bl)) => al == bl && a.is_same(b, cache), + (Type::Slice(a), Type::Slice(b)) => a.is_doc_subtype_of(b, cache), + (Type::Array(a, al), Type::Array(b, bl)) => al == bl && a.is_doc_subtype_of(b, cache), (Type::RawPointer(mutability, type_), Type::RawPointer(b_mutability, b_type_)) => { - mutability == b_mutability && type_.is_same(b_type_, cache) + mutability == b_mutability && type_.is_doc_subtype_of(b_type_, cache) } ( Type::BorrowedRef { mutability, type_, .. }, Type::BorrowedRef { mutability: b_mutability, type_: b_type_, .. }, - ) => mutability == b_mutability && type_.is_same(b_type_, cache), - // Placeholders and generics are equal to all other types. + ) => mutability == b_mutability && type_.is_doc_subtype_of(b_type_, cache), + // Placeholders are equal to all other types. (Type::Infer, _) | (_, Type::Infer) => true, - (Type::Generic(_), _) | (_, Type::Generic(_)) => true, + // Generics match everything on the right, but not on the left. + // If both sides are generic, this returns true. + (_, Type::Generic(_)) => true, + (Type::Generic(_), _) => false, + // Paths account for both the path itself and its generics. + (Type::Path { path: a }, Type::Path { path: b }) => { + a.def_id() == b.def_id() + && a.generics() + .zip(b.generics()) + .map(|(ag, bg)| { + ag.iter().zip(bg.iter()).all(|(at, bt)| at.is_doc_subtype_of(bt, cache)) + }) + .unwrap_or(true) + } // Other cases, such as primitives, just use recursion. (a, b) => a .def_id(cache) diff --git a/src/librustdoc/clean/types/tests.rs b/src/librustdoc/clean/types/tests.rs index 8f2331785f5..d8c91a96804 100644 --- a/src/librustdoc/clean/types/tests.rs +++ b/src/librustdoc/clean/types/tests.rs @@ -69,3 +69,14 @@ fn should_not_trim() { run_test("\t line1 \n\t line2", "line1 \nline2"); run_test(" \tline1 \n \tline2", "line1 \nline2"); } + +#[test] +fn is_same_generic() { + use crate::clean::types::{PrimitiveType, Type}; + use crate::formats::cache::Cache; + let cache = Cache::new(false); + let generic = Type::Generic(rustc_span::symbol::sym::Any); + let unit = Type::Primitive(PrimitiveType::Unit); + assert!(!generic.is_doc_subtype_of(&unit, &cache)); + assert!(unit.is_doc_subtype_of(&generic, &cache)); +} diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs index da1f1cf5ecc..d75d03071f8 100644 --- a/src/librustdoc/html/render/mod.rs +++ b/src/librustdoc/html/render/mod.rs @@ -1294,7 +1294,7 @@ pub(crate) fn notable_traits_button(ty: &clean::Type, cx: &mut Context<'_>) -> O if let Some(impls) = cx.cache().impls.get(&did) { for i in impls { let impl_ = i.inner_impl(); - if !impl_.for_.without_borrowed_ref().is_same(ty.without_borrowed_ref(), cx.cache()) { + if !ty.is_doc_subtype_of(&impl_.for_, cx.cache()) { // Two different types might have the same did, // without actually being the same. continue; @@ -1330,7 +1330,7 @@ fn notable_traits_decl(ty: &clean::Type, cx: &Context<'_>) -> (String, String) { for i in impls { let impl_ = i.inner_impl(); - if !impl_.for_.without_borrowed_ref().is_same(ty.without_borrowed_ref(), cx.cache()) { + if !ty.is_doc_subtype_of(&impl_.for_, cx.cache()) { // Two different types might have the same did, // without actually being the same. continue; diff --git a/tests/rustdoc/doc-notable_trait-mut_t_is_not_an_iterator.rs b/tests/rustdoc/notable-trait/doc-notable_trait-mut_t_is_not_an_iterator.rs index bfce46cf444..bfce46cf444 100644 --- a/tests/rustdoc/doc-notable_trait-mut_t_is_not_an_iterator.rs +++ b/tests/rustdoc/notable-trait/doc-notable_trait-mut_t_is_not_an_iterator.rs diff --git a/tests/rustdoc/doc-notable_trait-mut_t_is_not_ref_t.rs b/tests/rustdoc/notable-trait/doc-notable_trait-mut_t_is_not_ref_t.rs index b359dcea0ff..b359dcea0ff 100644 --- a/tests/rustdoc/doc-notable_trait-mut_t_is_not_ref_t.rs +++ b/tests/rustdoc/notable-trait/doc-notable_trait-mut_t_is_not_ref_t.rs diff --git a/tests/rustdoc/doc-notable_trait-slice.bare_fn_matches.html b/tests/rustdoc/notable-trait/doc-notable_trait-slice.bare_fn_matches.html index 46be00a0804..46be00a0804 100644 --- a/tests/rustdoc/doc-notable_trait-slice.bare_fn_matches.html +++ b/tests/rustdoc/notable-trait/doc-notable_trait-slice.bare_fn_matches.html diff --git a/tests/rustdoc/doc-notable_trait-slice.rs b/tests/rustdoc/notable-trait/doc-notable_trait-slice.rs index 2411da8cd45..ef206710b4b 100644 --- a/tests/rustdoc/doc-notable_trait-slice.rs +++ b/tests/rustdoc/notable-trait/doc-notable_trait-slice.rs @@ -18,3 +18,9 @@ pub fn bare_fn_matches() -> &'static [SomeStruct] { pub fn bare_fn_no_matches() -> &'static [OtherStruct] { &[] } + +// @has doc_notable_trait_slice/fn.bare_fn_mut_no_matches.html +// @count - '//script[@id="notable-traits-data"]' 0 +pub fn bare_fn_mut_no_matches() -> &'static mut [SomeStruct] { + &mut [] +} diff --git a/tests/rustdoc/doc-notable_trait.bare-fn.html b/tests/rustdoc/notable-trait/doc-notable_trait.bare-fn.html index f592e3b375c..f592e3b375c 100644 --- a/tests/rustdoc/doc-notable_trait.bare-fn.html +++ b/tests/rustdoc/notable-trait/doc-notable_trait.bare-fn.html diff --git a/tests/rustdoc/doc-notable_trait.rs b/tests/rustdoc/notable-trait/doc-notable_trait.rs index d8941769fa6..d8941769fa6 100644 --- a/tests/rustdoc/doc-notable_trait.rs +++ b/tests/rustdoc/notable-trait/doc-notable_trait.rs diff --git a/tests/rustdoc/doc-notable_trait.some-struct-new.html b/tests/rustdoc/notable-trait/doc-notable_trait.some-struct-new.html index e8f4f600045..e8f4f600045 100644 --- a/tests/rustdoc/doc-notable_trait.some-struct-new.html +++ b/tests/rustdoc/notable-trait/doc-notable_trait.some-struct-new.html diff --git a/tests/rustdoc/doc-notable_trait.wrap-me.html b/tests/rustdoc/notable-trait/doc-notable_trait.wrap-me.html index e7909669b15..e7909669b15 100644 --- a/tests/rustdoc/doc-notable_trait.wrap-me.html +++ b/tests/rustdoc/notable-trait/doc-notable_trait.wrap-me.html diff --git a/tests/rustdoc/doc-notable_trait_box_is_not_an_iterator.rs b/tests/rustdoc/notable-trait/doc-notable_trait_box_is_not_an_iterator.rs index 3fb00c7db84..3fb00c7db84 100644 --- a/tests/rustdoc/doc-notable_trait_box_is_not_an_iterator.rs +++ b/tests/rustdoc/notable-trait/doc-notable_trait_box_is_not_an_iterator.rs diff --git a/tests/rustdoc/notable-trait/notable-trait-generics.rs b/tests/rustdoc/notable-trait/notable-trait-generics.rs new file mode 100644 index 00000000000..611902abad6 --- /dev/null +++ b/tests/rustdoc/notable-trait/notable-trait-generics.rs @@ -0,0 +1,35 @@ +#![feature(doc_notable_trait)] + +// Notable traits SHOULD NOT be shown when the `impl` has a concrete type and +// the return type has a generic type. +pub mod generic_return { + pub struct Wrapper<T>(T); + + #[doc(notable_trait)] + pub trait NotableTrait {} + + impl NotableTrait for Wrapper<u8> {} + + // @has notable_trait_generics/generic_return/fn.returning.html + // @!has - '//a[@class="tooltip"]/@data-notable-ty' 'Wrapper<T>' + pub fn returning<T>() -> Wrapper<T> { + loop {} + } +} + +// Notable traits SHOULD be shown when the `impl` has a generic type and the +// return type has a concrete type. +pub mod generic_impl { + pub struct Wrapper<T>(T); + + #[doc(notable_trait)] + pub trait NotableTrait {} + + impl<T> NotableTrait for Wrapper<T> {} + + // @has notable_trait_generics/generic_impl/fn.returning.html + // @has - '//a[@class="tooltip"]/@data-notable-ty' 'Wrapper<u8>' + pub fn returning() -> Wrapper<u8> { + loop {} + } +} diff --git a/tests/rustdoc/spotlight-from-dependency.odd.html b/tests/rustdoc/notable-trait/spotlight-from-dependency.odd.html index 5f54b7522ae..5f54b7522ae 100644 --- a/tests/rustdoc/spotlight-from-dependency.odd.html +++ b/tests/rustdoc/notable-trait/spotlight-from-dependency.odd.html diff --git a/tests/rustdoc/spotlight-from-dependency.rs b/tests/rustdoc/notable-trait/spotlight-from-dependency.rs index 426759c7bf8..426759c7bf8 100644 --- a/tests/rustdoc/spotlight-from-dependency.rs +++ b/tests/rustdoc/notable-trait/spotlight-from-dependency.rs |
