]> git.lizzy.rs Git - rust.git/blob - compiler/rustc_ast_pretty/src/pprust/state.rs
991f6e0ba224340024055395ae91454109117a40
[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, AttrArgs, AttrArgsEq, BlockCheckMode, Mutability, PatKind};
15 use rustc_ast::{attr, BindingAnnotation, ByRef, DelimArgs, RangeEnd, RangeSyntax, Term};
16 use rustc_ast::{GenericArg, GenericBound, SelfKind, TraitBoundModifier};
17 use rustc_ast::{InlineAsmOperand, InlineAsmRegOrRegClass};
18 use rustc_ast::{InlineAsmOptions, InlineAsmTemplatePiece};
19 use rustc_span::edition::Edition;
20 use rustc_span::source_map::{SourceMap, Spanned};
21 use rustc_span::symbol::{kw, sym, Ident, IdentPrinter, Symbol};
22 use rustc_span::{BytePos, FileName, Span};
23
24 use rustc_ast::attr::AttrIdGenerator;
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     g: &AttrIdGenerator,
111 ) -> String {
112     let mut s =
113         State { s: pp::Printer::new(), comments: Some(Comments::new(sm, filename, input)), ann };
114
115     if is_expanded && !krate.attrs.iter().any(|attr| attr.has_name(sym::no_core)) {
116         // We need to print `#![no_std]` (and its feature gate) so that
117         // compiling pretty-printed source won't inject libstd again.
118         // However, we don't want these attributes in the AST because
119         // of the feature gate, so we fake them up here.
120
121         // `#![feature(prelude_import)]`
122         let pi_nested = attr::mk_nested_word_item(Ident::with_dummy_span(sym::prelude_import));
123         let list = attr::mk_list_item(Ident::with_dummy_span(sym::feature), vec![pi_nested]);
124         let fake_attr = attr::mk_attr_inner(g, list);
125         s.print_attribute(&fake_attr);
126
127         // Currently, in Rust 2018 we don't have `extern crate std;` at the crate
128         // root, so this is not needed, and actually breaks things.
129         if edition == Edition::Edition2015 {
130             // `#![no_std]`
131             let no_std_meta = attr::mk_word_item(Ident::with_dummy_span(sym::no_std));
132             let fake_attr = attr::mk_attr_inner(g, no_std_meta);
133             s.print_attribute(&fake_attr);
134         }
135     }
136
137     s.print_inner_attributes(&krate.attrs);
138     for item in &krate.items {
139         s.print_item(item);
140     }
141     s.print_remaining_comments();
142     s.ann.post(&mut s, AnnNode::Crate(krate));
143     s.s.eof()
144 }
145
146 /// This makes printed token streams look slightly nicer,
147 /// and also addresses some specific regressions described in #63896 and #73345.
148 fn tt_prepend_space(tt: &TokenTree, prev: &TokenTree) -> bool {
149     if let TokenTree::Token(token, _) = prev {
150         if matches!(token.kind, token::Dot | token::Dollar) {
151             return false;
152         }
153         if let token::DocComment(comment_kind, ..) = token.kind {
154             return comment_kind != CommentKind::Line;
155         }
156     }
157     match tt {
158         TokenTree::Token(token, _) => !matches!(token.kind, token::Comma | token::Not | token::Dot),
159         TokenTree::Delimited(_, Delimiter::Parenthesis, _) => {
160             !matches!(prev, TokenTree::Token(Token { kind: token::Ident(..), .. }, _))
161         }
162         TokenTree::Delimited(_, Delimiter::Bracket, _) => {
163             !matches!(prev, TokenTree::Token(Token { kind: token::Pound, .. }, _))
164         }
165         TokenTree::Delimited(..) => true,
166     }
167 }
168
169 fn binop_to_string(op: BinOpToken) -> &'static str {
170     match op {
171         token::Plus => "+",
172         token::Minus => "-",
173         token::Star => "*",
174         token::Slash => "/",
175         token::Percent => "%",
176         token::Caret => "^",
177         token::And => "&",
178         token::Or => "|",
179         token::Shl => "<<",
180         token::Shr => ">>",
181     }
182 }
183
184 fn doc_comment_to_string(
185     comment_kind: CommentKind,
186     attr_style: ast::AttrStyle,
187     data: Symbol,
188 ) -> String {
189     match (comment_kind, attr_style) {
190         (CommentKind::Line, ast::AttrStyle::Outer) => format!("///{}", data),
191         (CommentKind::Line, ast::AttrStyle::Inner) => format!("//!{}", data),
192         (CommentKind::Block, ast::AttrStyle::Outer) => format!("/**{}*/", data),
193         (CommentKind::Block, ast::AttrStyle::Inner) => format!("/*!{}*/", data),
194     }
195 }
196
197 pub fn literal_to_string(lit: token::Lit) -> String {
198     let token::Lit { kind, symbol, suffix } = lit;
199     let mut out = match kind {
200         token::Byte => format!("b'{}'", symbol),
201         token::Char => format!("'{}'", symbol),
202         token::Str => format!("\"{}\"", symbol),
203         token::StrRaw(n) => {
204             format!("r{delim}\"{string}\"{delim}", delim = "#".repeat(n as usize), string = symbol)
205         }
206         token::ByteStr => format!("b\"{}\"", symbol),
207         token::ByteStrRaw(n) => {
208             format!("br{delim}\"{string}\"{delim}", delim = "#".repeat(n as usize), string = symbol)
209         }
210         token::Integer | token::Float | token::Bool | token::Err => symbol.to_string(),
211     };
212
213     if let Some(suffix) = suffix {
214         out.push_str(suffix.as_str())
215     }
216
217     out
218 }
219
220 impl std::ops::Deref for State<'_> {
221     type Target = pp::Printer;
222     fn deref(&self) -> &Self::Target {
223         &self.s
224     }
225 }
226
227 impl std::ops::DerefMut for State<'_> {
228     fn deref_mut(&mut self) -> &mut Self::Target {
229         &mut self.s
230     }
231 }
232
233 pub trait PrintState<'a>: std::ops::Deref<Target = pp::Printer> + std::ops::DerefMut {
234     fn comments(&mut self) -> &mut Option<Comments<'a>>;
235     fn print_ident(&mut self, ident: Ident);
236     fn print_generic_args(&mut self, args: &ast::GenericArgs, colons_before_params: bool);
237
238     fn strsep<T, F>(
239         &mut self,
240         sep: &'static str,
241         space_before: bool,
242         b: Breaks,
243         elts: &[T],
244         mut op: F,
245     ) where
246         F: FnMut(&mut Self, &T),
247     {
248         self.rbox(0, b);
249         if let Some((first, rest)) = elts.split_first() {
250             op(self, first);
251             for elt in rest {
252                 if space_before {
253                     self.space();
254                 }
255                 self.word_space(sep);
256                 op(self, elt);
257             }
258         }
259         self.end();
260     }
261
262     fn commasep<T, F>(&mut self, b: Breaks, elts: &[T], op: F)
263     where
264         F: FnMut(&mut Self, &T),
265     {
266         self.strsep(",", false, b, elts, op)
267     }
268
269     fn maybe_print_comment(&mut self, pos: BytePos) -> bool {
270         let mut has_comment = false;
271         while let Some(ref cmnt) = self.next_comment() {
272             if cmnt.pos < pos {
273                 has_comment = true;
274                 self.print_comment(cmnt);
275             } else {
276                 break;
277             }
278         }
279         has_comment
280     }
281
282     fn print_comment(&mut self, cmnt: &Comment) {
283         match cmnt.style {
284             CommentStyle::Mixed => {
285                 if !self.is_beginning_of_line() {
286                     self.zerobreak();
287                 }
288                 if let Some((last, lines)) = cmnt.lines.split_last() {
289                     self.ibox(0);
290
291                     for line in lines {
292                         self.word(line.clone());
293                         self.hardbreak()
294                     }
295
296                     self.word(last.clone());
297                     self.space();
298
299                     self.end();
300                 }
301                 self.zerobreak()
302             }
303             CommentStyle::Isolated => {
304                 self.hardbreak_if_not_bol();
305                 for line in &cmnt.lines {
306                     // Don't print empty lines because they will end up as trailing
307                     // whitespace.
308                     if !line.is_empty() {
309                         self.word(line.clone());
310                     }
311                     self.hardbreak();
312                 }
313             }
314             CommentStyle::Trailing => {
315                 if !self.is_beginning_of_line() {
316                     self.word(" ");
317                 }
318                 if cmnt.lines.len() == 1 {
319                     self.word(cmnt.lines[0].clone());
320                     self.hardbreak()
321                 } else {
322                     self.visual_align();
323                     for line in &cmnt.lines {
324                         if !line.is_empty() {
325                             self.word(line.clone());
326                         }
327                         self.hardbreak();
328                     }
329                     self.end();
330                 }
331             }
332             CommentStyle::BlankLine => {
333                 // We need to do at least one, possibly two hardbreaks.
334                 let twice = match self.last_token() {
335                     Some(pp::Token::String(s)) => ";" == s,
336                     Some(pp::Token::Begin(_)) => true,
337                     Some(pp::Token::End) => true,
338                     _ => false,
339                 };
340                 if twice {
341                     self.hardbreak();
342                 }
343                 self.hardbreak();
344             }
345         }
346         if let Some(cmnts) = self.comments() {
347             cmnts.current += 1;
348         }
349     }
350
351     fn next_comment(&mut self) -> Option<Comment> {
352         self.comments().as_mut().and_then(|c| c.next())
353     }
354
355     fn maybe_print_trailing_comment(&mut self, span: rustc_span::Span, next_pos: Option<BytePos>) {
356         if let Some(cmnts) = self.comments() {
357             if let Some(cmnt) = cmnts.trailing_comment(span, next_pos) {
358                 self.print_comment(&cmnt);
359             }
360         }
361     }
362
363     fn print_remaining_comments(&mut self) {
364         // If there aren't any remaining comments, then we need to manually
365         // make sure there is a line break at the end.
366         if self.next_comment().is_none() {
367             self.hardbreak();
368         }
369         while let Some(ref cmnt) = self.next_comment() {
370             self.print_comment(cmnt)
371         }
372     }
373
374     fn print_literal(&mut self, lit: &ast::Lit) {
375         self.print_token_literal(lit.token_lit, lit.span)
376     }
377
378     fn print_token_literal(&mut self, token_lit: token::Lit, span: Span) {
379         self.maybe_print_comment(span.lo());
380         self.word(token_lit.to_string())
381     }
382
383     fn print_string(&mut self, st: &str, style: ast::StrStyle) {
384         let st = match style {
385             ast::StrStyle::Cooked => format!("\"{}\"", st.escape_debug()),
386             ast::StrStyle::Raw(n) => {
387                 format!("r{delim}\"{string}\"{delim}", delim = "#".repeat(n as usize), string = st)
388             }
389         };
390         self.word(st)
391     }
392
393     fn print_symbol(&mut self, sym: Symbol, style: ast::StrStyle) {
394         self.print_string(sym.as_str(), style);
395     }
396
397     fn print_inner_attributes(&mut self, attrs: &[ast::Attribute]) -> bool {
398         self.print_either_attributes(attrs, ast::AttrStyle::Inner, false, true)
399     }
400
401     fn print_inner_attributes_no_trailing_hardbreak(&mut self, attrs: &[ast::Attribute]) -> bool {
402         self.print_either_attributes(attrs, ast::AttrStyle::Inner, false, false)
403     }
404
405     fn print_outer_attributes(&mut self, attrs: &[ast::Attribute]) -> bool {
406         self.print_either_attributes(attrs, ast::AttrStyle::Outer, false, true)
407     }
408
409     fn print_inner_attributes_inline(&mut self, attrs: &[ast::Attribute]) -> bool {
410         self.print_either_attributes(attrs, ast::AttrStyle::Inner, true, true)
411     }
412
413     fn print_outer_attributes_inline(&mut self, attrs: &[ast::Attribute]) -> bool {
414         self.print_either_attributes(attrs, ast::AttrStyle::Outer, true, true)
415     }
416
417     fn print_either_attributes(
418         &mut self,
419         attrs: &[ast::Attribute],
420         kind: ast::AttrStyle,
421         is_inline: bool,
422         trailing_hardbreak: bool,
423     ) -> bool {
424         let mut printed = false;
425         for attr in attrs {
426             if attr.style == kind {
427                 self.print_attribute_inline(attr, is_inline);
428                 if is_inline {
429                     self.nbsp();
430                 }
431                 printed = true;
432             }
433         }
434         if printed && trailing_hardbreak && !is_inline {
435             self.hardbreak_if_not_bol();
436         }
437         printed
438     }
439
440     fn print_attribute(&mut self, attr: &ast::Attribute) {
441         self.print_attribute_inline(attr, false)
442     }
443
444     fn print_attribute_inline(&mut self, attr: &ast::Attribute, is_inline: bool) {
445         if !is_inline {
446             self.hardbreak_if_not_bol();
447         }
448         self.maybe_print_comment(attr.span.lo());
449         match attr.kind {
450             ast::AttrKind::Normal(ref normal) => {
451                 match attr.style {
452                     ast::AttrStyle::Inner => self.word("#!["),
453                     ast::AttrStyle::Outer => self.word("#["),
454                 }
455                 self.print_attr_item(&normal.item, attr.span);
456                 self.word("]");
457             }
458             ast::AttrKind::DocComment(comment_kind, data) => {
459                 self.word(doc_comment_to_string(comment_kind, attr.style, data));
460                 self.hardbreak()
461             }
462         }
463     }
464
465     fn print_attr_item(&mut self, item: &ast::AttrItem, span: Span) {
466         self.ibox(0);
467         match &item.args {
468             AttrArgs::Delimited(DelimArgs { dspan: _, delim, tokens }) => self.print_mac_common(
469                 Some(MacHeader::Path(&item.path)),
470                 false,
471                 None,
472                 delim.to_token(),
473                 tokens,
474                 true,
475                 span,
476             ),
477             AttrArgs::Empty => {
478                 self.print_path(&item.path, false, 0);
479             }
480             AttrArgs::Eq(_, AttrArgsEq::Ast(expr)) => {
481                 self.print_path(&item.path, false, 0);
482                 self.space();
483                 self.word_space("=");
484                 let token_str = self.expr_to_string(expr);
485                 self.word(token_str);
486             }
487             AttrArgs::Eq(_, AttrArgsEq::Hir(lit)) => {
488                 self.print_path(&item.path, false, 0);
489                 self.space();
490                 self.word_space("=");
491                 let token_str = self.literal_to_string(lit);
492                 self.word(token_str);
493             }
494         }
495         self.end();
496     }
497
498     fn print_meta_list_item(&mut self, item: &ast::NestedMetaItem) {
499         match item {
500             ast::NestedMetaItem::MetaItem(ref mi) => self.print_meta_item(mi),
501             ast::NestedMetaItem::Literal(ref lit) => self.print_literal(lit),
502         }
503     }
504
505     fn print_meta_item(&mut self, item: &ast::MetaItem) {
506         self.ibox(INDENT_UNIT);
507         match item.kind {
508             ast::MetaItemKind::Word => self.print_path(&item.path, false, 0),
509             ast::MetaItemKind::NameValue(ref value) => {
510                 self.print_path(&item.path, false, 0);
511                 self.space();
512                 self.word_space("=");
513                 self.print_literal(value);
514             }
515             ast::MetaItemKind::List(ref items) => {
516                 self.print_path(&item.path, false, 0);
517                 self.popen();
518                 self.commasep(Consistent, &items, |s, i| s.print_meta_list_item(i));
519                 self.pclose();
520             }
521         }
522         self.end();
523     }
524
525     /// This doesn't deserve to be called "pretty" printing, but it should be
526     /// meaning-preserving. A quick hack that might help would be to look at the
527     /// spans embedded in the TTs to decide where to put spaces and newlines.
528     /// But it'd be better to parse these according to the grammar of the
529     /// appropriate macro, transcribe back into the grammar we just parsed from,
530     /// and then pretty-print the resulting AST nodes (so, e.g., we print
531     /// expression arguments as expressions). It can be done! I think.
532     fn print_tt(&mut self, tt: &TokenTree, convert_dollar_crate: bool) {
533         match tt {
534             TokenTree::Token(token, _) => {
535                 let token_str = self.token_to_string_ext(&token, convert_dollar_crate);
536                 self.word(token_str);
537                 if let token::DocComment(..) = token.kind {
538                     self.hardbreak()
539                 }
540             }
541             TokenTree::Delimited(dspan, delim, tts) => {
542                 self.print_mac_common(
543                     None,
544                     false,
545                     None,
546                     *delim,
547                     tts,
548                     convert_dollar_crate,
549                     dspan.entire(),
550                 );
551             }
552         }
553     }
554
555     fn print_tts(&mut self, tts: &TokenStream, convert_dollar_crate: bool) {
556         let mut iter = tts.trees().peekable();
557         while let Some(tt) = iter.next() {
558             self.print_tt(tt, convert_dollar_crate);
559             if let Some(next) = iter.peek() {
560                 if tt_prepend_space(next, tt) {
561                     self.space();
562                 }
563             }
564         }
565     }
566
567     fn print_mac_common(
568         &mut self,
569         header: Option<MacHeader<'_>>,
570         has_bang: bool,
571         ident: Option<Ident>,
572         delim: Delimiter,
573         tts: &TokenStream,
574         convert_dollar_crate: bool,
575         span: Span,
576     ) {
577         if delim == Delimiter::Brace {
578             self.cbox(INDENT_UNIT);
579         }
580         match header {
581             Some(MacHeader::Path(path)) => self.print_path(path, false, 0),
582             Some(MacHeader::Keyword(kw)) => self.word(kw),
583             None => {}
584         }
585         if has_bang {
586             self.word("!");
587         }
588         if let Some(ident) = ident {
589             self.nbsp();
590             self.print_ident(ident);
591         }
592         match delim {
593             Delimiter::Brace => {
594                 if header.is_some() || has_bang || ident.is_some() {
595                     self.nbsp();
596                 }
597                 self.word("{");
598                 if !tts.is_empty() {
599                     self.space();
600                 }
601                 self.ibox(0);
602                 self.print_tts(tts, convert_dollar_crate);
603                 self.end();
604                 let empty = tts.is_empty();
605                 self.bclose(span, empty);
606             }
607             delim => {
608                 let token_str = self.token_kind_to_string(&token::OpenDelim(delim));
609                 self.word(token_str);
610                 self.ibox(0);
611                 self.print_tts(tts, convert_dollar_crate);
612                 self.end();
613                 let token_str = self.token_kind_to_string(&token::CloseDelim(delim));
614                 self.word(token_str);
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.to_token(),
637             &macro_def.body.tokens.clone(),
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.to_token(),
1228             &m.args.tokens.clone(),
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(BindingAnnotation(by_ref, mutbl), ident, ref sub) => {
1403                 if by_ref == ByRef::Yes {
1404                     self.word_nbsp("ref");
1405                 }
1406                 if mutbl == Mutability::Mut {
1407                     self.word_nbsp("mut");
1408                 }
1409                 self.print_ident(ident);
1410                 if let Some(ref p) = *sub {
1411                     self.space();
1412                     self.word_space("@");
1413                     self.print_pat(p);
1414                 }
1415             }
1416             PatKind::TupleStruct(ref qself, ref path, ref elts) => {
1417                 if let Some(qself) = qself {
1418                     self.print_qpath(path, qself, true);
1419                 } else {
1420                     self.print_path(path, true, 0);
1421                 }
1422                 self.popen();
1423                 self.commasep(Inconsistent, &elts, |s, p| s.print_pat(p));
1424                 self.pclose();
1425             }
1426             PatKind::Or(ref pats) => {
1427                 self.strsep("|", true, Inconsistent, &pats, |s, p| s.print_pat(p));
1428             }
1429             PatKind::Path(None, ref path) => {
1430                 self.print_path(path, true, 0);
1431             }
1432             PatKind::Path(Some(ref qself), ref path) => {
1433                 self.print_qpath(path, qself, false);
1434             }
1435             PatKind::Struct(ref qself, ref path, ref fields, etc) => {
1436                 if let Some(qself) = qself {
1437                     self.print_qpath(path, qself, true);
1438                 } else {
1439                     self.print_path(path, true, 0);
1440                 }
1441                 self.nbsp();
1442                 self.word("{");
1443                 let empty = fields.is_empty() && !etc;
1444                 if !empty {
1445                     self.space();
1446                 }
1447                 self.commasep_cmnt(
1448                     Consistent,
1449                     &fields,
1450                     |s, f| {
1451                         s.cbox(INDENT_UNIT);
1452                         if !f.is_shorthand {
1453                             s.print_ident(f.ident);
1454                             s.word_nbsp(":");
1455                         }
1456                         s.print_pat(&f.pat);
1457                         s.end();
1458                     },
1459                     |f| f.pat.span,
1460                 );
1461                 if etc {
1462                     if !fields.is_empty() {
1463                         self.word_space(",");
1464                     }
1465                     self.word("..");
1466                 }
1467                 if !empty {
1468                     self.space();
1469                 }
1470                 self.word("}");
1471             }
1472             PatKind::Tuple(ref elts) => {
1473                 self.popen();
1474                 self.commasep(Inconsistent, &elts, |s, p| s.print_pat(p));
1475                 if elts.len() == 1 {
1476                     self.word(",");
1477                 }
1478                 self.pclose();
1479             }
1480             PatKind::Box(ref inner) => {
1481                 self.word("box ");
1482                 self.print_pat(inner);
1483             }
1484             PatKind::Ref(ref inner, mutbl) => {
1485                 self.word("&");
1486                 if mutbl == Mutability::Mut {
1487                     self.word("mut ");
1488                 }
1489                 if let PatKind::Ident(ast::BindingAnnotation::MUT, ..) = inner.kind {
1490                     self.popen();
1491                     self.print_pat(inner);
1492                     self.pclose();
1493                 } else {
1494                     self.print_pat(inner);
1495                 }
1496             }
1497             PatKind::Lit(ref e) => self.print_expr(&**e),
1498             PatKind::Range(ref begin, ref end, Spanned { node: ref end_kind, .. }) => {
1499                 if let Some(e) = begin {
1500                     self.print_expr(e);
1501                 }
1502                 match *end_kind {
1503                     RangeEnd::Included(RangeSyntax::DotDotDot) => self.word("..."),
1504                     RangeEnd::Included(RangeSyntax::DotDotEq) => self.word("..="),
1505                     RangeEnd::Excluded => self.word(".."),
1506                 }
1507                 if let Some(e) = end {
1508                     self.print_expr(e);
1509                 }
1510             }
1511             PatKind::Slice(ref elts) => {
1512                 self.word("[");
1513                 self.commasep(Inconsistent, &elts, |s, p| s.print_pat(p));
1514                 self.word("]");
1515             }
1516             PatKind::Rest => self.word(".."),
1517             PatKind::Paren(ref inner) => {
1518                 self.popen();
1519                 self.print_pat(inner);
1520                 self.pclose();
1521             }
1522             PatKind::MacCall(ref m) => self.print_mac(m),
1523         }
1524         self.ann.post(self, AnnNode::Pat(pat))
1525     }
1526
1527     fn print_explicit_self(&mut self, explicit_self: &ast::ExplicitSelf) {
1528         match explicit_self.node {
1529             SelfKind::Value(m) => {
1530                 self.print_mutability(m, false);
1531                 self.word("self")
1532             }
1533             SelfKind::Region(ref lt, m) => {
1534                 self.word("&");
1535                 self.print_opt_lifetime(lt);
1536                 self.print_mutability(m, false);
1537                 self.word("self")
1538             }
1539             SelfKind::Explicit(ref typ, m) => {
1540                 self.print_mutability(m, false);
1541                 self.word("self");
1542                 self.word_space(":");
1543                 self.print_type(typ)
1544             }
1545         }
1546     }
1547
1548     pub(crate) fn print_asyncness(&mut self, asyncness: ast::Async) {
1549         if asyncness.is_async() {
1550             self.word_nbsp("async");
1551         }
1552     }
1553
1554     pub fn print_type_bounds(&mut self, bounds: &[ast::GenericBound]) {
1555         let mut first = true;
1556         for bound in bounds {
1557             if first {
1558                 first = false;
1559             } else {
1560                 self.nbsp();
1561                 self.word_space("+");
1562             }
1563
1564             match bound {
1565                 GenericBound::Trait(tref, modifier) => {
1566                     if modifier == &TraitBoundModifier::Maybe {
1567                         self.word("?");
1568                     }
1569                     self.print_poly_trait_ref(tref);
1570                 }
1571                 GenericBound::Outlives(lt) => self.print_lifetime(*lt),
1572             }
1573         }
1574     }
1575
1576     pub(crate) fn print_lifetime(&mut self, lifetime: ast::Lifetime) {
1577         self.print_name(lifetime.ident.name)
1578     }
1579
1580     pub(crate) fn print_lifetime_bounds(&mut self, bounds: &ast::GenericBounds) {
1581         for (i, bound) in bounds.iter().enumerate() {
1582             if i != 0 {
1583                 self.word(" + ");
1584             }
1585             match bound {
1586                 ast::GenericBound::Outlives(lt) => self.print_lifetime(*lt),
1587                 _ => panic!(),
1588             }
1589         }
1590     }
1591
1592     pub(crate) fn print_generic_params(&mut self, generic_params: &[ast::GenericParam]) {
1593         if generic_params.is_empty() {
1594             return;
1595         }
1596
1597         self.word("<");
1598
1599         self.commasep(Inconsistent, &generic_params, |s, param| {
1600             s.print_outer_attributes_inline(&param.attrs);
1601
1602             match param.kind {
1603                 ast::GenericParamKind::Lifetime => {
1604                     let lt = ast::Lifetime { id: param.id, ident: param.ident };
1605                     s.print_lifetime(lt);
1606                     if !param.bounds.is_empty() {
1607                         s.word_nbsp(":");
1608                         s.print_lifetime_bounds(&param.bounds)
1609                     }
1610                 }
1611                 ast::GenericParamKind::Type { ref default } => {
1612                     s.print_ident(param.ident);
1613                     if !param.bounds.is_empty() {
1614                         s.word_nbsp(":");
1615                         s.print_type_bounds(&param.bounds);
1616                     }
1617                     if let Some(ref default) = default {
1618                         s.space();
1619                         s.word_space("=");
1620                         s.print_type(default)
1621                     }
1622                 }
1623                 ast::GenericParamKind::Const { ref ty, kw_span: _, ref default } => {
1624                     s.word_space("const");
1625                     s.print_ident(param.ident);
1626                     s.space();
1627                     s.word_space(":");
1628                     s.print_type(ty);
1629                     if !param.bounds.is_empty() {
1630                         s.word_nbsp(":");
1631                         s.print_type_bounds(&param.bounds);
1632                     }
1633                     if let Some(ref default) = default {
1634                         s.space();
1635                         s.word_space("=");
1636                         s.print_expr(&default.value);
1637                     }
1638                 }
1639             }
1640         });
1641
1642         self.word(">");
1643     }
1644
1645     pub fn print_mutability(&mut self, mutbl: ast::Mutability, print_const: bool) {
1646         match mutbl {
1647             ast::Mutability::Mut => self.word_nbsp("mut"),
1648             ast::Mutability::Not => {
1649                 if print_const {
1650                     self.word_nbsp("const");
1651                 }
1652             }
1653         }
1654     }
1655
1656     pub(crate) fn print_mt(&mut self, mt: &ast::MutTy, print_const: bool) {
1657         self.print_mutability(mt.mutbl, print_const);
1658         self.print_type(&mt.ty)
1659     }
1660
1661     pub(crate) fn print_param(&mut self, input: &ast::Param, is_closure: bool) {
1662         self.ibox(INDENT_UNIT);
1663
1664         self.print_outer_attributes_inline(&input.attrs);
1665
1666         match input.ty.kind {
1667             ast::TyKind::Infer if is_closure => self.print_pat(&input.pat),
1668             _ => {
1669                 if let Some(eself) = input.to_self() {
1670                     self.print_explicit_self(&eself);
1671                 } else {
1672                     let invalid = if let PatKind::Ident(_, ident, _) = input.pat.kind {
1673                         ident.name == kw::Empty
1674                     } else {
1675                         false
1676                     };
1677                     if !invalid {
1678                         self.print_pat(&input.pat);
1679                         self.word(":");
1680                         self.space();
1681                     }
1682                     self.print_type(&input.ty);
1683                 }
1684             }
1685         }
1686         self.end();
1687     }
1688
1689     pub(crate) fn print_fn_ret_ty(&mut self, fn_ret_ty: &ast::FnRetTy) {
1690         if let ast::FnRetTy::Ty(ty) = fn_ret_ty {
1691             self.space_if_not_bol();
1692             self.ibox(INDENT_UNIT);
1693             self.word_space("->");
1694             self.print_type(ty);
1695             self.end();
1696             self.maybe_print_comment(ty.span.lo());
1697         }
1698     }
1699
1700     pub(crate) fn print_ty_fn(
1701         &mut self,
1702         ext: ast::Extern,
1703         unsafety: ast::Unsafe,
1704         decl: &ast::FnDecl,
1705         name: Option<Ident>,
1706         generic_params: &[ast::GenericParam],
1707     ) {
1708         self.ibox(INDENT_UNIT);
1709         self.print_formal_generic_params(generic_params);
1710         let generics = ast::Generics {
1711             params: Vec::new(),
1712             where_clause: ast::WhereClause {
1713                 has_where_token: false,
1714                 predicates: Vec::new(),
1715                 span: rustc_span::DUMMY_SP,
1716             },
1717             span: rustc_span::DUMMY_SP,
1718         };
1719         let header = ast::FnHeader { unsafety, ext, ..ast::FnHeader::default() };
1720         self.print_fn(decl, header, name, &generics);
1721         self.end();
1722     }
1723
1724     pub(crate) fn print_fn_header_info(&mut self, header: ast::FnHeader) {
1725         self.print_constness(header.constness);
1726         self.print_asyncness(header.asyncness);
1727         self.print_unsafety(header.unsafety);
1728
1729         match header.ext {
1730             ast::Extern::None => {}
1731             ast::Extern::Implicit(_) => {
1732                 self.word_nbsp("extern");
1733             }
1734             ast::Extern::Explicit(abi, _) => {
1735                 self.word_nbsp("extern");
1736                 self.print_token_literal(abi.as_token_lit(), abi.span);
1737                 self.nbsp();
1738             }
1739         }
1740
1741         self.word("fn")
1742     }
1743
1744     pub(crate) fn print_unsafety(&mut self, s: ast::Unsafe) {
1745         match s {
1746             ast::Unsafe::No => {}
1747             ast::Unsafe::Yes(_) => self.word_nbsp("unsafe"),
1748         }
1749     }
1750
1751     pub(crate) fn print_constness(&mut self, s: ast::Const) {
1752         match s {
1753             ast::Const::No => {}
1754             ast::Const::Yes(_) => self.word_nbsp("const"),
1755         }
1756     }
1757
1758     pub(crate) fn print_is_auto(&mut self, s: ast::IsAuto) {
1759         match s {
1760             ast::IsAuto::Yes => self.word_nbsp("auto"),
1761             ast::IsAuto::No => {}
1762         }
1763     }
1764 }