]> git.lizzy.rs Git - rust.git/blob - src/librustc/hir/print.rs
Rollup merge of #39115 - king6cong:master, r=nikomatsakis
[rust.git] / src / librustc / hir / print.rs
1 // Copyright 2015 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
4 //
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
10
11 pub use self::AnnNode::*;
12
13 use syntax::abi::Abi;
14 use syntax::ast;
15 use syntax::codemap::{CodeMap, Spanned};
16 use syntax::parse::lexer::comments;
17 use syntax::print::pp::{self, break_offset, word, space, hardbreak};
18 use syntax::print::pp::{Breaks, eof};
19 use syntax::print::pp::Breaks::{Consistent, Inconsistent};
20 use syntax::print::pprust::{self as ast_pp, PrintState};
21 use syntax::ptr::P;
22 use syntax::symbol::keywords;
23 use syntax_pos::{self, BytePos};
24 use errors;
25
26 use hir;
27 use hir::{PatKind, RegionTyParamBound, TraitTyParamBound, TraitBoundModifier};
28
29 use std::io::{self, Write, Read};
30
31 pub enum AnnNode<'a> {
32     NodeName(&'a ast::Name),
33     NodeBlock(&'a hir::Block),
34     NodeItem(&'a hir::Item),
35     NodeSubItem(ast::NodeId),
36     NodeExpr(&'a hir::Expr),
37     NodePat(&'a hir::Pat),
38 }
39
40 pub enum Nested {
41     Item(hir::ItemId),
42     TraitItem(hir::TraitItemId),
43     ImplItem(hir::ImplItemId),
44     Body(hir::BodyId),
45     BodyArgPat(hir::BodyId, usize)
46 }
47
48 pub trait PpAnn {
49     fn nested(&self, _state: &mut State, _nested: Nested) -> io::Result<()> {
50         Ok(())
51     }
52     fn pre(&self, _state: &mut State, _node: AnnNode) -> io::Result<()> {
53         Ok(())
54     }
55     fn post(&self, _state: &mut State, _node: AnnNode) -> io::Result<()> {
56         Ok(())
57     }
58 }
59
60 pub struct NoAnn;
61 impl PpAnn for NoAnn {}
62 pub const NO_ANN: &'static PpAnn = &NoAnn;
63
64 impl PpAnn for hir::Crate {
65     fn nested(&self, state: &mut State, nested: Nested) -> io::Result<()> {
66         match nested {
67             Nested::Item(id) => state.print_item(self.item(id.id)),
68             Nested::TraitItem(id) => state.print_trait_item(self.trait_item(id)),
69             Nested::ImplItem(id) => state.print_impl_item(self.impl_item(id)),
70             Nested::Body(id) => state.print_expr(&self.body(id).value),
71             Nested::BodyArgPat(id, i) => state.print_pat(&self.body(id).arguments[i].pat)
72         }
73     }
74 }
75
76 pub struct State<'a> {
77     pub s: pp::Printer<'a>,
78     cm: Option<&'a CodeMap>,
79     comments: Option<Vec<comments::Comment>>,
80     literals: Option<Vec<comments::Literal>>,
81     cur_cmnt_and_lit: ast_pp::CurrentCommentAndLiteral,
82     boxes: Vec<pp::Breaks>,
83     ann: &'a (PpAnn + 'a),
84 }
85
86 impl<'a> PrintState<'a> for State<'a> {
87     fn writer(&mut self) -> &mut pp::Printer<'a> {
88         &mut self.s
89     }
90
91     fn boxes(&mut self) -> &mut Vec<pp::Breaks> {
92         &mut self.boxes
93     }
94
95     fn comments(&mut self) -> &mut Option<Vec<comments::Comment>> {
96         &mut self.comments
97     }
98
99     fn cur_cmnt_and_lit(&mut self) -> &mut ast_pp::CurrentCommentAndLiteral {
100         &mut self.cur_cmnt_and_lit
101     }
102
103     fn literals(&self) -> &Option<Vec<comments::Literal>> {
104         &self.literals
105     }
106 }
107
108 #[allow(non_upper_case_globals)]
109 pub const indent_unit: usize = 4;
110
111 #[allow(non_upper_case_globals)]
112 pub const default_columns: usize = 78;
113
114
115 /// Requires you to pass an input filename and reader so that
116 /// it can scan the input text for comments and literals to
117 /// copy forward.
118 pub fn print_crate<'a>(cm: &'a CodeMap,
119                        span_diagnostic: &errors::Handler,
120                        krate: &hir::Crate,
121                        filename: String,
122                        input: &mut Read,
123                        out: Box<Write + 'a>,
124                        ann: &'a PpAnn,
125                        is_expanded: bool)
126                        -> io::Result<()> {
127     let mut s = State::new_from_input(cm, span_diagnostic, filename, input,
128                                       out, ann, is_expanded);
129
130     // When printing the AST, we sometimes need to inject `#[no_std]` here.
131     // Since you can't compile the HIR, it's not necessary.
132
133     s.print_mod(&krate.module, &krate.attrs)?;
134     s.print_remaining_comments()?;
135     eof(&mut s.s)
136 }
137
138 impl<'a> State<'a> {
139     pub fn new_from_input(cm: &'a CodeMap,
140                           span_diagnostic: &errors::Handler,
141                           filename: String,
142                           input: &mut Read,
143                           out: Box<Write + 'a>,
144                           ann: &'a PpAnn,
145                           is_expanded: bool)
146                           -> State<'a> {
147         let (cmnts, lits) = comments::gather_comments_and_literals(span_diagnostic,
148                                                                    filename,
149                                                                    input);
150
151         State::new(cm,
152                    out,
153                    ann,
154                    Some(cmnts),
155                    // If the code is post expansion, don't use the table of
156                    // literals, since it doesn't correspond with the literals
157                    // in the AST anymore.
158                    if is_expanded {
159                        None
160                    } else {
161                        Some(lits)
162                    })
163     }
164
165     pub fn new(cm: &'a CodeMap,
166                out: Box<Write + 'a>,
167                ann: &'a PpAnn,
168                comments: Option<Vec<comments::Comment>>,
169                literals: Option<Vec<comments::Literal>>)
170                -> State<'a> {
171         State {
172             s: pp::mk_printer(out, default_columns),
173             cm: Some(cm),
174             comments: comments.clone(),
175             literals: literals.clone(),
176             cur_cmnt_and_lit: ast_pp::CurrentCommentAndLiteral {
177                 cur_cmnt: 0,
178                 cur_lit: 0,
179             },
180             boxes: Vec::new(),
181             ann: ann,
182         }
183     }
184 }
185
186 pub fn to_string<F>(ann: &PpAnn, f: F) -> String
187     where F: FnOnce(&mut State) -> io::Result<()>
188 {
189     let mut wr = Vec::new();
190     {
191         let mut printer = State {
192             s: pp::mk_printer(Box::new(&mut wr), default_columns),
193             cm: None,
194             comments: None,
195             literals: None,
196             cur_cmnt_and_lit: ast_pp::CurrentCommentAndLiteral {
197                 cur_cmnt: 0,
198                 cur_lit: 0,
199             },
200             boxes: Vec::new(),
201             ann: ann,
202         };
203         f(&mut printer).unwrap();
204         eof(&mut printer.s).unwrap();
205     }
206     String::from_utf8(wr).unwrap()
207 }
208
209 pub fn visibility_qualified(vis: &hir::Visibility, w: &str) -> String {
210     to_string(NO_ANN, |s| {
211         s.print_visibility(vis)?;
212         word(&mut s.s, w)
213     })
214 }
215
216 fn needs_parentheses(expr: &hir::Expr) -> bool {
217     match expr.node {
218         hir::ExprAssign(..) |
219         hir::ExprBinary(..) |
220         hir::ExprClosure(..) |
221         hir::ExprAssignOp(..) |
222         hir::ExprCast(..) |
223         hir::ExprType(..) => true,
224         _ => false,
225     }
226 }
227
228 impl<'a> State<'a> {
229     pub fn cbox(&mut self, u: usize) -> io::Result<()> {
230         self.boxes.push(pp::Breaks::Consistent);
231         pp::cbox(&mut self.s, u)
232     }
233
234     pub fn nbsp(&mut self) -> io::Result<()> {
235         word(&mut self.s, " ")
236     }
237
238     pub fn word_nbsp(&mut self, w: &str) -> io::Result<()> {
239         word(&mut self.s, w)?;
240         self.nbsp()
241     }
242
243     pub fn head(&mut self, w: &str) -> io::Result<()> {
244         // outer-box is consistent
245         self.cbox(indent_unit)?;
246         // head-box is inconsistent
247         self.ibox(w.len() + 1)?;
248         // keyword that starts the head
249         if !w.is_empty() {
250             self.word_nbsp(w)?;
251         }
252         Ok(())
253     }
254
255     pub fn bopen(&mut self) -> io::Result<()> {
256         word(&mut self.s, "{")?;
257         self.end() // close the head-box
258     }
259
260     pub fn bclose_(&mut self, span: syntax_pos::Span, indented: usize) -> io::Result<()> {
261         self.bclose_maybe_open(span, indented, true)
262     }
263     pub fn bclose_maybe_open(&mut self,
264                              span: syntax_pos::Span,
265                              indented: usize,
266                              close_box: bool)
267                              -> io::Result<()> {
268         self.maybe_print_comment(span.hi)?;
269         self.break_offset_if_not_bol(1, -(indented as isize))?;
270         word(&mut self.s, "}")?;
271         if close_box {
272             self.end()?; // close the outer-box
273         }
274         Ok(())
275     }
276     pub fn bclose(&mut self, span: syntax_pos::Span) -> io::Result<()> {
277         self.bclose_(span, indent_unit)
278     }
279
280     pub fn in_cbox(&self) -> bool {
281         match self.boxes.last() {
282             Some(&last_box) => last_box == pp::Breaks::Consistent,
283             None => false,
284         }
285     }
286     pub fn space_if_not_bol(&mut self) -> io::Result<()> {
287         if !self.is_bol() {
288             space(&mut self.s)?;
289         }
290         Ok(())
291     }
292     pub fn break_offset_if_not_bol(&mut self, n: usize, off: isize) -> io::Result<()> {
293         if !self.is_bol() {
294             break_offset(&mut self.s, n, off)
295         } else {
296             if off != 0 && self.s.last_token().is_hardbreak_tok() {
297                 // We do something pretty sketchy here: tuck the nonzero
298                 // offset-adjustment we were going to deposit along with the
299                 // break into the previous hardbreak.
300                 self.s.replace_last_token(pp::hardbreak_tok_offset(off));
301             }
302             Ok(())
303         }
304     }
305
306     // Synthesizes a comment that was not textually present in the original source
307     // file.
308     pub fn synth_comment(&mut self, text: String) -> io::Result<()> {
309         word(&mut self.s, "/*")?;
310         space(&mut self.s)?;
311         word(&mut self.s, &text[..])?;
312         space(&mut self.s)?;
313         word(&mut self.s, "*/")
314     }
315
316
317     pub fn commasep_cmnt<T, F, G>(&mut self,
318                                   b: Breaks,
319                                   elts: &[T],
320                                   mut op: F,
321                                   mut get_span: G)
322                                   -> io::Result<()>
323         where F: FnMut(&mut State, &T) -> io::Result<()>,
324               G: FnMut(&T) -> syntax_pos::Span
325     {
326         self.rbox(0, b)?;
327         let len = elts.len();
328         let mut i = 0;
329         for elt in elts {
330             self.maybe_print_comment(get_span(elt).hi)?;
331             op(self, elt)?;
332             i += 1;
333             if i < len {
334                 word(&mut self.s, ",")?;
335                 self.maybe_print_trailing_comment(get_span(elt), Some(get_span(&elts[i]).hi))?;
336                 self.space_if_not_bol()?;
337             }
338         }
339         self.end()
340     }
341
342     pub fn commasep_exprs(&mut self, b: Breaks, exprs: &[hir::Expr]) -> io::Result<()> {
343         self.commasep_cmnt(b, exprs, |s, e| s.print_expr(&e), |e| e.span)
344     }
345
346     pub fn print_mod(&mut self, _mod: &hir::Mod, attrs: &[ast::Attribute]) -> io::Result<()> {
347         self.print_inner_attributes(attrs)?;
348         for &item_id in &_mod.item_ids {
349             self.ann.nested(self, Nested::Item(item_id))?;
350         }
351         Ok(())
352     }
353
354     pub fn print_foreign_mod(&mut self,
355                              nmod: &hir::ForeignMod,
356                              attrs: &[ast::Attribute])
357                              -> io::Result<()> {
358         self.print_inner_attributes(attrs)?;
359         for item in &nmod.items {
360             self.print_foreign_item(item)?;
361         }
362         Ok(())
363     }
364
365     pub fn print_opt_lifetime(&mut self, lifetime: &Option<hir::Lifetime>) -> io::Result<()> {
366         if let Some(l) = *lifetime {
367             self.print_lifetime(&l)?;
368             self.nbsp()?;
369         }
370         Ok(())
371     }
372
373     pub fn print_type(&mut self, ty: &hir::Ty) -> io::Result<()> {
374         self.maybe_print_comment(ty.span.lo)?;
375         self.ibox(0)?;
376         match ty.node {
377             hir::TySlice(ref ty) => {
378                 word(&mut self.s, "[")?;
379                 self.print_type(&ty)?;
380                 word(&mut self.s, "]")?;
381             }
382             hir::TyPtr(ref mt) => {
383                 word(&mut self.s, "*")?;
384                 match mt.mutbl {
385                     hir::MutMutable => self.word_nbsp("mut")?,
386                     hir::MutImmutable => self.word_nbsp("const")?,
387                 }
388                 self.print_type(&mt.ty)?;
389             }
390             hir::TyRptr(ref lifetime, ref mt) => {
391                 word(&mut self.s, "&")?;
392                 self.print_opt_lifetime(lifetime)?;
393                 self.print_mt(mt)?;
394             }
395             hir::TyNever => {
396                 word(&mut self.s, "!")?;
397             },
398             hir::TyTup(ref elts) => {
399                 self.popen()?;
400                 self.commasep(Inconsistent, &elts[..], |s, ty| s.print_type(&ty))?;
401                 if elts.len() == 1 {
402                     word(&mut self.s, ",")?;
403                 }
404                 self.pclose()?;
405             }
406             hir::TyBareFn(ref f) => {
407                 let generics = hir::Generics {
408                     lifetimes: f.lifetimes.clone(),
409                     ty_params: hir::HirVec::new(),
410                     where_clause: hir::WhereClause {
411                         id: ast::DUMMY_NODE_ID,
412                         predicates: hir::HirVec::new(),
413                     },
414                     span: syntax_pos::DUMMY_SP,
415                 };
416                 self.print_ty_fn(f.abi, f.unsafety, &f.decl, None, &generics)?;
417             }
418             hir::TyPath(ref qpath) => {
419                 self.print_qpath(qpath, false)?
420             }
421             hir::TyTraitObject(ref bounds) => {
422                 self.print_bounds("", &bounds[..])?;
423             }
424             hir::TyImplTrait(ref bounds) => {
425                 self.print_bounds("impl ", &bounds[..])?;
426             }
427             hir::TyArray(ref ty, v) => {
428                 word(&mut self.s, "[")?;
429                 self.print_type(&ty)?;
430                 word(&mut self.s, "; ")?;
431                 self.ann.nested(self, Nested::Body(v))?;
432                 word(&mut self.s, "]")?;
433             }
434             hir::TyTypeof(e) => {
435                 word(&mut self.s, "typeof(")?;
436                 self.ann.nested(self, Nested::Body(e))?;
437                 word(&mut self.s, ")")?;
438             }
439             hir::TyInfer => {
440                 word(&mut self.s, "_")?;
441             }
442         }
443         self.end()
444     }
445
446     pub fn print_foreign_item(&mut self, item: &hir::ForeignItem) -> io::Result<()> {
447         self.hardbreak_if_not_bol()?;
448         self.maybe_print_comment(item.span.lo)?;
449         self.print_outer_attributes(&item.attrs)?;
450         match item.node {
451             hir::ForeignItemFn(ref decl, ref arg_names, ref generics) => {
452                 self.head("")?;
453                 self.print_fn(decl,
454                               hir::Unsafety::Normal,
455                               hir::Constness::NotConst,
456                               Abi::Rust,
457                               Some(item.name),
458                               generics,
459                               &item.vis,
460                               arg_names,
461                               None)?;
462                 self.end()?; // end head-ibox
463                 word(&mut self.s, ";")?;
464                 self.end() // end the outer fn box
465             }
466             hir::ForeignItemStatic(ref t, m) => {
467                 self.head(&visibility_qualified(&item.vis, "static"))?;
468                 if m {
469                     self.word_space("mut")?;
470                 }
471                 self.print_name(item.name)?;
472                 self.word_space(":")?;
473                 self.print_type(&t)?;
474                 word(&mut self.s, ";")?;
475                 self.end()?; // end the head-ibox
476                 self.end() // end the outer cbox
477             }
478         }
479     }
480
481     fn print_associated_const(&mut self,
482                               name: ast::Name,
483                               ty: &hir::Ty,
484                               default: Option<hir::BodyId>,
485                               vis: &hir::Visibility)
486                               -> io::Result<()> {
487         word(&mut self.s, &visibility_qualified(vis, ""))?;
488         self.word_space("const")?;
489         self.print_name(name)?;
490         self.word_space(":")?;
491         self.print_type(ty)?;
492         if let Some(expr) = default {
493             space(&mut self.s)?;
494             self.word_space("=")?;
495             self.ann.nested(self, Nested::Body(expr))?;
496         }
497         word(&mut self.s, ";")
498     }
499
500     fn print_associated_type(&mut self,
501                              name: ast::Name,
502                              bounds: Option<&hir::TyParamBounds>,
503                              ty: Option<&hir::Ty>)
504                              -> io::Result<()> {
505         self.word_space("type")?;
506         self.print_name(name)?;
507         if let Some(bounds) = bounds {
508             self.print_bounds(":", bounds)?;
509         }
510         if let Some(ty) = ty {
511             space(&mut self.s)?;
512             self.word_space("=")?;
513             self.print_type(ty)?;
514         }
515         word(&mut self.s, ";")
516     }
517
518     /// Pretty-print an item
519     pub fn print_item(&mut self, item: &hir::Item) -> io::Result<()> {
520         self.hardbreak_if_not_bol()?;
521         self.maybe_print_comment(item.span.lo)?;
522         self.print_outer_attributes(&item.attrs)?;
523         self.ann.pre(self, NodeItem(item))?;
524         match item.node {
525             hir::ItemExternCrate(ref optional_path) => {
526                 self.head(&visibility_qualified(&item.vis, "extern crate"))?;
527                 if let Some(p) = *optional_path {
528                     let val = p.as_str();
529                     if val.contains("-") {
530                         self.print_string(&val, ast::StrStyle::Cooked)?;
531                     } else {
532                         self.print_name(p)?;
533                     }
534                     space(&mut self.s)?;
535                     word(&mut self.s, "as")?;
536                     space(&mut self.s)?;
537                 }
538                 self.print_name(item.name)?;
539                 word(&mut self.s, ";")?;
540                 self.end()?; // end inner head-block
541                 self.end()?; // end outer head-block
542             }
543             hir::ItemUse(ref path, kind) => {
544                 self.head(&visibility_qualified(&item.vis, "use"))?;
545                 self.print_path(path, false)?;
546
547                 match kind {
548                     hir::UseKind::Single => {
549                         if path.segments.last().unwrap().name != item.name {
550                             space(&mut self.s)?;
551                             self.word_space("as")?;
552                             self.print_name(item.name)?;
553                         }
554                         word(&mut self.s, ";")?;
555                     }
556                     hir::UseKind::Glob => word(&mut self.s, "::*;")?,
557                     hir::UseKind::ListStem => word(&mut self.s, "::{};")?
558                 }
559                 self.end()?; // end inner head-block
560                 self.end()?; // end outer head-block
561             }
562             hir::ItemStatic(ref ty, m, expr) => {
563                 self.head(&visibility_qualified(&item.vis, "static"))?;
564                 if m == hir::MutMutable {
565                     self.word_space("mut")?;
566                 }
567                 self.print_name(item.name)?;
568                 self.word_space(":")?;
569                 self.print_type(&ty)?;
570                 space(&mut self.s)?;
571                 self.end()?; // end the head-ibox
572
573                 self.word_space("=")?;
574                 self.ann.nested(self, Nested::Body(expr))?;
575                 word(&mut self.s, ";")?;
576                 self.end()?; // end the outer cbox
577             }
578             hir::ItemConst(ref ty, expr) => {
579                 self.head(&visibility_qualified(&item.vis, "const"))?;
580                 self.print_name(item.name)?;
581                 self.word_space(":")?;
582                 self.print_type(&ty)?;
583                 space(&mut self.s)?;
584                 self.end()?; // end the head-ibox
585
586                 self.word_space("=")?;
587                 self.ann.nested(self, Nested::Body(expr))?;
588                 word(&mut self.s, ";")?;
589                 self.end()?; // end the outer cbox
590             }
591             hir::ItemFn(ref decl, unsafety, constness, abi, ref typarams, body) => {
592                 self.head("")?;
593                 self.print_fn(decl,
594                               unsafety,
595                               constness,
596                               abi,
597                               Some(item.name),
598                               typarams,
599                               &item.vis,
600                               &[],
601                               Some(body))?;
602                 word(&mut self.s, " ")?;
603                 self.end()?; // need to close a box
604                 self.end()?; // need to close a box
605                 self.ann.nested(self, Nested::Body(body))?;
606             }
607             hir::ItemMod(ref _mod) => {
608                 self.head(&visibility_qualified(&item.vis, "mod"))?;
609                 self.print_name(item.name)?;
610                 self.nbsp()?;
611                 self.bopen()?;
612                 self.print_mod(_mod, &item.attrs)?;
613                 self.bclose(item.span)?;
614             }
615             hir::ItemForeignMod(ref nmod) => {
616                 self.head("extern")?;
617                 self.word_nbsp(&nmod.abi.to_string())?;
618                 self.bopen()?;
619                 self.print_foreign_mod(nmod, &item.attrs)?;
620                 self.bclose(item.span)?;
621             }
622             hir::ItemTy(ref ty, ref params) => {
623                 self.ibox(indent_unit)?;
624                 self.ibox(0)?;
625                 self.word_nbsp(&visibility_qualified(&item.vis, "type"))?;
626                 self.print_name(item.name)?;
627                 self.print_generics(params)?;
628                 self.end()?; // end the inner ibox
629
630                 self.print_where_clause(&params.where_clause)?;
631                 space(&mut self.s)?;
632                 self.word_space("=")?;
633                 self.print_type(&ty)?;
634                 word(&mut self.s, ";")?;
635                 self.end()?; // end the outer ibox
636             }
637             hir::ItemEnum(ref enum_definition, ref params) => {
638                 self.print_enum_def(enum_definition, params, item.name, item.span, &item.vis)?;
639             }
640             hir::ItemStruct(ref struct_def, ref generics) => {
641                 self.head(&visibility_qualified(&item.vis, "struct"))?;
642                 self.print_struct(struct_def, generics, item.name, item.span, true)?;
643             }
644             hir::ItemUnion(ref struct_def, ref generics) => {
645                 self.head(&visibility_qualified(&item.vis, "union"))?;
646                 self.print_struct(struct_def, generics, item.name, item.span, true)?;
647             }
648             hir::ItemDefaultImpl(unsafety, ref trait_ref) => {
649                 self.head("")?;
650                 self.print_visibility(&item.vis)?;
651                 self.print_unsafety(unsafety)?;
652                 self.word_nbsp("impl")?;
653                 self.print_trait_ref(trait_ref)?;
654                 space(&mut self.s)?;
655                 self.word_space("for")?;
656                 self.word_space("..")?;
657                 self.bopen()?;
658                 self.bclose(item.span)?;
659             }
660             hir::ItemImpl(unsafety,
661                           polarity,
662                           ref generics,
663                           ref opt_trait,
664                           ref ty,
665                           ref impl_items) => {
666                 self.head("")?;
667                 self.print_visibility(&item.vis)?;
668                 self.print_unsafety(unsafety)?;
669                 self.word_nbsp("impl")?;
670
671                 if generics.is_parameterized() {
672                     self.print_generics(generics)?;
673                     space(&mut self.s)?;
674                 }
675
676                 match polarity {
677                     hir::ImplPolarity::Negative => {
678                         word(&mut self.s, "!")?;
679                     }
680                     _ => {}
681                 }
682
683                 match opt_trait {
684                     &Some(ref t) => {
685                         self.print_trait_ref(t)?;
686                         space(&mut self.s)?;
687                         self.word_space("for")?;
688                     }
689                     &None => {}
690                 }
691
692                 self.print_type(&ty)?;
693                 self.print_where_clause(&generics.where_clause)?;
694
695                 space(&mut self.s)?;
696                 self.bopen()?;
697                 self.print_inner_attributes(&item.attrs)?;
698                 for impl_item in impl_items {
699                     self.ann.nested(self, Nested::ImplItem(impl_item.id))?;
700                 }
701                 self.bclose(item.span)?;
702             }
703             hir::ItemTrait(unsafety, ref generics, ref bounds, ref trait_items) => {
704                 self.head("")?;
705                 self.print_visibility(&item.vis)?;
706                 self.print_unsafety(unsafety)?;
707                 self.word_nbsp("trait")?;
708                 self.print_name(item.name)?;
709                 self.print_generics(generics)?;
710                 let mut real_bounds = Vec::with_capacity(bounds.len());
711                 for b in bounds.iter() {
712                     if let TraitTyParamBound(ref ptr, hir::TraitBoundModifier::Maybe) = *b {
713                         space(&mut self.s)?;
714                         self.word_space("for ?")?;
715                         self.print_trait_ref(&ptr.trait_ref)?;
716                     } else {
717                         real_bounds.push(b.clone());
718                     }
719                 }
720                 self.print_bounds(":", &real_bounds[..])?;
721                 self.print_where_clause(&generics.where_clause)?;
722                 word(&mut self.s, " ")?;
723                 self.bopen()?;
724                 for trait_item in trait_items {
725                     self.ann.nested(self, Nested::TraitItem(trait_item.id))?;
726                 }
727                 self.bclose(item.span)?;
728             }
729         }
730         self.ann.post(self, NodeItem(item))
731     }
732
733     pub fn print_trait_ref(&mut self, t: &hir::TraitRef) -> io::Result<()> {
734         self.print_path(&t.path, false)
735     }
736
737     fn print_formal_lifetime_list(&mut self, lifetimes: &[hir::LifetimeDef]) -> io::Result<()> {
738         if !lifetimes.is_empty() {
739             word(&mut self.s, "for<")?;
740             let mut comma = false;
741             for lifetime_def in lifetimes {
742                 if comma {
743                     self.word_space(",")?
744                 }
745                 self.print_lifetime_def(lifetime_def)?;
746                 comma = true;
747             }
748             word(&mut self.s, ">")?;
749         }
750         Ok(())
751     }
752
753     fn print_poly_trait_ref(&mut self, t: &hir::PolyTraitRef) -> io::Result<()> {
754         self.print_formal_lifetime_list(&t.bound_lifetimes)?;
755         self.print_trait_ref(&t.trait_ref)
756     }
757
758     pub fn print_enum_def(&mut self,
759                           enum_definition: &hir::EnumDef,
760                           generics: &hir::Generics,
761                           name: ast::Name,
762                           span: syntax_pos::Span,
763                           visibility: &hir::Visibility)
764                           -> io::Result<()> {
765         self.head(&visibility_qualified(visibility, "enum"))?;
766         self.print_name(name)?;
767         self.print_generics(generics)?;
768         self.print_where_clause(&generics.where_clause)?;
769         space(&mut self.s)?;
770         self.print_variants(&enum_definition.variants, span)
771     }
772
773     pub fn print_variants(&mut self,
774                           variants: &[hir::Variant],
775                           span: syntax_pos::Span)
776                           -> io::Result<()> {
777         self.bopen()?;
778         for v in variants {
779             self.space_if_not_bol()?;
780             self.maybe_print_comment(v.span.lo)?;
781             self.print_outer_attributes(&v.node.attrs)?;
782             self.ibox(indent_unit)?;
783             self.print_variant(v)?;
784             word(&mut self.s, ",")?;
785             self.end()?;
786             self.maybe_print_trailing_comment(v.span, None)?;
787         }
788         self.bclose(span)
789     }
790
791     pub fn print_visibility(&mut self, vis: &hir::Visibility) -> io::Result<()> {
792         match *vis {
793             hir::Public => self.word_nbsp("pub"),
794             hir::Visibility::Crate => self.word_nbsp("pub(crate)"),
795             hir::Visibility::Restricted { ref path, .. } => {
796                 word(&mut self.s, "pub(")?;
797                 self.print_path(path, false)?;
798                 self.word_nbsp(")")
799             }
800             hir::Inherited => Ok(()),
801         }
802     }
803
804     pub fn print_struct(&mut self,
805                         struct_def: &hir::VariantData,
806                         generics: &hir::Generics,
807                         name: ast::Name,
808                         span: syntax_pos::Span,
809                         print_finalizer: bool)
810                         -> io::Result<()> {
811         self.print_name(name)?;
812         self.print_generics(generics)?;
813         if !struct_def.is_struct() {
814             if struct_def.is_tuple() {
815                 self.popen()?;
816                 self.commasep(Inconsistent, struct_def.fields(), |s, field| {
817                     s.maybe_print_comment(field.span.lo)?;
818                     s.print_outer_attributes(&field.attrs)?;
819                     s.print_visibility(&field.vis)?;
820                     s.print_type(&field.ty)
821                 })?;
822                 self.pclose()?;
823             }
824             self.print_where_clause(&generics.where_clause)?;
825             if print_finalizer {
826                 word(&mut self.s, ";")?;
827             }
828             self.end()?;
829             self.end() // close the outer-box
830         } else {
831             self.print_where_clause(&generics.where_clause)?;
832             self.nbsp()?;
833             self.bopen()?;
834             self.hardbreak_if_not_bol()?;
835
836             for field in struct_def.fields() {
837                 self.hardbreak_if_not_bol()?;
838                 self.maybe_print_comment(field.span.lo)?;
839                 self.print_outer_attributes(&field.attrs)?;
840                 self.print_visibility(&field.vis)?;
841                 self.print_name(field.name)?;
842                 self.word_nbsp(":")?;
843                 self.print_type(&field.ty)?;
844                 word(&mut self.s, ",")?;
845             }
846
847             self.bclose(span)
848         }
849     }
850
851     pub fn print_variant(&mut self, v: &hir::Variant) -> io::Result<()> {
852         self.head("")?;
853         let generics = hir::Generics::empty();
854         self.print_struct(&v.node.data, &generics, v.node.name, v.span, false)?;
855         if let Some(d) = v.node.disr_expr {
856             space(&mut self.s)?;
857             self.word_space("=")?;
858             self.ann.nested(self, Nested::Body(d))?;
859         }
860         Ok(())
861     }
862     pub fn print_method_sig(&mut self,
863                             name: ast::Name,
864                             m: &hir::MethodSig,
865                             vis: &hir::Visibility,
866                             arg_names: &[Spanned<ast::Name>],
867                             body_id: Option<hir::BodyId>)
868                             -> io::Result<()> {
869         self.print_fn(&m.decl,
870                       m.unsafety,
871                       m.constness,
872                       m.abi,
873                       Some(name),
874                       &m.generics,
875                       vis,
876                       arg_names,
877                       body_id)
878     }
879
880     pub fn print_trait_item(&mut self, ti: &hir::TraitItem) -> io::Result<()> {
881         self.ann.pre(self, NodeSubItem(ti.id))?;
882         self.hardbreak_if_not_bol()?;
883         self.maybe_print_comment(ti.span.lo)?;
884         self.print_outer_attributes(&ti.attrs)?;
885         match ti.node {
886             hir::TraitItemKind::Const(ref ty, default) => {
887                 self.print_associated_const(ti.name, &ty, default, &hir::Inherited)?;
888             }
889             hir::TraitItemKind::Method(ref sig, hir::TraitMethod::Required(ref arg_names)) => {
890                 self.print_method_sig(ti.name, sig, &hir::Inherited, arg_names, None)?;
891                 word(&mut self.s, ";")?;
892             }
893             hir::TraitItemKind::Method(ref sig, hir::TraitMethod::Provided(body)) => {
894                 self.head("")?;
895                 self.print_method_sig(ti.name, sig, &hir::Inherited, &[], Some(body))?;
896                 self.nbsp()?;
897                 self.end()?; // need to close a box
898                 self.end()?; // need to close a box
899                 self.ann.nested(self, Nested::Body(body))?;
900             }
901             hir::TraitItemKind::Type(ref bounds, ref default) => {
902                 self.print_associated_type(ti.name,
903                                            Some(bounds),
904                                            default.as_ref().map(|ty| &**ty))?;
905             }
906         }
907         self.ann.post(self, NodeSubItem(ti.id))
908     }
909
910     pub fn print_impl_item(&mut self, ii: &hir::ImplItem) -> io::Result<()> {
911         self.ann.pre(self, NodeSubItem(ii.id))?;
912         self.hardbreak_if_not_bol()?;
913         self.maybe_print_comment(ii.span.lo)?;
914         self.print_outer_attributes(&ii.attrs)?;
915
916         match ii.defaultness {
917             hir::Defaultness::Default { .. } => self.word_nbsp("default")?,
918             hir::Defaultness::Final => (),
919         }
920
921         match ii.node {
922             hir::ImplItemKind::Const(ref ty, expr) => {
923                 self.print_associated_const(ii.name, &ty, Some(expr), &ii.vis)?;
924             }
925             hir::ImplItemKind::Method(ref sig, body) => {
926                 self.head("")?;
927                 self.print_method_sig(ii.name, sig, &ii.vis, &[], Some(body))?;
928                 self.nbsp()?;
929                 self.end()?; // need to close a box
930                 self.end()?; // need to close a box
931                 self.ann.nested(self, Nested::Body(body))?;
932             }
933             hir::ImplItemKind::Type(ref ty) => {
934                 self.print_associated_type(ii.name, None, Some(ty))?;
935             }
936         }
937         self.ann.post(self, NodeSubItem(ii.id))
938     }
939
940     pub fn print_stmt(&mut self, st: &hir::Stmt) -> io::Result<()> {
941         self.maybe_print_comment(st.span.lo)?;
942         match st.node {
943             hir::StmtDecl(ref decl, _) => {
944                 self.print_decl(&decl)?;
945             }
946             hir::StmtExpr(ref expr, _) => {
947                 self.space_if_not_bol()?;
948                 self.print_expr(&expr)?;
949             }
950             hir::StmtSemi(ref expr, _) => {
951                 self.space_if_not_bol()?;
952                 self.print_expr(&expr)?;
953                 word(&mut self.s, ";")?;
954             }
955         }
956         if stmt_ends_with_semi(&st.node) {
957             word(&mut self.s, ";")?;
958         }
959         self.maybe_print_trailing_comment(st.span, None)
960     }
961
962     pub fn print_block(&mut self, blk: &hir::Block) -> io::Result<()> {
963         self.print_block_with_attrs(blk, &[])
964     }
965
966     pub fn print_block_unclosed(&mut self, blk: &hir::Block) -> io::Result<()> {
967         self.print_block_unclosed_indent(blk, indent_unit)
968     }
969
970     pub fn print_block_unclosed_indent(&mut self,
971                                        blk: &hir::Block,
972                                        indented: usize)
973                                        -> io::Result<()> {
974         self.print_block_maybe_unclosed(blk, indented, &[], false)
975     }
976
977     pub fn print_block_with_attrs(&mut self,
978                                   blk: &hir::Block,
979                                   attrs: &[ast::Attribute])
980                                   -> io::Result<()> {
981         self.print_block_maybe_unclosed(blk, indent_unit, attrs, true)
982     }
983
984     pub fn print_block_maybe_unclosed(&mut self,
985                                       blk: &hir::Block,
986                                       indented: usize,
987                                       attrs: &[ast::Attribute],
988                                       close_box: bool)
989                                       -> io::Result<()> {
990         match blk.rules {
991             hir::UnsafeBlock(..) => self.word_space("unsafe")?,
992             hir::PushUnsafeBlock(..) => self.word_space("push_unsafe")?,
993             hir::PopUnsafeBlock(..) => self.word_space("pop_unsafe")?,
994             hir::DefaultBlock => (),
995         }
996         self.maybe_print_comment(blk.span.lo)?;
997         self.ann.pre(self, NodeBlock(blk))?;
998         self.bopen()?;
999
1000         self.print_inner_attributes(attrs)?;
1001
1002         for st in &blk.stmts {
1003             self.print_stmt(st)?;
1004         }
1005         match blk.expr {
1006             Some(ref expr) => {
1007                 self.space_if_not_bol()?;
1008                 self.print_expr(&expr)?;
1009                 self.maybe_print_trailing_comment(expr.span, Some(blk.span.hi))?;
1010             }
1011             _ => (),
1012         }
1013         self.bclose_maybe_open(blk.span, indented, close_box)?;
1014         self.ann.post(self, NodeBlock(blk))
1015     }
1016
1017     fn print_else(&mut self, els: Option<&hir::Expr>) -> io::Result<()> {
1018         match els {
1019             Some(_else) => {
1020                 match _else.node {
1021                     // "another else-if"
1022                     hir::ExprIf(ref i, ref then, ref e) => {
1023                         self.cbox(indent_unit - 1)?;
1024                         self.ibox(0)?;
1025                         word(&mut self.s, " else if ")?;
1026                         self.print_expr(&i)?;
1027                         space(&mut self.s)?;
1028                         self.print_block(&then)?;
1029                         self.print_else(e.as_ref().map(|e| &**e))
1030                     }
1031                     // "final else"
1032                     hir::ExprBlock(ref b) => {
1033                         self.cbox(indent_unit - 1)?;
1034                         self.ibox(0)?;
1035                         word(&mut self.s, " else ")?;
1036                         self.print_block(&b)
1037                     }
1038                     // BLEAH, constraints would be great here
1039                     _ => {
1040                         panic!("print_if saw if with weird alternative");
1041                     }
1042                 }
1043             }
1044             _ => Ok(()),
1045         }
1046     }
1047
1048     pub fn print_if(&mut self,
1049                     test: &hir::Expr,
1050                     blk: &hir::Block,
1051                     elseopt: Option<&hir::Expr>)
1052                     -> io::Result<()> {
1053         self.head("if")?;
1054         self.print_expr(test)?;
1055         space(&mut self.s)?;
1056         self.print_block(blk)?;
1057         self.print_else(elseopt)
1058     }
1059
1060     pub fn print_if_let(&mut self,
1061                         pat: &hir::Pat,
1062                         expr: &hir::Expr,
1063                         blk: &hir::Block,
1064                         elseopt: Option<&hir::Expr>)
1065                         -> io::Result<()> {
1066         self.head("if let")?;
1067         self.print_pat(pat)?;
1068         space(&mut self.s)?;
1069         self.word_space("=")?;
1070         self.print_expr(expr)?;
1071         space(&mut self.s)?;
1072         self.print_block(blk)?;
1073         self.print_else(elseopt)
1074     }
1075
1076
1077     fn print_call_post(&mut self, args: &[hir::Expr]) -> io::Result<()> {
1078         self.popen()?;
1079         self.commasep_exprs(Inconsistent, args)?;
1080         self.pclose()
1081     }
1082
1083     pub fn print_expr_maybe_paren(&mut self, expr: &hir::Expr) -> io::Result<()> {
1084         let needs_par = needs_parentheses(expr);
1085         if needs_par {
1086             self.popen()?;
1087         }
1088         self.print_expr(expr)?;
1089         if needs_par {
1090             self.pclose()?;
1091         }
1092         Ok(())
1093     }
1094
1095     fn print_expr_vec(&mut self, exprs: &[hir::Expr]) -> io::Result<()> {
1096         self.ibox(indent_unit)?;
1097         word(&mut self.s, "[")?;
1098         self.commasep_exprs(Inconsistent, exprs)?;
1099         word(&mut self.s, "]")?;
1100         self.end()
1101     }
1102
1103     fn print_expr_repeat(&mut self, element: &hir::Expr, count: hir::BodyId) -> io::Result<()> {
1104         self.ibox(indent_unit)?;
1105         word(&mut self.s, "[")?;
1106         self.print_expr(element)?;
1107         self.word_space(";")?;
1108         self.ann.nested(self, Nested::Body(count))?;
1109         word(&mut self.s, "]")?;
1110         self.end()
1111     }
1112
1113     fn print_expr_struct(&mut self,
1114                          qpath: &hir::QPath,
1115                          fields: &[hir::Field],
1116                          wth: &Option<P<hir::Expr>>)
1117                          -> io::Result<()> {
1118         self.print_qpath(qpath, true)?;
1119         word(&mut self.s, "{")?;
1120         self.commasep_cmnt(Consistent,
1121                            &fields[..],
1122                            |s, field| {
1123                                s.ibox(indent_unit)?;
1124                                if !field.is_shorthand {
1125                                     s.print_name(field.name.node)?;
1126                                     s.word_space(":")?;
1127                                }
1128                                s.print_expr(&field.expr)?;
1129                                s.end()
1130                            },
1131                            |f| f.span)?;
1132         match *wth {
1133             Some(ref expr) => {
1134                 self.ibox(indent_unit)?;
1135                 if !fields.is_empty() {
1136                     word(&mut self.s, ",")?;
1137                     space(&mut self.s)?;
1138                 }
1139                 word(&mut self.s, "..")?;
1140                 self.print_expr(&expr)?;
1141                 self.end()?;
1142             }
1143             _ => if !fields.is_empty() {
1144                 word(&mut self.s, ",")?
1145             },
1146         }
1147         word(&mut self.s, "}")?;
1148         Ok(())
1149     }
1150
1151     fn print_expr_tup(&mut self, exprs: &[hir::Expr]) -> io::Result<()> {
1152         self.popen()?;
1153         self.commasep_exprs(Inconsistent, exprs)?;
1154         if exprs.len() == 1 {
1155             word(&mut self.s, ",")?;
1156         }
1157         self.pclose()
1158     }
1159
1160     fn print_expr_call(&mut self, func: &hir::Expr, args: &[hir::Expr]) -> io::Result<()> {
1161         self.print_expr_maybe_paren(func)?;
1162         self.print_call_post(args)
1163     }
1164
1165     fn print_expr_method_call(&mut self,
1166                               name: Spanned<ast::Name>,
1167                               tys: &[P<hir::Ty>],
1168                               args: &[hir::Expr])
1169                               -> io::Result<()> {
1170         let base_args = &args[1..];
1171         self.print_expr(&args[0])?;
1172         word(&mut self.s, ".")?;
1173         self.print_name(name.node)?;
1174         if !tys.is_empty() {
1175             word(&mut self.s, "::<")?;
1176             self.commasep(Inconsistent, tys, |s, ty| s.print_type(&ty))?;
1177             word(&mut self.s, ">")?;
1178         }
1179         self.print_call_post(base_args)
1180     }
1181
1182     fn print_expr_binary(&mut self,
1183                          op: hir::BinOp,
1184                          lhs: &hir::Expr,
1185                          rhs: &hir::Expr)
1186                          -> io::Result<()> {
1187         self.print_expr(lhs)?;
1188         space(&mut self.s)?;
1189         self.word_space(op.node.as_str())?;
1190         self.print_expr(rhs)
1191     }
1192
1193     fn print_expr_unary(&mut self, op: hir::UnOp, expr: &hir::Expr) -> io::Result<()> {
1194         word(&mut self.s, op.as_str())?;
1195         self.print_expr_maybe_paren(expr)
1196     }
1197
1198     fn print_expr_addr_of(&mut self,
1199                           mutability: hir::Mutability,
1200                           expr: &hir::Expr)
1201                           -> io::Result<()> {
1202         word(&mut self.s, "&")?;
1203         self.print_mutability(mutability)?;
1204         self.print_expr_maybe_paren(expr)
1205     }
1206
1207     pub fn print_expr(&mut self, expr: &hir::Expr) -> io::Result<()> {
1208         self.maybe_print_comment(expr.span.lo)?;
1209         self.print_outer_attributes(&expr.attrs)?;
1210         self.ibox(indent_unit)?;
1211         self.ann.pre(self, NodeExpr(expr))?;
1212         match expr.node {
1213             hir::ExprBox(ref expr) => {
1214                 self.word_space("box")?;
1215                 self.print_expr(expr)?;
1216             }
1217             hir::ExprArray(ref exprs) => {
1218                 self.print_expr_vec(exprs)?;
1219             }
1220             hir::ExprRepeat(ref element, count) => {
1221                 self.print_expr_repeat(&element, count)?;
1222             }
1223             hir::ExprStruct(ref qpath, ref fields, ref wth) => {
1224                 self.print_expr_struct(qpath, &fields[..], wth)?;
1225             }
1226             hir::ExprTup(ref exprs) => {
1227                 self.print_expr_tup(exprs)?;
1228             }
1229             hir::ExprCall(ref func, ref args) => {
1230                 self.print_expr_call(&func, args)?;
1231             }
1232             hir::ExprMethodCall(name, ref tys, ref args) => {
1233                 self.print_expr_method_call(name, &tys[..], args)?;
1234             }
1235             hir::ExprBinary(op, ref lhs, ref rhs) => {
1236                 self.print_expr_binary(op, &lhs, &rhs)?;
1237             }
1238             hir::ExprUnary(op, ref expr) => {
1239                 self.print_expr_unary(op, &expr)?;
1240             }
1241             hir::ExprAddrOf(m, ref expr) => {
1242                 self.print_expr_addr_of(m, &expr)?;
1243             }
1244             hir::ExprLit(ref lit) => {
1245                 self.print_literal(&lit)?;
1246             }
1247             hir::ExprCast(ref expr, ref ty) => {
1248                 self.print_expr(&expr)?;
1249                 space(&mut self.s)?;
1250                 self.word_space("as")?;
1251                 self.print_type(&ty)?;
1252             }
1253             hir::ExprType(ref expr, ref ty) => {
1254                 self.print_expr(&expr)?;
1255                 self.word_space(":")?;
1256                 self.print_type(&ty)?;
1257             }
1258             hir::ExprIf(ref test, ref blk, ref elseopt) => {
1259                 self.print_if(&test, &blk, elseopt.as_ref().map(|e| &**e))?;
1260             }
1261             hir::ExprWhile(ref test, ref blk, opt_sp_name) => {
1262                 if let Some(sp_name) = opt_sp_name {
1263                     self.print_name(sp_name.node)?;
1264                     self.word_space(":")?;
1265                 }
1266                 self.head("while")?;
1267                 self.print_expr(&test)?;
1268                 space(&mut self.s)?;
1269                 self.print_block(&blk)?;
1270             }
1271             hir::ExprLoop(ref blk, opt_sp_name, _) => {
1272                 if let Some(sp_name) = opt_sp_name {
1273                     self.print_name(sp_name.node)?;
1274                     self.word_space(":")?;
1275                 }
1276                 self.head("loop")?;
1277                 space(&mut self.s)?;
1278                 self.print_block(&blk)?;
1279             }
1280             hir::ExprMatch(ref expr, ref arms, _) => {
1281                 self.cbox(indent_unit)?;
1282                 self.ibox(4)?;
1283                 self.word_nbsp("match")?;
1284                 self.print_expr(&expr)?;
1285                 space(&mut self.s)?;
1286                 self.bopen()?;
1287                 for arm in arms {
1288                     self.print_arm(arm)?;
1289                 }
1290                 self.bclose_(expr.span, indent_unit)?;
1291             }
1292             hir::ExprClosure(capture_clause, ref decl, body, _fn_decl_span) => {
1293                 self.print_capture_clause(capture_clause)?;
1294
1295                 self.print_closure_args(&decl, body)?;
1296                 space(&mut self.s)?;
1297
1298                 // this is a bare expression
1299                 self.ann.nested(self, Nested::Body(body))?;
1300                 self.end()?; // need to close a box
1301
1302                 // a box will be closed by print_expr, but we didn't want an overall
1303                 // wrapper so we closed the corresponding opening. so create an
1304                 // empty box to satisfy the close.
1305                 self.ibox(0)?;
1306             }
1307             hir::ExprBlock(ref blk) => {
1308                 // containing cbox, will be closed by print-block at }
1309                 self.cbox(indent_unit)?;
1310                 // head-box, will be closed by print-block after {
1311                 self.ibox(0)?;
1312                 self.print_block(&blk)?;
1313             }
1314             hir::ExprAssign(ref lhs, ref rhs) => {
1315                 self.print_expr(&lhs)?;
1316                 space(&mut self.s)?;
1317                 self.word_space("=")?;
1318                 self.print_expr(&rhs)?;
1319             }
1320             hir::ExprAssignOp(op, ref lhs, ref rhs) => {
1321                 self.print_expr(&lhs)?;
1322                 space(&mut self.s)?;
1323                 word(&mut self.s, op.node.as_str())?;
1324                 self.word_space("=")?;
1325                 self.print_expr(&rhs)?;
1326             }
1327             hir::ExprField(ref expr, name) => {
1328                 self.print_expr(&expr)?;
1329                 word(&mut self.s, ".")?;
1330                 self.print_name(name.node)?;
1331             }
1332             hir::ExprTupField(ref expr, id) => {
1333                 self.print_expr(&expr)?;
1334                 word(&mut self.s, ".")?;
1335                 self.print_usize(id.node)?;
1336             }
1337             hir::ExprIndex(ref expr, ref index) => {
1338                 self.print_expr(&expr)?;
1339                 word(&mut self.s, "[")?;
1340                 self.print_expr(&index)?;
1341                 word(&mut self.s, "]")?;
1342             }
1343             hir::ExprPath(ref qpath) => {
1344                 self.print_qpath(qpath, true)?
1345             }
1346             hir::ExprBreak(opt_label, ref opt_expr) => {
1347                 word(&mut self.s, "break")?;
1348                 space(&mut self.s)?;
1349                 if let Some(label) = opt_label {
1350                     self.print_name(label.name)?;
1351                     space(&mut self.s)?;
1352                 }
1353                 if let Some(ref expr) = *opt_expr {
1354                     self.print_expr(expr)?;
1355                     space(&mut self.s)?;
1356                 }
1357             }
1358             hir::ExprAgain(opt_label) => {
1359                 word(&mut self.s, "continue")?;
1360                 space(&mut self.s)?;
1361                 if let Some(label) = opt_label {
1362                     self.print_name(label.name)?;
1363                     space(&mut self.s)?
1364                 }
1365             }
1366             hir::ExprRet(ref result) => {
1367                 word(&mut self.s, "return")?;
1368                 match *result {
1369                     Some(ref expr) => {
1370                         word(&mut self.s, " ")?;
1371                         self.print_expr(&expr)?;
1372                     }
1373                     _ => (),
1374                 }
1375             }
1376             hir::ExprInlineAsm(ref a, ref outputs, ref inputs) => {
1377                 word(&mut self.s, "asm!")?;
1378                 self.popen()?;
1379                 self.print_string(&a.asm.as_str(), a.asm_str_style)?;
1380                 self.word_space(":")?;
1381
1382                 let mut out_idx = 0;
1383                 self.commasep(Inconsistent, &a.outputs, |s, out| {
1384                     let constraint = out.constraint.as_str();
1385                     let mut ch = constraint.chars();
1386                     match ch.next() {
1387                         Some('=') if out.is_rw => {
1388                             s.print_string(&format!("+{}", ch.as_str()),
1389                                            ast::StrStyle::Cooked)?
1390                         }
1391                         _ => s.print_string(&constraint, ast::StrStyle::Cooked)?,
1392                     }
1393                     s.popen()?;
1394                     s.print_expr(&outputs[out_idx])?;
1395                     s.pclose()?;
1396                     out_idx += 1;
1397                     Ok(())
1398                 })?;
1399                 space(&mut self.s)?;
1400                 self.word_space(":")?;
1401
1402                 let mut in_idx = 0;
1403                 self.commasep(Inconsistent, &a.inputs, |s, co| {
1404                     s.print_string(&co.as_str(), ast::StrStyle::Cooked)?;
1405                     s.popen()?;
1406                     s.print_expr(&inputs[in_idx])?;
1407                     s.pclose()?;
1408                     in_idx += 1;
1409                     Ok(())
1410                 })?;
1411                 space(&mut self.s)?;
1412                 self.word_space(":")?;
1413
1414                 self.commasep(Inconsistent, &a.clobbers, |s, co| {
1415                     s.print_string(&co.as_str(), ast::StrStyle::Cooked)?;
1416                     Ok(())
1417                 })?;
1418
1419                 let mut options = vec![];
1420                 if a.volatile {
1421                     options.push("volatile");
1422                 }
1423                 if a.alignstack {
1424                     options.push("alignstack");
1425                 }
1426                 if a.dialect == ast::AsmDialect::Intel {
1427                     options.push("intel");
1428                 }
1429
1430                 if !options.is_empty() {
1431                     space(&mut self.s)?;
1432                     self.word_space(":")?;
1433                     self.commasep(Inconsistent, &options, |s, &co| {
1434                         s.print_string(co, ast::StrStyle::Cooked)?;
1435                         Ok(())
1436                     })?;
1437                 }
1438
1439                 self.pclose()?;
1440             }
1441         }
1442         self.ann.post(self, NodeExpr(expr))?;
1443         self.end()
1444     }
1445
1446     pub fn print_local_decl(&mut self, loc: &hir::Local) -> io::Result<()> {
1447         self.print_pat(&loc.pat)?;
1448         if let Some(ref ty) = loc.ty {
1449             self.word_space(":")?;
1450             self.print_type(&ty)?;
1451         }
1452         Ok(())
1453     }
1454
1455     pub fn print_decl(&mut self, decl: &hir::Decl) -> io::Result<()> {
1456         self.maybe_print_comment(decl.span.lo)?;
1457         match decl.node {
1458             hir::DeclLocal(ref loc) => {
1459                 self.space_if_not_bol()?;
1460                 self.ibox(indent_unit)?;
1461                 self.word_nbsp("let")?;
1462
1463                 self.ibox(indent_unit)?;
1464                 self.print_local_decl(&loc)?;
1465                 self.end()?;
1466                 if let Some(ref init) = loc.init {
1467                     self.nbsp()?;
1468                     self.word_space("=")?;
1469                     self.print_expr(&init)?;
1470                 }
1471                 self.end()
1472             }
1473             hir::DeclItem(item) => {
1474                 self.ann.nested(self, Nested::Item(item))
1475             }
1476         }
1477     }
1478
1479     pub fn print_usize(&mut self, i: usize) -> io::Result<()> {
1480         word(&mut self.s, &i.to_string())
1481     }
1482
1483     pub fn print_name(&mut self, name: ast::Name) -> io::Result<()> {
1484         word(&mut self.s, &name.as_str())?;
1485         self.ann.post(self, NodeName(&name))
1486     }
1487
1488     pub fn print_for_decl(&mut self, loc: &hir::Local, coll: &hir::Expr) -> io::Result<()> {
1489         self.print_local_decl(loc)?;
1490         space(&mut self.s)?;
1491         self.word_space("in")?;
1492         self.print_expr(coll)
1493     }
1494
1495     pub fn print_path(&mut self,
1496                       path: &hir::Path,
1497                       colons_before_params: bool)
1498                       -> io::Result<()> {
1499         self.maybe_print_comment(path.span.lo)?;
1500
1501         for (i, segment) in path.segments.iter().enumerate() {
1502             if i > 0 {
1503                 word(&mut self.s, "::")?
1504             }
1505             if segment.name != keywords::CrateRoot.name() && segment.name != "$crate" {
1506                 self.print_name(segment.name)?;
1507                 self.print_path_parameters(&segment.parameters, colons_before_params)?;
1508             }
1509         }
1510
1511         Ok(())
1512     }
1513
1514     pub fn print_qpath(&mut self,
1515                        qpath: &hir::QPath,
1516                        colons_before_params: bool)
1517                        -> io::Result<()> {
1518         match *qpath {
1519             hir::QPath::Resolved(None, ref path) => {
1520                 self.print_path(path, colons_before_params)
1521             }
1522             hir::QPath::Resolved(Some(ref qself), ref path) => {
1523                 word(&mut self.s, "<")?;
1524                 self.print_type(qself)?;
1525                 space(&mut self.s)?;
1526                 self.word_space("as")?;
1527
1528                 for (i, segment) in path.segments[..path.segments.len() - 1].iter().enumerate() {
1529                     if i > 0 {
1530                         word(&mut self.s, "::")?
1531                     }
1532                     if segment.name != keywords::CrateRoot.name() && segment.name != "$crate" {
1533                         self.print_name(segment.name)?;
1534                         self.print_path_parameters(&segment.parameters, colons_before_params)?;
1535                     }
1536                 }
1537
1538                 word(&mut self.s, ">")?;
1539                 word(&mut self.s, "::")?;
1540                 let item_segment = path.segments.last().unwrap();
1541                 self.print_name(item_segment.name)?;
1542                 self.print_path_parameters(&item_segment.parameters, colons_before_params)
1543             }
1544             hir::QPath::TypeRelative(ref qself, ref item_segment) => {
1545                 word(&mut self.s, "<")?;
1546                 self.print_type(qself)?;
1547                 word(&mut self.s, ">")?;
1548                 word(&mut self.s, "::")?;
1549                 self.print_name(item_segment.name)?;
1550                 self.print_path_parameters(&item_segment.parameters, colons_before_params)
1551             }
1552         }
1553     }
1554
1555     fn print_path_parameters(&mut self,
1556                              parameters: &hir::PathParameters,
1557                              colons_before_params: bool)
1558                              -> io::Result<()> {
1559         if parameters.is_empty() {
1560             let infer_types = match *parameters {
1561                 hir::AngleBracketedParameters(ref data) => data.infer_types,
1562                 hir::ParenthesizedParameters(_) => false
1563             };
1564
1565             // FIXME(eddyb) See the comment below about infer_types.
1566             if !(infer_types && false) {
1567                 return Ok(());
1568             }
1569         }
1570
1571         if colons_before_params {
1572             word(&mut self.s, "::")?
1573         }
1574
1575         match *parameters {
1576             hir::AngleBracketedParameters(ref data) => {
1577                 word(&mut self.s, "<")?;
1578
1579                 let mut comma = false;
1580                 for lifetime in &data.lifetimes {
1581                     if comma {
1582                         self.word_space(",")?
1583                     }
1584                     self.print_lifetime(lifetime)?;
1585                     comma = true;
1586                 }
1587
1588                 if !data.types.is_empty() {
1589                     if comma {
1590                         self.word_space(",")?
1591                     }
1592                     self.commasep(Inconsistent, &data.types, |s, ty| s.print_type(&ty))?;
1593                     comma = true;
1594                 }
1595
1596                 // FIXME(eddyb) This would leak into error messages, e.g.:
1597                 // "non-exhaustive patterns: `Some::<..>(_)` not covered".
1598                 if data.infer_types && false {
1599                     if comma {
1600                         self.word_space(",")?
1601                     }
1602                     word(&mut self.s, "..")?;
1603                     comma = true;
1604                 }
1605
1606                 for binding in data.bindings.iter() {
1607                     if comma {
1608                         self.word_space(",")?
1609                     }
1610                     self.print_name(binding.name)?;
1611                     space(&mut self.s)?;
1612                     self.word_space("=")?;
1613                     self.print_type(&binding.ty)?;
1614                     comma = true;
1615                 }
1616
1617                 word(&mut self.s, ">")?
1618             }
1619
1620             hir::ParenthesizedParameters(ref data) => {
1621                 word(&mut self.s, "(")?;
1622                 self.commasep(Inconsistent, &data.inputs, |s, ty| s.print_type(&ty))?;
1623                 word(&mut self.s, ")")?;
1624
1625                 if let Some(ref ty) = data.output {
1626                     self.space_if_not_bol()?;
1627                     self.word_space("->")?;
1628                     self.print_type(&ty)?;
1629                 }
1630             }
1631         }
1632
1633         Ok(())
1634     }
1635
1636     pub fn print_pat(&mut self, pat: &hir::Pat) -> io::Result<()> {
1637         self.maybe_print_comment(pat.span.lo)?;
1638         self.ann.pre(self, NodePat(pat))?;
1639         // Pat isn't normalized, but the beauty of it
1640         // is that it doesn't matter
1641         match pat.node {
1642             PatKind::Wild => word(&mut self.s, "_")?,
1643             PatKind::Binding(binding_mode, _, ref path1, ref sub) => {
1644                 match binding_mode {
1645                     hir::BindByRef(mutbl) => {
1646                         self.word_nbsp("ref")?;
1647                         self.print_mutability(mutbl)?;
1648                     }
1649                     hir::BindByValue(hir::MutImmutable) => {}
1650                     hir::BindByValue(hir::MutMutable) => {
1651                         self.word_nbsp("mut")?;
1652                     }
1653                 }
1654                 self.print_name(path1.node)?;
1655                 if let Some(ref p) = *sub {
1656                     word(&mut self.s, "@")?;
1657                     self.print_pat(&p)?;
1658                 }
1659             }
1660             PatKind::TupleStruct(ref qpath, ref elts, ddpos) => {
1661                 self.print_qpath(qpath, true)?;
1662                 self.popen()?;
1663                 if let Some(ddpos) = ddpos {
1664                     self.commasep(Inconsistent, &elts[..ddpos], |s, p| s.print_pat(&p))?;
1665                     if ddpos != 0 {
1666                         self.word_space(",")?;
1667                     }
1668                     word(&mut self.s, "..")?;
1669                     if ddpos != elts.len() {
1670                         word(&mut self.s, ",")?;
1671                         self.commasep(Inconsistent, &elts[ddpos..], |s, p| s.print_pat(&p))?;
1672                     }
1673                 } else {
1674                     self.commasep(Inconsistent, &elts[..], |s, p| s.print_pat(&p))?;
1675                 }
1676                 self.pclose()?;
1677             }
1678             PatKind::Path(ref qpath) => {
1679                 self.print_qpath(qpath, true)?;
1680             }
1681             PatKind::Struct(ref qpath, ref fields, etc) => {
1682                 self.print_qpath(qpath, true)?;
1683                 self.nbsp()?;
1684                 self.word_space("{")?;
1685                 self.commasep_cmnt(Consistent,
1686                                    &fields[..],
1687                                    |s, f| {
1688                                        s.cbox(indent_unit)?;
1689                                        if !f.node.is_shorthand {
1690                                            s.print_name(f.node.name)?;
1691                                            s.word_nbsp(":")?;
1692                                        }
1693                                        s.print_pat(&f.node.pat)?;
1694                                        s.end()
1695                                    },
1696                                    |f| f.node.pat.span)?;
1697                 if etc {
1698                     if !fields.is_empty() {
1699                         self.word_space(",")?;
1700                     }
1701                     word(&mut self.s, "..")?;
1702                 }
1703                 space(&mut self.s)?;
1704                 word(&mut self.s, "}")?;
1705             }
1706             PatKind::Tuple(ref elts, ddpos) => {
1707                 self.popen()?;
1708                 if let Some(ddpos) = ddpos {
1709                     self.commasep(Inconsistent, &elts[..ddpos], |s, p| s.print_pat(&p))?;
1710                     if ddpos != 0 {
1711                         self.word_space(",")?;
1712                     }
1713                     word(&mut self.s, "..")?;
1714                     if ddpos != elts.len() {
1715                         word(&mut self.s, ",")?;
1716                         self.commasep(Inconsistent, &elts[ddpos..], |s, p| s.print_pat(&p))?;
1717                     }
1718                 } else {
1719                     self.commasep(Inconsistent, &elts[..], |s, p| s.print_pat(&p))?;
1720                     if elts.len() == 1 {
1721                         word(&mut self.s, ",")?;
1722                     }
1723                 }
1724                 self.pclose()?;
1725             }
1726             PatKind::Box(ref inner) => {
1727                 word(&mut self.s, "box ")?;
1728                 self.print_pat(&inner)?;
1729             }
1730             PatKind::Ref(ref inner, mutbl) => {
1731                 word(&mut self.s, "&")?;
1732                 if mutbl == hir::MutMutable {
1733                     word(&mut self.s, "mut ")?;
1734                 }
1735                 self.print_pat(&inner)?;
1736             }
1737             PatKind::Lit(ref e) => self.print_expr(&e)?,
1738             PatKind::Range(ref begin, ref end) => {
1739                 self.print_expr(&begin)?;
1740                 space(&mut self.s)?;
1741                 word(&mut self.s, "...")?;
1742                 self.print_expr(&end)?;
1743             }
1744             PatKind::Slice(ref before, ref slice, ref after) => {
1745                 word(&mut self.s, "[")?;
1746                 self.commasep(Inconsistent, &before[..], |s, p| s.print_pat(&p))?;
1747                 if let Some(ref p) = *slice {
1748                     if !before.is_empty() {
1749                         self.word_space(",")?;
1750                     }
1751                     if p.node != PatKind::Wild {
1752                         self.print_pat(&p)?;
1753                     }
1754                     word(&mut self.s, "..")?;
1755                     if !after.is_empty() {
1756                         self.word_space(",")?;
1757                     }
1758                 }
1759                 self.commasep(Inconsistent, &after[..], |s, p| s.print_pat(&p))?;
1760                 word(&mut self.s, "]")?;
1761             }
1762         }
1763         self.ann.post(self, NodePat(pat))
1764     }
1765
1766     fn print_arm(&mut self, arm: &hir::Arm) -> io::Result<()> {
1767         // I have no idea why this check is necessary, but here it
1768         // is :(
1769         if arm.attrs.is_empty() {
1770             space(&mut self.s)?;
1771         }
1772         self.cbox(indent_unit)?;
1773         self.ibox(0)?;
1774         self.print_outer_attributes(&arm.attrs)?;
1775         let mut first = true;
1776         for p in &arm.pats {
1777             if first {
1778                 first = false;
1779             } else {
1780                 space(&mut self.s)?;
1781                 self.word_space("|")?;
1782             }
1783             self.print_pat(&p)?;
1784         }
1785         space(&mut self.s)?;
1786         if let Some(ref e) = arm.guard {
1787             self.word_space("if")?;
1788             self.print_expr(&e)?;
1789             space(&mut self.s)?;
1790         }
1791         self.word_space("=>")?;
1792
1793         match arm.body.node {
1794             hir::ExprBlock(ref blk) => {
1795                 // the block will close the pattern's ibox
1796                 self.print_block_unclosed_indent(&blk, indent_unit)?;
1797
1798                 // If it is a user-provided unsafe block, print a comma after it
1799                 if let hir::UnsafeBlock(hir::UserProvided) = blk.rules {
1800                     word(&mut self.s, ",")?;
1801                 }
1802             }
1803             _ => {
1804                 self.end()?; // close the ibox for the pattern
1805                 self.print_expr(&arm.body)?;
1806                 word(&mut self.s, ",")?;
1807             }
1808         }
1809         self.end() // close enclosing cbox
1810     }
1811
1812     pub fn print_fn(&mut self,
1813                     decl: &hir::FnDecl,
1814                     unsafety: hir::Unsafety,
1815                     constness: hir::Constness,
1816                     abi: Abi,
1817                     name: Option<ast::Name>,
1818                     generics: &hir::Generics,
1819                     vis: &hir::Visibility,
1820                     arg_names: &[Spanned<ast::Name>],
1821                     body_id: Option<hir::BodyId>)
1822                     -> io::Result<()> {
1823         self.print_fn_header_info(unsafety, constness, abi, vis)?;
1824
1825         if let Some(name) = name {
1826             self.nbsp()?;
1827             self.print_name(name)?;
1828         }
1829         self.print_generics(generics)?;
1830
1831         self.popen()?;
1832         let mut i = 0;
1833         // Make sure we aren't supplied *both* `arg_names` and `body_id`.
1834         assert!(arg_names.is_empty() || body_id.is_none());
1835         self.commasep(Inconsistent, &decl.inputs, |s, ty| {
1836             s.ibox(indent_unit)?;
1837             if let Some(name) = arg_names.get(i) {
1838                 word(&mut s.s, &name.node.as_str())?;
1839                 word(&mut s.s, ":")?;
1840                 space(&mut s.s)?;
1841             } else if let Some(body_id) = body_id {
1842                 s.ann.nested(s, Nested::BodyArgPat(body_id, i))?;
1843                 word(&mut s.s, ":")?;
1844                 space(&mut s.s)?;
1845             }
1846             i += 1;
1847             s.print_type(ty)?;
1848             s.end()
1849         })?;
1850         if decl.variadic {
1851             word(&mut self.s, ", ...")?;
1852         }
1853         self.pclose()?;
1854
1855         self.print_fn_output(decl)?;
1856         self.print_where_clause(&generics.where_clause)
1857     }
1858
1859     fn print_closure_args(&mut self, decl: &hir::FnDecl, body_id: hir::BodyId) -> io::Result<()> {
1860         word(&mut self.s, "|")?;
1861         let mut i = 0;
1862         self.commasep(Inconsistent, &decl.inputs, |s, ty| {
1863             s.ibox(indent_unit)?;
1864
1865             s.ann.nested(s, Nested::BodyArgPat(body_id, i))?;
1866             i += 1;
1867
1868             if ty.node != hir::TyInfer {
1869                 word(&mut s.s, ":")?;
1870                 space(&mut s.s)?;
1871                 s.print_type(ty)?;
1872             }
1873             s.end()
1874         })?;
1875         word(&mut self.s, "|")?;
1876
1877         if let hir::DefaultReturn(..) = decl.output {
1878             return Ok(());
1879         }
1880
1881         self.space_if_not_bol()?;
1882         self.word_space("->")?;
1883         match decl.output {
1884             hir::Return(ref ty) => {
1885                 self.print_type(&ty)?;
1886                 self.maybe_print_comment(ty.span.lo)
1887             }
1888             hir::DefaultReturn(..) => unreachable!(),
1889         }
1890     }
1891
1892     pub fn print_capture_clause(&mut self, capture_clause: hir::CaptureClause) -> io::Result<()> {
1893         match capture_clause {
1894             hir::CaptureByValue => self.word_space("move"),
1895             hir::CaptureByRef => Ok(()),
1896         }
1897     }
1898
1899     pub fn print_bounds(&mut self, prefix: &str, bounds: &[hir::TyParamBound]) -> io::Result<()> {
1900         if !bounds.is_empty() {
1901             word(&mut self.s, prefix)?;
1902             let mut first = true;
1903             for bound in bounds {
1904                 self.nbsp()?;
1905                 if first {
1906                     first = false;
1907                 } else {
1908                     self.word_space("+")?;
1909                 }
1910
1911                 match *bound {
1912                     TraitTyParamBound(ref tref, TraitBoundModifier::None) => {
1913                         self.print_poly_trait_ref(tref)
1914                     }
1915                     TraitTyParamBound(ref tref, TraitBoundModifier::Maybe) => {
1916                         word(&mut self.s, "?")?;
1917                         self.print_poly_trait_ref(tref)
1918                     }
1919                     RegionTyParamBound(ref lt) => {
1920                         self.print_lifetime(lt)
1921                     }
1922                 }?
1923             }
1924             Ok(())
1925         } else {
1926             Ok(())
1927         }
1928     }
1929
1930     pub fn print_lifetime(&mut self, lifetime: &hir::Lifetime) -> io::Result<()> {
1931         self.print_name(lifetime.name)
1932     }
1933
1934     pub fn print_lifetime_def(&mut self, lifetime: &hir::LifetimeDef) -> io::Result<()> {
1935         self.print_lifetime(&lifetime.lifetime)?;
1936         let mut sep = ":";
1937         for v in &lifetime.bounds {
1938             word(&mut self.s, sep)?;
1939             self.print_lifetime(v)?;
1940             sep = "+";
1941         }
1942         Ok(())
1943     }
1944
1945     pub fn print_generics(&mut self, generics: &hir::Generics) -> io::Result<()> {
1946         let total = generics.lifetimes.len() + generics.ty_params.len();
1947         if total == 0 {
1948             return Ok(());
1949         }
1950
1951         word(&mut self.s, "<")?;
1952
1953         let mut ints = Vec::new();
1954         for i in 0..total {
1955             ints.push(i);
1956         }
1957
1958         self.commasep(Inconsistent, &ints[..], |s, &idx| {
1959             if idx < generics.lifetimes.len() {
1960                 let lifetime = &generics.lifetimes[idx];
1961                 s.print_lifetime_def(lifetime)
1962             } else {
1963                 let idx = idx - generics.lifetimes.len();
1964                 let param = &generics.ty_params[idx];
1965                 s.print_ty_param(param)
1966             }
1967         })?;
1968
1969         word(&mut self.s, ">")?;
1970         Ok(())
1971     }
1972
1973     pub fn print_ty_param(&mut self, param: &hir::TyParam) -> io::Result<()> {
1974         self.print_name(param.name)?;
1975         self.print_bounds(":", &param.bounds)?;
1976         match param.default {
1977             Some(ref default) => {
1978                 space(&mut self.s)?;
1979                 self.word_space("=")?;
1980                 self.print_type(&default)
1981             }
1982             _ => Ok(()),
1983         }
1984     }
1985
1986     pub fn print_where_clause(&mut self, where_clause: &hir::WhereClause) -> io::Result<()> {
1987         if where_clause.predicates.is_empty() {
1988             return Ok(());
1989         }
1990
1991         space(&mut self.s)?;
1992         self.word_space("where")?;
1993
1994         for (i, predicate) in where_clause.predicates.iter().enumerate() {
1995             if i != 0 {
1996                 self.word_space(",")?;
1997             }
1998
1999             match predicate {
2000                 &hir::WherePredicate::BoundPredicate(hir::WhereBoundPredicate{ref bound_lifetimes,
2001                                                                               ref bounded_ty,
2002                                                                               ref bounds,
2003                                                                               ..}) => {
2004                     self.print_formal_lifetime_list(bound_lifetimes)?;
2005                     self.print_type(&bounded_ty)?;
2006                     self.print_bounds(":", bounds)?;
2007                 }
2008                 &hir::WherePredicate::RegionPredicate(hir::WhereRegionPredicate{ref lifetime,
2009                                                                                 ref bounds,
2010                                                                                 ..}) => {
2011                     self.print_lifetime(lifetime)?;
2012                     word(&mut self.s, ":")?;
2013
2014                     for (i, bound) in bounds.iter().enumerate() {
2015                         self.print_lifetime(bound)?;
2016
2017                         if i != 0 {
2018                             word(&mut self.s, ":")?;
2019                         }
2020                     }
2021                 }
2022                 &hir::WherePredicate::EqPredicate(hir::WhereEqPredicate{ref lhs_ty,
2023                                                                         ref rhs_ty,
2024                                                                         ..}) => {
2025                     self.print_type(lhs_ty)?;
2026                     space(&mut self.s)?;
2027                     self.word_space("=")?;
2028                     self.print_type(rhs_ty)?;
2029                 }
2030             }
2031         }
2032
2033         Ok(())
2034     }
2035
2036     pub fn print_mutability(&mut self, mutbl: hir::Mutability) -> io::Result<()> {
2037         match mutbl {
2038             hir::MutMutable => self.word_nbsp("mut"),
2039             hir::MutImmutable => Ok(()),
2040         }
2041     }
2042
2043     pub fn print_mt(&mut self, mt: &hir::MutTy) -> io::Result<()> {
2044         self.print_mutability(mt.mutbl)?;
2045         self.print_type(&mt.ty)
2046     }
2047
2048     pub fn print_fn_output(&mut self, decl: &hir::FnDecl) -> io::Result<()> {
2049         if let hir::DefaultReturn(..) = decl.output {
2050             return Ok(());
2051         }
2052
2053         self.space_if_not_bol()?;
2054         self.ibox(indent_unit)?;
2055         self.word_space("->")?;
2056         match decl.output {
2057             hir::DefaultReturn(..) => unreachable!(),
2058             hir::Return(ref ty) => self.print_type(&ty)?,
2059         }
2060         self.end()?;
2061
2062         match decl.output {
2063             hir::Return(ref output) => self.maybe_print_comment(output.span.lo),
2064             _ => Ok(()),
2065         }
2066     }
2067
2068     pub fn print_ty_fn(&mut self,
2069                        abi: Abi,
2070                        unsafety: hir::Unsafety,
2071                        decl: &hir::FnDecl,
2072                        name: Option<ast::Name>,
2073                        generics: &hir::Generics)
2074                        -> io::Result<()> {
2075         self.ibox(indent_unit)?;
2076         if !generics.lifetimes.is_empty() || !generics.ty_params.is_empty() {
2077             word(&mut self.s, "for")?;
2078             self.print_generics(generics)?;
2079         }
2080         let generics = hir::Generics {
2081             lifetimes: hir::HirVec::new(),
2082             ty_params: hir::HirVec::new(),
2083             where_clause: hir::WhereClause {
2084                 id: ast::DUMMY_NODE_ID,
2085                 predicates: hir::HirVec::new(),
2086             },
2087             span: syntax_pos::DUMMY_SP,
2088         };
2089         self.print_fn(decl,
2090                       unsafety,
2091                       hir::Constness::NotConst,
2092                       abi,
2093                       name,
2094                       &generics,
2095                       &hir::Inherited,
2096                       &[],
2097                       None)?;
2098         self.end()
2099     }
2100
2101     pub fn maybe_print_trailing_comment(&mut self,
2102                                         span: syntax_pos::Span,
2103                                         next_pos: Option<BytePos>)
2104                                         -> io::Result<()> {
2105         let cm = match self.cm {
2106             Some(cm) => cm,
2107             _ => return Ok(()),
2108         };
2109         if let Some(ref cmnt) = self.next_comment() {
2110             if (*cmnt).style != comments::Trailing {
2111                 return Ok(());
2112             }
2113             let span_line = cm.lookup_char_pos(span.hi);
2114             let comment_line = cm.lookup_char_pos((*cmnt).pos);
2115             let mut next = (*cmnt).pos + BytePos(1);
2116             if let Some(p) = next_pos {
2117                 next = p;
2118             }
2119             if span.hi < (*cmnt).pos && (*cmnt).pos < next &&
2120                span_line.line == comment_line.line {
2121                 self.print_comment(cmnt)?;
2122                 self.cur_cmnt_and_lit.cur_cmnt += 1;
2123             }
2124         }
2125         Ok(())
2126     }
2127
2128     pub fn print_remaining_comments(&mut self) -> io::Result<()> {
2129         // If there aren't any remaining comments, then we need to manually
2130         // make sure there is a line break at the end.
2131         if self.next_comment().is_none() {
2132             hardbreak(&mut self.s)?;
2133         }
2134         loop {
2135             match self.next_comment() {
2136                 Some(ref cmnt) => {
2137                     self.print_comment(cmnt)?;
2138                     self.cur_cmnt_and_lit.cur_cmnt += 1;
2139                 }
2140                 _ => break,
2141             }
2142         }
2143         Ok(())
2144     }
2145
2146     pub fn print_opt_abi_and_extern_if_nondefault(&mut self,
2147                                                   opt_abi: Option<Abi>)
2148                                                   -> io::Result<()> {
2149         match opt_abi {
2150             Some(Abi::Rust) => Ok(()),
2151             Some(abi) => {
2152                 self.word_nbsp("extern")?;
2153                 self.word_nbsp(&abi.to_string())
2154             }
2155             None => Ok(()),
2156         }
2157     }
2158
2159     pub fn print_extern_opt_abi(&mut self, opt_abi: Option<Abi>) -> io::Result<()> {
2160         match opt_abi {
2161             Some(abi) => {
2162                 self.word_nbsp("extern")?;
2163                 self.word_nbsp(&abi.to_string())
2164             }
2165             None => Ok(()),
2166         }
2167     }
2168
2169     pub fn print_fn_header_info(&mut self,
2170                                 unsafety: hir::Unsafety,
2171                                 constness: hir::Constness,
2172                                 abi: Abi,
2173                                 vis: &hir::Visibility)
2174                                 -> io::Result<()> {
2175         word(&mut self.s, &visibility_qualified(vis, ""))?;
2176         self.print_unsafety(unsafety)?;
2177
2178         match constness {
2179             hir::Constness::NotConst => {}
2180             hir::Constness::Const => self.word_nbsp("const")?,
2181         }
2182
2183         if abi != Abi::Rust {
2184             self.word_nbsp("extern")?;
2185             self.word_nbsp(&abi.to_string())?;
2186         }
2187
2188         word(&mut self.s, "fn")
2189     }
2190
2191     pub fn print_unsafety(&mut self, s: hir::Unsafety) -> io::Result<()> {
2192         match s {
2193             hir::Unsafety::Normal => Ok(()),
2194             hir::Unsafety::Unsafe => self.word_nbsp("unsafe"),
2195         }
2196     }
2197 }
2198
2199 // Dup'ed from parse::classify, but adapted for the HIR.
2200 /// Does this expression require a semicolon to be treated
2201 /// as a statement? The negation of this: 'can this expression
2202 /// be used as a statement without a semicolon' -- is used
2203 /// as an early-bail-out in the parser so that, for instance,
2204 ///     if true {...} else {...}
2205 ///      |x| 5
2206 /// isn't parsed as (if true {...} else {...} | x) | 5
2207 fn expr_requires_semi_to_be_stmt(e: &hir::Expr) -> bool {
2208     match e.node {
2209         hir::ExprIf(..) |
2210         hir::ExprMatch(..) |
2211         hir::ExprBlock(_) |
2212         hir::ExprWhile(..) |
2213         hir::ExprLoop(..) => false,
2214         _ => true,
2215     }
2216 }
2217
2218 /// this statement requires a semicolon after it.
2219 /// note that in one case (stmt_semi), we've already
2220 /// seen the semicolon, and thus don't need another.
2221 fn stmt_ends_with_semi(stmt: &hir::Stmt_) -> bool {
2222     match *stmt {
2223         hir::StmtDecl(ref d, _) => {
2224             match d.node {
2225                 hir::DeclLocal(_) => true,
2226                 hir::DeclItem(_) => false,
2227             }
2228         }
2229         hir::StmtExpr(ref e, _) => {
2230             expr_requires_semi_to_be_stmt(&e)
2231         }
2232         hir::StmtSemi(..) => {
2233             false
2234         }
2235     }
2236 }