Rollup merge of #138063 - compiler-errors:improve-attr-unpretty, r=jdonszelmann

Improve `-Zunpretty=hir` for parsed attrs

0. Rename `print_something` to `should_render` to make it distinct from `print_attribute` in that it doesn't print anything, it's just a way to probe if a type renders anything.
1. Fixes a few bugs in the `PrintAttribute` derive. Namely, the `__printed_anything` variable was entangled with the `should_render` call, leading us to always render field names but never render commas.
2. Remove the outermost `""` from the attr.
3. Debug print `Symbol`s. I know that this is redundant for some parsed attributes, but there's no good way to distinguish symbols that are ident-like and symbols which are cooked string literals. We could perhaps *conditionally* to fall back to a debug printing if the symbol doesn't match an ident? But seems like overkill.

Based on #138060, only review the commits not in that one.
This commit is contained in:
Jakub Beránek 2025-03-11 13:30:51 +01:00 committed by GitHub
commit c054bac89a
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
8 changed files with 60 additions and 52 deletions

View file

@ -35,13 +35,17 @@ pub trait HashStableContext: rustc_ast::HashStableContext + rustc_abi::HashStabl
/// like [`Span`]s and empty tuples, are gracefully skipped so they don't clutter the /// like [`Span`]s and empty tuples, are gracefully skipped so they don't clutter the
/// representation much. /// representation much.
pub trait PrintAttribute { pub trait PrintAttribute {
fn print_something(&self) -> bool; /// Whether or not this will render as something meaningful, or if it's skipped
/// (which will force the containing struct to also skip printing a comma
/// and the field name).
fn should_render(&self) -> bool;
fn print_attribute(&self, p: &mut Printer); fn print_attribute(&self, p: &mut Printer);
} }
impl<T: PrintAttribute> PrintAttribute for &T { impl<T: PrintAttribute> PrintAttribute for &T {
fn print_something(&self) -> bool { fn should_render(&self) -> bool {
T::print_something(self) T::should_render(self)
} }
fn print_attribute(&self, p: &mut Printer) { fn print_attribute(&self, p: &mut Printer) {
@ -49,9 +53,10 @@ impl<T: PrintAttribute> PrintAttribute for &T {
} }
} }
impl<T: PrintAttribute> PrintAttribute for Option<T> { impl<T: PrintAttribute> PrintAttribute for Option<T> {
fn print_something(&self) -> bool { fn should_render(&self) -> bool {
self.as_ref().is_some_and(|x| x.print_something()) self.as_ref().is_some_and(|x| x.should_render())
} }
fn print_attribute(&self, p: &mut Printer) { fn print_attribute(&self, p: &mut Printer) {
if let Some(i) = self { if let Some(i) = self {
T::print_attribute(i, p) T::print_attribute(i, p)
@ -59,9 +64,10 @@ impl<T: PrintAttribute> PrintAttribute for Option<T> {
} }
} }
impl<T: PrintAttribute> PrintAttribute for ThinVec<T> { impl<T: PrintAttribute> PrintAttribute for ThinVec<T> {
fn print_something(&self) -> bool { fn should_render(&self) -> bool {
self.is_empty() || self[0].print_something() self.is_empty() || self[0].should_render()
} }
fn print_attribute(&self, p: &mut Printer) { fn print_attribute(&self, p: &mut Printer) {
let mut last_printed = false; let mut last_printed = false;
p.word("["); p.word("[");
@ -70,7 +76,7 @@ impl<T: PrintAttribute> PrintAttribute for ThinVec<T> {
p.word_space(","); p.word_space(",");
} }
i.print_attribute(p); i.print_attribute(p);
last_printed = i.print_something(); last_printed = i.should_render();
} }
p.word("]"); p.word("]");
} }
@ -78,7 +84,7 @@ impl<T: PrintAttribute> PrintAttribute for ThinVec<T> {
macro_rules! print_skip { macro_rules! print_skip {
($($t: ty),* $(,)?) => {$( ($($t: ty),* $(,)?) => {$(
impl PrintAttribute for $t { impl PrintAttribute for $t {
fn print_something(&self) -> bool { false } fn should_render(&self) -> bool { false }
fn print_attribute(&self, _: &mut Printer) { } fn print_attribute(&self, _: &mut Printer) { }
})* })*
}; };
@ -87,7 +93,7 @@ macro_rules! print_skip {
macro_rules! print_disp { macro_rules! print_disp {
($($t: ty),* $(,)?) => {$( ($($t: ty),* $(,)?) => {$(
impl PrintAttribute for $t { impl PrintAttribute for $t {
fn print_something(&self) -> bool { true } fn should_render(&self) -> bool { true }
fn print_attribute(&self, p: &mut Printer) { fn print_attribute(&self, p: &mut Printer) {
p.word(format!("{}", self)); p.word(format!("{}", self));
} }
@ -97,7 +103,7 @@ macro_rules! print_disp {
macro_rules! print_debug { macro_rules! print_debug {
($($t: ty),* $(,)?) => {$( ($($t: ty),* $(,)?) => {$(
impl PrintAttribute for $t { impl PrintAttribute for $t {
fn print_something(&self) -> bool { true } fn should_render(&self) -> bool { true }
fn print_attribute(&self, p: &mut Printer) { fn print_attribute(&self, p: &mut Printer) {
p.word(format!("{:?}", self)); p.word(format!("{:?}", self));
} }
@ -106,37 +112,39 @@ macro_rules! print_debug {
} }
macro_rules! print_tup { macro_rules! print_tup {
(num_print_something $($ts: ident)*) => { 0 $(+ $ts.print_something() as usize)* }; (num_should_render $($ts: ident)*) => { 0 $(+ $ts.should_render() as usize)* };
() => {}; () => {};
($t: ident $($ts: ident)*) => { ($t: ident $($ts: ident)*) => {
#[allow(non_snake_case, unused)] #[allow(non_snake_case, unused)]
impl<$t: PrintAttribute, $($ts: PrintAttribute),*> PrintAttribute for ($t, $($ts),*) { impl<$t: PrintAttribute, $($ts: PrintAttribute),*> PrintAttribute for ($t, $($ts),*) {
fn print_something(&self) -> bool { fn should_render(&self) -> bool {
let ($t, $($ts),*) = self; let ($t, $($ts),*) = self;
print_tup!(num_print_something $t $($ts)*) != 0 print_tup!(num_should_render $t $($ts)*) != 0
} }
fn print_attribute(&self, p: &mut Printer) { fn print_attribute(&self, p: &mut Printer) {
let ($t, $($ts),*) = self; let ($t, $($ts),*) = self;
let parens = print_tup!(num_print_something $t $($ts)*) > 1; let parens = print_tup!(num_should_render $t $($ts)*) > 1;
if parens { if parens {
p.word("("); p.popen();
} }
let mut printed_anything = $t.print_something(); let mut printed_anything = $t.should_render();
$t.print_attribute(p); $t.print_attribute(p);
$( $(
if printed_anything && $ts.print_something() { if $ts.should_render() {
if printed_anything {
p.word_space(","); p.word_space(",");
}
printed_anything = true; printed_anything = true;
} }
$ts.print_attribute(p); $ts.print_attribute(p);
)* )*
if parens { if parens {
p.word(")"); p.pclose();
} }
} }
} }
@ -147,8 +155,8 @@ macro_rules! print_tup {
print_tup!(A B C D E F G H); print_tup!(A B C D E F G H);
print_skip!(Span, ()); print_skip!(Span, ());
print_disp!(Symbol, u16, bool, NonZero<u32>); print_disp!(u16, bool, NonZero<u32>);
print_debug!(UintTy, IntTy, Align, AttrStyle, CommentKind, Transparency); print_debug!(Symbol, UintTy, IntTy, Align, AttrStyle, CommentKind, Transparency);
/// Finds attributes in sequences of attributes by pattern matching. /// Finds attributes in sequences of attributes by pattern matching.
/// ///

View file

@ -118,9 +118,9 @@ impl<'a> State<'a> {
self.hardbreak() self.hardbreak()
} }
hir::Attribute::Parsed(pa) => { hir::Attribute::Parsed(pa) => {
self.word("#[attr=\""); self.word("#[attr = ");
pa.print_attribute(self); pa.print_attribute(self);
self.word("\")]"); self.word("]");
self.hardbreak() self.hardbreak()
} }
} }

View file

@ -16,12 +16,14 @@ fn print_fields(name: &Ident, fields: &Fields) -> (TokenStream, TokenStream, Tok
let name = field.ident.as_ref().unwrap(); let name = field.ident.as_ref().unwrap();
let string_name = name.to_string(); let string_name = name.to_string();
disps.push(quote! { disps.push(quote! {
if __printed_anything && #name.print_something() { if #name.should_render() {
if __printed_anything {
__p.word_space(","); __p.word_space(",");
__printed_anything = true;
} }
__p.word(#string_name); __p.word(#string_name);
__p.word_space(":"); __p.word_space(":");
__printed_anything = true;
}
#name.print_attribute(__p); #name.print_attribute(__p);
}); });
field_names.push(name); field_names.push(name);
@ -31,10 +33,11 @@ fn print_fields(name: &Ident, fields: &Fields) -> (TokenStream, TokenStream, Tok
quote! { {#(#field_names),*} }, quote! { {#(#field_names),*} },
quote! { quote! {
__p.word(#string_name); __p.word(#string_name);
if true #(&& !#field_names.print_something())* { if true #(&& !#field_names.should_render())* {
return; return;
} }
__p.nbsp();
__p.word("{"); __p.word("{");
#(#disps)* #(#disps)*
__p.word("}"); __p.word("}");
@ -48,8 +51,10 @@ fn print_fields(name: &Ident, fields: &Fields) -> (TokenStream, TokenStream, Tok
for idx in 0..fields_unnamed.unnamed.len() { for idx in 0..fields_unnamed.unnamed.len() {
let name = format_ident!("f{idx}"); let name = format_ident!("f{idx}");
disps.push(quote! { disps.push(quote! {
if __printed_anything && #name.print_something() { if #name.should_render() {
if __printed_anything {
__p.word_space(","); __p.word_space(",");
}
__printed_anything = true; __printed_anything = true;
} }
#name.print_attribute(__p); #name.print_attribute(__p);
@ -62,13 +67,13 @@ fn print_fields(name: &Ident, fields: &Fields) -> (TokenStream, TokenStream, Tok
quote! { quote! {
__p.word(#string_name); __p.word(#string_name);
if true #(&& !#field_names.print_something())* { if true #(&& !#field_names.should_render())* {
return; return;
} }
__p.word("("); __p.popen();
#(#disps)* #(#disps)*
__p.word(")"); __p.pclose();
}, },
quote! { true }, quote! { true },
) )
@ -138,7 +143,7 @@ pub(crate) fn print_attribute(input: Structure<'_>) -> TokenStream {
input.gen_impl(quote! { input.gen_impl(quote! {
#[allow(unused)] #[allow(unused)]
gen impl PrintAttribute for @Self { gen impl PrintAttribute for @Self {
fn print_something(&self) -> bool { #printed } fn should_render(&self) -> bool { #printed }
fn print_attribute(&self, __p: &mut rustc_ast_pretty::pp::Printer) { #code } fn print_attribute(&self, __p: &mut rustc_ast_pretty::pp::Printer) { #code }
} }
}) })

View file

@ -6,6 +6,6 @@ extern crate std;
//@ pretty-mode:hir //@ pretty-mode:hir
//@ pp-exact:hir-pretty-attr.pp //@ pp-exact:hir-pretty-attr.pp
#[attr="Repr([ReprC, ReprPacked(Align(4 bytes)), ReprTransparent])")] #[attr = Repr([ReprC, ReprPacked(Align(4 bytes)), ReprTransparent])]
struct Example { struct Example {
} }

View file

@ -1,5 +1,5 @@
#[repr(i32)] #[repr(i32)]
//@ is "$.index[*][?(@.name=='Foo')].attrs" '["#[attr=\"Repr([ReprInt(SignedInt(I32))])\")]\n"]' //@ is "$.index[*][?(@.name=='Foo')].attrs" '["#[attr = Repr([ReprInt(SignedInt(I32))])]\n"]'
pub enum Foo { pub enum Foo {
//@ is "$.index[*][?(@.name=='Struct')].inner.variant.discriminant" null //@ is "$.index[*][?(@.name=='Struct')].inner.variant.discriminant" null
//@ count "$.index[*][?(@.name=='Struct')].inner.variant.kind.struct.fields[*]" 0 //@ count "$.index[*][?(@.name=='Struct')].inner.variant.kind.struct.fields[*]" 0

View file

@ -1,5 +1,5 @@
#[repr(u32)] #[repr(u32)]
//@ is "$.index[*][?(@.name=='Foo')].attrs" '["#[attr=\"Repr([ReprInt(UnsignedInt(U32))])\")]\n"]' //@ is "$.index[*][?(@.name=='Foo')].attrs" '["#[attr = Repr([ReprInt(UnsignedInt(U32))])]\n"]'
pub enum Foo { pub enum Foo {
//@ is "$.index[*][?(@.name=='Tuple')].inner.variant.discriminant" null //@ is "$.index[*][?(@.name=='Tuple')].inner.variant.discriminant" null
//@ count "$.index[*][?(@.name=='Tuple')].inner.variant.kind.tuple[*]" 0 //@ count "$.index[*][?(@.name=='Tuple')].inner.variant.kind.tuple[*]" 0

View file

@ -1,8 +1,6 @@
//@ compile-flags: -Zunpretty=hir //@ compile-flags: -Zunpretty=hir
//@ check-pass //@ check-pass
// FIXME(jdonszelmann): the pretty printing output for deprecated (and possibly more attrs) is
// slightly broken.
#[deprecated] #[deprecated]
pub struct PlainDeprecated; pub struct PlainDeprecated;

View file

@ -5,24 +5,21 @@ extern crate std;
//@ compile-flags: -Zunpretty=hir //@ compile-flags: -Zunpretty=hir
//@ check-pass //@ check-pass
// FIXME(jdonszelmann): the pretty printing output for deprecated (and possibly more attrs) is #[attr = Deprecation {deprecation: Deprecation {since: Unspecified}}]
// slightly broken.
#[attr="Deprecation{deprecation: Deprecation{since: Unspecifiednote:
suggestion: }span: }")]
struct PlainDeprecated; struct PlainDeprecated;
#[attr="Deprecation{deprecation: Deprecation{since: Unspecifiednote: #[attr = Deprecation {deprecation: Deprecation {since: Unspecified, note:
here's why this is deprecatedsuggestion: }span: }")] "here's why this is deprecated"}}]
struct DirectNote; struct DirectNote;
#[attr="Deprecation{deprecation: Deprecation{since: Unspecifiednote: #[attr = Deprecation {deprecation: Deprecation {since: Unspecified, note:
here's why this is deprecatedsuggestion: }span: }")] "here's why this is deprecated"}}]
struct ExplicitNote; struct ExplicitNote;
#[attr="Deprecation{deprecation: Deprecation{since: NonStandard(1.2.3)note: #[attr = Deprecation {deprecation: Deprecation {since: NonStandard("1.2.3"),
here's why this is deprecatedsuggestion: }span: }")] note: "here's why this is deprecated"}}]
struct SinceAndNote; struct SinceAndNote;
#[attr="Deprecation{deprecation: Deprecation{since: NonStandard(1.2.3)note: #[attr = Deprecation {deprecation: Deprecation {since: NonStandard("1.2.3"),
here's why this is deprecatedsuggestion: }span: }")] note: "here's why this is deprecated"}}]
struct FlippedOrder; struct FlippedOrder;