]> git.lizzy.rs Git - rust.git/blob - compiler/rustc_ast_pretty/src/pprust/state.rs
Auto merge of #91924 - Aaron1011:serialize-adt-def, r=michaelwoerister
[rust.git] / compiler / rustc_ast_pretty / src / pprust / state.rs
1 use crate::pp::Breaks::{Consistent, Inconsistent};
2 use crate::pp::{self, Breaks};
3
4 use rustc_ast::attr;
5 use rustc_ast::ptr::P;
6 use rustc_ast::token::{self, BinOpToken, CommentKind, DelimToken, Nonterminal, Token, TokenKind};
7 use rustc_ast::tokenstream::{TokenStream, TokenTree};
8 use rustc_ast::util::classify;
9 use rustc_ast::util::comments::{gather_comments, Comment, CommentStyle};
10 use rustc_ast::util::parser::{self, AssocOp, Fixity};
11 use rustc_ast::{self as ast, BlockCheckMode, PatKind, RangeEnd, RangeSyntax};
12 use rustc_ast::{GenericArg, MacArgs, ModKind};
13 use rustc_ast::{GenericBound, SelfKind, TraitBoundModifier};
14 use rustc_ast::{InlineAsmOperand, InlineAsmRegOrRegClass};
15 use rustc_ast::{InlineAsmOptions, InlineAsmTemplatePiece};
16 use rustc_span::edition::Edition;
17 use rustc_span::source_map::{SourceMap, Spanned};
18 use rustc_span::symbol::{kw, sym, Ident, IdentPrinter, Symbol};
19 use rustc_span::{BytePos, FileName, Span};
20
21 use std::borrow::Cow;
22
23 pub enum MacHeader<'a> {
24     Path(&'a ast::Path),
25     Keyword(&'static str),
26 }
27
28 pub enum AnnNode<'a> {
29     Ident(&'a Ident),
30     Name(&'a Symbol),
31     Block(&'a ast::Block),
32     Item(&'a ast::Item),
33     SubItem(ast::NodeId),
34     Expr(&'a ast::Expr),
35     Pat(&'a ast::Pat),
36     Crate(&'a ast::Crate),
37 }
38
39 pub trait PpAnn {
40     fn pre(&self, _state: &mut State<'_>, _node: AnnNode<'_>) {}
41     fn post(&self, _state: &mut State<'_>, _node: AnnNode<'_>) {}
42 }
43
44 #[derive(Copy, Clone)]
45 pub struct NoAnn;
46
47 impl PpAnn for NoAnn {}
48
49 pub struct Comments<'a> {
50     sm: &'a SourceMap,
51     comments: Vec<Comment>,
52     current: usize,
53 }
54
55 impl<'a> Comments<'a> {
56     pub fn new(sm: &'a SourceMap, filename: FileName, input: String) -> Comments<'a> {
57         let comments = gather_comments(sm, filename, input);
58         Comments { sm, comments, current: 0 }
59     }
60
61     pub fn next(&self) -> Option<Comment> {
62         self.comments.get(self.current).cloned()
63     }
64
65     pub fn trailing_comment(
66         &self,
67         span: rustc_span::Span,
68         next_pos: Option<BytePos>,
69     ) -> Option<Comment> {
70         if let Some(cmnt) = self.next() {
71             if cmnt.style != CommentStyle::Trailing {
72                 return None;
73             }
74             let span_line = self.sm.lookup_char_pos(span.hi());
75             let comment_line = self.sm.lookup_char_pos(cmnt.pos);
76             let next = next_pos.unwrap_or_else(|| cmnt.pos + BytePos(1));
77             if span.hi() < cmnt.pos && cmnt.pos < next && span_line.line == comment_line.line {
78                 return Some(cmnt);
79             }
80         }
81
82         None
83     }
84 }
85
86 pub struct State<'a> {
87     pub s: pp::Printer,
88     comments: Option<Comments<'a>>,
89     ann: &'a (dyn PpAnn + 'a),
90 }
91
92 crate const INDENT_UNIT: usize = 4;
93
94 /// Requires you to pass an input filename and reader so that
95 /// it can scan the input text for comments to copy forward.
96 pub fn print_crate<'a>(
97     sm: &'a SourceMap,
98     krate: &ast::Crate,
99     filename: FileName,
100     input: String,
101     ann: &'a dyn PpAnn,
102     is_expanded: bool,
103     edition: Edition,
104 ) -> String {
105     let mut s =
106         State { s: pp::mk_printer(), comments: Some(Comments::new(sm, filename, input)), ann };
107
108     if is_expanded && !krate.attrs.iter().any(|attr| attr.has_name(sym::no_core)) {
109         // We need to print `#![no_std]` (and its feature gate) so that
110         // compiling pretty-printed source won't inject libstd again.
111         // However, we don't want these attributes in the AST because
112         // of the feature gate, so we fake them up here.
113
114         // `#![feature(prelude_import)]`
115         let pi_nested = attr::mk_nested_word_item(Ident::with_dummy_span(sym::prelude_import));
116         let list = attr::mk_list_item(Ident::with_dummy_span(sym::feature), vec![pi_nested]);
117         let fake_attr = attr::mk_attr_inner(list);
118         s.print_attribute(&fake_attr);
119
120         // Currently, in Rust 2018 we don't have `extern crate std;` at the crate
121         // root, so this is not needed, and actually breaks things.
122         if edition == Edition::Edition2015 {
123             // `#![no_std]`
124             let no_std_meta = attr::mk_word_item(Ident::with_dummy_span(sym::no_std));
125             let fake_attr = attr::mk_attr_inner(no_std_meta);
126             s.print_attribute(&fake_attr);
127         }
128     }
129
130     s.print_inner_attributes(&krate.attrs);
131     for item in &krate.items {
132         s.print_item(item);
133     }
134     s.print_remaining_comments();
135     s.ann.post(&mut s, AnnNode::Crate(krate));
136     s.s.eof()
137 }
138
139 /// This makes printed token streams look slightly nicer,
140 /// and also addresses some specific regressions described in #63896 and #73345.
141 fn tt_prepend_space(tt: &TokenTree, prev: &TokenTree) -> bool {
142     if let TokenTree::Token(token) = prev {
143         if matches!(token.kind, token::Dot | token::Dollar) {
144             return false;
145         }
146         if let token::DocComment(comment_kind, ..) = token.kind {
147             return comment_kind != CommentKind::Line;
148         }
149     }
150     match tt {
151         TokenTree::Token(token) => !matches!(token.kind, token::Comma | token::Not | token::Dot),
152         TokenTree::Delimited(_, DelimToken::Paren, _) => {
153             !matches!(prev, TokenTree::Token(Token { kind: token::Ident(..), .. }))
154         }
155         TokenTree::Delimited(_, DelimToken::Bracket, _) => {
156             !matches!(prev, TokenTree::Token(Token { kind: token::Pound, .. }))
157         }
158         TokenTree::Delimited(..) => true,
159     }
160 }
161
162 fn binop_to_string(op: BinOpToken) -> &'static str {
163     match op {
164         token::Plus => "+",
165         token::Minus => "-",
166         token::Star => "*",
167         token::Slash => "/",
168         token::Percent => "%",
169         token::Caret => "^",
170         token::And => "&",
171         token::Or => "|",
172         token::Shl => "<<",
173         token::Shr => ">>",
174     }
175 }
176
177 fn doc_comment_to_string(
178     comment_kind: CommentKind,
179     attr_style: ast::AttrStyle,
180     data: Symbol,
181 ) -> String {
182     match (comment_kind, attr_style) {
183         (CommentKind::Line, ast::AttrStyle::Outer) => format!("///{}", data),
184         (CommentKind::Line, ast::AttrStyle::Inner) => format!("//!{}", data),
185         (CommentKind::Block, ast::AttrStyle::Outer) => format!("/**{}*/", data),
186         (CommentKind::Block, ast::AttrStyle::Inner) => format!("/*!{}*/", data),
187     }
188 }
189
190 pub fn literal_to_string(lit: token::Lit) -> String {
191     let token::Lit { kind, symbol, suffix } = lit;
192     let mut out = match kind {
193         token::Byte => format!("b'{}'", symbol),
194         token::Char => format!("'{}'", symbol),
195         token::Str => format!("\"{}\"", symbol),
196         token::StrRaw(n) => {
197             format!("r{delim}\"{string}\"{delim}", delim = "#".repeat(n as usize), string = symbol)
198         }
199         token::ByteStr => format!("b\"{}\"", symbol),
200         token::ByteStrRaw(n) => {
201             format!("br{delim}\"{string}\"{delim}", delim = "#".repeat(n as usize), string = symbol)
202         }
203         token::Integer | token::Float | token::Bool | token::Err => symbol.to_string(),
204     };
205
206     if let Some(suffix) = suffix {
207         out.push_str(suffix.as_str())
208     }
209
210     out
211 }
212
213 fn visibility_qualified(vis: &ast::Visibility, s: &str) -> String {
214     format!("{}{}", State::new().to_string(|s| s.print_visibility(vis)), s)
215 }
216
217 impl std::ops::Deref for State<'_> {
218     type Target = pp::Printer;
219     fn deref(&self) -> &Self::Target {
220         &self.s
221     }
222 }
223
224 impl std::ops::DerefMut for State<'_> {
225     fn deref_mut(&mut self) -> &mut Self::Target {
226         &mut self.s
227     }
228 }
229
230 pub trait PrintState<'a>: std::ops::Deref<Target = pp::Printer> + std::ops::DerefMut {
231     fn comments(&mut self) -> &mut Option<Comments<'a>>;
232     fn print_ident(&mut self, ident: Ident);
233     fn print_generic_args(&mut self, args: &ast::GenericArgs, colons_before_params: bool);
234
235     fn strsep<T, F>(
236         &mut self,
237         sep: &'static str,
238         space_before: bool,
239         b: Breaks,
240         elts: &[T],
241         mut op: F,
242     ) where
243         F: FnMut(&mut Self, &T),
244     {
245         self.rbox(0, b);
246         if let Some((first, rest)) = elts.split_first() {
247             op(self, first);
248             for elt in rest {
249                 if space_before {
250                     self.space();
251                 }
252                 self.word_space(sep);
253                 op(self, elt);
254             }
255         }
256         self.end();
257     }
258
259     fn commasep<T, F>(&mut self, b: Breaks, elts: &[T], op: F)
260     where
261         F: FnMut(&mut Self, &T),
262     {
263         self.strsep(",", false, b, elts, op)
264     }
265
266     fn maybe_print_comment(&mut self, pos: BytePos) -> bool {
267         let mut has_comment = false;
268         while let Some(ref cmnt) = self.next_comment() {
269             if cmnt.pos < pos {
270                 has_comment = true;
271                 self.print_comment(cmnt);
272             } else {
273                 break;
274             }
275         }
276         has_comment
277     }
278
279     fn print_comment(&mut self, cmnt: &Comment) {
280         match cmnt.style {
281             CommentStyle::Mixed => {
282                 if !self.is_beginning_of_line() {
283                     self.zerobreak();
284                 }
285                 if let Some((last, lines)) = cmnt.lines.split_last() {
286                     self.ibox(0);
287
288                     for line in lines {
289                         self.word(line.clone());
290                         self.hardbreak()
291                     }
292
293                     self.word(last.clone());
294                     self.space();
295
296                     self.end();
297                 }
298                 self.zerobreak()
299             }
300             CommentStyle::Isolated => {
301                 self.hardbreak_if_not_bol();
302                 for line in &cmnt.lines {
303                     // Don't print empty lines because they will end up as trailing
304                     // whitespace.
305                     if !line.is_empty() {
306                         self.word(line.clone());
307                     }
308                     self.hardbreak();
309                 }
310             }
311             CommentStyle::Trailing => {
312                 if !self.is_beginning_of_line() {
313                     self.word(" ");
314                 }
315                 if cmnt.lines.len() == 1 {
316                     self.word(cmnt.lines[0].clone());
317                     self.hardbreak()
318                 } else {
319                     self.ibox(0);
320                     for line in &cmnt.lines {
321                         if !line.is_empty() {
322                             self.word(line.clone());
323                         }
324                         self.hardbreak();
325                     }
326                     self.end();
327                 }
328             }
329             CommentStyle::BlankLine => {
330                 // We need to do at least one, possibly two hardbreaks.
331                 let twice = match self.last_token() {
332                     pp::Token::String(s) => ";" == s,
333                     pp::Token::Begin(_) => true,
334                     pp::Token::End => true,
335                     _ => false,
336                 };
337                 if twice {
338                     self.hardbreak();
339                 }
340                 self.hardbreak();
341             }
342         }
343         if let Some(cmnts) = self.comments() {
344             cmnts.current += 1;
345         }
346     }
347
348     fn next_comment(&mut self) -> Option<Comment> {
349         self.comments().as_mut().and_then(|c| c.next())
350     }
351
352     fn maybe_print_trailing_comment(&mut self, span: rustc_span::Span, next_pos: Option<BytePos>) {
353         if let Some(cmnts) = self.comments() {
354             if let Some(cmnt) = cmnts.trailing_comment(span, next_pos) {
355                 self.print_comment(&cmnt);
356             }
357         }
358     }
359
360     fn print_remaining_comments(&mut self) {
361         // If there aren't any remaining comments, then we need to manually
362         // make sure there is a line break at the end.
363         if self.next_comment().is_none() {
364             self.hardbreak();
365         }
366         while let Some(ref cmnt) = self.next_comment() {
367             self.print_comment(cmnt)
368         }
369     }
370
371     fn print_literal(&mut self, lit: &ast::Lit) {
372         self.maybe_print_comment(lit.span.lo());
373         self.word(lit.token.to_string())
374     }
375
376     fn print_string(&mut self, st: &str, style: ast::StrStyle) {
377         let st = match style {
378             ast::StrStyle::Cooked => (format!("\"{}\"", st.escape_debug())),
379             ast::StrStyle::Raw(n) => {
380                 format!("r{delim}\"{string}\"{delim}", delim = "#".repeat(n as usize), string = st)
381             }
382         };
383         self.word(st)
384     }
385
386     fn print_symbol(&mut self, sym: Symbol, style: ast::StrStyle) {
387         self.print_string(sym.as_str(), style);
388     }
389
390     fn print_inner_attributes(&mut self, attrs: &[ast::Attribute]) {
391         self.print_either_attributes(attrs, ast::AttrStyle::Inner, false, true)
392     }
393
394     fn print_inner_attributes_no_trailing_hardbreak(&mut self, attrs: &[ast::Attribute]) {
395         self.print_either_attributes(attrs, ast::AttrStyle::Inner, false, false)
396     }
397
398     fn print_outer_attributes(&mut self, attrs: &[ast::Attribute]) {
399         self.print_either_attributes(attrs, ast::AttrStyle::Outer, false, true)
400     }
401
402     fn print_inner_attributes_inline(&mut self, attrs: &[ast::Attribute]) {
403         self.print_either_attributes(attrs, ast::AttrStyle::Inner, true, true)
404     }
405
406     fn print_outer_attributes_inline(&mut self, attrs: &[ast::Attribute]) {
407         self.print_either_attributes(attrs, ast::AttrStyle::Outer, true, true)
408     }
409
410     fn print_either_attributes(
411         &mut self,
412         attrs: &[ast::Attribute],
413         kind: ast::AttrStyle,
414         is_inline: bool,
415         trailing_hardbreak: bool,
416     ) {
417         let mut count = 0;
418         for attr in attrs {
419             if attr.style == kind {
420                 self.print_attribute_inline(attr, is_inline);
421                 if is_inline {
422                     self.nbsp();
423                 }
424                 count += 1;
425             }
426         }
427         if count > 0 && trailing_hardbreak && !is_inline {
428             self.hardbreak_if_not_bol();
429         }
430     }
431
432     fn print_attribute(&mut self, attr: &ast::Attribute) {
433         self.print_attribute_inline(attr, false)
434     }
435
436     fn print_attribute_inline(&mut self, attr: &ast::Attribute, is_inline: bool) {
437         if !is_inline {
438             self.hardbreak_if_not_bol();
439         }
440         self.maybe_print_comment(attr.span.lo());
441         match attr.kind {
442             ast::AttrKind::Normal(ref item, _) => {
443                 match attr.style {
444                     ast::AttrStyle::Inner => self.word("#!["),
445                     ast::AttrStyle::Outer => self.word("#["),
446                 }
447                 self.print_attr_item(&item, attr.span);
448                 self.word("]");
449             }
450             ast::AttrKind::DocComment(comment_kind, data) => {
451                 self.word(doc_comment_to_string(comment_kind, attr.style, data));
452                 self.hardbreak()
453             }
454         }
455     }
456
457     fn print_attr_item(&mut self, item: &ast::AttrItem, span: Span) {
458         self.ibox(0);
459         match &item.args {
460             MacArgs::Delimited(_, delim, tokens) => self.print_mac_common(
461                 Some(MacHeader::Path(&item.path)),
462                 false,
463                 None,
464                 delim.to_token(),
465                 tokens,
466                 true,
467                 span,
468             ),
469             MacArgs::Empty | MacArgs::Eq(..) => {
470                 self.print_path(&item.path, false, 0);
471                 if let MacArgs::Eq(_, token) = &item.args {
472                     self.space();
473                     self.word_space("=");
474                     let token_str = self.token_to_string_ext(token, true);
475                     self.word(token_str);
476                 }
477             }
478         }
479         self.end();
480     }
481
482     fn print_meta_list_item(&mut self, item: &ast::NestedMetaItem) {
483         match item {
484             ast::NestedMetaItem::MetaItem(ref mi) => self.print_meta_item(mi),
485             ast::NestedMetaItem::Literal(ref lit) => self.print_literal(lit),
486         }
487     }
488
489     fn print_meta_item(&mut self, item: &ast::MetaItem) {
490         self.ibox(INDENT_UNIT);
491         match item.kind {
492             ast::MetaItemKind::Word => self.print_path(&item.path, false, 0),
493             ast::MetaItemKind::NameValue(ref value) => {
494                 self.print_path(&item.path, false, 0);
495                 self.space();
496                 self.word_space("=");
497                 self.print_literal(value);
498             }
499             ast::MetaItemKind::List(ref items) => {
500                 self.print_path(&item.path, false, 0);
501                 self.popen();
502                 self.commasep(Consistent, &items, |s, i| s.print_meta_list_item(i));
503                 self.pclose();
504             }
505         }
506         self.end();
507     }
508
509     /// This doesn't deserve to be called "pretty" printing, but it should be
510     /// meaning-preserving. A quick hack that might help would be to look at the
511     /// spans embedded in the TTs to decide where to put spaces and newlines.
512     /// But it'd be better to parse these according to the grammar of the
513     /// appropriate macro, transcribe back into the grammar we just parsed from,
514     /// and then pretty-print the resulting AST nodes (so, e.g., we print
515     /// expression arguments as expressions). It can be done! I think.
516     fn print_tt(&mut self, tt: &TokenTree, convert_dollar_crate: bool) {
517         match tt {
518             TokenTree::Token(token) => {
519                 let token_str = self.token_to_string_ext(&token, convert_dollar_crate);
520                 self.word(token_str);
521                 if let token::DocComment(..) = token.kind {
522                     self.hardbreak()
523                 }
524             }
525             TokenTree::Delimited(dspan, delim, tts) => {
526                 self.print_mac_common(
527                     None,
528                     false,
529                     None,
530                     *delim,
531                     tts,
532                     convert_dollar_crate,
533                     dspan.entire(),
534                 );
535             }
536         }
537     }
538
539     fn print_tts(&mut self, tts: &TokenStream, convert_dollar_crate: bool) {
540         let mut iter = tts.trees().peekable();
541         while let Some(tt) = iter.next() {
542             self.print_tt(&tt, convert_dollar_crate);
543             if let Some(next) = iter.peek() {
544                 if tt_prepend_space(next, &tt) {
545                     self.space();
546                 }
547             }
548         }
549     }
550
551     fn print_mac_common(
552         &mut self,
553         header: Option<MacHeader<'_>>,
554         has_bang: bool,
555         ident: Option<Ident>,
556         delim: DelimToken,
557         tts: &TokenStream,
558         convert_dollar_crate: bool,
559         span: Span,
560     ) {
561         if delim == DelimToken::Brace {
562             self.cbox(INDENT_UNIT);
563         }
564         match header {
565             Some(MacHeader::Path(path)) => self.print_path(path, false, 0),
566             Some(MacHeader::Keyword(kw)) => self.word(kw),
567             None => {}
568         }
569         if has_bang {
570             self.word("!");
571         }
572         if let Some(ident) = ident {
573             self.nbsp();
574             self.print_ident(ident);
575         }
576         match delim {
577             DelimToken::Brace => {
578                 if header.is_some() || has_bang || ident.is_some() {
579                     self.nbsp();
580                 }
581                 self.word("{");
582                 if !tts.is_empty() {
583                     self.space();
584                 }
585             }
586             _ => {
587                 let token_str = self.token_kind_to_string(&token::OpenDelim(delim));
588                 self.word(token_str)
589             }
590         }
591         self.ibox(0);
592         self.print_tts(tts, convert_dollar_crate);
593         self.end();
594         match delim {
595             DelimToken::Brace => {
596                 let empty = tts.is_empty();
597                 self.bclose(span, empty);
598             }
599             _ => {
600                 let token_str = self.token_kind_to_string(&token::CloseDelim(delim));
601                 self.word(token_str)
602             }
603         }
604     }
605
606     fn print_mac_def(
607         &mut self,
608         macro_def: &ast::MacroDef,
609         ident: &Ident,
610         sp: &Span,
611         print_visibility: impl FnOnce(&mut Self),
612     ) {
613         let (kw, has_bang) = if macro_def.macro_rules {
614             ("macro_rules", true)
615         } else {
616             print_visibility(self);
617             ("macro", false)
618         };
619         self.print_mac_common(
620             Some(MacHeader::Keyword(kw)),
621             has_bang,
622             Some(*ident),
623             macro_def.body.delim(),
624             &macro_def.body.inner_tokens(),
625             true,
626             *sp,
627         );
628         if macro_def.body.need_semicolon() {
629             self.word(";");
630         }
631     }
632
633     fn print_path(&mut self, path: &ast::Path, colons_before_params: bool, depth: usize) {
634         self.maybe_print_comment(path.span.lo());
635
636         for (i, segment) in path.segments[..path.segments.len() - depth].iter().enumerate() {
637             if i > 0 {
638                 self.word("::")
639             }
640             self.print_path_segment(segment, colons_before_params);
641         }
642     }
643
644     fn print_path_segment(&mut self, segment: &ast::PathSegment, colons_before_params: bool) {
645         if segment.ident.name != kw::PathRoot {
646             self.print_ident(segment.ident);
647             if let Some(ref args) = segment.args {
648                 self.print_generic_args(args, colons_before_params);
649             }
650         }
651     }
652
653     fn head<S: Into<Cow<'static, str>>>(&mut self, w: S) {
654         let w = w.into();
655         // Outer-box is consistent.
656         self.cbox(INDENT_UNIT);
657         // Head-box is inconsistent.
658         self.ibox(w.len() + 1);
659         // Keyword that starts the head.
660         if !w.is_empty() {
661             self.word_nbsp(w);
662         }
663     }
664
665     fn bopen(&mut self) {
666         self.word("{");
667         self.end(); // Close the head-box.
668     }
669
670     fn bclose_maybe_open(&mut self, span: rustc_span::Span, empty: bool, close_box: bool) {
671         let has_comment = self.maybe_print_comment(span.hi());
672         if !empty || has_comment {
673             self.break_offset_if_not_bol(1, -(INDENT_UNIT as isize));
674         }
675         self.word("}");
676         if close_box {
677             self.end(); // Close the outer-box.
678         }
679     }
680
681     fn bclose(&mut self, span: rustc_span::Span, empty: bool) {
682         let close_box = true;
683         self.bclose_maybe_open(span, empty, close_box)
684     }
685
686     fn break_offset_if_not_bol(&mut self, n: usize, off: isize) {
687         if !self.is_beginning_of_line() {
688             self.break_offset(n, off)
689         } else if off != 0 && self.last_token().is_hardbreak_tok() {
690             // We do something pretty sketchy here: tuck the nonzero
691             // offset-adjustment we were going to deposit along with the
692             // break into the previous hardbreak.
693             self.replace_last_token(pp::Printer::hardbreak_tok_offset(off));
694         }
695     }
696
697     fn nonterminal_to_string(&self, nt: &Nonterminal) -> String {
698         match *nt {
699             token::NtExpr(ref e) => self.expr_to_string(e),
700             token::NtMeta(ref e) => self.attr_item_to_string(e),
701             token::NtTy(ref e) => self.ty_to_string(e),
702             token::NtPath(ref e) => self.path_to_string(e),
703             token::NtItem(ref e) => self.item_to_string(e),
704             token::NtBlock(ref e) => self.block_to_string(e),
705             token::NtStmt(ref e) => self.stmt_to_string(e),
706             token::NtPat(ref e) => self.pat_to_string(e),
707             token::NtIdent(e, is_raw) => IdentPrinter::for_ast_ident(e, is_raw).to_string(),
708             token::NtLifetime(e) => e.to_string(),
709             token::NtLiteral(ref e) => self.expr_to_string(e),
710             token::NtTT(ref tree) => self.tt_to_string(tree),
711             token::NtVis(ref e) => self.vis_to_string(e),
712         }
713     }
714
715     /// Print the token kind precisely, without converting `$crate` into its respective crate name.
716     fn token_kind_to_string(&self, tok: &TokenKind) -> Cow<'static, str> {
717         self.token_kind_to_string_ext(tok, None)
718     }
719
720     fn token_kind_to_string_ext(
721         &self,
722         tok: &TokenKind,
723         convert_dollar_crate: Option<Span>,
724     ) -> Cow<'static, str> {
725         match *tok {
726             token::Eq => "=".into(),
727             token::Lt => "<".into(),
728             token::Le => "<=".into(),
729             token::EqEq => "==".into(),
730             token::Ne => "!=".into(),
731             token::Ge => ">=".into(),
732             token::Gt => ">".into(),
733             token::Not => "!".into(),
734             token::Tilde => "~".into(),
735             token::OrOr => "||".into(),
736             token::AndAnd => "&&".into(),
737             token::BinOp(op) => binop_to_string(op).into(),
738             token::BinOpEq(op) => format!("{}=", binop_to_string(op)).into(),
739
740             /* Structural symbols */
741             token::At => "@".into(),
742             token::Dot => ".".into(),
743             token::DotDot => "..".into(),
744             token::DotDotDot => "...".into(),
745             token::DotDotEq => "..=".into(),
746             token::Comma => ",".into(),
747             token::Semi => ";".into(),
748             token::Colon => ":".into(),
749             token::ModSep => "::".into(),
750             token::RArrow => "->".into(),
751             token::LArrow => "<-".into(),
752             token::FatArrow => "=>".into(),
753             token::OpenDelim(token::Paren) => "(".into(),
754             token::CloseDelim(token::Paren) => ")".into(),
755             token::OpenDelim(token::Bracket) => "[".into(),
756             token::CloseDelim(token::Bracket) => "]".into(),
757             token::OpenDelim(token::Brace) => "{".into(),
758             token::CloseDelim(token::Brace) => "}".into(),
759             token::OpenDelim(token::NoDelim) | token::CloseDelim(token::NoDelim) => "".into(),
760             token::Pound => "#".into(),
761             token::Dollar => "$".into(),
762             token::Question => "?".into(),
763             token::SingleQuote => "'".into(),
764
765             /* Literals */
766             token::Literal(lit) => literal_to_string(lit).into(),
767
768             /* Name components */
769             token::Ident(s, is_raw) => {
770                 IdentPrinter::new(s, is_raw, convert_dollar_crate).to_string().into()
771             }
772             token::Lifetime(s) => s.to_string().into(),
773
774             /* Other */
775             token::DocComment(comment_kind, attr_style, data) => {
776                 doc_comment_to_string(comment_kind, attr_style, data).into()
777             }
778             token::Eof => "<eof>".into(),
779
780             token::Interpolated(ref nt) => self.nonterminal_to_string(nt).into(),
781         }
782     }
783
784     /// Print the token precisely, without converting `$crate` into its respective crate name.
785     fn token_to_string(&self, token: &Token) -> Cow<'static, str> {
786         self.token_to_string_ext(token, false)
787     }
788
789     fn token_to_string_ext(&self, token: &Token, convert_dollar_crate: bool) -> Cow<'static, str> {
790         let convert_dollar_crate = convert_dollar_crate.then_some(token.span);
791         self.token_kind_to_string_ext(&token.kind, convert_dollar_crate)
792     }
793
794     fn ty_to_string(&self, ty: &ast::Ty) -> String {
795         self.to_string(|s| s.print_type(ty))
796     }
797
798     fn bounds_to_string(&self, bounds: &[ast::GenericBound]) -> String {
799         self.to_string(|s| s.print_type_bounds("", bounds))
800     }
801
802     fn pat_to_string(&self, pat: &ast::Pat) -> String {
803         self.to_string(|s| s.print_pat(pat))
804     }
805
806     fn expr_to_string(&self, e: &ast::Expr) -> String {
807         self.to_string(|s| s.print_expr(e))
808     }
809
810     fn tt_to_string(&self, tt: &TokenTree) -> String {
811         self.to_string(|s| s.print_tt(tt, false))
812     }
813
814     fn tts_to_string(&self, tokens: &TokenStream) -> String {
815         self.to_string(|s| s.print_tts(tokens, false))
816     }
817
818     fn stmt_to_string(&self, stmt: &ast::Stmt) -> String {
819         self.to_string(|s| s.print_stmt(stmt))
820     }
821
822     fn item_to_string(&self, i: &ast::Item) -> String {
823         self.to_string(|s| s.print_item(i))
824     }
825
826     fn generic_params_to_string(&self, generic_params: &[ast::GenericParam]) -> String {
827         self.to_string(|s| s.print_generic_params(generic_params))
828     }
829
830     fn path_to_string(&self, p: &ast::Path) -> String {
831         self.to_string(|s| s.print_path(p, false, 0))
832     }
833
834     fn path_segment_to_string(&self, p: &ast::PathSegment) -> String {
835         self.to_string(|s| s.print_path_segment(p, false))
836     }
837
838     fn vis_to_string(&self, v: &ast::Visibility) -> String {
839         self.to_string(|s| s.print_visibility(v))
840     }
841
842     fn block_to_string(&self, blk: &ast::Block) -> String {
843         self.to_string(|s| {
844             // Containing cbox, will be closed by `print_block` at `}`.
845             s.cbox(INDENT_UNIT);
846             // Head-ibox, will be closed by `print_block` after `{`.
847             s.ibox(0);
848             s.print_block(blk)
849         })
850     }
851
852     fn meta_list_item_to_string(&self, li: &ast::NestedMetaItem) -> String {
853         self.to_string(|s| s.print_meta_list_item(li))
854     }
855
856     fn attr_item_to_string(&self, ai: &ast::AttrItem) -> String {
857         self.to_string(|s| s.print_attr_item(ai, ai.path.span))
858     }
859
860     fn attribute_to_string(&self, attr: &ast::Attribute) -> String {
861         self.to_string(|s| s.print_attribute(attr))
862     }
863
864     fn param_to_string(&self, arg: &ast::Param) -> String {
865         self.to_string(|s| s.print_param(arg, false))
866     }
867
868     fn to_string(&self, f: impl FnOnce(&mut State<'_>)) -> String {
869         let mut printer = State::new();
870         f(&mut printer);
871         printer.s.eof()
872     }
873 }
874
875 impl<'a> PrintState<'a> for State<'a> {
876     fn comments(&mut self) -> &mut Option<Comments<'a>> {
877         &mut self.comments
878     }
879
880     fn print_ident(&mut self, ident: Ident) {
881         self.word(IdentPrinter::for_ast_ident(ident, ident.is_raw_guess()).to_string());
882         self.ann.post(self, AnnNode::Ident(&ident))
883     }
884
885     fn print_generic_args(&mut self, args: &ast::GenericArgs, colons_before_params: bool) {
886         if colons_before_params {
887             self.word("::")
888         }
889
890         match *args {
891             ast::GenericArgs::AngleBracketed(ref data) => {
892                 self.word("<");
893                 self.commasep(Inconsistent, &data.args, |s, arg| match arg {
894                     ast::AngleBracketedArg::Arg(a) => s.print_generic_arg(a),
895                     ast::AngleBracketedArg::Constraint(c) => s.print_assoc_constraint(c),
896                 });
897                 self.word(">")
898             }
899
900             ast::GenericArgs::Parenthesized(ref data) => {
901                 self.word("(");
902                 self.commasep(Inconsistent, &data.inputs, |s, ty| s.print_type(ty));
903                 self.word(")");
904                 self.print_fn_ret_ty(&data.output);
905             }
906         }
907     }
908 }
909
910 impl<'a> State<'a> {
911     pub fn new() -> State<'a> {
912         State { s: pp::mk_printer(), comments: None, ann: &NoAnn }
913     }
914
915     crate fn commasep_cmnt<T, F, G>(&mut self, b: Breaks, elts: &[T], mut op: F, mut get_span: G)
916     where
917         F: FnMut(&mut State<'_>, &T),
918         G: FnMut(&T) -> rustc_span::Span,
919     {
920         self.rbox(0, b);
921         let len = elts.len();
922         let mut i = 0;
923         for elt in elts {
924             self.maybe_print_comment(get_span(elt).hi());
925             op(self, elt);
926             i += 1;
927             if i < len {
928                 self.word(",");
929                 self.maybe_print_trailing_comment(get_span(elt), Some(get_span(&elts[i]).hi()));
930                 self.space_if_not_bol();
931             }
932         }
933         self.end();
934     }
935
936     crate fn commasep_exprs(&mut self, b: Breaks, exprs: &[P<ast::Expr>]) {
937         self.commasep_cmnt(b, exprs, |s, e| s.print_expr(e), |e| e.span)
938     }
939
940     crate fn print_foreign_mod(&mut self, nmod: &ast::ForeignMod, attrs: &[ast::Attribute]) {
941         self.print_inner_attributes(attrs);
942         for item in &nmod.items {
943             self.print_foreign_item(item);
944         }
945     }
946
947     pub fn print_opt_lifetime(&mut self, lifetime: &Option<ast::Lifetime>) {
948         if let Some(lt) = *lifetime {
949             self.print_lifetime(lt);
950             self.nbsp();
951         }
952     }
953
954     pub fn print_assoc_constraint(&mut self, constraint: &ast::AssocTyConstraint) {
955         self.print_ident(constraint.ident);
956         constraint.gen_args.as_ref().map(|args| self.print_generic_args(args, false));
957         self.space();
958         match &constraint.kind {
959             ast::AssocTyConstraintKind::Equality { ty } => {
960                 self.word_space("=");
961                 self.print_type(ty);
962             }
963             ast::AssocTyConstraintKind::Bound { bounds } => {
964                 self.print_type_bounds(":", &*bounds);
965             }
966         }
967     }
968
969     pub fn print_generic_arg(&mut self, generic_arg: &GenericArg) {
970         match generic_arg {
971             GenericArg::Lifetime(lt) => self.print_lifetime(*lt),
972             GenericArg::Type(ty) => self.print_type(ty),
973             GenericArg::Const(ct) => self.print_expr(&ct.value),
974         }
975     }
976
977     pub fn print_type(&mut self, ty: &ast::Ty) {
978         self.maybe_print_comment(ty.span.lo());
979         self.ibox(0);
980         match ty.kind {
981             ast::TyKind::Slice(ref ty) => {
982                 self.word("[");
983                 self.print_type(ty);
984                 self.word("]");
985             }
986             ast::TyKind::Ptr(ref mt) => {
987                 self.word("*");
988                 self.print_mt(mt, true);
989             }
990             ast::TyKind::Rptr(ref lifetime, ref mt) => {
991                 self.word("&");
992                 self.print_opt_lifetime(lifetime);
993                 self.print_mt(mt, false);
994             }
995             ast::TyKind::Never => {
996                 self.word("!");
997             }
998             ast::TyKind::Tup(ref elts) => {
999                 self.popen();
1000                 self.commasep(Inconsistent, &elts, |s, ty| s.print_type(ty));
1001                 if elts.len() == 1 {
1002                     self.word(",");
1003                 }
1004                 self.pclose();
1005             }
1006             ast::TyKind::Paren(ref typ) => {
1007                 self.popen();
1008                 self.print_type(typ);
1009                 self.pclose();
1010             }
1011             ast::TyKind::BareFn(ref f) => {
1012                 self.print_ty_fn(f.ext, f.unsafety, &f.decl, None, &f.generic_params);
1013             }
1014             ast::TyKind::Path(None, ref path) => {
1015                 self.print_path(path, false, 0);
1016             }
1017             ast::TyKind::Path(Some(ref qself), ref path) => self.print_qpath(path, qself, false),
1018             ast::TyKind::TraitObject(ref bounds, syntax) => {
1019                 let prefix = if syntax == ast::TraitObjectSyntax::Dyn { "dyn" } else { "" };
1020                 self.print_type_bounds(prefix, &bounds);
1021             }
1022             ast::TyKind::ImplTrait(_, ref bounds) => {
1023                 self.print_type_bounds("impl", &bounds);
1024             }
1025             ast::TyKind::Array(ref ty, ref length) => {
1026                 self.word("[");
1027                 self.print_type(ty);
1028                 self.word("; ");
1029                 self.print_expr(&length.value);
1030                 self.word("]");
1031             }
1032             ast::TyKind::Typeof(ref e) => {
1033                 self.word("typeof(");
1034                 self.print_expr(&e.value);
1035                 self.word(")");
1036             }
1037             ast::TyKind::Infer => {
1038                 self.word("_");
1039             }
1040             ast::TyKind::Err => {
1041                 self.popen();
1042                 self.word("/*ERROR*/");
1043                 self.pclose();
1044             }
1045             ast::TyKind::ImplicitSelf => {
1046                 self.word("Self");
1047             }
1048             ast::TyKind::MacCall(ref m) => {
1049                 self.print_mac(m);
1050             }
1051             ast::TyKind::CVarArgs => {
1052                 self.word("...");
1053             }
1054         }
1055         self.end();
1056     }
1057
1058     crate fn print_foreign_item(&mut self, item: &ast::ForeignItem) {
1059         let ast::Item { id, span, ident, ref attrs, ref kind, ref vis, tokens: _ } = *item;
1060         self.ann.pre(self, AnnNode::SubItem(id));
1061         self.hardbreak_if_not_bol();
1062         self.maybe_print_comment(span.lo());
1063         self.print_outer_attributes(attrs);
1064         match kind {
1065             ast::ForeignItemKind::Fn(box ast::Fn { defaultness, sig, generics, body }) => {
1066                 self.print_fn_full(sig, ident, generics, vis, *defaultness, body.as_deref(), attrs);
1067             }
1068             ast::ForeignItemKind::Static(ty, mutbl, body) => {
1069                 let def = ast::Defaultness::Final;
1070                 self.print_item_const(ident, Some(*mutbl), ty, body.as_deref(), vis, def);
1071             }
1072             ast::ForeignItemKind::TyAlias(box ast::TyAlias {
1073                 defaultness,
1074                 generics,
1075                 bounds,
1076                 ty,
1077             }) => {
1078                 self.print_associated_type(
1079                     ident,
1080                     generics,
1081                     bounds,
1082                     ty.as_deref(),
1083                     vis,
1084                     *defaultness,
1085                 );
1086             }
1087             ast::ForeignItemKind::MacCall(m) => {
1088                 self.print_mac(m);
1089                 if m.args.need_semicolon() {
1090                     self.word(";");
1091                 }
1092             }
1093         }
1094         self.ann.post(self, AnnNode::SubItem(id))
1095     }
1096
1097     fn print_item_const(
1098         &mut self,
1099         ident: Ident,
1100         mutbl: Option<ast::Mutability>,
1101         ty: &ast::Ty,
1102         body: Option<&ast::Expr>,
1103         vis: &ast::Visibility,
1104         defaultness: ast::Defaultness,
1105     ) {
1106         self.head("");
1107         self.print_visibility(vis);
1108         self.print_defaultness(defaultness);
1109         let leading = match mutbl {
1110             None => "const",
1111             Some(ast::Mutability::Not) => "static",
1112             Some(ast::Mutability::Mut) => "static mut",
1113         };
1114         self.word_space(leading);
1115         self.print_ident(ident);
1116         self.word_space(":");
1117         self.print_type(ty);
1118         self.space();
1119         self.end(); // end the head-ibox
1120         if let Some(body) = body {
1121             self.word_space("=");
1122             self.print_expr(body);
1123         }
1124         self.word(";");
1125         self.end(); // end the outer cbox
1126     }
1127
1128     fn print_associated_type(
1129         &mut self,
1130         ident: Ident,
1131         generics: &ast::Generics,
1132         bounds: &ast::GenericBounds,
1133         ty: Option<&ast::Ty>,
1134         vis: &ast::Visibility,
1135         defaultness: ast::Defaultness,
1136     ) {
1137         self.head("");
1138         self.print_visibility(vis);
1139         self.print_defaultness(defaultness);
1140         self.word_space("type");
1141         self.print_ident(ident);
1142         self.print_generic_params(&generics.params);
1143         self.print_type_bounds(":", bounds);
1144         self.print_where_clause(&generics.where_clause);
1145         if let Some(ty) = ty {
1146             self.space();
1147             self.word_space("=");
1148             self.print_type(ty);
1149         }
1150         self.word(";");
1151         self.end(); // end inner head-block
1152         self.end(); // end outer head-block
1153     }
1154
1155     /// Pretty-prints an item.
1156     crate fn print_item(&mut self, item: &ast::Item) {
1157         self.hardbreak_if_not_bol();
1158         self.maybe_print_comment(item.span.lo());
1159         self.print_outer_attributes(&item.attrs);
1160         self.ann.pre(self, AnnNode::Item(item));
1161         match item.kind {
1162             ast::ItemKind::ExternCrate(orig_name) => {
1163                 self.head(visibility_qualified(&item.vis, "extern crate"));
1164                 if let Some(orig_name) = orig_name {
1165                     self.print_name(orig_name);
1166                     self.space();
1167                     self.word("as");
1168                     self.space();
1169                 }
1170                 self.print_ident(item.ident);
1171                 self.word(";");
1172                 self.end(); // end inner head-block
1173                 self.end(); // end outer head-block
1174             }
1175             ast::ItemKind::Use(ref tree) => {
1176                 self.head(visibility_qualified(&item.vis, "use"));
1177                 self.print_use_tree(tree);
1178                 self.word(";");
1179                 self.end(); // end inner head-block
1180                 self.end(); // end outer head-block
1181             }
1182             ast::ItemKind::Static(ref ty, mutbl, ref body) => {
1183                 let def = ast::Defaultness::Final;
1184                 self.print_item_const(item.ident, Some(mutbl), ty, body.as_deref(), &item.vis, def);
1185             }
1186             ast::ItemKind::Const(def, ref ty, ref body) => {
1187                 self.print_item_const(item.ident, None, ty, body.as_deref(), &item.vis, def);
1188             }
1189             ast::ItemKind::Fn(box ast::Fn { defaultness, ref sig, ref generics, ref body }) => {
1190                 let body = body.as_deref();
1191                 self.print_fn_full(
1192                     sig,
1193                     item.ident,
1194                     generics,
1195                     &item.vis,
1196                     defaultness,
1197                     body,
1198                     &item.attrs,
1199                 );
1200             }
1201             ast::ItemKind::Mod(unsafety, ref mod_kind) => {
1202                 self.head(self.to_string(|s| {
1203                     s.print_visibility(&item.vis);
1204                     s.print_unsafety(unsafety);
1205                     s.word("mod");
1206                 }));
1207                 self.print_ident(item.ident);
1208
1209                 match mod_kind {
1210                     ModKind::Loaded(items, ..) => {
1211                         self.nbsp();
1212                         self.bopen();
1213                         self.print_inner_attributes(&item.attrs);
1214                         for item in items {
1215                             self.print_item(item);
1216                         }
1217                         let empty = item.attrs.is_empty() && items.is_empty();
1218                         self.bclose(item.span, empty);
1219                     }
1220                     ModKind::Unloaded => {
1221                         self.word(";");
1222                         self.end(); // end inner head-block
1223                         self.end(); // end outer head-block
1224                     }
1225                 }
1226             }
1227             ast::ItemKind::ForeignMod(ref nmod) => {
1228                 self.head(self.to_string(|s| {
1229                     s.print_unsafety(nmod.unsafety);
1230                     s.word("extern");
1231                 }));
1232                 if let Some(abi) = nmod.abi {
1233                     self.print_literal(&abi.as_lit());
1234                     self.nbsp();
1235                 }
1236                 self.bopen();
1237                 self.print_foreign_mod(nmod, &item.attrs);
1238                 let empty = item.attrs.is_empty() && nmod.items.is_empty();
1239                 self.bclose(item.span, empty);
1240             }
1241             ast::ItemKind::GlobalAsm(ref asm) => {
1242                 self.head(visibility_qualified(&item.vis, "global_asm!"));
1243                 self.print_inline_asm(asm);
1244                 self.end();
1245             }
1246             ast::ItemKind::TyAlias(box ast::TyAlias {
1247                 defaultness,
1248                 ref generics,
1249                 ref bounds,
1250                 ref ty,
1251             }) => {
1252                 let ty = ty.as_deref();
1253                 self.print_associated_type(
1254                     item.ident,
1255                     generics,
1256                     bounds,
1257                     ty,
1258                     &item.vis,
1259                     defaultness,
1260                 );
1261             }
1262             ast::ItemKind::Enum(ref enum_definition, ref params) => {
1263                 self.print_enum_def(enum_definition, params, item.ident, item.span, &item.vis);
1264             }
1265             ast::ItemKind::Struct(ref struct_def, ref generics) => {
1266                 self.head(visibility_qualified(&item.vis, "struct"));
1267                 self.print_struct(struct_def, generics, item.ident, item.span, true);
1268             }
1269             ast::ItemKind::Union(ref struct_def, ref generics) => {
1270                 self.head(visibility_qualified(&item.vis, "union"));
1271                 self.print_struct(struct_def, generics, item.ident, item.span, true);
1272             }
1273             ast::ItemKind::Impl(box ast::Impl {
1274                 unsafety,
1275                 polarity,
1276                 defaultness,
1277                 constness,
1278                 ref generics,
1279                 ref of_trait,
1280                 ref self_ty,
1281                 ref items,
1282             }) => {
1283                 self.head("");
1284                 self.print_visibility(&item.vis);
1285                 self.print_defaultness(defaultness);
1286                 self.print_unsafety(unsafety);
1287                 self.word_nbsp("impl");
1288                 self.print_constness(constness);
1289
1290                 if !generics.params.is_empty() {
1291                     self.print_generic_params(&generics.params);
1292                     self.space();
1293                 }
1294
1295                 if let ast::ImplPolarity::Negative(_) = polarity {
1296                     self.word("!");
1297                 }
1298
1299                 if let Some(ref t) = *of_trait {
1300                     self.print_trait_ref(t);
1301                     self.space();
1302                     self.word_space("for");
1303                 }
1304
1305                 self.print_type(self_ty);
1306                 self.print_where_clause(&generics.where_clause);
1307
1308                 self.space();
1309                 self.bopen();
1310                 self.print_inner_attributes(&item.attrs);
1311                 for impl_item in items {
1312                     self.print_assoc_item(impl_item);
1313                 }
1314                 let empty = item.attrs.is_empty() && items.is_empty();
1315                 self.bclose(item.span, empty);
1316             }
1317             ast::ItemKind::Trait(box ast::Trait {
1318                 is_auto,
1319                 unsafety,
1320                 ref generics,
1321                 ref bounds,
1322                 ref items,
1323                 ..
1324             }) => {
1325                 self.head("");
1326                 self.print_visibility(&item.vis);
1327                 self.print_unsafety(unsafety);
1328                 self.print_is_auto(is_auto);
1329                 self.word_nbsp("trait");
1330                 self.print_ident(item.ident);
1331                 self.print_generic_params(&generics.params);
1332                 let mut real_bounds = Vec::with_capacity(bounds.len());
1333                 for b in bounds.iter() {
1334                     if let GenericBound::Trait(ref ptr, ast::TraitBoundModifier::Maybe) = *b {
1335                         self.space();
1336                         self.word_space("for ?");
1337                         self.print_trait_ref(&ptr.trait_ref);
1338                     } else {
1339                         real_bounds.push(b.clone());
1340                     }
1341                 }
1342                 self.print_type_bounds(":", &real_bounds);
1343                 self.print_where_clause(&generics.where_clause);
1344                 self.word(" ");
1345                 self.bopen();
1346                 self.print_inner_attributes(&item.attrs);
1347                 for trait_item in items {
1348                     self.print_assoc_item(trait_item);
1349                 }
1350                 let empty = item.attrs.is_empty() && items.is_empty();
1351                 self.bclose(item.span, empty);
1352             }
1353             ast::ItemKind::TraitAlias(ref generics, ref bounds) => {
1354                 self.head("");
1355                 self.print_visibility(&item.vis);
1356                 self.word_nbsp("trait");
1357                 self.print_ident(item.ident);
1358                 self.print_generic_params(&generics.params);
1359                 let mut real_bounds = Vec::with_capacity(bounds.len());
1360                 // FIXME(durka) this seems to be some quite outdated syntax
1361                 for b in bounds.iter() {
1362                     if let GenericBound::Trait(ref ptr, ast::TraitBoundModifier::Maybe) = *b {
1363                         self.space();
1364                         self.word_space("for ?");
1365                         self.print_trait_ref(&ptr.trait_ref);
1366                     } else {
1367                         real_bounds.push(b.clone());
1368                     }
1369                 }
1370                 self.nbsp();
1371                 self.print_type_bounds("=", &real_bounds);
1372                 self.print_where_clause(&generics.where_clause);
1373                 self.word(";");
1374             }
1375             ast::ItemKind::MacCall(ref mac) => {
1376                 self.print_mac(mac);
1377                 if mac.args.need_semicolon() {
1378                     self.word(";");
1379                 }
1380             }
1381             ast::ItemKind::MacroDef(ref macro_def) => {
1382                 self.print_mac_def(macro_def, &item.ident, &item.span, |state| {
1383                     state.print_visibility(&item.vis)
1384                 });
1385             }
1386         }
1387         self.ann.post(self, AnnNode::Item(item))
1388     }
1389
1390     fn print_trait_ref(&mut self, t: &ast::TraitRef) {
1391         self.print_path(&t.path, false, 0)
1392     }
1393
1394     fn print_formal_generic_params(&mut self, generic_params: &[ast::GenericParam]) {
1395         if !generic_params.is_empty() {
1396             self.word("for");
1397             self.print_generic_params(generic_params);
1398             self.nbsp();
1399         }
1400     }
1401
1402     fn print_poly_trait_ref(&mut self, t: &ast::PolyTraitRef) {
1403         self.print_formal_generic_params(&t.bound_generic_params);
1404         self.print_trait_ref(&t.trait_ref)
1405     }
1406
1407     crate fn print_enum_def(
1408         &mut self,
1409         enum_definition: &ast::EnumDef,
1410         generics: &ast::Generics,
1411         ident: Ident,
1412         span: rustc_span::Span,
1413         visibility: &ast::Visibility,
1414     ) {
1415         self.head(visibility_qualified(visibility, "enum"));
1416         self.print_ident(ident);
1417         self.print_generic_params(&generics.params);
1418         self.print_where_clause(&generics.where_clause);
1419         self.space();
1420         self.print_variants(&enum_definition.variants, span)
1421     }
1422
1423     crate fn print_variants(&mut self, variants: &[ast::Variant], span: rustc_span::Span) {
1424         self.bopen();
1425         for v in variants {
1426             self.space_if_not_bol();
1427             self.maybe_print_comment(v.span.lo());
1428             self.print_outer_attributes(&v.attrs);
1429             self.ibox(INDENT_UNIT);
1430             self.print_variant(v);
1431             self.word(",");
1432             self.end();
1433             self.maybe_print_trailing_comment(v.span, None);
1434         }
1435         let empty = variants.is_empty();
1436         self.bclose(span, empty)
1437     }
1438
1439     crate fn print_visibility(&mut self, vis: &ast::Visibility) {
1440         match vis.kind {
1441             ast::VisibilityKind::Public => self.word_nbsp("pub"),
1442             ast::VisibilityKind::Crate(sugar) => match sugar {
1443                 ast::CrateSugar::PubCrate => self.word_nbsp("pub(crate)"),
1444                 ast::CrateSugar::JustCrate => self.word_nbsp("crate"),
1445             },
1446             ast::VisibilityKind::Restricted { ref path, .. } => {
1447                 let path = self.to_string(|s| s.print_path(path, false, 0));
1448                 if path == "self" || path == "super" {
1449                     self.word_nbsp(format!("pub({})", path))
1450                 } else {
1451                     self.word_nbsp(format!("pub(in {})", path))
1452                 }
1453             }
1454             ast::VisibilityKind::Inherited => {}
1455         }
1456     }
1457
1458     crate fn print_defaultness(&mut self, defaultness: ast::Defaultness) {
1459         if let ast::Defaultness::Default(_) = defaultness {
1460             self.word_nbsp("default");
1461         }
1462     }
1463
1464     crate fn print_record_struct_body(&mut self, fields: &[ast::FieldDef], span: rustc_span::Span) {
1465         self.nbsp();
1466         self.bopen();
1467
1468         let empty = fields.is_empty();
1469         if !empty {
1470             self.hardbreak_if_not_bol();
1471
1472             for field in fields {
1473                 self.hardbreak_if_not_bol();
1474                 self.maybe_print_comment(field.span.lo());
1475                 self.print_outer_attributes(&field.attrs);
1476                 self.print_visibility(&field.vis);
1477                 self.print_ident(field.ident.unwrap());
1478                 self.word_nbsp(":");
1479                 self.print_type(&field.ty);
1480                 self.word(",");
1481             }
1482         }
1483
1484         self.bclose(span, empty);
1485     }
1486
1487     crate fn print_struct(
1488         &mut self,
1489         struct_def: &ast::VariantData,
1490         generics: &ast::Generics,
1491         ident: Ident,
1492         span: rustc_span::Span,
1493         print_finalizer: bool,
1494     ) {
1495         self.print_ident(ident);
1496         self.print_generic_params(&generics.params);
1497         match struct_def {
1498             ast::VariantData::Tuple(..) | ast::VariantData::Unit(..) => {
1499                 if let ast::VariantData::Tuple(..) = struct_def {
1500                     self.popen();
1501                     self.commasep(Inconsistent, struct_def.fields(), |s, field| {
1502                         s.maybe_print_comment(field.span.lo());
1503                         s.print_outer_attributes(&field.attrs);
1504                         s.print_visibility(&field.vis);
1505                         s.print_type(&field.ty)
1506                     });
1507                     self.pclose();
1508                 }
1509                 self.print_where_clause(&generics.where_clause);
1510                 if print_finalizer {
1511                     self.word(";");
1512                 }
1513                 self.end();
1514                 self.end(); // Close the outer-box.
1515             }
1516             ast::VariantData::Struct(ref fields, ..) => {
1517                 self.print_where_clause(&generics.where_clause);
1518                 self.print_record_struct_body(fields, span);
1519             }
1520         }
1521     }
1522
1523     crate fn print_variant(&mut self, v: &ast::Variant) {
1524         self.head("");
1525         self.print_visibility(&v.vis);
1526         let generics = ast::Generics::default();
1527         self.print_struct(&v.data, &generics, v.ident, v.span, false);
1528         if let Some(ref d) = v.disr_expr {
1529             self.space();
1530             self.word_space("=");
1531             self.print_expr(&d.value)
1532         }
1533     }
1534
1535     crate fn print_assoc_item(&mut self, item: &ast::AssocItem) {
1536         let ast::Item { id, span, ident, ref attrs, ref kind, ref vis, tokens: _ } = *item;
1537         self.ann.pre(self, AnnNode::SubItem(id));
1538         self.hardbreak_if_not_bol();
1539         self.maybe_print_comment(span.lo());
1540         self.print_outer_attributes(attrs);
1541         match kind {
1542             ast::AssocItemKind::Fn(box ast::Fn { defaultness, sig, generics, body }) => {
1543                 self.print_fn_full(sig, ident, generics, vis, *defaultness, body.as_deref(), attrs);
1544             }
1545             ast::AssocItemKind::Const(def, ty, body) => {
1546                 self.print_item_const(ident, None, ty, body.as_deref(), vis, *def);
1547             }
1548             ast::AssocItemKind::TyAlias(box ast::TyAlias { defaultness, generics, bounds, ty }) => {
1549                 self.print_associated_type(
1550                     ident,
1551                     generics,
1552                     bounds,
1553                     ty.as_deref(),
1554                     vis,
1555                     *defaultness,
1556                 );
1557             }
1558             ast::AssocItemKind::MacCall(m) => {
1559                 self.print_mac(m);
1560                 if m.args.need_semicolon() {
1561                     self.word(";");
1562                 }
1563             }
1564         }
1565         self.ann.post(self, AnnNode::SubItem(id))
1566     }
1567
1568     crate fn print_stmt(&mut self, st: &ast::Stmt) {
1569         self.maybe_print_comment(st.span.lo());
1570         match st.kind {
1571             ast::StmtKind::Local(ref loc) => {
1572                 self.print_outer_attributes(&loc.attrs);
1573                 self.space_if_not_bol();
1574                 self.ibox(INDENT_UNIT);
1575                 self.word_nbsp("let");
1576
1577                 self.ibox(INDENT_UNIT);
1578                 self.print_local_decl(loc);
1579                 self.end();
1580                 if let Some((init, els)) = loc.kind.init_else_opt() {
1581                     self.nbsp();
1582                     self.word_space("=");
1583                     self.print_expr(init);
1584                     if let Some(els) = els {
1585                         self.cbox(INDENT_UNIT);
1586                         self.ibox(INDENT_UNIT);
1587                         self.word(" else ");
1588                         self.print_block(els);
1589                     }
1590                 }
1591                 self.word(";");
1592                 self.end(); // `let` ibox
1593             }
1594             ast::StmtKind::Item(ref item) => self.print_item(item),
1595             ast::StmtKind::Expr(ref expr) => {
1596                 self.space_if_not_bol();
1597                 self.print_expr_outer_attr_style(expr, false);
1598                 if classify::expr_requires_semi_to_be_stmt(expr) {
1599                     self.word(";");
1600                 }
1601             }
1602             ast::StmtKind::Semi(ref expr) => {
1603                 self.space_if_not_bol();
1604                 self.print_expr_outer_attr_style(expr, false);
1605                 self.word(";");
1606             }
1607             ast::StmtKind::Empty => {
1608                 self.space_if_not_bol();
1609                 self.word(";");
1610             }
1611             ast::StmtKind::MacCall(ref mac) => {
1612                 self.space_if_not_bol();
1613                 self.print_outer_attributes(&mac.attrs);
1614                 self.print_mac(&mac.mac);
1615                 if mac.style == ast::MacStmtStyle::Semicolon {
1616                     self.word(";");
1617                 }
1618             }
1619         }
1620         self.maybe_print_trailing_comment(st.span, None)
1621     }
1622
1623     crate fn print_block(&mut self, blk: &ast::Block) {
1624         self.print_block_with_attrs(blk, &[])
1625     }
1626
1627     crate fn print_block_unclosed_indent(&mut self, blk: &ast::Block) {
1628         self.print_block_maybe_unclosed(blk, &[], false)
1629     }
1630
1631     crate fn print_block_with_attrs(&mut self, blk: &ast::Block, attrs: &[ast::Attribute]) {
1632         self.print_block_maybe_unclosed(blk, attrs, true)
1633     }
1634
1635     crate fn print_block_maybe_unclosed(
1636         &mut self,
1637         blk: &ast::Block,
1638         attrs: &[ast::Attribute],
1639         close_box: bool,
1640     ) {
1641         match blk.rules {
1642             BlockCheckMode::Unsafe(..) => self.word_space("unsafe"),
1643             BlockCheckMode::Default => (),
1644         }
1645         self.maybe_print_comment(blk.span.lo());
1646         self.ann.pre(self, AnnNode::Block(blk));
1647         self.bopen();
1648
1649         self.print_inner_attributes(attrs);
1650
1651         for (i, st) in blk.stmts.iter().enumerate() {
1652             match st.kind {
1653                 ast::StmtKind::Expr(ref expr) if i == blk.stmts.len() - 1 => {
1654                     self.maybe_print_comment(st.span.lo());
1655                     self.space_if_not_bol();
1656                     self.print_expr_outer_attr_style(expr, false);
1657                     self.maybe_print_trailing_comment(expr.span, Some(blk.span.hi()));
1658                 }
1659                 _ => self.print_stmt(st),
1660             }
1661         }
1662
1663         let empty = attrs.is_empty() && blk.stmts.is_empty();
1664         self.bclose_maybe_open(blk.span, empty, close_box);
1665         self.ann.post(self, AnnNode::Block(blk))
1666     }
1667
1668     /// Print a `let pat = expr` expression.
1669     crate fn print_let(&mut self, pat: &ast::Pat, expr: &ast::Expr) {
1670         self.word("let ");
1671         self.print_pat(pat);
1672         self.space();
1673         self.word_space("=");
1674         let npals = || parser::needs_par_as_let_scrutinee(expr.precedence().order());
1675         self.print_expr_cond_paren(expr, Self::cond_needs_par(expr) || npals())
1676     }
1677
1678     fn print_else(&mut self, els: Option<&ast::Expr>) {
1679         if let Some(_else) = els {
1680             match _else.kind {
1681                 // Another `else if` block.
1682                 ast::ExprKind::If(ref i, ref then, ref e) => {
1683                     self.cbox(INDENT_UNIT - 1);
1684                     self.ibox(0);
1685                     self.word(" else if ");
1686                     self.print_expr_as_cond(i);
1687                     self.space();
1688                     self.print_block(then);
1689                     self.print_else(e.as_deref())
1690                 }
1691                 // Final `else` block.
1692                 ast::ExprKind::Block(ref b, _) => {
1693                     self.cbox(INDENT_UNIT - 1);
1694                     self.ibox(0);
1695                     self.word(" else ");
1696                     self.print_block(b)
1697                 }
1698                 // Constraints would be great here!
1699                 _ => {
1700                     panic!("print_if saw if with weird alternative");
1701                 }
1702             }
1703         }
1704     }
1705
1706     crate fn print_if(&mut self, test: &ast::Expr, blk: &ast::Block, elseopt: Option<&ast::Expr>) {
1707         self.head("if");
1708         self.print_expr_as_cond(test);
1709         self.space();
1710         self.print_block(blk);
1711         self.print_else(elseopt)
1712     }
1713
1714     crate fn print_mac(&mut self, m: &ast::MacCall) {
1715         self.print_mac_common(
1716             Some(MacHeader::Path(&m.path)),
1717             true,
1718             None,
1719             m.args.delim(),
1720             &m.args.inner_tokens(),
1721             true,
1722             m.span(),
1723         );
1724     }
1725
1726     fn print_call_post(&mut self, args: &[P<ast::Expr>]) {
1727         self.popen();
1728         self.commasep_exprs(Inconsistent, args);
1729         self.pclose()
1730     }
1731
1732     crate fn print_expr_maybe_paren(&mut self, expr: &ast::Expr, prec: i8) {
1733         self.print_expr_cond_paren(expr, expr.precedence().order() < prec)
1734     }
1735
1736     /// Prints an expr using syntax that's acceptable in a condition position, such as the `cond` in
1737     /// `if cond { ... }`.
1738     crate fn print_expr_as_cond(&mut self, expr: &ast::Expr) {
1739         self.print_expr_cond_paren(expr, Self::cond_needs_par(expr))
1740     }
1741
1742     // Does `expr` need parentheses when printed in a condition position?
1743     //
1744     // These cases need parens due to the parse error observed in #26461: `if return {}`
1745     // parses as the erroneous construct `if (return {})`, not `if (return) {}`.
1746     fn cond_needs_par(expr: &ast::Expr) -> bool {
1747         match expr.kind {
1748             ast::ExprKind::Break(..) | ast::ExprKind::Closure(..) | ast::ExprKind::Ret(..) => true,
1749             _ => parser::contains_exterior_struct_lit(expr),
1750         }
1751     }
1752
1753     /// Prints `expr` or `(expr)` when `needs_par` holds.
1754     fn print_expr_cond_paren(&mut self, expr: &ast::Expr, needs_par: bool) {
1755         if needs_par {
1756             self.popen();
1757         }
1758         self.print_expr(expr);
1759         if needs_par {
1760             self.pclose();
1761         }
1762     }
1763
1764     fn print_expr_vec(&mut self, exprs: &[P<ast::Expr>]) {
1765         self.ibox(INDENT_UNIT);
1766         self.word("[");
1767         self.commasep_exprs(Inconsistent, exprs);
1768         self.word("]");
1769         self.end();
1770     }
1771
1772     fn print_expr_anon_const(&mut self, expr: &ast::AnonConst) {
1773         self.ibox(INDENT_UNIT);
1774         self.word("const");
1775         self.print_expr(&expr.value);
1776         self.end();
1777     }
1778
1779     fn print_expr_repeat(&mut self, element: &ast::Expr, count: &ast::AnonConst) {
1780         self.ibox(INDENT_UNIT);
1781         self.word("[");
1782         self.print_expr(element);
1783         self.word_space(";");
1784         self.print_expr(&count.value);
1785         self.word("]");
1786         self.end();
1787     }
1788
1789     fn print_expr_struct(
1790         &mut self,
1791         qself: &Option<ast::QSelf>,
1792         path: &ast::Path,
1793         fields: &[ast::ExprField],
1794         rest: &ast::StructRest,
1795     ) {
1796         if let Some(qself) = qself {
1797             self.print_qpath(path, qself, true);
1798         } else {
1799             self.print_path(path, true, 0);
1800         }
1801         self.word("{");
1802         self.commasep_cmnt(
1803             Consistent,
1804             fields,
1805             |s, field| {
1806                 s.print_outer_attributes(&field.attrs);
1807                 s.ibox(INDENT_UNIT);
1808                 if !field.is_shorthand {
1809                     s.print_ident(field.ident);
1810                     s.word_space(":");
1811                 }
1812                 s.print_expr(&field.expr);
1813                 s.end();
1814             },
1815             |f| f.span,
1816         );
1817         match rest {
1818             ast::StructRest::Base(_) | ast::StructRest::Rest(_) => {
1819                 self.ibox(INDENT_UNIT);
1820                 if !fields.is_empty() {
1821                     self.word(",");
1822                     self.space();
1823                 }
1824                 self.word("..");
1825                 if let ast::StructRest::Base(ref expr) = *rest {
1826                     self.print_expr(expr);
1827                 }
1828                 self.end();
1829             }
1830             ast::StructRest::None if !fields.is_empty() => self.word(","),
1831             _ => {}
1832         }
1833         self.word("}");
1834     }
1835
1836     fn print_expr_tup(&mut self, exprs: &[P<ast::Expr>]) {
1837         self.popen();
1838         self.commasep_exprs(Inconsistent, exprs);
1839         if exprs.len() == 1 {
1840             self.word(",");
1841         }
1842         self.pclose()
1843     }
1844
1845     fn print_expr_call(&mut self, func: &ast::Expr, args: &[P<ast::Expr>]) {
1846         let prec = match func.kind {
1847             ast::ExprKind::Field(..) => parser::PREC_FORCE_PAREN,
1848             _ => parser::PREC_POSTFIX,
1849         };
1850
1851         self.print_expr_maybe_paren(func, prec);
1852         self.print_call_post(args)
1853     }
1854
1855     fn print_expr_method_call(&mut self, segment: &ast::PathSegment, args: &[P<ast::Expr>]) {
1856         let base_args = &args[1..];
1857         self.print_expr_maybe_paren(&args[0], parser::PREC_POSTFIX);
1858         self.word(".");
1859         self.print_ident(segment.ident);
1860         if let Some(ref args) = segment.args {
1861             self.print_generic_args(args, true);
1862         }
1863         self.print_call_post(base_args)
1864     }
1865
1866     fn print_expr_binary(&mut self, op: ast::BinOp, lhs: &ast::Expr, rhs: &ast::Expr) {
1867         let assoc_op = AssocOp::from_ast_binop(op.node);
1868         let prec = assoc_op.precedence() as i8;
1869         let fixity = assoc_op.fixity();
1870
1871         let (left_prec, right_prec) = match fixity {
1872             Fixity::Left => (prec, prec + 1),
1873             Fixity::Right => (prec + 1, prec),
1874             Fixity::None => (prec + 1, prec + 1),
1875         };
1876
1877         let left_prec = match (&lhs.kind, op.node) {
1878             // These cases need parens: `x as i32 < y` has the parser thinking that `i32 < y` is
1879             // the beginning of a path type. It starts trying to parse `x as (i32 < y ...` instead
1880             // of `(x as i32) < ...`. We need to convince it _not_ to do that.
1881             (&ast::ExprKind::Cast { .. }, ast::BinOpKind::Lt | ast::BinOpKind::Shl) => {
1882                 parser::PREC_FORCE_PAREN
1883             }
1884             // We are given `(let _ = a) OP b`.
1885             //
1886             // - When `OP <= LAnd` we should print `let _ = a OP b` to avoid redundant parens
1887             //   as the parser will interpret this as `(let _ = a) OP b`.
1888             //
1889             // - Otherwise, e.g. when we have `(let a = b) < c` in AST,
1890             //   parens are required since the parser would interpret `let a = b < c` as
1891             //   `let a = (b < c)`. To achieve this, we force parens.
1892             (&ast::ExprKind::Let { .. }, _) if !parser::needs_par_as_let_scrutinee(prec) => {
1893                 parser::PREC_FORCE_PAREN
1894             }
1895             _ => left_prec,
1896         };
1897
1898         self.print_expr_maybe_paren(lhs, left_prec);
1899         self.space();
1900         self.word_space(op.node.to_string());
1901         self.print_expr_maybe_paren(rhs, right_prec)
1902     }
1903
1904     fn print_expr_unary(&mut self, op: ast::UnOp, expr: &ast::Expr) {
1905         self.word(ast::UnOp::to_string(op));
1906         self.print_expr_maybe_paren(expr, parser::PREC_PREFIX)
1907     }
1908
1909     fn print_expr_addr_of(
1910         &mut self,
1911         kind: ast::BorrowKind,
1912         mutability: ast::Mutability,
1913         expr: &ast::Expr,
1914     ) {
1915         self.word("&");
1916         match kind {
1917             ast::BorrowKind::Ref => self.print_mutability(mutability, false),
1918             ast::BorrowKind::Raw => {
1919                 self.word_nbsp("raw");
1920                 self.print_mutability(mutability, true);
1921             }
1922         }
1923         self.print_expr_maybe_paren(expr, parser::PREC_PREFIX)
1924     }
1925
1926     pub fn print_expr(&mut self, expr: &ast::Expr) {
1927         self.print_expr_outer_attr_style(expr, true)
1928     }
1929
1930     fn print_expr_outer_attr_style(&mut self, expr: &ast::Expr, is_inline: bool) {
1931         self.maybe_print_comment(expr.span.lo());
1932
1933         let attrs = &expr.attrs;
1934         if is_inline {
1935             self.print_outer_attributes_inline(attrs);
1936         } else {
1937             self.print_outer_attributes(attrs);
1938         }
1939
1940         self.ibox(INDENT_UNIT);
1941         self.ann.pre(self, AnnNode::Expr(expr));
1942         match expr.kind {
1943             ast::ExprKind::Box(ref expr) => {
1944                 self.word_space("box");
1945                 self.print_expr_maybe_paren(expr, parser::PREC_PREFIX);
1946             }
1947             ast::ExprKind::Array(ref exprs) => {
1948                 self.print_expr_vec(exprs);
1949             }
1950             ast::ExprKind::ConstBlock(ref anon_const) => {
1951                 self.print_expr_anon_const(anon_const);
1952             }
1953             ast::ExprKind::Repeat(ref element, ref count) => {
1954                 self.print_expr_repeat(element, count);
1955             }
1956             ast::ExprKind::Struct(ref se) => {
1957                 self.print_expr_struct(&se.qself, &se.path, &se.fields, &se.rest);
1958             }
1959             ast::ExprKind::Tup(ref exprs) => {
1960                 self.print_expr_tup(exprs);
1961             }
1962             ast::ExprKind::Call(ref func, ref args) => {
1963                 self.print_expr_call(func, &args);
1964             }
1965             ast::ExprKind::MethodCall(ref segment, ref args, _) => {
1966                 self.print_expr_method_call(segment, &args);
1967             }
1968             ast::ExprKind::Binary(op, ref lhs, ref rhs) => {
1969                 self.print_expr_binary(op, lhs, rhs);
1970             }
1971             ast::ExprKind::Unary(op, ref expr) => {
1972                 self.print_expr_unary(op, expr);
1973             }
1974             ast::ExprKind::AddrOf(k, m, ref expr) => {
1975                 self.print_expr_addr_of(k, m, expr);
1976             }
1977             ast::ExprKind::Lit(ref lit) => {
1978                 self.print_literal(lit);
1979             }
1980             ast::ExprKind::Cast(ref expr, ref ty) => {
1981                 let prec = AssocOp::As.precedence() as i8;
1982                 self.print_expr_maybe_paren(expr, prec);
1983                 self.space();
1984                 self.word_space("as");
1985                 self.print_type(ty);
1986             }
1987             ast::ExprKind::Type(ref expr, ref ty) => {
1988                 let prec = AssocOp::Colon.precedence() as i8;
1989                 self.print_expr_maybe_paren(expr, prec);
1990                 self.word_space(":");
1991                 self.print_type(ty);
1992             }
1993             ast::ExprKind::Let(ref pat, ref scrutinee, _) => {
1994                 self.print_let(pat, scrutinee);
1995             }
1996             ast::ExprKind::If(ref test, ref blk, ref elseopt) => {
1997                 self.print_if(test, blk, elseopt.as_deref())
1998             }
1999             ast::ExprKind::While(ref test, ref blk, opt_label) => {
2000                 if let Some(label) = opt_label {
2001                     self.print_ident(label.ident);
2002                     self.word_space(":");
2003                 }
2004                 self.head("while");
2005                 self.print_expr_as_cond(test);
2006                 self.space();
2007                 self.print_block_with_attrs(blk, attrs);
2008             }
2009             ast::ExprKind::ForLoop(ref pat, ref iter, ref blk, opt_label) => {
2010                 if let Some(label) = opt_label {
2011                     self.print_ident(label.ident);
2012                     self.word_space(":");
2013                 }
2014                 self.head("for");
2015                 self.print_pat(pat);
2016                 self.space();
2017                 self.word_space("in");
2018                 self.print_expr_as_cond(iter);
2019                 self.space();
2020                 self.print_block_with_attrs(blk, attrs);
2021             }
2022             ast::ExprKind::Loop(ref blk, opt_label) => {
2023                 if let Some(label) = opt_label {
2024                     self.print_ident(label.ident);
2025                     self.word_space(":");
2026                 }
2027                 self.head("loop");
2028                 self.print_block_with_attrs(blk, attrs);
2029             }
2030             ast::ExprKind::Match(ref expr, ref arms) => {
2031                 self.cbox(INDENT_UNIT);
2032                 self.ibox(INDENT_UNIT);
2033                 self.word_nbsp("match");
2034                 self.print_expr_as_cond(expr);
2035                 self.space();
2036                 self.bopen();
2037                 self.print_inner_attributes_no_trailing_hardbreak(attrs);
2038                 for arm in arms {
2039                     self.print_arm(arm);
2040                 }
2041                 let empty = attrs.is_empty() && arms.is_empty();
2042                 self.bclose(expr.span, empty);
2043             }
2044             ast::ExprKind::Closure(
2045                 capture_clause,
2046                 asyncness,
2047                 movability,
2048                 ref decl,
2049                 ref body,
2050                 _,
2051             ) => {
2052                 self.print_movability(movability);
2053                 self.print_asyncness(asyncness);
2054                 self.print_capture_clause(capture_clause);
2055
2056                 self.print_fn_params_and_ret(decl, true);
2057                 self.space();
2058                 self.print_expr(body);
2059                 self.end(); // need to close a box
2060
2061                 // a box will be closed by print_expr, but we didn't want an overall
2062                 // wrapper so we closed the corresponding opening. so create an
2063                 // empty box to satisfy the close.
2064                 self.ibox(0);
2065             }
2066             ast::ExprKind::Block(ref blk, opt_label) => {
2067                 if let Some(label) = opt_label {
2068                     self.print_ident(label.ident);
2069                     self.word_space(":");
2070                 }
2071                 // containing cbox, will be closed by print-block at }
2072                 self.cbox(INDENT_UNIT);
2073                 // head-box, will be closed by print-block after {
2074                 self.ibox(0);
2075                 self.print_block_with_attrs(blk, attrs);
2076             }
2077             ast::ExprKind::Async(capture_clause, _, ref blk) => {
2078                 self.word_nbsp("async");
2079                 self.print_capture_clause(capture_clause);
2080                 // cbox/ibox in analogy to the `ExprKind::Block` arm above
2081                 self.cbox(INDENT_UNIT);
2082                 self.ibox(0);
2083                 self.print_block_with_attrs(blk, attrs);
2084             }
2085             ast::ExprKind::Await(ref expr) => {
2086                 self.print_expr_maybe_paren(expr, parser::PREC_POSTFIX);
2087                 self.word(".await");
2088             }
2089             ast::ExprKind::Assign(ref lhs, ref rhs, _) => {
2090                 let prec = AssocOp::Assign.precedence() as i8;
2091                 self.print_expr_maybe_paren(lhs, prec + 1);
2092                 self.space();
2093                 self.word_space("=");
2094                 self.print_expr_maybe_paren(rhs, prec);
2095             }
2096             ast::ExprKind::AssignOp(op, ref lhs, ref rhs) => {
2097                 let prec = AssocOp::Assign.precedence() as i8;
2098                 self.print_expr_maybe_paren(lhs, prec + 1);
2099                 self.space();
2100                 self.word(op.node.to_string());
2101                 self.word_space("=");
2102                 self.print_expr_maybe_paren(rhs, prec);
2103             }
2104             ast::ExprKind::Field(ref expr, ident) => {
2105                 self.print_expr_maybe_paren(expr, parser::PREC_POSTFIX);
2106                 self.word(".");
2107                 self.print_ident(ident);
2108             }
2109             ast::ExprKind::Index(ref expr, ref index) => {
2110                 self.print_expr_maybe_paren(expr, parser::PREC_POSTFIX);
2111                 self.word("[");
2112                 self.print_expr(index);
2113                 self.word("]");
2114             }
2115             ast::ExprKind::Range(ref start, ref end, limits) => {
2116                 // Special case for `Range`.  `AssocOp` claims that `Range` has higher precedence
2117                 // than `Assign`, but `x .. x = x` gives a parse error instead of `x .. (x = x)`.
2118                 // Here we use a fake precedence value so that any child with lower precedence than
2119                 // a "normal" binop gets parenthesized.  (`LOr` is the lowest-precedence binop.)
2120                 let fake_prec = AssocOp::LOr.precedence() as i8;
2121                 if let Some(ref e) = *start {
2122                     self.print_expr_maybe_paren(e, fake_prec);
2123                 }
2124                 if limits == ast::RangeLimits::HalfOpen {
2125                     self.word("..");
2126                 } else {
2127                     self.word("..=");
2128                 }
2129                 if let Some(ref e) = *end {
2130                     self.print_expr_maybe_paren(e, fake_prec);
2131                 }
2132             }
2133             ast::ExprKind::Underscore => self.word("_"),
2134             ast::ExprKind::Path(None, ref path) => self.print_path(path, true, 0),
2135             ast::ExprKind::Path(Some(ref qself), ref path) => self.print_qpath(path, qself, true),
2136             ast::ExprKind::Break(opt_label, ref opt_expr) => {
2137                 self.word("break");
2138                 if let Some(label) = opt_label {
2139                     self.space();
2140                     self.print_ident(label.ident);
2141                 }
2142                 if let Some(ref expr) = *opt_expr {
2143                     self.space();
2144                     self.print_expr_maybe_paren(expr, parser::PREC_JUMP);
2145                 }
2146             }
2147             ast::ExprKind::Continue(opt_label) => {
2148                 self.word("continue");
2149                 if let Some(label) = opt_label {
2150                     self.space();
2151                     self.print_ident(label.ident);
2152                 }
2153             }
2154             ast::ExprKind::Ret(ref result) => {
2155                 self.word("return");
2156                 if let Some(ref expr) = *result {
2157                     self.word(" ");
2158                     self.print_expr_maybe_paren(expr, parser::PREC_JUMP);
2159                 }
2160             }
2161             ast::ExprKind::InlineAsm(ref a) => {
2162                 self.word("asm!");
2163                 self.print_inline_asm(a);
2164             }
2165             ast::ExprKind::LlvmInlineAsm(ref a) => {
2166                 self.word("llvm_asm!");
2167                 self.popen();
2168                 self.print_symbol(a.asm, a.asm_str_style);
2169                 self.word_space(":");
2170
2171                 self.commasep(Inconsistent, &a.outputs, |s, out| {
2172                     let constraint = out.constraint.as_str();
2173                     let mut ch = constraint.chars();
2174                     match ch.next() {
2175                         Some('=') if out.is_rw => {
2176                             s.print_string(&format!("+{}", ch.as_str()), ast::StrStyle::Cooked)
2177                         }
2178                         _ => s.print_string(&constraint, ast::StrStyle::Cooked),
2179                     }
2180                     s.popen();
2181                     s.print_expr(&out.expr);
2182                     s.pclose();
2183                 });
2184                 self.space();
2185                 self.word_space(":");
2186
2187                 self.commasep(Inconsistent, &a.inputs, |s, &(co, ref o)| {
2188                     s.print_symbol(co, ast::StrStyle::Cooked);
2189                     s.popen();
2190                     s.print_expr(o);
2191                     s.pclose();
2192                 });
2193                 self.space();
2194                 self.word_space(":");
2195
2196                 self.commasep(Inconsistent, &a.clobbers, |s, &co| {
2197                     s.print_symbol(co, ast::StrStyle::Cooked);
2198                 });
2199
2200                 let mut options = vec![];
2201                 if a.volatile {
2202                     options.push("volatile");
2203                 }
2204                 if a.alignstack {
2205                     options.push("alignstack");
2206                 }
2207                 if a.dialect == ast::LlvmAsmDialect::Intel {
2208                     options.push("intel");
2209                 }
2210
2211                 if !options.is_empty() {
2212                     self.space();
2213                     self.word_space(":");
2214                     self.commasep(Inconsistent, &options, |s, &co| {
2215                         s.print_string(co, ast::StrStyle::Cooked);
2216                     });
2217                 }
2218
2219                 self.pclose();
2220             }
2221             ast::ExprKind::MacCall(ref m) => self.print_mac(m),
2222             ast::ExprKind::Paren(ref e) => {
2223                 self.popen();
2224                 self.print_expr(e);
2225                 self.pclose();
2226             }
2227             ast::ExprKind::Yield(ref e) => {
2228                 self.word("yield");
2229
2230                 if let Some(ref expr) = *e {
2231                     self.space();
2232                     self.print_expr_maybe_paren(expr, parser::PREC_JUMP);
2233                 }
2234             }
2235             ast::ExprKind::Try(ref e) => {
2236                 self.print_expr_maybe_paren(e, parser::PREC_POSTFIX);
2237                 self.word("?")
2238             }
2239             ast::ExprKind::TryBlock(ref blk) => {
2240                 self.head("try");
2241                 self.space();
2242                 self.print_block_with_attrs(blk, attrs)
2243             }
2244             ast::ExprKind::Err => {
2245                 self.popen();
2246                 self.word("/*ERROR*/");
2247                 self.pclose()
2248             }
2249         }
2250         self.ann.post(self, AnnNode::Expr(expr));
2251         self.end();
2252     }
2253
2254     fn print_inline_asm(&mut self, asm: &ast::InlineAsm) {
2255         enum AsmArg<'a> {
2256             Template(String),
2257             Operand(&'a InlineAsmOperand),
2258             ClobberAbi(Symbol),
2259             Options(InlineAsmOptions),
2260         }
2261
2262         let mut args = vec![AsmArg::Template(InlineAsmTemplatePiece::to_string(&asm.template))];
2263         args.extend(asm.operands.iter().map(|(o, _)| AsmArg::Operand(o)));
2264         for (abi, _) in &asm.clobber_abis {
2265             args.push(AsmArg::ClobberAbi(*abi));
2266         }
2267         if !asm.options.is_empty() {
2268             args.push(AsmArg::Options(asm.options));
2269         }
2270
2271         self.popen();
2272         self.commasep(Consistent, &args, |s, arg| match arg {
2273             AsmArg::Template(template) => s.print_string(&template, ast::StrStyle::Cooked),
2274             AsmArg::Operand(op) => {
2275                 let print_reg_or_class = |s: &mut Self, r: &InlineAsmRegOrRegClass| match r {
2276                     InlineAsmRegOrRegClass::Reg(r) => s.print_symbol(*r, ast::StrStyle::Cooked),
2277                     InlineAsmRegOrRegClass::RegClass(r) => s.word(r.to_string()),
2278                 };
2279                 match op {
2280                     InlineAsmOperand::In { reg, expr } => {
2281                         s.word("in");
2282                         s.popen();
2283                         print_reg_or_class(s, reg);
2284                         s.pclose();
2285                         s.space();
2286                         s.print_expr(expr);
2287                     }
2288                     InlineAsmOperand::Out { reg, late, expr } => {
2289                         s.word(if *late { "lateout" } else { "out" });
2290                         s.popen();
2291                         print_reg_or_class(s, reg);
2292                         s.pclose();
2293                         s.space();
2294                         match expr {
2295                             Some(expr) => s.print_expr(expr),
2296                             None => s.word("_"),
2297                         }
2298                     }
2299                     InlineAsmOperand::InOut { reg, late, expr } => {
2300                         s.word(if *late { "inlateout" } else { "inout" });
2301                         s.popen();
2302                         print_reg_or_class(s, reg);
2303                         s.pclose();
2304                         s.space();
2305                         s.print_expr(expr);
2306                     }
2307                     InlineAsmOperand::SplitInOut { reg, late, in_expr, out_expr } => {
2308                         s.word(if *late { "inlateout" } else { "inout" });
2309                         s.popen();
2310                         print_reg_or_class(s, reg);
2311                         s.pclose();
2312                         s.space();
2313                         s.print_expr(in_expr);
2314                         s.space();
2315                         s.word_space("=>");
2316                         match out_expr {
2317                             Some(out_expr) => s.print_expr(out_expr),
2318                             None => s.word("_"),
2319                         }
2320                     }
2321                     InlineAsmOperand::Const { anon_const } => {
2322                         s.word("const");
2323                         s.space();
2324                         s.print_expr(&anon_const.value);
2325                     }
2326                     InlineAsmOperand::Sym { expr } => {
2327                         s.word("sym");
2328                         s.space();
2329                         s.print_expr(expr);
2330                     }
2331                 }
2332             }
2333             AsmArg::ClobberAbi(abi) => {
2334                 s.word("clobber_abi");
2335                 s.popen();
2336                 s.print_symbol(*abi, ast::StrStyle::Cooked);
2337                 s.pclose();
2338             }
2339             AsmArg::Options(opts) => {
2340                 s.word("options");
2341                 s.popen();
2342                 let mut options = vec![];
2343                 if opts.contains(InlineAsmOptions::PURE) {
2344                     options.push("pure");
2345                 }
2346                 if opts.contains(InlineAsmOptions::NOMEM) {
2347                     options.push("nomem");
2348                 }
2349                 if opts.contains(InlineAsmOptions::READONLY) {
2350                     options.push("readonly");
2351                 }
2352                 if opts.contains(InlineAsmOptions::PRESERVES_FLAGS) {
2353                     options.push("preserves_flags");
2354                 }
2355                 if opts.contains(InlineAsmOptions::NORETURN) {
2356                     options.push("noreturn");
2357                 }
2358                 if opts.contains(InlineAsmOptions::NOSTACK) {
2359                     options.push("nostack");
2360                 }
2361                 if opts.contains(InlineAsmOptions::ATT_SYNTAX) {
2362                     options.push("att_syntax");
2363                 }
2364                 if opts.contains(InlineAsmOptions::RAW) {
2365                     options.push("raw");
2366                 }
2367                 if opts.contains(InlineAsmOptions::MAY_UNWIND) {
2368                     options.push("may_unwind");
2369                 }
2370                 s.commasep(Inconsistent, &options, |s, &opt| {
2371                     s.word(opt);
2372                 });
2373                 s.pclose();
2374             }
2375         });
2376         self.pclose();
2377     }
2378
2379     crate fn print_local_decl(&mut self, loc: &ast::Local) {
2380         self.print_pat(&loc.pat);
2381         if let Some(ref ty) = loc.ty {
2382             self.word_space(":");
2383             self.print_type(ty);
2384         }
2385     }
2386
2387     crate fn print_name(&mut self, name: Symbol) {
2388         self.word(name.to_string());
2389         self.ann.post(self, AnnNode::Name(&name))
2390     }
2391
2392     fn print_qpath(&mut self, path: &ast::Path, qself: &ast::QSelf, colons_before_params: bool) {
2393         self.word("<");
2394         self.print_type(&qself.ty);
2395         if qself.position > 0 {
2396             self.space();
2397             self.word_space("as");
2398             let depth = path.segments.len() - qself.position;
2399             self.print_path(path, false, depth);
2400         }
2401         self.word(">");
2402         for item_segment in &path.segments[qself.position..] {
2403             self.word("::");
2404             self.print_ident(item_segment.ident);
2405             if let Some(ref args) = item_segment.args {
2406                 self.print_generic_args(args, colons_before_params)
2407             }
2408         }
2409     }
2410
2411     crate fn print_pat(&mut self, pat: &ast::Pat) {
2412         self.maybe_print_comment(pat.span.lo());
2413         self.ann.pre(self, AnnNode::Pat(pat));
2414         /* Pat isn't normalized, but the beauty of it
2415         is that it doesn't matter */
2416         match pat.kind {
2417             PatKind::Wild => self.word("_"),
2418             PatKind::Ident(binding_mode, ident, ref sub) => {
2419                 match binding_mode {
2420                     ast::BindingMode::ByRef(mutbl) => {
2421                         self.word_nbsp("ref");
2422                         self.print_mutability(mutbl, false);
2423                     }
2424                     ast::BindingMode::ByValue(ast::Mutability::Not) => {}
2425                     ast::BindingMode::ByValue(ast::Mutability::Mut) => {
2426                         self.word_nbsp("mut");
2427                     }
2428                 }
2429                 self.print_ident(ident);
2430                 if let Some(ref p) = *sub {
2431                     self.space();
2432                     self.word_space("@");
2433                     self.print_pat(p);
2434                 }
2435             }
2436             PatKind::TupleStruct(ref qself, ref path, ref elts) => {
2437                 if let Some(qself) = qself {
2438                     self.print_qpath(path, qself, true);
2439                 } else {
2440                     self.print_path(path, true, 0);
2441                 }
2442                 self.popen();
2443                 self.commasep(Inconsistent, &elts, |s, p| s.print_pat(p));
2444                 self.pclose();
2445             }
2446             PatKind::Or(ref pats) => {
2447                 self.strsep("|", true, Inconsistent, &pats, |s, p| s.print_pat(p));
2448             }
2449             PatKind::Path(None, ref path) => {
2450                 self.print_path(path, true, 0);
2451             }
2452             PatKind::Path(Some(ref qself), ref path) => {
2453                 self.print_qpath(path, qself, false);
2454             }
2455             PatKind::Struct(ref qself, ref path, ref fields, etc) => {
2456                 if let Some(qself) = qself {
2457                     self.print_qpath(path, qself, true);
2458                 } else {
2459                     self.print_path(path, true, 0);
2460                 }
2461                 self.nbsp();
2462                 self.word_space("{");
2463                 self.commasep_cmnt(
2464                     Consistent,
2465                     &fields,
2466                     |s, f| {
2467                         s.cbox(INDENT_UNIT);
2468                         if !f.is_shorthand {
2469                             s.print_ident(f.ident);
2470                             s.word_nbsp(":");
2471                         }
2472                         s.print_pat(&f.pat);
2473                         s.end();
2474                     },
2475                     |f| f.pat.span,
2476                 );
2477                 if etc {
2478                     if !fields.is_empty() {
2479                         self.word_space(",");
2480                     }
2481                     self.word("..");
2482                 }
2483                 self.space();
2484                 self.word("}");
2485             }
2486             PatKind::Tuple(ref elts) => {
2487                 self.popen();
2488                 self.commasep(Inconsistent, &elts, |s, p| s.print_pat(p));
2489                 if elts.len() == 1 {
2490                     self.word(",");
2491                 }
2492                 self.pclose();
2493             }
2494             PatKind::Box(ref inner) => {
2495                 self.word("box ");
2496                 self.print_pat(inner);
2497             }
2498             PatKind::Ref(ref inner, mutbl) => {
2499                 self.word("&");
2500                 if mutbl == ast::Mutability::Mut {
2501                     self.word("mut ");
2502                 }
2503                 if let PatKind::Ident(ast::BindingMode::ByValue(ast::Mutability::Mut), ..) =
2504                     inner.kind
2505                 {
2506                     self.popen();
2507                     self.print_pat(inner);
2508                     self.pclose();
2509                 } else {
2510                     self.print_pat(inner);
2511                 }
2512             }
2513             PatKind::Lit(ref e) => self.print_expr(&**e),
2514             PatKind::Range(ref begin, ref end, Spanned { node: ref end_kind, .. }) => {
2515                 if let Some(e) = begin {
2516                     self.print_expr(e);
2517                     self.space();
2518                 }
2519                 match *end_kind {
2520                     RangeEnd::Included(RangeSyntax::DotDotDot) => self.word("..."),
2521                     RangeEnd::Included(RangeSyntax::DotDotEq) => self.word("..="),
2522                     RangeEnd::Excluded => self.word(".."),
2523                 }
2524                 if let Some(e) = end {
2525                     self.print_expr(e);
2526                 }
2527             }
2528             PatKind::Slice(ref elts) => {
2529                 self.word("[");
2530                 self.commasep(Inconsistent, &elts, |s, p| s.print_pat(p));
2531                 self.word("]");
2532             }
2533             PatKind::Rest => self.word(".."),
2534             PatKind::Paren(ref inner) => {
2535                 self.popen();
2536                 self.print_pat(inner);
2537                 self.pclose();
2538             }
2539             PatKind::MacCall(ref m) => self.print_mac(m),
2540         }
2541         self.ann.post(self, AnnNode::Pat(pat))
2542     }
2543
2544     fn print_arm(&mut self, arm: &ast::Arm) {
2545         // Note, I have no idea why this check is necessary, but here it is.
2546         if arm.attrs.is_empty() {
2547             self.space();
2548         }
2549         self.cbox(INDENT_UNIT);
2550         self.ibox(0);
2551         self.maybe_print_comment(arm.pat.span.lo());
2552         self.print_outer_attributes(&arm.attrs);
2553         self.print_pat(&arm.pat);
2554         self.space();
2555         if let Some(ref e) = arm.guard {
2556             self.word_space("if");
2557             self.print_expr(e);
2558             self.space();
2559         }
2560         self.word_space("=>");
2561
2562         match arm.body.kind {
2563             ast::ExprKind::Block(ref blk, opt_label) => {
2564                 if let Some(label) = opt_label {
2565                     self.print_ident(label.ident);
2566                     self.word_space(":");
2567                 }
2568
2569                 // The block will close the pattern's ibox.
2570                 self.print_block_unclosed_indent(blk);
2571
2572                 // If it is a user-provided unsafe block, print a comma after it.
2573                 if let BlockCheckMode::Unsafe(ast::UserProvided) = blk.rules {
2574                     self.word(",");
2575                 }
2576             }
2577             _ => {
2578                 self.end(); // Close the ibox for the pattern.
2579                 self.print_expr(&arm.body);
2580                 self.word(",");
2581             }
2582         }
2583         self.end(); // Close enclosing cbox.
2584     }
2585
2586     fn print_explicit_self(&mut self, explicit_self: &ast::ExplicitSelf) {
2587         match explicit_self.node {
2588             SelfKind::Value(m) => {
2589                 self.print_mutability(m, false);
2590                 self.word("self")
2591             }
2592             SelfKind::Region(ref lt, m) => {
2593                 self.word("&");
2594                 self.print_opt_lifetime(lt);
2595                 self.print_mutability(m, false);
2596                 self.word("self")
2597             }
2598             SelfKind::Explicit(ref typ, m) => {
2599                 self.print_mutability(m, false);
2600                 self.word("self");
2601                 self.word_space(":");
2602                 self.print_type(typ)
2603             }
2604         }
2605     }
2606
2607     fn print_fn_full(
2608         &mut self,
2609         sig: &ast::FnSig,
2610         name: Ident,
2611         generics: &ast::Generics,
2612         vis: &ast::Visibility,
2613         defaultness: ast::Defaultness,
2614         body: Option<&ast::Block>,
2615         attrs: &[ast::Attribute],
2616     ) {
2617         if body.is_some() {
2618             self.head("");
2619         }
2620         self.print_visibility(vis);
2621         self.print_defaultness(defaultness);
2622         self.print_fn(&sig.decl, sig.header, Some(name), generics);
2623         if let Some(body) = body {
2624             self.nbsp();
2625             self.print_block_with_attrs(body, attrs);
2626         } else {
2627             self.word(";");
2628         }
2629     }
2630
2631     crate fn print_fn(
2632         &mut self,
2633         decl: &ast::FnDecl,
2634         header: ast::FnHeader,
2635         name: Option<Ident>,
2636         generics: &ast::Generics,
2637     ) {
2638         self.print_fn_header_info(header);
2639         if let Some(name) = name {
2640             self.nbsp();
2641             self.print_ident(name);
2642         }
2643         self.print_generic_params(&generics.params);
2644         self.print_fn_params_and_ret(decl, false);
2645         self.print_where_clause(&generics.where_clause)
2646     }
2647
2648     crate fn print_fn_params_and_ret(&mut self, decl: &ast::FnDecl, is_closure: bool) {
2649         let (open, close) = if is_closure { ("|", "|") } else { ("(", ")") };
2650         self.word(open);
2651         self.commasep(Inconsistent, &decl.inputs, |s, param| s.print_param(param, is_closure));
2652         self.word(close);
2653         self.print_fn_ret_ty(&decl.output)
2654     }
2655
2656     crate fn print_movability(&mut self, movability: ast::Movability) {
2657         match movability {
2658             ast::Movability::Static => self.word_space("static"),
2659             ast::Movability::Movable => {}
2660         }
2661     }
2662
2663     crate fn print_asyncness(&mut self, asyncness: ast::Async) {
2664         if asyncness.is_async() {
2665             self.word_nbsp("async");
2666         }
2667     }
2668
2669     crate fn print_capture_clause(&mut self, capture_clause: ast::CaptureBy) {
2670         match capture_clause {
2671             ast::CaptureBy::Value => self.word_space("move"),
2672             ast::CaptureBy::Ref => {}
2673         }
2674     }
2675
2676     pub fn print_type_bounds(&mut self, prefix: &'static str, bounds: &[ast::GenericBound]) {
2677         if !bounds.is_empty() {
2678             self.word(prefix);
2679             let mut first = true;
2680             for bound in bounds {
2681                 if !(first && prefix.is_empty()) {
2682                     self.nbsp();
2683                 }
2684                 if first {
2685                     first = false;
2686                 } else {
2687                     self.word_space("+");
2688                 }
2689
2690                 match bound {
2691                     GenericBound::Trait(tref, modifier) => {
2692                         if modifier == &TraitBoundModifier::Maybe {
2693                             self.word("?");
2694                         }
2695                         self.print_poly_trait_ref(tref);
2696                     }
2697                     GenericBound::Outlives(lt) => self.print_lifetime(*lt),
2698                 }
2699             }
2700         }
2701     }
2702
2703     crate fn print_lifetime(&mut self, lifetime: ast::Lifetime) {
2704         self.print_name(lifetime.ident.name)
2705     }
2706
2707     crate fn print_lifetime_bounds(
2708         &mut self,
2709         lifetime: ast::Lifetime,
2710         bounds: &ast::GenericBounds,
2711     ) {
2712         self.print_lifetime(lifetime);
2713         if !bounds.is_empty() {
2714             self.word(": ");
2715             for (i, bound) in bounds.iter().enumerate() {
2716                 if i != 0 {
2717                     self.word(" + ");
2718                 }
2719                 match bound {
2720                     ast::GenericBound::Outlives(lt) => self.print_lifetime(*lt),
2721                     _ => panic!(),
2722                 }
2723             }
2724         }
2725     }
2726
2727     crate fn print_generic_params(&mut self, generic_params: &[ast::GenericParam]) {
2728         if generic_params.is_empty() {
2729             return;
2730         }
2731
2732         self.word("<");
2733
2734         self.commasep(Inconsistent, &generic_params, |s, param| {
2735             s.print_outer_attributes_inline(&param.attrs);
2736
2737             match param.kind {
2738                 ast::GenericParamKind::Lifetime => {
2739                     let lt = ast::Lifetime { id: param.id, ident: param.ident };
2740                     s.print_lifetime_bounds(lt, &param.bounds)
2741                 }
2742                 ast::GenericParamKind::Type { ref default } => {
2743                     s.print_ident(param.ident);
2744                     s.print_type_bounds(":", &param.bounds);
2745                     if let Some(ref default) = default {
2746                         s.space();
2747                         s.word_space("=");
2748                         s.print_type(default)
2749                     }
2750                 }
2751                 ast::GenericParamKind::Const { ref ty, kw_span: _, ref default } => {
2752                     s.word_space("const");
2753                     s.print_ident(param.ident);
2754                     s.space();
2755                     s.word_space(":");
2756                     s.print_type(ty);
2757                     s.print_type_bounds(":", &param.bounds);
2758                     if let Some(ref default) = default {
2759                         s.space();
2760                         s.word_space("=");
2761                         s.print_expr(&default.value);
2762                     }
2763                 }
2764             }
2765         });
2766
2767         self.word(">");
2768     }
2769
2770     crate fn print_where_clause(&mut self, where_clause: &ast::WhereClause) {
2771         if where_clause.predicates.is_empty() && !where_clause.has_where_token {
2772             return;
2773         }
2774
2775         self.space();
2776         self.word_space("where");
2777
2778         for (i, predicate) in where_clause.predicates.iter().enumerate() {
2779             if i != 0 {
2780                 self.word_space(",");
2781             }
2782
2783             match *predicate {
2784                 ast::WherePredicate::BoundPredicate(ast::WhereBoundPredicate {
2785                     ref bound_generic_params,
2786                     ref bounded_ty,
2787                     ref bounds,
2788                     ..
2789                 }) => {
2790                     self.print_formal_generic_params(bound_generic_params);
2791                     self.print_type(bounded_ty);
2792                     self.print_type_bounds(":", bounds);
2793                 }
2794                 ast::WherePredicate::RegionPredicate(ast::WhereRegionPredicate {
2795                     ref lifetime,
2796                     ref bounds,
2797                     ..
2798                 }) => {
2799                     self.print_lifetime_bounds(*lifetime, bounds);
2800                 }
2801                 ast::WherePredicate::EqPredicate(ast::WhereEqPredicate {
2802                     ref lhs_ty,
2803                     ref rhs_ty,
2804                     ..
2805                 }) => {
2806                     self.print_type(lhs_ty);
2807                     self.space();
2808                     self.word_space("=");
2809                     self.print_type(rhs_ty);
2810                 }
2811             }
2812         }
2813     }
2814
2815     crate fn print_use_tree(&mut self, tree: &ast::UseTree) {
2816         match tree.kind {
2817             ast::UseTreeKind::Simple(rename, ..) => {
2818                 self.print_path(&tree.prefix, false, 0);
2819                 if let Some(rename) = rename {
2820                     self.space();
2821                     self.word_space("as");
2822                     self.print_ident(rename);
2823                 }
2824             }
2825             ast::UseTreeKind::Glob => {
2826                 if !tree.prefix.segments.is_empty() {
2827                     self.print_path(&tree.prefix, false, 0);
2828                     self.word("::");
2829                 }
2830                 self.word("*");
2831             }
2832             ast::UseTreeKind::Nested(ref items) => {
2833                 if tree.prefix.segments.is_empty() {
2834                     self.word("{");
2835                 } else {
2836                     self.print_path(&tree.prefix, false, 0);
2837                     self.word("::{");
2838                 }
2839                 self.commasep(Inconsistent, &items, |this, &(ref tree, _)| {
2840                     this.print_use_tree(tree)
2841                 });
2842                 self.word("}");
2843             }
2844         }
2845     }
2846
2847     pub fn print_mutability(&mut self, mutbl: ast::Mutability, print_const: bool) {
2848         match mutbl {
2849             ast::Mutability::Mut => self.word_nbsp("mut"),
2850             ast::Mutability::Not => {
2851                 if print_const {
2852                     self.word_nbsp("const");
2853                 }
2854             }
2855         }
2856     }
2857
2858     crate fn print_mt(&mut self, mt: &ast::MutTy, print_const: bool) {
2859         self.print_mutability(mt.mutbl, print_const);
2860         self.print_type(&mt.ty)
2861     }
2862
2863     crate fn print_param(&mut self, input: &ast::Param, is_closure: bool) {
2864         self.ibox(INDENT_UNIT);
2865
2866         self.print_outer_attributes_inline(&input.attrs);
2867
2868         match input.ty.kind {
2869             ast::TyKind::Infer if is_closure => self.print_pat(&input.pat),
2870             _ => {
2871                 if let Some(eself) = input.to_self() {
2872                     self.print_explicit_self(&eself);
2873                 } else {
2874                     let invalid = if let PatKind::Ident(_, ident, _) = input.pat.kind {
2875                         ident.name == kw::Empty
2876                     } else {
2877                         false
2878                     };
2879                     if !invalid {
2880                         self.print_pat(&input.pat);
2881                         self.word(":");
2882                         self.space();
2883                     }
2884                     self.print_type(&input.ty);
2885                 }
2886             }
2887         }
2888         self.end();
2889     }
2890
2891     crate fn print_fn_ret_ty(&mut self, fn_ret_ty: &ast::FnRetTy) {
2892         if let ast::FnRetTy::Ty(ty) = fn_ret_ty {
2893             self.space_if_not_bol();
2894             self.ibox(INDENT_UNIT);
2895             self.word_space("->");
2896             self.print_type(ty);
2897             self.end();
2898             self.maybe_print_comment(ty.span.lo());
2899         }
2900     }
2901
2902     crate fn print_ty_fn(
2903         &mut self,
2904         ext: ast::Extern,
2905         unsafety: ast::Unsafe,
2906         decl: &ast::FnDecl,
2907         name: Option<Ident>,
2908         generic_params: &[ast::GenericParam],
2909     ) {
2910         self.ibox(INDENT_UNIT);
2911         if !generic_params.is_empty() {
2912             self.word("for");
2913             self.print_generic_params(generic_params);
2914         }
2915         let generics = ast::Generics {
2916             params: Vec::new(),
2917             where_clause: ast::WhereClause {
2918                 has_where_token: false,
2919                 predicates: Vec::new(),
2920                 span: rustc_span::DUMMY_SP,
2921             },
2922             span: rustc_span::DUMMY_SP,
2923         };
2924         let header = ast::FnHeader { unsafety, ext, ..ast::FnHeader::default() };
2925         self.print_fn(decl, header, name, &generics);
2926         self.end();
2927     }
2928
2929     crate fn print_fn_header_info(&mut self, header: ast::FnHeader) {
2930         self.print_constness(header.constness);
2931         self.print_asyncness(header.asyncness);
2932         self.print_unsafety(header.unsafety);
2933
2934         match header.ext {
2935             ast::Extern::None => {}
2936             ast::Extern::Implicit => {
2937                 self.word_nbsp("extern");
2938             }
2939             ast::Extern::Explicit(abi) => {
2940                 self.word_nbsp("extern");
2941                 self.print_literal(&abi.as_lit());
2942                 self.nbsp();
2943             }
2944         }
2945
2946         self.word("fn")
2947     }
2948
2949     crate fn print_unsafety(&mut self, s: ast::Unsafe) {
2950         match s {
2951             ast::Unsafe::No => {}
2952             ast::Unsafe::Yes(_) => self.word_nbsp("unsafe"),
2953         }
2954     }
2955
2956     crate fn print_constness(&mut self, s: ast::Const) {
2957         match s {
2958             ast::Const::No => {}
2959             ast::Const::Yes(_) => self.word_nbsp("const"),
2960         }
2961     }
2962
2963     crate fn print_is_auto(&mut self, s: ast::IsAuto) {
2964         match s {
2965             ast::IsAuto::Yes => self.word_nbsp("auto"),
2966             ast::IsAuto::No => {}
2967         }
2968     }
2969 }