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