diff --git a/compiler/rustc_ast_pretty/src/pprust/state.rs b/compiler/rustc_ast_pretty/src/pprust/state.rs index e88d37ec102dc..b2c62383fb69a 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state.rs @@ -1,3 +1,4 @@ +mod delimited; mod expr; mod item; @@ -23,6 +24,8 @@ use rustc_span::{BytePos, FileName, Span}; use std::borrow::Cow; +pub use self::delimited::IterDelimited; + pub enum MacHeader<'a> { Path(&'a ast::Path), Keyword(&'static str), diff --git a/compiler/rustc_ast_pretty/src/pprust/state/delimited.rs b/compiler/rustc_ast_pretty/src/pprust/state/delimited.rs new file mode 100644 index 0000000000000..fe0640baaa1b0 --- /dev/null +++ b/compiler/rustc_ast_pretty/src/pprust/state/delimited.rs @@ -0,0 +1,41 @@ +use std::iter::Peekable; +use std::mem; +use std::ops::Deref; + +pub struct Delimited { + is_first: bool, + iter: Peekable, +} + +pub trait IterDelimited: Iterator + Sized { + fn delimited(self) -> Delimited { + Delimited { is_first: true, iter: self.peekable() } + } +} + +impl IterDelimited for I {} + +pub struct IteratorItem { + value: T, + pub is_first: bool, + pub is_last: bool, +} + +impl Iterator for Delimited { + type Item = IteratorItem; + + fn next(&mut self) -> Option { + let value = self.iter.next()?; + let is_first = mem::replace(&mut self.is_first, false); + let is_last = self.iter.peek().is_none(); + Some(IteratorItem { value, is_first, is_last }) + } +} + +impl Deref for IteratorItem { + type Target = T; + + fn deref(&self) -> &Self::Target { + &self.value + } +} diff --git a/compiler/rustc_ast_pretty/src/pprust/state/expr.rs b/compiler/rustc_ast_pretty/src/pprust/state/expr.rs index 6a5bba30b8bca..44116fa76a0c1 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state/expr.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state/expr.rs @@ -1,5 +1,5 @@ -use crate::pp::Breaks::{Consistent, Inconsistent}; -use crate::pprust::state::{AnnNode, PrintState, State, INDENT_UNIT}; +use crate::pp::Breaks::Inconsistent; +use crate::pprust::state::{AnnNode, IterDelimited, PrintState, State, INDENT_UNIT}; use rustc_ast::ptr::P; use rustc_ast::util::parser::{self, AssocOp, Fixity}; @@ -117,38 +117,46 @@ impl<'a> State<'a> { } else { self.print_path(path, true, 0); } + self.nbsp(); self.word("{"); - self.commasep_cmnt( - Consistent, - fields, - |s, field| { - s.print_outer_attributes(&field.attrs); - s.ibox(INDENT_UNIT); - if !field.is_shorthand { - s.print_ident(field.ident); - s.word_space(":"); - } - s.print_expr(&field.expr); - s.end(); - }, - |f| f.span, - ); - match rest { - ast::StructRest::Base(_) | ast::StructRest::Rest(_) => { - self.ibox(INDENT_UNIT); - if !fields.is_empty() { - self.word(","); - self.space(); - } - self.word(".."); - if let ast::StructRest::Base(ref expr) = *rest { - self.print_expr(expr); - } - self.end(); + let has_rest = match rest { + ast::StructRest::Base(_) | ast::StructRest::Rest(_) => true, + ast::StructRest::None => false, + }; + if fields.is_empty() && !has_rest { + self.word("}"); + return; + } + self.cbox(0); + for field in fields.iter().delimited() { + self.maybe_print_comment(field.span.hi()); + self.print_outer_attributes(&field.attrs); + if field.is_first { + self.space_if_not_bol(); + } + if !field.is_shorthand { + self.print_ident(field.ident); + self.word_nbsp(":"); + } + self.print_expr(&field.expr); + if !field.is_last || has_rest { + self.word_space(","); + } else { + self.trailing_comma(); } - ast::StructRest::None if !fields.is_empty() => self.word(","), - _ => {} } + if has_rest { + if fields.is_empty() { + self.space(); + } + self.word(".."); + if let ast::StructRest::Base(expr) = rest { + self.print_expr(expr); + } + self.space(); + } + self.offset(-INDENT_UNIT); + self.end(); self.word("}"); }