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