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