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