]> git.lizzy.rs Git - rust.git/blob - compiler/rustc_ast_pretty/src/pprust/state.rs
Auto merge of #99052 - tmiasko:bitset-clone-from, r=Mark-Simulacrum
[rust.git] / compiler / rustc_ast_pretty / src / pprust / state.rs
1 mod delimited;
2 mod expr;
3 mod item;
4
5 use crate::pp::Breaks::{Consistent, Inconsistent};
6 use crate::pp::{self, Breaks};
7
8 use rustc_ast::ptr::P;
9 use rustc_ast::token::{self, BinOpToken, CommentKind, Delimiter, Nonterminal, Token, TokenKind};
10 use rustc_ast::tokenstream::{TokenStream, TokenTree};
11 use rustc_ast::util::classify;
12 use rustc_ast::util::comments::{gather_comments, Comment, CommentStyle};
13 use rustc_ast::util::parser;
14 use rustc_ast::{self as ast, BlockCheckMode, PatKind, RangeEnd, RangeSyntax};
15 use rustc_ast::{attr, Term};
16 use rustc_ast::{GenericArg, MacArgs, MacArgsEq};
17 use rustc_ast::{GenericBound, SelfKind, TraitBoundModifier};
18 use rustc_ast::{InlineAsmOperand, InlineAsmRegOrRegClass};
19 use rustc_ast::{InlineAsmOptions, InlineAsmTemplatePiece};
20 use rustc_span::edition::Edition;
21 use rustc_span::source_map::{SourceMap, Spanned};
22 use rustc_span::symbol::{kw, sym, Ident, IdentPrinter, Symbol};
23 use rustc_span::{BytePos, FileName, Span};
24
25 use std::borrow::Cow;
26
27 pub use self::delimited::IterDelimited;
28
29 pub enum MacHeader<'a> {
30     Path(&'a ast::Path),
31     Keyword(&'static str),
32 }
33
34 pub enum AnnNode<'a> {
35     Ident(&'a Ident),
36     Name(&'a Symbol),
37     Block(&'a ast::Block),
38     Item(&'a ast::Item),
39     SubItem(ast::NodeId),
40     Expr(&'a ast::Expr),
41     Pat(&'a ast::Pat),
42     Crate(&'a ast::Crate),
43 }
44
45 pub trait PpAnn {
46     fn pre(&self, _state: &mut State<'_>, _node: AnnNode<'_>) {}
47     fn post(&self, _state: &mut State<'_>, _node: AnnNode<'_>) {}
48 }
49
50 #[derive(Copy, Clone)]
51 pub struct NoAnn;
52
53 impl PpAnn for NoAnn {}
54
55 pub struct Comments<'a> {
56     sm: &'a SourceMap,
57     comments: Vec<Comment>,
58     current: usize,
59 }
60
61 impl<'a> Comments<'a> {
62     pub fn new(sm: &'a SourceMap, filename: FileName, input: String) -> Comments<'a> {
63         let comments = gather_comments(sm, filename, input);
64         Comments { sm, comments, current: 0 }
65     }
66
67     pub fn next(&self) -> Option<Comment> {
68         self.comments.get(self.current).cloned()
69     }
70
71     pub fn trailing_comment(
72         &self,
73         span: rustc_span::Span,
74         next_pos: Option<BytePos>,
75     ) -> Option<Comment> {
76         if let Some(cmnt) = self.next() {
77             if cmnt.style != CommentStyle::Trailing {
78                 return None;
79             }
80             let span_line = self.sm.lookup_char_pos(span.hi());
81             let comment_line = self.sm.lookup_char_pos(cmnt.pos);
82             let next = next_pos.unwrap_or_else(|| cmnt.pos + BytePos(1));
83             if span.hi() < cmnt.pos && cmnt.pos < next && span_line.line == comment_line.line {
84                 return Some(cmnt);
85             }
86         }
87
88         None
89     }
90 }
91
92 pub struct State<'a> {
93     pub s: pp::Printer,
94     comments: Option<Comments<'a>>,
95     ann: &'a (dyn PpAnn + 'a),
96 }
97
98 pub(crate) const INDENT_UNIT: isize = 4;
99
100 /// Requires you to pass an input filename and reader so that
101 /// it can scan the input text for comments to copy forward.
102 pub fn print_crate<'a>(
103     sm: &'a SourceMap,
104     krate: &ast::Crate,
105     filename: FileName,
106     input: String,
107     ann: &'a dyn PpAnn,
108     is_expanded: bool,
109     edition: Edition,
110 ) -> String {
111     let mut s =
112         State { s: pp::Printer::new(), comments: Some(Comments::new(sm, filename, input)), ann };
113
114     if is_expanded && !krate.attrs.iter().any(|attr| attr.has_name(sym::no_core)) {
115         // We need to print `#![no_std]` (and its feature gate) so that
116         // compiling pretty-printed source won't inject libstd again.
117         // However, we don't want these attributes in the AST because
118         // of the feature gate, so we fake them up here.
119
120         // `#![feature(prelude_import)]`
121         let pi_nested = attr::mk_nested_word_item(Ident::with_dummy_span(sym::prelude_import));
122         let list = attr::mk_list_item(Ident::with_dummy_span(sym::feature), vec![pi_nested]);
123         let fake_attr = attr::mk_attr_inner(list);
124         s.print_attribute(&fake_attr);
125
126         // Currently, in Rust 2018 we don't have `extern crate std;` at the crate
127         // root, so this is not needed, and actually breaks things.
128         if edition == Edition::Edition2015 {
129             // `#![no_std]`
130             let no_std_meta = attr::mk_word_item(Ident::with_dummy_span(sym::no_std));
131             let fake_attr = attr::mk_attr_inner(no_std_meta);
132             s.print_attribute(&fake_attr);
133         }
134     }
135
136     s.print_inner_attributes(&krate.attrs);
137     for item in &krate.items {
138         s.print_item(item);
139     }
140     s.print_remaining_comments();
141     s.ann.post(&mut s, AnnNode::Crate(krate));
142     s.s.eof()
143 }
144
145 /// This makes printed token streams look slightly nicer,
146 /// and also addresses some specific regressions described in #63896 and #73345.
147 fn tt_prepend_space(tt: &TokenTree, prev: &TokenTree) -> bool {
148     if let TokenTree::Token(token, _) = prev {
149         if matches!(token.kind, token::Dot | token::Dollar) {
150             return false;
151         }
152         if let token::DocComment(comment_kind, ..) = token.kind {
153             return comment_kind != CommentKind::Line;
154         }
155     }
156     match tt {
157         TokenTree::Token(token, _) => !matches!(token.kind, token::Comma | token::Not | token::Dot),
158         TokenTree::Delimited(_, Delimiter::Parenthesis, _) => {
159             !matches!(prev, TokenTree::Token(Token { kind: token::Ident(..), .. }, _))
160         }
161         TokenTree::Delimited(_, Delimiter::Bracket, _) => {
162             !matches!(prev, TokenTree::Token(Token { kind: token::Pound, .. }, _))
163         }
164         TokenTree::Delimited(..) => true,
165     }
166 }
167
168 fn binop_to_string(op: BinOpToken) -> &'static str {
169     match op {
170         token::Plus => "+",
171         token::Minus => "-",
172         token::Star => "*",
173         token::Slash => "/",
174         token::Percent => "%",
175         token::Caret => "^",
176         token::And => "&",
177         token::Or => "|",
178         token::Shl => "<<",
179         token::Shr => ">>",
180     }
181 }
182
183 fn doc_comment_to_string(
184     comment_kind: CommentKind,
185     attr_style: ast::AttrStyle,
186     data: Symbol,
187 ) -> String {
188     match (comment_kind, attr_style) {
189         (CommentKind::Line, ast::AttrStyle::Outer) => format!("///{}", data),
190         (CommentKind::Line, ast::AttrStyle::Inner) => format!("//!{}", data),
191         (CommentKind::Block, ast::AttrStyle::Outer) => format!("/**{}*/", data),
192         (CommentKind::Block, ast::AttrStyle::Inner) => format!("/*!{}*/", data),
193     }
194 }
195
196 pub fn literal_to_string(lit: token::Lit) -> String {
197     let token::Lit { kind, symbol, suffix } = lit;
198     let mut out = match kind {
199         token::Byte => format!("b'{}'", symbol),
200         token::Char => format!("'{}'", symbol),
201         token::Str => format!("\"{}\"", symbol),
202         token::StrRaw(n) => {
203             format!("r{delim}\"{string}\"{delim}", delim = "#".repeat(n as usize), string = symbol)
204         }
205         token::ByteStr => format!("b\"{}\"", symbol),
206         token::ByteStrRaw(n) => {
207             format!("br{delim}\"{string}\"{delim}", delim = "#".repeat(n as usize), string = symbol)
208         }
209         token::Integer | token::Float | token::Bool | token::Err => symbol.to_string(),
210     };
211
212     if let Some(suffix) = suffix {
213         out.push_str(suffix.as_str())
214     }
215
216     out
217 }
218
219 impl std::ops::Deref for State<'_> {
220     type Target = pp::Printer;
221     fn deref(&self) -> &Self::Target {
222         &self.s
223     }
224 }
225
226 impl std::ops::DerefMut for State<'_> {
227     fn deref_mut(&mut self) -> &mut Self::Target {
228         &mut self.s
229     }
230 }
231
232 pub trait PrintState<'a>: std::ops::Deref<Target = pp::Printer> + std::ops::DerefMut {
233     fn comments(&mut self) -> &mut Option<Comments<'a>>;
234     fn print_ident(&mut self, ident: Ident);
235     fn print_generic_args(&mut self, args: &ast::GenericArgs, colons_before_params: bool);
236
237     fn strsep<T, F>(
238         &mut self,
239         sep: &'static str,
240         space_before: bool,
241         b: Breaks,
242         elts: &[T],
243         mut op: F,
244     ) where
245         F: FnMut(&mut Self, &T),
246     {
247         self.rbox(0, b);
248         if let Some((first, rest)) = elts.split_first() {
249             op(self, first);
250             for elt in rest {
251                 if space_before {
252                     self.space();
253                 }
254                 self.word_space(sep);
255                 op(self, elt);
256             }
257         }
258         self.end();
259     }
260
261     fn commasep<T, F>(&mut self, b: Breaks, elts: &[T], op: F)
262     where
263         F: FnMut(&mut Self, &T),
264     {
265         self.strsep(",", false, b, elts, op)
266     }
267
268     fn maybe_print_comment(&mut self, pos: BytePos) -> bool {
269         let mut has_comment = false;
270         while let Some(ref cmnt) = self.next_comment() {
271             if cmnt.pos < pos {
272                 has_comment = true;
273                 self.print_comment(cmnt);
274             } else {
275                 break;
276             }
277         }
278         has_comment
279     }
280
281     fn print_comment(&mut self, cmnt: &Comment) {
282         match cmnt.style {
283             CommentStyle::Mixed => {
284                 if !self.is_beginning_of_line() {
285                     self.zerobreak();
286                 }
287                 if let Some((last, lines)) = cmnt.lines.split_last() {
288                     self.ibox(0);
289
290                     for line in lines {
291                         self.word(line.clone());
292                         self.hardbreak()
293                     }
294
295                     self.word(last.clone());
296                     self.space();
297
298                     self.end();
299                 }
300                 self.zerobreak()
301             }
302             CommentStyle::Isolated => {
303                 self.hardbreak_if_not_bol();
304                 for line in &cmnt.lines {
305                     // Don't print empty lines because they will end up as trailing
306                     // whitespace.
307                     if !line.is_empty() {
308                         self.word(line.clone());
309                     }
310                     self.hardbreak();
311                 }
312             }
313             CommentStyle::Trailing => {
314                 if !self.is_beginning_of_line() {
315                     self.word(" ");
316                 }
317                 if cmnt.lines.len() == 1 {
318                     self.word(cmnt.lines[0].clone());
319                     self.hardbreak()
320                 } else {
321                     self.visual_align();
322                     for line in &cmnt.lines {
323                         if !line.is_empty() {
324                             self.word(line.clone());
325                         }
326                         self.hardbreak();
327                     }
328                     self.end();
329                 }
330             }
331             CommentStyle::BlankLine => {
332                 // We need to do at least one, possibly two hardbreaks.
333                 let twice = match self.last_token() {
334                     Some(pp::Token::String(s)) => ";" == s,
335                     Some(pp::Token::Begin(_)) => true,
336                     Some(pp::Token::End) => true,
337                     _ => false,
338                 };
339                 if twice {
340                     self.hardbreak();
341                 }
342                 self.hardbreak();
343             }
344         }
345         if let Some(cmnts) = self.comments() {
346             cmnts.current += 1;
347         }
348     }
349
350     fn next_comment(&mut self) -> Option<Comment> {
351         self.comments().as_mut().and_then(|c| c.next())
352     }
353
354     fn maybe_print_trailing_comment(&mut self, span: rustc_span::Span, next_pos: Option<BytePos>) {
355         if let Some(cmnts) = self.comments() {
356             if let Some(cmnt) = cmnts.trailing_comment(span, next_pos) {
357                 self.print_comment(&cmnt);
358             }
359         }
360     }
361
362     fn print_remaining_comments(&mut self) {
363         // If there aren't any remaining comments, then we need to manually
364         // make sure there is a line break at the end.
365         if self.next_comment().is_none() {
366             self.hardbreak();
367         }
368         while let Some(ref cmnt) = self.next_comment() {
369             self.print_comment(cmnt)
370         }
371     }
372
373     fn print_literal(&mut self, lit: &ast::Lit) {
374         self.maybe_print_comment(lit.span.lo());
375         self.word(lit.token.to_string())
376     }
377
378     fn print_string(&mut self, st: &str, style: ast::StrStyle) {
379         let st = match style {
380             ast::StrStyle::Cooked => (format!("\"{}\"", st.escape_debug())),
381             ast::StrStyle::Raw(n) => {
382                 format!("r{delim}\"{string}\"{delim}", delim = "#".repeat(n as usize), string = st)
383             }
384         };
385         self.word(st)
386     }
387
388     fn print_symbol(&mut self, sym: Symbol, style: ast::StrStyle) {
389         self.print_string(sym.as_str(), style);
390     }
391
392     fn print_inner_attributes(&mut self, attrs: &[ast::Attribute]) -> bool {
393         self.print_either_attributes(attrs, ast::AttrStyle::Inner, false, true)
394     }
395
396     fn print_inner_attributes_no_trailing_hardbreak(&mut self, attrs: &[ast::Attribute]) -> bool {
397         self.print_either_attributes(attrs, ast::AttrStyle::Inner, false, false)
398     }
399
400     fn print_outer_attributes(&mut self, attrs: &[ast::Attribute]) -> bool {
401         self.print_either_attributes(attrs, ast::AttrStyle::Outer, false, true)
402     }
403
404     fn print_inner_attributes_inline(&mut self, attrs: &[ast::Attribute]) -> bool {
405         self.print_either_attributes(attrs, ast::AttrStyle::Inner, true, true)
406     }
407
408     fn print_outer_attributes_inline(&mut self, attrs: &[ast::Attribute]) -> bool {
409         self.print_either_attributes(attrs, ast::AttrStyle::Outer, true, true)
410     }
411
412     fn print_either_attributes(
413         &mut self,
414         attrs: &[ast::Attribute],
415         kind: ast::AttrStyle,
416         is_inline: bool,
417         trailing_hardbreak: bool,
418     ) -> bool {
419         let mut printed = false;
420         for attr in attrs {
421             if attr.style == kind {
422                 self.print_attribute_inline(attr, is_inline);
423                 if is_inline {
424                     self.nbsp();
425                 }
426                 printed = true;
427             }
428         }
429         if printed && trailing_hardbreak && !is_inline {
430             self.hardbreak_if_not_bol();
431         }
432         printed
433     }
434
435     fn print_attribute(&mut self, attr: &ast::Attribute) {
436         self.print_attribute_inline(attr, false)
437     }
438
439     fn print_attribute_inline(&mut self, attr: &ast::Attribute, is_inline: bool) {
440         if !is_inline {
441             self.hardbreak_if_not_bol();
442         }
443         self.maybe_print_comment(attr.span.lo());
444         match attr.kind {
445             ast::AttrKind::Normal(ref item, _) => {
446                 match attr.style {
447                     ast::AttrStyle::Inner => self.word("#!["),
448                     ast::AttrStyle::Outer => self.word("#["),
449                 }
450                 self.print_attr_item(&item, attr.span);
451                 self.word("]");
452             }
453             ast::AttrKind::DocComment(comment_kind, data) => {
454                 self.word(doc_comment_to_string(comment_kind, attr.style, data));
455                 self.hardbreak()
456             }
457         }
458     }
459
460     fn print_attr_item(&mut self, item: &ast::AttrItem, span: Span) {
461         self.ibox(0);
462         match &item.args {
463             MacArgs::Delimited(_, delim, tokens) => self.print_mac_common(
464                 Some(MacHeader::Path(&item.path)),
465                 false,
466                 None,
467                 Some(delim.to_token()),
468                 tokens,
469                 true,
470                 span,
471             ),
472             MacArgs::Empty => {
473                 self.print_path(&item.path, false, 0);
474             }
475             MacArgs::Eq(_, MacArgsEq::Ast(expr)) => {
476                 self.print_path(&item.path, false, 0);
477                 self.space();
478                 self.word_space("=");
479                 let token_str = self.expr_to_string(expr);
480                 self.word(token_str);
481             }
482             MacArgs::Eq(_, MacArgsEq::Hir(lit)) => {
483                 self.print_path(&item.path, false, 0);
484                 self.space();
485                 self.word_space("=");
486                 let token_str = self.literal_to_string(lit);
487                 self.word(token_str);
488             }
489         }
490         self.end();
491     }
492
493     fn print_meta_list_item(&mut self, item: &ast::NestedMetaItem) {
494         match item {
495             ast::NestedMetaItem::MetaItem(ref mi) => self.print_meta_item(mi),
496             ast::NestedMetaItem::Literal(ref lit) => self.print_literal(lit),
497         }
498     }
499
500     fn print_meta_item(&mut self, item: &ast::MetaItem) {
501         self.ibox(INDENT_UNIT);
502         match item.kind {
503             ast::MetaItemKind::Word => self.print_path(&item.path, false, 0),
504             ast::MetaItemKind::NameValue(ref value) => {
505                 self.print_path(&item.path, false, 0);
506                 self.space();
507                 self.word_space("=");
508                 self.print_literal(value);
509             }
510             ast::MetaItemKind::List(ref items) => {
511                 self.print_path(&item.path, false, 0);
512                 self.popen();
513                 self.commasep(Consistent, &items, |s, i| s.print_meta_list_item(i));
514                 self.pclose();
515             }
516         }
517         self.end();
518     }
519
520     /// This doesn't deserve to be called "pretty" printing, but it should be
521     /// meaning-preserving. A quick hack that might help would be to look at the
522     /// spans embedded in the TTs to decide where to put spaces and newlines.
523     /// But it'd be better to parse these according to the grammar of the
524     /// appropriate macro, transcribe back into the grammar we just parsed from,
525     /// and then pretty-print the resulting AST nodes (so, e.g., we print
526     /// expression arguments as expressions). It can be done! I think.
527     fn print_tt(&mut self, tt: &TokenTree, convert_dollar_crate: bool) {
528         match tt {
529             TokenTree::Token(token, _) => {
530                 let token_str = self.token_to_string_ext(&token, convert_dollar_crate);
531                 self.word(token_str);
532                 if let token::DocComment(..) = token.kind {
533                     self.hardbreak()
534                 }
535             }
536             TokenTree::Delimited(dspan, delim, tts) => {
537                 self.print_mac_common(
538                     None,
539                     false,
540                     None,
541                     Some(*delim),
542                     tts,
543                     convert_dollar_crate,
544                     dspan.entire(),
545                 );
546             }
547         }
548     }
549
550     fn print_tts(&mut self, tts: &TokenStream, convert_dollar_crate: bool) {
551         let mut iter = tts.trees().peekable();
552         while let Some(tt) = iter.next() {
553             self.print_tt(tt, convert_dollar_crate);
554             if let Some(next) = iter.peek() {
555                 if tt_prepend_space(next, tt) {
556                     self.space();
557                 }
558             }
559         }
560     }
561
562     fn print_mac_common(
563         &mut self,
564         header: Option<MacHeader<'_>>,
565         has_bang: bool,
566         ident: Option<Ident>,
567         delim: Option<Delimiter>,
568         tts: &TokenStream,
569         convert_dollar_crate: bool,
570         span: Span,
571     ) {
572         if delim == Some(Delimiter::Brace) {
573             self.cbox(INDENT_UNIT);
574         }
575         match header {
576             Some(MacHeader::Path(path)) => self.print_path(path, false, 0),
577             Some(MacHeader::Keyword(kw)) => self.word(kw),
578             None => {}
579         }
580         if has_bang {
581             self.word("!");
582         }
583         if let Some(ident) = ident {
584             self.nbsp();
585             self.print_ident(ident);
586         }
587         match delim {
588             Some(Delimiter::Brace) => {
589                 if header.is_some() || has_bang || ident.is_some() {
590                     self.nbsp();
591                 }
592                 self.word("{");
593                 if !tts.is_empty() {
594                     self.space();
595                 }
596                 self.ibox(0);
597                 self.print_tts(tts, convert_dollar_crate);
598                 self.end();
599                 let empty = tts.is_empty();
600                 self.bclose(span, empty);
601             }
602             Some(delim) => {
603                 let token_str = self.token_kind_to_string(&token::OpenDelim(delim));
604                 self.word(token_str);
605                 self.ibox(0);
606                 self.print_tts(tts, convert_dollar_crate);
607                 self.end();
608                 let token_str = self.token_kind_to_string(&token::CloseDelim(delim));
609                 self.word(token_str);
610             }
611             None => {
612                 self.ibox(0);
613                 self.print_tts(tts, convert_dollar_crate);
614                 self.end();
615             }
616         }
617     }
618
619     fn print_mac_def(
620         &mut self,
621         macro_def: &ast::MacroDef,
622         ident: &Ident,
623         sp: Span,
624         print_visibility: impl FnOnce(&mut Self),
625     ) {
626         let (kw, has_bang) = if macro_def.macro_rules {
627             ("macro_rules", true)
628         } else {
629             print_visibility(self);
630             ("macro", false)
631         };
632         self.print_mac_common(
633             Some(MacHeader::Keyword(kw)),
634             has_bang,
635             Some(*ident),
636             macro_def.body.delim(),
637             &macro_def.body.inner_tokens(),
638             true,
639             sp,
640         );
641         if macro_def.body.need_semicolon() {
642             self.word(";");
643         }
644     }
645
646     fn print_path(&mut self, path: &ast::Path, colons_before_params: bool, depth: usize) {
647         self.maybe_print_comment(path.span.lo());
648
649         for (i, segment) in path.segments[..path.segments.len() - depth].iter().enumerate() {
650             if i > 0 {
651                 self.word("::")
652             }
653             self.print_path_segment(segment, colons_before_params);
654         }
655     }
656
657     fn print_path_segment(&mut self, segment: &ast::PathSegment, colons_before_params: bool) {
658         if segment.ident.name != kw::PathRoot {
659             self.print_ident(segment.ident);
660             if let Some(ref args) = segment.args {
661                 self.print_generic_args(args, colons_before_params);
662             }
663         }
664     }
665
666     fn head<S: Into<Cow<'static, str>>>(&mut self, w: S) {
667         let w = w.into();
668         // Outer-box is consistent.
669         self.cbox(INDENT_UNIT);
670         // Head-box is inconsistent.
671         self.ibox(0);
672         // Keyword that starts the head.
673         if !w.is_empty() {
674             self.word_nbsp(w);
675         }
676     }
677
678     fn bopen(&mut self) {
679         self.word("{");
680         self.end(); // Close the head-box.
681     }
682
683     fn bclose_maybe_open(&mut self, span: rustc_span::Span, empty: bool, close_box: bool) {
684         let has_comment = self.maybe_print_comment(span.hi());
685         if !empty || has_comment {
686             self.break_offset_if_not_bol(1, -(INDENT_UNIT as isize));
687         }
688         self.word("}");
689         if close_box {
690             self.end(); // Close the outer-box.
691         }
692     }
693
694     fn bclose(&mut self, span: rustc_span::Span, empty: bool) {
695         let close_box = true;
696         self.bclose_maybe_open(span, empty, close_box)
697     }
698
699     fn break_offset_if_not_bol(&mut self, n: usize, off: isize) {
700         if !self.is_beginning_of_line() {
701             self.break_offset(n, off)
702         } else if off != 0 {
703             if let Some(last_token) = self.last_token_still_buffered() {
704                 if last_token.is_hardbreak_tok() {
705                     // We do something pretty sketchy here: tuck the nonzero
706                     // offset-adjustment we were going to deposit along with the
707                     // break into the previous hardbreak.
708                     self.replace_last_token_still_buffered(pp::Printer::hardbreak_tok_offset(off));
709                 }
710             }
711         }
712     }
713
714     fn nonterminal_to_string(&self, nt: &Nonterminal) -> String {
715         match *nt {
716             token::NtExpr(ref e) => self.expr_to_string(e),
717             token::NtMeta(ref e) => self.attr_item_to_string(e),
718             token::NtTy(ref e) => self.ty_to_string(e),
719             token::NtPath(ref e) => self.path_to_string(e),
720             token::NtItem(ref e) => self.item_to_string(e),
721             token::NtBlock(ref e) => self.block_to_string(e),
722             token::NtStmt(ref e) => self.stmt_to_string(e),
723             token::NtPat(ref e) => self.pat_to_string(e),
724             token::NtIdent(e, is_raw) => IdentPrinter::for_ast_ident(e, is_raw).to_string(),
725             token::NtLifetime(e) => e.to_string(),
726             token::NtLiteral(ref e) => self.expr_to_string(e),
727             token::NtVis(ref e) => self.vis_to_string(e),
728         }
729     }
730
731     /// Print the token kind precisely, without converting `$crate` into its respective crate name.
732     fn token_kind_to_string(&self, tok: &TokenKind) -> Cow<'static, str> {
733         self.token_kind_to_string_ext(tok, None)
734     }
735
736     fn token_kind_to_string_ext(
737         &self,
738         tok: &TokenKind,
739         convert_dollar_crate: Option<Span>,
740     ) -> Cow<'static, str> {
741         match *tok {
742             token::Eq => "=".into(),
743             token::Lt => "<".into(),
744             token::Le => "<=".into(),
745             token::EqEq => "==".into(),
746             token::Ne => "!=".into(),
747             token::Ge => ">=".into(),
748             token::Gt => ">".into(),
749             token::Not => "!".into(),
750             token::Tilde => "~".into(),
751             token::OrOr => "||".into(),
752             token::AndAnd => "&&".into(),
753             token::BinOp(op) => binop_to_string(op).into(),
754             token::BinOpEq(op) => format!("{}=", binop_to_string(op)).into(),
755
756             /* Structural symbols */
757             token::At => "@".into(),
758             token::Dot => ".".into(),
759             token::DotDot => "..".into(),
760             token::DotDotDot => "...".into(),
761             token::DotDotEq => "..=".into(),
762             token::Comma => ",".into(),
763             token::Semi => ";".into(),
764             token::Colon => ":".into(),
765             token::ModSep => "::".into(),
766             token::RArrow => "->".into(),
767             token::LArrow => "<-".into(),
768             token::FatArrow => "=>".into(),
769             token::OpenDelim(Delimiter::Parenthesis) => "(".into(),
770             token::CloseDelim(Delimiter::Parenthesis) => ")".into(),
771             token::OpenDelim(Delimiter::Bracket) => "[".into(),
772             token::CloseDelim(Delimiter::Bracket) => "]".into(),
773             token::OpenDelim(Delimiter::Brace) => "{".into(),
774             token::CloseDelim(Delimiter::Brace) => "}".into(),
775             token::OpenDelim(Delimiter::Invisible) | token::CloseDelim(Delimiter::Invisible) => {
776                 "".into()
777             }
778             token::Pound => "#".into(),
779             token::Dollar => "$".into(),
780             token::Question => "?".into(),
781             token::SingleQuote => "'".into(),
782
783             /* Literals */
784             token::Literal(lit) => literal_to_string(lit).into(),
785
786             /* Name components */
787             token::Ident(s, is_raw) => {
788                 IdentPrinter::new(s, is_raw, convert_dollar_crate).to_string().into()
789             }
790             token::Lifetime(s) => s.to_string().into(),
791
792             /* Other */
793             token::DocComment(comment_kind, attr_style, data) => {
794                 doc_comment_to_string(comment_kind, attr_style, data).into()
795             }
796             token::Eof => "<eof>".into(),
797
798             token::Interpolated(ref nt) => self.nonterminal_to_string(nt).into(),
799         }
800     }
801
802     /// Print the token precisely, without converting `$crate` into its respective crate name.
803     fn token_to_string(&self, token: &Token) -> Cow<'static, str> {
804         self.token_to_string_ext(token, false)
805     }
806
807     fn token_to_string_ext(&self, token: &Token, convert_dollar_crate: bool) -> Cow<'static, str> {
808         let convert_dollar_crate = convert_dollar_crate.then_some(token.span);
809         self.token_kind_to_string_ext(&token.kind, convert_dollar_crate)
810     }
811
812     fn ty_to_string(&self, ty: &ast::Ty) -> String {
813         Self::to_string(|s| s.print_type(ty))
814     }
815
816     fn bounds_to_string(&self, bounds: &[ast::GenericBound]) -> String {
817         Self::to_string(|s| s.print_type_bounds(bounds))
818     }
819
820     fn pat_to_string(&self, pat: &ast::Pat) -> String {
821         Self::to_string(|s| s.print_pat(pat))
822     }
823
824     fn expr_to_string(&self, e: &ast::Expr) -> String {
825         Self::to_string(|s| s.print_expr(e))
826     }
827
828     fn literal_to_string(&self, lit: &ast::Lit) -> String {
829         Self::to_string(|s| s.print_literal(lit))
830     }
831
832     fn tt_to_string(&self, tt: &TokenTree) -> String {
833         Self::to_string(|s| s.print_tt(tt, false))
834     }
835
836     fn tts_to_string(&self, tokens: &TokenStream) -> String {
837         Self::to_string(|s| s.print_tts(tokens, false))
838     }
839
840     fn stmt_to_string(&self, stmt: &ast::Stmt) -> String {
841         Self::to_string(|s| s.print_stmt(stmt))
842     }
843
844     fn item_to_string(&self, i: &ast::Item) -> String {
845         Self::to_string(|s| s.print_item(i))
846     }
847
848     fn assoc_item_to_string(&self, i: &ast::AssocItem) -> String {
849         Self::to_string(|s| s.print_assoc_item(i))
850     }
851
852     fn foreign_item_to_string(&self, i: &ast::ForeignItem) -> String {
853         Self::to_string(|s| s.print_foreign_item(i))
854     }
855
856     fn generic_params_to_string(&self, generic_params: &[ast::GenericParam]) -> String {
857         Self::to_string(|s| s.print_generic_params(generic_params))
858     }
859
860     fn path_to_string(&self, p: &ast::Path) -> String {
861         Self::to_string(|s| s.print_path(p, false, 0))
862     }
863
864     fn path_segment_to_string(&self, p: &ast::PathSegment) -> String {
865         Self::to_string(|s| s.print_path_segment(p, false))
866     }
867
868     fn vis_to_string(&self, v: &ast::Visibility) -> String {
869         Self::to_string(|s| s.print_visibility(v))
870     }
871
872     fn block_to_string(&self, blk: &ast::Block) -> String {
873         Self::to_string(|s| {
874             // Containing cbox, will be closed by `print_block` at `}`.
875             s.cbox(INDENT_UNIT);
876             // Head-ibox, will be closed by `print_block` after `{`.
877             s.ibox(0);
878             s.print_block(blk)
879         })
880     }
881
882     fn meta_list_item_to_string(&self, li: &ast::NestedMetaItem) -> String {
883         Self::to_string(|s| s.print_meta_list_item(li))
884     }
885
886     fn attr_item_to_string(&self, ai: &ast::AttrItem) -> String {
887         Self::to_string(|s| s.print_attr_item(ai, ai.path.span))
888     }
889
890     fn attribute_to_string(&self, attr: &ast::Attribute) -> String {
891         Self::to_string(|s| s.print_attribute(attr))
892     }
893
894     fn param_to_string(&self, arg: &ast::Param) -> String {
895         Self::to_string(|s| s.print_param(arg, false))
896     }
897
898     fn to_string(f: impl FnOnce(&mut State<'_>)) -> String {
899         let mut printer = State::new();
900         f(&mut printer);
901         printer.s.eof()
902     }
903 }
904
905 impl<'a> PrintState<'a> for State<'a> {
906     fn comments(&mut self) -> &mut Option<Comments<'a>> {
907         &mut self.comments
908     }
909
910     fn print_ident(&mut self, ident: Ident) {
911         self.word(IdentPrinter::for_ast_ident(ident, ident.is_raw_guess()).to_string());
912         self.ann.post(self, AnnNode::Ident(&ident))
913     }
914
915     fn print_generic_args(&mut self, args: &ast::GenericArgs, colons_before_params: bool) {
916         if colons_before_params {
917             self.word("::")
918         }
919
920         match *args {
921             ast::GenericArgs::AngleBracketed(ref data) => {
922                 self.word("<");
923                 self.commasep(Inconsistent, &data.args, |s, arg| match arg {
924                     ast::AngleBracketedArg::Arg(a) => s.print_generic_arg(a),
925                     ast::AngleBracketedArg::Constraint(c) => s.print_assoc_constraint(c),
926                 });
927                 self.word(">")
928             }
929
930             ast::GenericArgs::Parenthesized(ref data) => {
931                 self.word("(");
932                 self.commasep(Inconsistent, &data.inputs, |s, ty| s.print_type(ty));
933                 self.word(")");
934                 self.print_fn_ret_ty(&data.output);
935             }
936         }
937     }
938 }
939
940 impl<'a> State<'a> {
941     pub fn new() -> State<'a> {
942         State { s: pp::Printer::new(), comments: None, ann: &NoAnn }
943     }
944
945     pub(crate) fn commasep_cmnt<T, F, G>(
946         &mut self,
947         b: Breaks,
948         elts: &[T],
949         mut op: F,
950         mut get_span: G,
951     ) where
952         F: FnMut(&mut State<'_>, &T),
953         G: FnMut(&T) -> rustc_span::Span,
954     {
955         self.rbox(0, b);
956         let len = elts.len();
957         let mut i = 0;
958         for elt in elts {
959             self.maybe_print_comment(get_span(elt).hi());
960             op(self, elt);
961             i += 1;
962             if i < len {
963                 self.word(",");
964                 self.maybe_print_trailing_comment(get_span(elt), Some(get_span(&elts[i]).hi()));
965                 self.space_if_not_bol();
966             }
967         }
968         self.end();
969     }
970
971     pub(crate) fn commasep_exprs(&mut self, b: Breaks, exprs: &[P<ast::Expr>]) {
972         self.commasep_cmnt(b, exprs, |s, e| s.print_expr(e), |e| e.span)
973     }
974
975     pub fn print_opt_lifetime(&mut self, lifetime: &Option<ast::Lifetime>) {
976         if let Some(lt) = *lifetime {
977             self.print_lifetime(lt);
978             self.nbsp();
979         }
980     }
981
982     pub fn print_assoc_constraint(&mut self, constraint: &ast::AssocConstraint) {
983         self.print_ident(constraint.ident);
984         constraint.gen_args.as_ref().map(|args| self.print_generic_args(args, false));
985         self.space();
986         match &constraint.kind {
987             ast::AssocConstraintKind::Equality { term } => {
988                 self.word_space("=");
989                 match term {
990                     Term::Ty(ty) => self.print_type(ty),
991                     Term::Const(c) => self.print_expr_anon_const(c, &[]),
992                 }
993             }
994             ast::AssocConstraintKind::Bound { bounds } => {
995                 if !bounds.is_empty() {
996                     self.word_nbsp(":");
997                     self.print_type_bounds(&bounds);
998                 }
999             }
1000         }
1001     }
1002
1003     pub fn print_generic_arg(&mut self, generic_arg: &GenericArg) {
1004         match generic_arg {
1005             GenericArg::Lifetime(lt) => self.print_lifetime(*lt),
1006             GenericArg::Type(ty) => self.print_type(ty),
1007             GenericArg::Const(ct) => self.print_expr(&ct.value),
1008         }
1009     }
1010
1011     pub fn print_type(&mut self, ty: &ast::Ty) {
1012         self.maybe_print_comment(ty.span.lo());
1013         self.ibox(0);
1014         match ty.kind {
1015             ast::TyKind::Slice(ref ty) => {
1016                 self.word("[");
1017                 self.print_type(ty);
1018                 self.word("]");
1019             }
1020             ast::TyKind::Ptr(ref mt) => {
1021                 self.word("*");
1022                 self.print_mt(mt, true);
1023             }
1024             ast::TyKind::Rptr(ref lifetime, ref mt) => {
1025                 self.word("&");
1026                 self.print_opt_lifetime(lifetime);
1027                 self.print_mt(mt, false);
1028             }
1029             ast::TyKind::Never => {
1030                 self.word("!");
1031             }
1032             ast::TyKind::Tup(ref elts) => {
1033                 self.popen();
1034                 self.commasep(Inconsistent, &elts, |s, ty| s.print_type(ty));
1035                 if elts.len() == 1 {
1036                     self.word(",");
1037                 }
1038                 self.pclose();
1039             }
1040             ast::TyKind::Paren(ref typ) => {
1041                 self.popen();
1042                 self.print_type(typ);
1043                 self.pclose();
1044             }
1045             ast::TyKind::BareFn(ref f) => {
1046                 self.print_ty_fn(f.ext, f.unsafety, &f.decl, None, &f.generic_params);
1047             }
1048             ast::TyKind::Path(None, ref path) => {
1049                 self.print_path(path, false, 0);
1050             }
1051             ast::TyKind::Path(Some(ref qself), ref path) => self.print_qpath(path, qself, false),
1052             ast::TyKind::TraitObject(ref bounds, syntax) => {
1053                 if syntax == ast::TraitObjectSyntax::Dyn {
1054                     self.word_nbsp("dyn");
1055                 }
1056                 self.print_type_bounds(bounds);
1057             }
1058             ast::TyKind::ImplTrait(_, ref bounds) => {
1059                 self.word_nbsp("impl");
1060                 self.print_type_bounds(bounds);
1061             }
1062             ast::TyKind::Array(ref ty, ref length) => {
1063                 self.word("[");
1064                 self.print_type(ty);
1065                 self.word("; ");
1066                 self.print_expr(&length.value);
1067                 self.word("]");
1068             }
1069             ast::TyKind::Typeof(ref e) => {
1070                 self.word("typeof(");
1071                 self.print_expr(&e.value);
1072                 self.word(")");
1073             }
1074             ast::TyKind::Infer => {
1075                 self.word("_");
1076             }
1077             ast::TyKind::Err => {
1078                 self.popen();
1079                 self.word("/*ERROR*/");
1080                 self.pclose();
1081             }
1082             ast::TyKind::ImplicitSelf => {
1083                 self.word("Self");
1084             }
1085             ast::TyKind::MacCall(ref m) => {
1086                 self.print_mac(m);
1087             }
1088             ast::TyKind::CVarArgs => {
1089                 self.word("...");
1090             }
1091         }
1092         self.end();
1093     }
1094
1095     fn print_trait_ref(&mut self, t: &ast::TraitRef) {
1096         self.print_path(&t.path, false, 0)
1097     }
1098
1099     fn print_formal_generic_params(&mut self, generic_params: &[ast::GenericParam]) {
1100         if !generic_params.is_empty() {
1101             self.word("for");
1102             self.print_generic_params(generic_params);
1103             self.nbsp();
1104         }
1105     }
1106
1107     fn print_poly_trait_ref(&mut self, t: &ast::PolyTraitRef) {
1108         self.print_formal_generic_params(&t.bound_generic_params);
1109         self.print_trait_ref(&t.trait_ref)
1110     }
1111
1112     pub(crate) fn print_stmt(&mut self, st: &ast::Stmt) {
1113         self.maybe_print_comment(st.span.lo());
1114         match st.kind {
1115             ast::StmtKind::Local(ref loc) => {
1116                 self.print_outer_attributes(&loc.attrs);
1117                 self.space_if_not_bol();
1118                 self.ibox(INDENT_UNIT);
1119                 self.word_nbsp("let");
1120
1121                 self.ibox(INDENT_UNIT);
1122                 self.print_local_decl(loc);
1123                 self.end();
1124                 if let Some((init, els)) = loc.kind.init_else_opt() {
1125                     self.nbsp();
1126                     self.word_space("=");
1127                     self.print_expr(init);
1128                     if let Some(els) = els {
1129                         self.cbox(INDENT_UNIT);
1130                         self.ibox(INDENT_UNIT);
1131                         self.word(" else ");
1132                         self.print_block(els);
1133                     }
1134                 }
1135                 self.word(";");
1136                 self.end(); // `let` ibox
1137             }
1138             ast::StmtKind::Item(ref item) => self.print_item(item),
1139             ast::StmtKind::Expr(ref expr) => {
1140                 self.space_if_not_bol();
1141                 self.print_expr_outer_attr_style(expr, false);
1142                 if classify::expr_requires_semi_to_be_stmt(expr) {
1143                     self.word(";");
1144                 }
1145             }
1146             ast::StmtKind::Semi(ref expr) => {
1147                 self.space_if_not_bol();
1148                 self.print_expr_outer_attr_style(expr, false);
1149                 self.word(";");
1150             }
1151             ast::StmtKind::Empty => {
1152                 self.space_if_not_bol();
1153                 self.word(";");
1154             }
1155             ast::StmtKind::MacCall(ref mac) => {
1156                 self.space_if_not_bol();
1157                 self.print_outer_attributes(&mac.attrs);
1158                 self.print_mac(&mac.mac);
1159                 if mac.style == ast::MacStmtStyle::Semicolon {
1160                     self.word(";");
1161                 }
1162             }
1163         }
1164         self.maybe_print_trailing_comment(st.span, None)
1165     }
1166
1167     pub(crate) fn print_block(&mut self, blk: &ast::Block) {
1168         self.print_block_with_attrs(blk, &[])
1169     }
1170
1171     pub(crate) fn print_block_unclosed_indent(&mut self, blk: &ast::Block) {
1172         self.print_block_maybe_unclosed(blk, &[], false)
1173     }
1174
1175     pub(crate) fn print_block_with_attrs(&mut self, blk: &ast::Block, attrs: &[ast::Attribute]) {
1176         self.print_block_maybe_unclosed(blk, attrs, true)
1177     }
1178
1179     pub(crate) fn print_block_maybe_unclosed(
1180         &mut self,
1181         blk: &ast::Block,
1182         attrs: &[ast::Attribute],
1183         close_box: bool,
1184     ) {
1185         match blk.rules {
1186             BlockCheckMode::Unsafe(..) => self.word_space("unsafe"),
1187             BlockCheckMode::Default => (),
1188         }
1189         self.maybe_print_comment(blk.span.lo());
1190         self.ann.pre(self, AnnNode::Block(blk));
1191         self.bopen();
1192
1193         let has_attrs = self.print_inner_attributes(attrs);
1194
1195         for (i, st) in blk.stmts.iter().enumerate() {
1196             match st.kind {
1197                 ast::StmtKind::Expr(ref expr) if i == blk.stmts.len() - 1 => {
1198                     self.maybe_print_comment(st.span.lo());
1199                     self.space_if_not_bol();
1200                     self.print_expr_outer_attr_style(expr, false);
1201                     self.maybe_print_trailing_comment(expr.span, Some(blk.span.hi()));
1202                 }
1203                 _ => self.print_stmt(st),
1204             }
1205         }
1206
1207         let empty = !has_attrs && blk.stmts.is_empty();
1208         self.bclose_maybe_open(blk.span, empty, close_box);
1209         self.ann.post(self, AnnNode::Block(blk))
1210     }
1211
1212     /// Print a `let pat = expr` expression.
1213     pub(crate) fn print_let(&mut self, pat: &ast::Pat, expr: &ast::Expr) {
1214         self.word("let ");
1215         self.print_pat(pat);
1216         self.space();
1217         self.word_space("=");
1218         let npals = || parser::needs_par_as_let_scrutinee(expr.precedence().order());
1219         self.print_expr_cond_paren(expr, Self::cond_needs_par(expr) || npals())
1220     }
1221
1222     pub(crate) fn print_mac(&mut self, m: &ast::MacCall) {
1223         self.print_mac_common(
1224             Some(MacHeader::Path(&m.path)),
1225             true,
1226             None,
1227             m.args.delim(),
1228             &m.args.inner_tokens(),
1229             true,
1230             m.span(),
1231         );
1232     }
1233
1234     fn print_inline_asm(&mut self, asm: &ast::InlineAsm) {
1235         enum AsmArg<'a> {
1236             Template(String),
1237             Operand(&'a InlineAsmOperand),
1238             ClobberAbi(Symbol),
1239             Options(InlineAsmOptions),
1240         }
1241
1242         let mut args = vec![AsmArg::Template(InlineAsmTemplatePiece::to_string(&asm.template))];
1243         args.extend(asm.operands.iter().map(|(o, _)| AsmArg::Operand(o)));
1244         for (abi, _) in &asm.clobber_abis {
1245             args.push(AsmArg::ClobberAbi(*abi));
1246         }
1247         if !asm.options.is_empty() {
1248             args.push(AsmArg::Options(asm.options));
1249         }
1250
1251         self.popen();
1252         self.commasep(Consistent, &args, |s, arg| match arg {
1253             AsmArg::Template(template) => s.print_string(&template, ast::StrStyle::Cooked),
1254             AsmArg::Operand(op) => {
1255                 let print_reg_or_class = |s: &mut Self, r: &InlineAsmRegOrRegClass| match r {
1256                     InlineAsmRegOrRegClass::Reg(r) => s.print_symbol(*r, ast::StrStyle::Cooked),
1257                     InlineAsmRegOrRegClass::RegClass(r) => s.word(r.to_string()),
1258                 };
1259                 match op {
1260                     InlineAsmOperand::In { reg, expr } => {
1261                         s.word("in");
1262                         s.popen();
1263                         print_reg_or_class(s, reg);
1264                         s.pclose();
1265                         s.space();
1266                         s.print_expr(expr);
1267                     }
1268                     InlineAsmOperand::Out { reg, late, expr } => {
1269                         s.word(if *late { "lateout" } else { "out" });
1270                         s.popen();
1271                         print_reg_or_class(s, reg);
1272                         s.pclose();
1273                         s.space();
1274                         match expr {
1275                             Some(expr) => s.print_expr(expr),
1276                             None => s.word("_"),
1277                         }
1278                     }
1279                     InlineAsmOperand::InOut { reg, late, expr } => {
1280                         s.word(if *late { "inlateout" } else { "inout" });
1281                         s.popen();
1282                         print_reg_or_class(s, reg);
1283                         s.pclose();
1284                         s.space();
1285                         s.print_expr(expr);
1286                     }
1287                     InlineAsmOperand::SplitInOut { reg, late, in_expr, out_expr } => {
1288                         s.word(if *late { "inlateout" } else { "inout" });
1289                         s.popen();
1290                         print_reg_or_class(s, reg);
1291                         s.pclose();
1292                         s.space();
1293                         s.print_expr(in_expr);
1294                         s.space();
1295                         s.word_space("=>");
1296                         match out_expr {
1297                             Some(out_expr) => s.print_expr(out_expr),
1298                             None => s.word("_"),
1299                         }
1300                     }
1301                     InlineAsmOperand::Const { anon_const } => {
1302                         s.word("const");
1303                         s.space();
1304                         s.print_expr(&anon_const.value);
1305                     }
1306                     InlineAsmOperand::Sym { sym } => {
1307                         s.word("sym");
1308                         s.space();
1309                         if let Some(qself) = &sym.qself {
1310                             s.print_qpath(&sym.path, qself, true);
1311                         } else {
1312                             s.print_path(&sym.path, true, 0);
1313                         }
1314                     }
1315                 }
1316             }
1317             AsmArg::ClobberAbi(abi) => {
1318                 s.word("clobber_abi");
1319                 s.popen();
1320                 s.print_symbol(*abi, ast::StrStyle::Cooked);
1321                 s.pclose();
1322             }
1323             AsmArg::Options(opts) => {
1324                 s.word("options");
1325                 s.popen();
1326                 let mut options = vec![];
1327                 if opts.contains(InlineAsmOptions::PURE) {
1328                     options.push("pure");
1329                 }
1330                 if opts.contains(InlineAsmOptions::NOMEM) {
1331                     options.push("nomem");
1332                 }
1333                 if opts.contains(InlineAsmOptions::READONLY) {
1334                     options.push("readonly");
1335                 }
1336                 if opts.contains(InlineAsmOptions::PRESERVES_FLAGS) {
1337                     options.push("preserves_flags");
1338                 }
1339                 if opts.contains(InlineAsmOptions::NORETURN) {
1340                     options.push("noreturn");
1341                 }
1342                 if opts.contains(InlineAsmOptions::NOSTACK) {
1343                     options.push("nostack");
1344                 }
1345                 if opts.contains(InlineAsmOptions::ATT_SYNTAX) {
1346                     options.push("att_syntax");
1347                 }
1348                 if opts.contains(InlineAsmOptions::RAW) {
1349                     options.push("raw");
1350                 }
1351                 if opts.contains(InlineAsmOptions::MAY_UNWIND) {
1352                     options.push("may_unwind");
1353                 }
1354                 s.commasep(Inconsistent, &options, |s, &opt| {
1355                     s.word(opt);
1356                 });
1357                 s.pclose();
1358             }
1359         });
1360         self.pclose();
1361     }
1362
1363     pub(crate) fn print_local_decl(&mut self, loc: &ast::Local) {
1364         self.print_pat(&loc.pat);
1365         if let Some(ref ty) = loc.ty {
1366             self.word_space(":");
1367             self.print_type(ty);
1368         }
1369     }
1370
1371     pub(crate) fn print_name(&mut self, name: Symbol) {
1372         self.word(name.to_string());
1373         self.ann.post(self, AnnNode::Name(&name))
1374     }
1375
1376     fn print_qpath(&mut self, path: &ast::Path, qself: &ast::QSelf, colons_before_params: bool) {
1377         self.word("<");
1378         self.print_type(&qself.ty);
1379         if qself.position > 0 {
1380             self.space();
1381             self.word_space("as");
1382             let depth = path.segments.len() - qself.position;
1383             self.print_path(path, false, depth);
1384         }
1385         self.word(">");
1386         for item_segment in &path.segments[qself.position..] {
1387             self.word("::");
1388             self.print_ident(item_segment.ident);
1389             if let Some(ref args) = item_segment.args {
1390                 self.print_generic_args(args, colons_before_params)
1391             }
1392         }
1393     }
1394
1395     pub(crate) fn print_pat(&mut self, pat: &ast::Pat) {
1396         self.maybe_print_comment(pat.span.lo());
1397         self.ann.pre(self, AnnNode::Pat(pat));
1398         /* Pat isn't normalized, but the beauty of it
1399         is that it doesn't matter */
1400         match pat.kind {
1401             PatKind::Wild => self.word("_"),
1402             PatKind::Ident(binding_mode, ident, ref sub) => {
1403                 match binding_mode {
1404                     ast::BindingMode::ByRef(mutbl) => {
1405                         self.word_nbsp("ref");
1406                         self.print_mutability(mutbl, false);
1407                     }
1408                     ast::BindingMode::ByValue(ast::Mutability::Not) => {}
1409                     ast::BindingMode::ByValue(ast::Mutability::Mut) => {
1410                         self.word_nbsp("mut");
1411                     }
1412                 }
1413                 self.print_ident(ident);
1414                 if let Some(ref p) = *sub {
1415                     self.space();
1416                     self.word_space("@");
1417                     self.print_pat(p);
1418                 }
1419             }
1420             PatKind::TupleStruct(ref qself, ref path, ref elts) => {
1421                 if let Some(qself) = qself {
1422                     self.print_qpath(path, qself, true);
1423                 } else {
1424                     self.print_path(path, true, 0);
1425                 }
1426                 self.popen();
1427                 self.commasep(Inconsistent, &elts, |s, p| s.print_pat(p));
1428                 self.pclose();
1429             }
1430             PatKind::Or(ref pats) => {
1431                 self.strsep("|", true, Inconsistent, &pats, |s, p| s.print_pat(p));
1432             }
1433             PatKind::Path(None, ref path) => {
1434                 self.print_path(path, true, 0);
1435             }
1436             PatKind::Path(Some(ref qself), ref path) => {
1437                 self.print_qpath(path, qself, false);
1438             }
1439             PatKind::Struct(ref qself, ref path, ref fields, etc) => {
1440                 if let Some(qself) = qself {
1441                     self.print_qpath(path, qself, true);
1442                 } else {
1443                     self.print_path(path, true, 0);
1444                 }
1445                 self.nbsp();
1446                 self.word("{");
1447                 let empty = fields.is_empty() && !etc;
1448                 if !empty {
1449                     self.space();
1450                 }
1451                 self.commasep_cmnt(
1452                     Consistent,
1453                     &fields,
1454                     |s, f| {
1455                         s.cbox(INDENT_UNIT);
1456                         if !f.is_shorthand {
1457                             s.print_ident(f.ident);
1458                             s.word_nbsp(":");
1459                         }
1460                         s.print_pat(&f.pat);
1461                         s.end();
1462                     },
1463                     |f| f.pat.span,
1464                 );
1465                 if etc {
1466                     if !fields.is_empty() {
1467                         self.word_space(",");
1468                     }
1469                     self.word("..");
1470                 }
1471                 if !empty {
1472                     self.space();
1473                 }
1474                 self.word("}");
1475             }
1476             PatKind::Tuple(ref elts) => {
1477                 self.popen();
1478                 self.commasep(Inconsistent, &elts, |s, p| s.print_pat(p));
1479                 if elts.len() == 1 {
1480                     self.word(",");
1481                 }
1482                 self.pclose();
1483             }
1484             PatKind::Box(ref inner) => {
1485                 self.word("box ");
1486                 self.print_pat(inner);
1487             }
1488             PatKind::Ref(ref inner, mutbl) => {
1489                 self.word("&");
1490                 if mutbl == ast::Mutability::Mut {
1491                     self.word("mut ");
1492                 }
1493                 if let PatKind::Ident(ast::BindingMode::ByValue(ast::Mutability::Mut), ..) =
1494                     inner.kind
1495                 {
1496                     self.popen();
1497                     self.print_pat(inner);
1498                     self.pclose();
1499                 } else {
1500                     self.print_pat(inner);
1501                 }
1502             }
1503             PatKind::Lit(ref e) => self.print_expr(&**e),
1504             PatKind::Range(ref begin, ref end, Spanned { node: ref end_kind, .. }) => {
1505                 if let Some(e) = begin {
1506                     self.print_expr(e);
1507                 }
1508                 match *end_kind {
1509                     RangeEnd::Included(RangeSyntax::DotDotDot) => self.word("..."),
1510                     RangeEnd::Included(RangeSyntax::DotDotEq) => self.word("..="),
1511                     RangeEnd::Excluded => self.word(".."),
1512                 }
1513                 if let Some(e) = end {
1514                     self.print_expr(e);
1515                 }
1516             }
1517             PatKind::Slice(ref elts) => {
1518                 self.word("[");
1519                 self.commasep(Inconsistent, &elts, |s, p| s.print_pat(p));
1520                 self.word("]");
1521             }
1522             PatKind::Rest => self.word(".."),
1523             PatKind::Paren(ref inner) => {
1524                 self.popen();
1525                 self.print_pat(inner);
1526                 self.pclose();
1527             }
1528             PatKind::MacCall(ref m) => self.print_mac(m),
1529         }
1530         self.ann.post(self, AnnNode::Pat(pat))
1531     }
1532
1533     fn print_explicit_self(&mut self, explicit_self: &ast::ExplicitSelf) {
1534         match explicit_self.node {
1535             SelfKind::Value(m) => {
1536                 self.print_mutability(m, false);
1537                 self.word("self")
1538             }
1539             SelfKind::Region(ref lt, m) => {
1540                 self.word("&");
1541                 self.print_opt_lifetime(lt);
1542                 self.print_mutability(m, false);
1543                 self.word("self")
1544             }
1545             SelfKind::Explicit(ref typ, m) => {
1546                 self.print_mutability(m, false);
1547                 self.word("self");
1548                 self.word_space(":");
1549                 self.print_type(typ)
1550             }
1551         }
1552     }
1553
1554     pub(crate) fn print_asyncness(&mut self, asyncness: ast::Async) {
1555         if asyncness.is_async() {
1556             self.word_nbsp("async");
1557         }
1558     }
1559
1560     pub fn print_type_bounds(&mut self, bounds: &[ast::GenericBound]) {
1561         let mut first = true;
1562         for bound in bounds {
1563             if first {
1564                 first = false;
1565             } else {
1566                 self.nbsp();
1567                 self.word_space("+");
1568             }
1569
1570             match bound {
1571                 GenericBound::Trait(tref, modifier) => {
1572                     if modifier == &TraitBoundModifier::Maybe {
1573                         self.word("?");
1574                     }
1575                     self.print_poly_trait_ref(tref);
1576                 }
1577                 GenericBound::Outlives(lt) => self.print_lifetime(*lt),
1578             }
1579         }
1580     }
1581
1582     pub(crate) fn print_lifetime(&mut self, lifetime: ast::Lifetime) {
1583         self.print_name(lifetime.ident.name)
1584     }
1585
1586     pub(crate) fn print_lifetime_bounds(&mut self, bounds: &ast::GenericBounds) {
1587         for (i, bound) in bounds.iter().enumerate() {
1588             if i != 0 {
1589                 self.word(" + ");
1590             }
1591             match bound {
1592                 ast::GenericBound::Outlives(lt) => self.print_lifetime(*lt),
1593                 _ => panic!(),
1594             }
1595         }
1596     }
1597
1598     pub(crate) fn print_generic_params(&mut self, generic_params: &[ast::GenericParam]) {
1599         if generic_params.is_empty() {
1600             return;
1601         }
1602
1603         self.word("<");
1604
1605         self.commasep(Inconsistent, &generic_params, |s, param| {
1606             s.print_outer_attributes_inline(&param.attrs);
1607
1608             match param.kind {
1609                 ast::GenericParamKind::Lifetime => {
1610                     let lt = ast::Lifetime { id: param.id, ident: param.ident };
1611                     s.print_lifetime(lt);
1612                     if !param.bounds.is_empty() {
1613                         s.word_nbsp(":");
1614                         s.print_lifetime_bounds(&param.bounds)
1615                     }
1616                 }
1617                 ast::GenericParamKind::Type { ref default } => {
1618                     s.print_ident(param.ident);
1619                     if !param.bounds.is_empty() {
1620                         s.word_nbsp(":");
1621                         s.print_type_bounds(&param.bounds);
1622                     }
1623                     if let Some(ref default) = default {
1624                         s.space();
1625                         s.word_space("=");
1626                         s.print_type(default)
1627                     }
1628                 }
1629                 ast::GenericParamKind::Const { ref ty, kw_span: _, ref default } => {
1630                     s.word_space("const");
1631                     s.print_ident(param.ident);
1632                     s.space();
1633                     s.word_space(":");
1634                     s.print_type(ty);
1635                     if !param.bounds.is_empty() {
1636                         s.word_nbsp(":");
1637                         s.print_type_bounds(&param.bounds);
1638                     }
1639                     if let Some(ref default) = default {
1640                         s.space();
1641                         s.word_space("=");
1642                         s.print_expr(&default.value);
1643                     }
1644                 }
1645             }
1646         });
1647
1648         self.word(">");
1649     }
1650
1651     pub fn print_mutability(&mut self, mutbl: ast::Mutability, print_const: bool) {
1652         match mutbl {
1653             ast::Mutability::Mut => self.word_nbsp("mut"),
1654             ast::Mutability::Not => {
1655                 if print_const {
1656                     self.word_nbsp("const");
1657                 }
1658             }
1659         }
1660     }
1661
1662     pub(crate) fn print_mt(&mut self, mt: &ast::MutTy, print_const: bool) {
1663         self.print_mutability(mt.mutbl, print_const);
1664         self.print_type(&mt.ty)
1665     }
1666
1667     pub(crate) fn print_param(&mut self, input: &ast::Param, is_closure: bool) {
1668         self.ibox(INDENT_UNIT);
1669
1670         self.print_outer_attributes_inline(&input.attrs);
1671
1672         match input.ty.kind {
1673             ast::TyKind::Infer if is_closure => self.print_pat(&input.pat),
1674             _ => {
1675                 if let Some(eself) = input.to_self() {
1676                     self.print_explicit_self(&eself);
1677                 } else {
1678                     let invalid = if let PatKind::Ident(_, ident, _) = input.pat.kind {
1679                         ident.name == kw::Empty
1680                     } else {
1681                         false
1682                     };
1683                     if !invalid {
1684                         self.print_pat(&input.pat);
1685                         self.word(":");
1686                         self.space();
1687                     }
1688                     self.print_type(&input.ty);
1689                 }
1690             }
1691         }
1692         self.end();
1693     }
1694
1695     pub(crate) fn print_fn_ret_ty(&mut self, fn_ret_ty: &ast::FnRetTy) {
1696         if let ast::FnRetTy::Ty(ty) = fn_ret_ty {
1697             self.space_if_not_bol();
1698             self.ibox(INDENT_UNIT);
1699             self.word_space("->");
1700             self.print_type(ty);
1701             self.end();
1702             self.maybe_print_comment(ty.span.lo());
1703         }
1704     }
1705
1706     pub(crate) fn print_ty_fn(
1707         &mut self,
1708         ext: ast::Extern,
1709         unsafety: ast::Unsafe,
1710         decl: &ast::FnDecl,
1711         name: Option<Ident>,
1712         generic_params: &[ast::GenericParam],
1713     ) {
1714         self.ibox(INDENT_UNIT);
1715         self.print_formal_generic_params(generic_params);
1716         let generics = ast::Generics {
1717             params: Vec::new(),
1718             where_clause: ast::WhereClause {
1719                 has_where_token: false,
1720                 predicates: Vec::new(),
1721                 span: rustc_span::DUMMY_SP,
1722             },
1723             span: rustc_span::DUMMY_SP,
1724         };
1725         let header = ast::FnHeader { unsafety, ext, ..ast::FnHeader::default() };
1726         self.print_fn(decl, header, name, &generics);
1727         self.end();
1728     }
1729
1730     pub(crate) fn print_fn_header_info(&mut self, header: ast::FnHeader) {
1731         self.print_constness(header.constness);
1732         self.print_asyncness(header.asyncness);
1733         self.print_unsafety(header.unsafety);
1734
1735         match header.ext {
1736             ast::Extern::None => {}
1737             ast::Extern::Implicit(_) => {
1738                 self.word_nbsp("extern");
1739             }
1740             ast::Extern::Explicit(abi, _) => {
1741                 self.word_nbsp("extern");
1742                 self.print_literal(&abi.as_lit());
1743                 self.nbsp();
1744             }
1745         }
1746
1747         self.word("fn")
1748     }
1749
1750     pub(crate) fn print_unsafety(&mut self, s: ast::Unsafe) {
1751         match s {
1752             ast::Unsafe::No => {}
1753             ast::Unsafe::Yes(_) => self.word_nbsp("unsafe"),
1754         }
1755     }
1756
1757     pub(crate) fn print_constness(&mut self, s: ast::Const) {
1758         match s {
1759             ast::Const::No => {}
1760             ast::Const::Yes(_) => self.word_nbsp("const"),
1761         }
1762     }
1763
1764     pub(crate) fn print_is_auto(&mut self, s: ast::IsAuto) {
1765         match s {
1766             ast::IsAuto::Yes => self.word_nbsp("auto"),
1767             ast::IsAuto::No => {}
1768         }
1769     }
1770 }