Remove support for specializing ToString outside the standard library

This is the only trait specializable outside of the standard library.
Before stabilizing specialization we will probably want to remove
support for this. It was originally made specializable to allow a more
efficient ToString in libproc_macro back when this way the only way to
get any data out of a TokenStream. We now support getting individual
tokens, so proc macros no longer need to call it as often.
This commit is contained in:
bjorn3 2023-12-31 18:35:49 +00:00
parent 8e37e15183
commit b805f30542
5 changed files with 43 additions and 117 deletions

View file

@ -25,7 +25,6 @@
#![feature(hash_set_entry)] #![feature(hash_set_entry)]
#![feature(if_let_guard)] #![feature(if_let_guard)]
#![feature(let_chains)] #![feature(let_chains)]
#![feature(min_specialization)]
#![feature(negative_impls)] #![feature(negative_impls)]
#![feature(read_buf)] #![feature(read_buf)]
#![feature(round_char_boundary)] #![feature(round_char_boundary)]

View file

@ -2471,13 +2471,6 @@ impl fmt::Display for Symbol {
} }
} }
// takes advantage of `str::to_string` specialization
impl ToString for Symbol {
fn to_string(&self) -> String {
self.as_str().to_string()
}
}
impl<CTX> HashStable<CTX> for Symbol { impl<CTX> HashStable<CTX> for Symbol {
#[inline] #[inline]
fn hash_stable(&self, hcx: &mut CTX, hasher: &mut StableHasher) { fn hash_stable(&self, hcx: &mut CTX, hasher: &mut StableHasher) {

View file

@ -2675,12 +2675,25 @@ pub trait ToString {
#[cfg(not(no_global_oom_handling))] #[cfg(not(no_global_oom_handling))]
#[stable(feature = "rust1", since = "1.0.0")] #[stable(feature = "rust1", since = "1.0.0")]
impl<T: fmt::Display + ?Sized> ToString for T { impl<T: fmt::Display + ?Sized> ToString for T {
#[inline]
fn to_string(&self) -> String {
<Self as SpecToString>::spec_to_string(self)
}
}
#[cfg(not(no_global_oom_handling))]
trait SpecToString {
fn spec_to_string(&self) -> String;
}
#[cfg(not(no_global_oom_handling))]
impl<T: fmt::Display + ?Sized> SpecToString for T {
// A common guideline is to not inline generic functions. However, // A common guideline is to not inline generic functions. However,
// removing `#[inline]` from this method causes non-negligible regressions. // removing `#[inline]` from this method causes non-negligible regressions.
// See <https://github.com/rust-lang/rust/pull/74852>, the last attempt // See <https://github.com/rust-lang/rust/pull/74852>, the last attempt
// to try to remove it. // to try to remove it.
#[inline] #[inline]
default fn to_string(&self) -> String { default fn spec_to_string(&self) -> String {
let mut buf = String::new(); let mut buf = String::new();
let mut formatter = let mut formatter =
core::fmt::Formatter::new(&mut buf, core::fmt::FormattingOptions::new()); core::fmt::Formatter::new(&mut buf, core::fmt::FormattingOptions::new());
@ -2691,42 +2704,34 @@ impl<T: fmt::Display + ?Sized> ToString for T {
} }
} }
#[doc(hidden)]
#[cfg(not(no_global_oom_handling))] #[cfg(not(no_global_oom_handling))]
#[unstable(feature = "ascii_char", issue = "110998")] impl SpecToString for core::ascii::Char {
impl ToString for core::ascii::Char {
#[inline] #[inline]
fn to_string(&self) -> String { fn spec_to_string(&self) -> String {
self.as_str().to_owned() self.as_str().to_owned()
} }
} }
#[doc(hidden)]
#[cfg(not(no_global_oom_handling))] #[cfg(not(no_global_oom_handling))]
#[stable(feature = "char_to_string_specialization", since = "1.46.0")] impl SpecToString for char {
impl ToString for char {
#[inline] #[inline]
fn to_string(&self) -> String { fn spec_to_string(&self) -> String {
String::from(self.encode_utf8(&mut [0; 4])) String::from(self.encode_utf8(&mut [0; 4]))
} }
} }
#[doc(hidden)]
#[cfg(not(no_global_oom_handling))] #[cfg(not(no_global_oom_handling))]
#[stable(feature = "bool_to_string_specialization", since = "1.68.0")] impl SpecToString for bool {
impl ToString for bool {
#[inline] #[inline]
fn to_string(&self) -> String { fn spec_to_string(&self) -> String {
String::from(if *self { "true" } else { "false" }) String::from(if *self { "true" } else { "false" })
} }
} }
#[doc(hidden)]
#[cfg(not(no_global_oom_handling))] #[cfg(not(no_global_oom_handling))]
#[stable(feature = "u8_to_string_specialization", since = "1.54.0")] impl SpecToString for u8 {
impl ToString for u8 {
#[inline] #[inline]
fn to_string(&self) -> String { fn spec_to_string(&self) -> String {
let mut buf = String::with_capacity(3); let mut buf = String::with_capacity(3);
let mut n = *self; let mut n = *self;
if n >= 10 { if n >= 10 {
@ -2742,12 +2747,10 @@ impl ToString for u8 {
} }
} }
#[doc(hidden)]
#[cfg(not(no_global_oom_handling))] #[cfg(not(no_global_oom_handling))]
#[stable(feature = "i8_to_string_specialization", since = "1.54.0")] impl SpecToString for i8 {
impl ToString for i8 {
#[inline] #[inline]
fn to_string(&self) -> String { fn spec_to_string(&self) -> String {
let mut buf = String::with_capacity(4); let mut buf = String::with_capacity(4);
if self.is_negative() { if self.is_negative() {
buf.push('-'); buf.push('-');
@ -2788,11 +2791,9 @@ macro_rules! to_string_expr_wrap_in_deref {
macro_rules! to_string_str { macro_rules! to_string_str {
{$($($x:ident)*),+} => { {$($($x:ident)*),+} => {
$( $(
#[doc(hidden)] impl SpecToString for to_string_str_wrap_in_ref!($($x)*) {
#[stable(feature = "str_to_string_specialization", since = "1.9.0")]
impl ToString for to_string_str_wrap_in_ref!($($x)*) {
#[inline] #[inline]
fn to_string(&self) -> String { fn spec_to_string(&self) -> String {
String::from(to_string_expr_wrap_in_deref!(self ; $($x)*)) String::from(to_string_expr_wrap_in_deref!(self ; $($x)*))
} }
} }
@ -2816,32 +2817,26 @@ to_string_str! {
x, x,
} }
#[doc(hidden)]
#[cfg(not(no_global_oom_handling))] #[cfg(not(no_global_oom_handling))]
#[stable(feature = "cow_str_to_string_specialization", since = "1.17.0")] impl SpecToString for Cow<'_, str> {
impl ToString for Cow<'_, str> {
#[inline] #[inline]
fn to_string(&self) -> String { fn spec_to_string(&self) -> String {
self[..].to_owned() self[..].to_owned()
} }
} }
#[doc(hidden)]
#[cfg(not(no_global_oom_handling))] #[cfg(not(no_global_oom_handling))]
#[stable(feature = "string_to_string_specialization", since = "1.17.0")] impl SpecToString for String {
impl ToString for String {
#[inline] #[inline]
fn to_string(&self) -> String { fn spec_to_string(&self) -> String {
self.to_owned() self.to_owned()
} }
} }
#[doc(hidden)]
#[cfg(not(no_global_oom_handling))] #[cfg(not(no_global_oom_handling))]
#[stable(feature = "fmt_arguments_to_string_specialization", since = "1.71.0")] impl SpecToString for fmt::Arguments<'_> {
impl ToString for fmt::Arguments<'_> {
#[inline] #[inline]
fn to_string(&self) -> String { fn spec_to_string(&self) -> String {
crate::fmt::format(*self) crate::fmt::format(*self)
} }
} }

View file

@ -91,12 +91,6 @@ impl fmt::Debug for Symbol {
} }
} }
impl ToString for Symbol {
fn to_string(&self) -> String {
self.with(|s| s.to_owned())
}
}
impl fmt::Display for Symbol { impl fmt::Display for Symbol {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.with(|s| fmt::Display::fmt(s, f)) self.with(|s| fmt::Display::fmt(s, f))

View file

@ -19,9 +19,6 @@
)] )]
#![doc(rust_logo)] #![doc(rust_logo)]
#![feature(rustdoc_internals)] #![feature(rustdoc_internals)]
// This library is copied into rust-analyzer to allow loading rustc compiled proc macros.
// Please avoid unstable features where possible to minimize the amount of changes necessary
// to make it compile with rust-analyzer on stable.
#![feature(staged_api)] #![feature(staged_api)]
#![feature(allow_internal_unstable)] #![feature(allow_internal_unstable)]
#![feature(decl_macro)] #![feature(decl_macro)]
@ -30,7 +27,6 @@
#![feature(panic_can_unwind)] #![feature(panic_can_unwind)]
#![feature(restricted_std)] #![feature(restricted_std)]
#![feature(rustc_attrs)] #![feature(rustc_attrs)]
#![feature(min_specialization)]
#![feature(extend_one)] #![feature(extend_one)]
#![recursion_limit = "256"] #![recursion_limit = "256"]
#![allow(internal_features)] #![allow(internal_features)]
@ -185,16 +181,6 @@ impl FromStr for TokenStream {
} }
} }
// N.B., the bridge only provides `to_string`, implement `fmt::Display`
// based on it (the reverse of the usual relationship between the two).
#[doc(hidden)]
#[stable(feature = "proc_macro_lib", since = "1.15.0")]
impl ToString for TokenStream {
fn to_string(&self) -> String {
self.0.as_ref().map(|t| t.to_string()).unwrap_or_default()
}
}
/// Prints the token stream as a string that is supposed to be losslessly convertible back /// Prints the token stream as a string that is supposed to be losslessly convertible back
/// into the same token stream (modulo spans), except for possibly `TokenTree::Group`s /// into the same token stream (modulo spans), except for possibly `TokenTree::Group`s
/// with `Delimiter::None` delimiters and negative numeric literals. /// with `Delimiter::None` delimiters and negative numeric literals.
@ -210,7 +196,10 @@ impl ToString for TokenStream {
impl fmt::Display for TokenStream { impl fmt::Display for TokenStream {
#[allow(clippy::recursive_format_impl)] // clippy doesn't see the specialization #[allow(clippy::recursive_format_impl)] // clippy doesn't see the specialization
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str(&self.to_string()) match &self.0 {
Some(ts) => write!(f, "{}", ts.to_string()),
None => Ok(()),
}
} }
} }
@ -756,21 +745,6 @@ impl From<Literal> for TokenTree {
} }
} }
// N.B., the bridge only provides `to_string`, implement `fmt::Display`
// based on it (the reverse of the usual relationship between the two).
#[doc(hidden)]
#[stable(feature = "proc_macro_lib", since = "1.15.0")]
impl ToString for TokenTree {
fn to_string(&self) -> String {
match *self {
TokenTree::Group(ref t) => t.to_string(),
TokenTree::Ident(ref t) => t.to_string(),
TokenTree::Punct(ref t) => t.to_string(),
TokenTree::Literal(ref t) => t.to_string(),
}
}
}
/// Prints the token tree as a string that is supposed to be losslessly convertible back /// Prints the token tree as a string that is supposed to be losslessly convertible back
/// into the same token tree (modulo spans), except for possibly `TokenTree::Group`s /// into the same token tree (modulo spans), except for possibly `TokenTree::Group`s
/// with `Delimiter::None` delimiters and negative numeric literals. /// with `Delimiter::None` delimiters and negative numeric literals.
@ -786,7 +760,12 @@ impl ToString for TokenTree {
impl fmt::Display for TokenTree { impl fmt::Display for TokenTree {
#[allow(clippy::recursive_format_impl)] // clippy doesn't see the specialization #[allow(clippy::recursive_format_impl)] // clippy doesn't see the specialization
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str(&self.to_string()) match self {
TokenTree::Group(t) => write!(f, "{t}"),
TokenTree::Ident(t) => write!(f, "{t}"),
TokenTree::Punct(t) => write!(f, "{t}"),
TokenTree::Literal(t) => write!(f, "{t}"),
}
} }
} }
@ -912,16 +891,6 @@ impl Group {
} }
} }
// N.B., the bridge only provides `to_string`, implement `fmt::Display`
// based on it (the reverse of the usual relationship between the two).
#[doc(hidden)]
#[stable(feature = "proc_macro_lib", since = "1.15.0")]
impl ToString for Group {
fn to_string(&self) -> String {
TokenStream::from(TokenTree::from(self.clone())).to_string()
}
}
/// Prints the group as a string that should be losslessly convertible back /// Prints the group as a string that should be losslessly convertible back
/// into the same group (modulo spans), except for possibly `TokenTree::Group`s /// into the same group (modulo spans), except for possibly `TokenTree::Group`s
/// with `Delimiter::None` delimiters. /// with `Delimiter::None` delimiters.
@ -929,7 +898,7 @@ impl ToString for Group {
impl fmt::Display for Group { impl fmt::Display for Group {
#[allow(clippy::recursive_format_impl)] // clippy doesn't see the specialization #[allow(clippy::recursive_format_impl)] // clippy doesn't see the specialization
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str(&self.to_string()) write!(f, "{}", TokenStream::from(TokenTree::from(self.clone())))
} }
} }
@ -1035,14 +1004,6 @@ impl Punct {
} }
} }
#[doc(hidden)]
#[stable(feature = "proc_macro_lib2", since = "1.29.0")]
impl ToString for Punct {
fn to_string(&self) -> String {
self.as_char().to_string()
}
}
/// Prints the punctuation character as a string that should be losslessly convertible /// Prints the punctuation character as a string that should be losslessly convertible
/// back into the same character. /// back into the same character.
#[stable(feature = "proc_macro_lib2", since = "1.29.0")] #[stable(feature = "proc_macro_lib2", since = "1.29.0")]
@ -1138,14 +1099,6 @@ impl Ident {
} }
} }
#[doc(hidden)]
#[stable(feature = "proc_macro_lib2", since = "1.29.0")]
impl ToString for Ident {
fn to_string(&self) -> String {
self.0.sym.with(|sym| if self.0.is_raw { ["r#", sym].concat() } else { sym.to_owned() })
}
}
/// Prints the identifier as a string that should be losslessly convertible back /// Prints the identifier as a string that should be losslessly convertible back
/// into the same identifier. /// into the same identifier.
#[stable(feature = "proc_macro_lib2", since = "1.29.0")] #[stable(feature = "proc_macro_lib2", since = "1.29.0")]
@ -1520,14 +1473,6 @@ impl FromStr for Literal {
} }
} }
#[doc(hidden)]
#[stable(feature = "proc_macro_lib2", since = "1.29.0")]
impl ToString for Literal {
fn to_string(&self) -> String {
self.with_stringify_parts(|parts| parts.concat())
}
}
/// Prints the literal as a string that should be losslessly convertible /// Prints the literal as a string that should be losslessly convertible
/// back into the same literal (except for possible rounding for floating point literals). /// back into the same literal (except for possible rounding for floating point literals).
#[stable(feature = "proc_macro_lib2", since = "1.29.0")] #[stable(feature = "proc_macro_lib2", since = "1.29.0")]