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