From dc1c39b10ed4650de784e860e2778c3e246f585e Mon Sep 17 00:00:00 2001 From: Andy Russell Date: Thu, 9 Dec 2021 00:21:36 -0500 Subject: [PATCH] rustdoc: decouple stability and const-stability --- src/librustdoc/html/render/mod.rs | 91 ++++++++++++++++++------------ src/test/rustdoc/const-display.rs | 17 ++++++ src/test/rustdoc/deref-const-fn.rs | 2 +- 3 files changed, 73 insertions(+), 37 deletions(-) diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs index dda7490493197..3dfe03b54e9f2 100644 --- a/src/librustdoc/html/render/mod.rs +++ b/src/librustdoc/html/render/mod.rs @@ -792,6 +792,20 @@ fn assoc_type( } } +/// Writes a span containing the versions at which an item became stable and/or const-stable. For +/// example, if the item became stable at 1.0.0, and const-stable at 1.45.0, this function would +/// write a span containing "1.0.0 (const: 1.45.0)". +/// +/// Returns `true` if a stability annotation was rendered. +/// +/// Stability and const-stability are considered separately. If the item is unstable, no version +/// will be written. If the item is const-unstable, "const: unstable" will be appended to the +/// span, with a link to the tracking issue if present. If an item's stability or const-stability +/// version matches the version of its enclosing item, that version will be omitted. +/// +/// Note that it is possible for an unstable function to be const-stable. In that case, the span +/// will include the const-stable version, but no stable version will be emitted, as a natural +/// consequence of the above rules. fn render_stability_since_raw( w: &mut Buffer, ver: Option, @@ -799,51 +813,56 @@ fn render_stability_since_raw( containing_ver: Option, containing_const_ver: Option, ) -> bool { - let ver = ver.filter(|inner| !inner.is_empty()); + let stable_version = ver.filter(|inner| !inner.is_empty() && Some(*inner) != containing_ver); - match (ver, const_stability) { - // stable and const stable - (Some(v), Some(ConstStability { level: StabilityLevel::Stable { since }, .. })) + let mut title = String::new(); + let mut stability = String::new(); + + if let Some(ver) = stable_version { + stability.push_str(&ver.as_str()); + title.push_str(&format!("Stable since Rust version {}", ver)); + } + + let const_title_and_stability = match const_stability { + Some(ConstStability { level: StabilityLevel::Stable { since }, .. }) if Some(since) != containing_const_ver => { - write!( - w, - "{0} (const: {1})", - v, since - ); + Some((format!("const since {}", since), format!("const: {}", since))) } - // stable and const unstable - ( - Some(v), - Some(ConstStability { level: StabilityLevel::Unstable { issue, .. }, feature, .. }), - ) => { - write!( - w, - "{0} (const: ", - v - ); - if let Some(n) = issue { - write!( - w, - "unstable", + Some(ConstStability { level: StabilityLevel::Unstable { issue, .. }, feature, .. }) => { + let unstable = if let Some(n) = issue { + format!( + r#"unstable"#, n, feature - ); + ) } else { - write!(w, "unstable"); - } - write!(w, ")"); + String::from("unstable") + }; + + Some((String::from("const unstable"), format!("const: {}", unstable))) } - // stable - (Some(v), _) if ver != containing_ver => { - write!( - w, - "{0}", - v - ); + _ => None, + }; + + if let Some((const_title, const_stability)) = const_title_and_stability { + if !title.is_empty() { + title.push_str(&format!(", {}", const_title)); + } else { + title.push_str(&const_title); + } + + if !stability.is_empty() { + stability.push_str(&format!(" ({})", const_stability)); + } else { + stability.push_str(&const_stability); } - _ => return false, } - true + + if !stability.is_empty() { + write!(w, r#"{}"#, title, stability); + } + + !stability.is_empty() } fn render_assoc_item( diff --git a/src/test/rustdoc/const-display.rs b/src/test/rustdoc/const-display.rs index fb8ea7e33c28c..b8e101038f8f1 100644 --- a/src/test/rustdoc/const-display.rs +++ b/src/test/rustdoc/const-display.rs @@ -67,3 +67,20 @@ impl Foo { #[rustc_const_stable(feature = "rust1", since = "1.2.0")] pub const fn stable_impl() -> u32 { 42 } } + +#[stable(feature = "rust1", since = "1.0.0")] +pub struct Bar; + +impl Bar { + // Do not show non-const stabilities that are the same as the enclosing item. + // @matches 'foo/struct.Bar.html' '//span[@class="since"]' '^const: 1.2.0$' + #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_stable(feature = "rust1", since = "1.2.0")] + pub const fn stable_impl() -> u32 { 42 } + + // Show const-stability even for unstable functions. + // @matches 'foo/struct.Bar.html' '//span[@class="since"]' '^const: 1.3.0$' + #[unstable(feature = "foo2", issue = "none")] + #[rustc_const_stable(feature = "rust1", since = "1.3.0")] + pub const fn const_stable_unstable() -> u32 { 42 } +} diff --git a/src/test/rustdoc/deref-const-fn.rs b/src/test/rustdoc/deref-const-fn.rs index ca51f3c7b5af0..8ecca6d12d24a 100644 --- a/src/test/rustdoc/deref-const-fn.rs +++ b/src/test/rustdoc/deref-const-fn.rs @@ -13,7 +13,7 @@ pub struct Bar; impl Bar { // @has - '//*[@id="method.len"]' 'pub const fn len(&self) -> usize' - // @has - '//*[@id="method.len"]//span[@class="since"]' '1.0.0 (const: 1.0.0)' + // @has - '//*[@id="method.len"]//span[@class="since"]' 'const: 1.0.0' #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_stable(feature = "rust1", since = "1.0.0")] pub const fn len(&self) -> usize { 0 }