]> git.lizzy.rs Git - rust.git/blob - src/items.rs
Fix a bug with nested impls
[rust.git] / src / items.rs
1 // Copyright 2015 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
4 //
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
10
11 // Formatting top-level items - functions, structs, enums, traits, impls.
12
13 use Indent;
14 use utils::{format_mutability, format_visibility, contains_skip, span_after, end_typaram,
15             wrap_str, last_line_width, semicolon_for_expr, format_unsafety, trim_newlines};
16 use lists::{write_list, itemize_list, ListItem, ListFormatting, SeparatorTactic,
17             DefinitiveListTactic, definitive_tactic, format_item_list};
18 use expr::{is_empty_block, is_simple_block_stmt, rewrite_assign_rhs};
19 use comment::FindUncommented;
20 use visitor::FmtVisitor;
21 use rewrite::{Rewrite, RewriteContext};
22 use config::{Config, BlockIndentStyle, Density, ReturnIndent, BraceStyle, StructLitStyle};
23
24 use syntax::{ast, abi};
25 use syntax::codemap::{Span, BytePos, mk_sp};
26 use syntax::print::pprust;
27 use syntax::parse::token;
28
29 // Statements of the form
30 // let pat: ty = init;
31 impl Rewrite for ast::Local {
32     fn rewrite(&self, context: &RewriteContext, width: usize, offset: Indent) -> Option<String> {
33         let mut result = "let ".to_owned();
34         let pattern_offset = offset + result.len();
35         // 1 = ;
36         let pattern_width = try_opt!(width.checked_sub(pattern_offset.width() + 1));
37
38         let pat_str = try_opt!(self.pat.rewrite(&context, pattern_width, pattern_offset));
39         result.push_str(&pat_str);
40
41         // String that is placed within the assignment pattern and expression.
42         let infix = {
43             let mut infix = String::new();
44
45             if let Some(ref ty) = self.ty {
46                 // 2 = ": ".len()
47                 // 1 = ;
48                 let indent = offset + last_line_width(&result) + 2;
49                 let budget = try_opt!(width.checked_sub(indent.width() + 1));
50                 let rewrite = try_opt!(ty.rewrite(context, budget, indent));
51
52                 infix.push_str(": ");
53                 infix.push_str(&rewrite);
54             }
55
56             if self.init.is_some() {
57                 infix.push_str(" =");
58             }
59
60             infix
61         };
62
63         result.push_str(&infix);
64
65         if let Some(ref ex) = self.init {
66             let budget = try_opt!(width.checked_sub(context.block_indent.width() + 1));
67
68             // 1 = trailing semicolon;
69             result = try_opt!(rewrite_assign_rhs(&context,
70                                                  result,
71                                                  ex,
72                                                  budget,
73                                                  context.block_indent));
74         }
75
76         result.push(';');
77         Some(result)
78     }
79 }
80
81 impl<'a> FmtVisitor<'a> {
82     pub fn format_foreign_mod(&mut self, fm: &ast::ForeignMod, span: Span) {
83         self.buffer.push_str(&::utils::format_abi(fm.abi));
84
85         let snippet = self.snippet(span);
86         let brace_pos = snippet.find_uncommented("{").unwrap() as u32;
87
88         // FIXME: this skips comments between the extern keyword and the opening
89         // brace.
90         self.last_pos = span.lo + BytePos(brace_pos);
91         self.block_indent = self.block_indent.block_indent(self.config);
92
93         for item in &fm.items {
94             self.format_foreign_item(&*item);
95         }
96
97         self.block_indent = self.block_indent.block_unindent(self.config);
98         self.format_missing_with_indent(span.hi - BytePos(1));
99         self.buffer.push_str("}");
100         self.last_pos = span.hi;
101     }
102
103     fn format_foreign_item(&mut self, item: &ast::ForeignItem) {
104         self.format_missing_with_indent(item.span.lo);
105         // Drop semicolon or it will be interpreted as comment.
106         // FIXME: this may be a faulty span from libsyntax.
107         let span = mk_sp(item.span.lo, item.span.hi - BytePos(1));
108
109         match item.node {
110             ast::ForeignItem_::ForeignItemFn(ref fn_decl, ref generics) => {
111                 let indent = self.block_indent;
112                 let rewrite = rewrite_fn_base(&self.get_context(),
113                                               indent,
114                                               item.ident,
115                                               fn_decl,
116                                               None,
117                                               generics,
118                                               ast::Unsafety::Normal,
119                                               ast::Constness::NotConst,
120                                               // These are not actually rust functions,
121                                               // but we format them as such.
122                                               abi::Abi::Rust,
123                                               item.vis,
124                                               span,
125                                               false,
126                                               false);
127
128                 match rewrite {
129                     Some((new_fn, _)) => {
130                         self.buffer.push_str(&new_fn);
131                         self.buffer.push_str(";");
132                     }
133                     None => self.format_missing(item.span.hi),
134                 }
135             }
136             ast::ForeignItem_::ForeignItemStatic(ref ty, is_mutable) => {
137                 // FIXME(#21): we're dropping potential comments in between the
138                 // function keywords here.
139                 let mut_str = if is_mutable {
140                     "mut "
141                 } else {
142                     ""
143                 };
144                 let prefix = format!("{}static {}{}: ",
145                                      format_visibility(item.vis),
146                                      mut_str,
147                                      item.ident);
148                 let offset = self.block_indent + prefix.len();
149                 // 1 = ;
150                 let width = self.config.max_width - offset.width() - 1;
151                 let rewrite = ty.rewrite(&self.get_context(), width, offset);
152
153                 match rewrite {
154                     Some(result) => {
155                         self.buffer.push_str(&prefix);
156                         self.buffer.push_str(&result);
157                         self.buffer.push_str(";");
158                     }
159                     None => self.format_missing(item.span.hi),
160                 }
161             }
162         }
163
164         self.last_pos = item.span.hi;
165     }
166
167     pub fn rewrite_fn(&mut self,
168                       indent: Indent,
169                       ident: ast::Ident,
170                       fd: &ast::FnDecl,
171                       explicit_self: Option<&ast::ExplicitSelf>,
172                       generics: &ast::Generics,
173                       unsafety: ast::Unsafety,
174                       constness: ast::Constness,
175                       abi: abi::Abi,
176                       vis: ast::Visibility,
177                       span: Span,
178                       block: &ast::Block)
179                       -> Option<String> {
180         let mut newline_brace = newline_for_brace(self.config, &generics.where_clause);
181         let context = self.get_context();
182
183         let (mut result, force_newline_brace) = try_opt!(rewrite_fn_base(&context,
184                                                                          indent,
185                                                                          ident,
186                                                                          fd,
187                                                                          explicit_self,
188                                                                          generics,
189                                                                          unsafety,
190                                                                          constness,
191                                                                          abi,
192                                                                          vis,
193                                                                          span,
194                                                                          newline_brace,
195                                                                          true));
196
197         if self.config.fn_brace_style != BraceStyle::AlwaysNextLine && !result.contains('\n') {
198             newline_brace = false;
199         } else if force_newline_brace {
200             newline_brace = true;
201         }
202
203         // Prepare for the function body by possibly adding a newline and
204         // indent.
205         // FIXME we'll miss anything between the end of the signature and the
206         // start of the body, but we need more spans from the compiler to solve
207         // this.
208         if newline_brace {
209             result.push('\n');
210             result.push_str(&indent.to_string(self.config));
211         } else {
212             result.push(' ');
213         }
214
215         self.single_line_fn(&result, block).or_else(|| Some(result))
216     }
217
218     pub fn rewrite_required_fn(&mut self,
219                                indent: Indent,
220                                ident: ast::Ident,
221                                sig: &ast::MethodSig,
222                                span: Span)
223                                -> Option<String> {
224         // Drop semicolon or it will be interpreted as comment
225         let span = mk_sp(span.lo, span.hi - BytePos(1));
226         let context = self.get_context();
227
228         // FIXME: silly formatting of the `.0`.
229         let mut result = try_opt!(rewrite_fn_base(&context,
230                                                   indent,
231                                                   ident,
232                                                   &sig.decl,
233                                                   Some(&sig.explicit_self),
234                                                   &sig.generics,
235                                                   sig.unsafety,
236                                                   sig.constness,
237                                                   sig.abi,
238                                                   ast::Visibility::Inherited,
239                                                   span,
240                                                   false,
241                                                   false))
242                              .0;
243
244         // Re-attach semicolon
245         result.push(';');
246
247         Some(result)
248     }
249
250     fn single_line_fn(&self, fn_str: &str, block: &ast::Block) -> Option<String> {
251         if fn_str.contains('\n') {
252             return None;
253         }
254
255         let codemap = self.get_context().codemap;
256
257         if self.config.fn_empty_single_line && is_empty_block(block, codemap) &&
258            self.block_indent.width() + fn_str.len() + 2 <= self.config.max_width {
259             return Some(format!("{}{{}}", fn_str));
260         }
261
262         if self.config.fn_single_line && is_simple_block_stmt(block, codemap) {
263             let rewrite = {
264                 if let Some(ref e) = block.expr {
265                     let suffix = if semicolon_for_expr(e) {
266                         ";"
267                     } else {
268                         ""
269                     };
270
271                     e.rewrite(&self.get_context(),
272                               self.config.max_width - self.block_indent.width(),
273                               self.block_indent)
274                      .map(|s| s + suffix)
275                      .or_else(|| Some(self.snippet(e.span)))
276                 } else if let Some(ref stmt) = block.stmts.first() {
277                     stmt.rewrite(&self.get_context(),
278                                  self.config.max_width - self.block_indent.width(),
279                                  self.block_indent)
280                 } else {
281                     None
282                 }
283             };
284
285             if let Some(res) = rewrite {
286                 let width = self.block_indent.width() + fn_str.len() + res.len() + 4;
287                 if !res.contains('\n') && width <= self.config.max_width {
288                     return Some(format!("{}{{ {} }}", fn_str, res));
289                 }
290             }
291         }
292
293         None
294     }
295
296     pub fn visit_enum(&mut self,
297                       ident: ast::Ident,
298                       vis: ast::Visibility,
299                       enum_def: &ast::EnumDef,
300                       generics: &ast::Generics,
301                       span: Span) {
302         let header_str = format_header("enum ", ident, vis);
303         self.buffer.push_str(&header_str);
304
305         let enum_snippet = self.snippet(span);
306         let body_start = span.lo + BytePos(enum_snippet.find_uncommented("{").unwrap() as u32 + 1);
307         let generics_str = format_generics(&self.get_context(),
308                                            generics,
309                                            "{",
310                                            "{",
311                                            self.config.item_brace_style,
312                                            enum_def.variants.is_empty(),
313                                            self.block_indent,
314                                            self.block_indent.block_indent(self.config),
315                                            mk_sp(span.lo, body_start))
316                                .unwrap();
317         self.buffer.push_str(&generics_str);
318
319         self.last_pos = body_start;
320
321         self.block_indent = self.block_indent.block_indent(self.config);
322         let variant_list = self.format_variant_list(enum_def, body_start, span.hi - BytePos(1));
323         match variant_list {
324             Some(ref body_str) => self.buffer.push_str(&body_str),
325             None => self.format_missing(span.hi - BytePos(1)),
326         }
327         self.block_indent = self.block_indent.block_unindent(self.config);
328
329         if variant_list.is_some() {
330             self.buffer.push_str(&self.block_indent.to_string(self.config));
331         }
332         self.buffer.push_str("}");
333         self.last_pos = span.hi;
334     }
335
336     // Format the body of an enum definition
337     fn format_variant_list(&self,
338                            enum_def: &ast::EnumDef,
339                            body_lo: BytePos,
340                            body_hi: BytePos)
341                            -> Option<String> {
342         if enum_def.variants.is_empty() {
343             return None;
344         }
345         let mut result = String::with_capacity(1024);
346         result.push('\n');
347         let indentation = self.block_indent.to_string(self.config);
348         result.push_str(&indentation);
349
350         let items = itemize_list(self.codemap,
351                                  enum_def.variants.iter(),
352                                  "}",
353                                  |f| {
354                                      if !f.node.attrs.is_empty() {
355                                          f.node.attrs[0].span.lo
356                                      } else {
357                                          f.span.lo
358                                      }
359                                  },
360                                  |f| f.span.hi,
361                                  |f| self.format_variant(f),
362                                  body_lo,
363                                  body_hi);
364
365         let budget = self.config.max_width - self.block_indent.width() - 2;
366         let fmt = ListFormatting {
367             tactic: DefinitiveListTactic::Vertical,
368             separator: ",",
369             trailing_separator: SeparatorTactic::from_bool(self.config.enum_trailing_comma),
370             indent: self.block_indent,
371             width: budget,
372             ends_with_newline: true,
373             config: self.config,
374         };
375
376         let list = try_opt!(write_list(items, &fmt));
377         result.push_str(&list);
378         result.push('\n');
379         Some(result)
380     }
381
382     // Variant of an enum.
383     fn format_variant(&self, field: &ast::Variant) -> Option<String> {
384         if contains_skip(&field.node.attrs) {
385             let lo = field.node.attrs[0].span.lo;
386             let span = mk_sp(lo, field.span.hi);
387             return Some(self.snippet(span));
388         }
389
390         let indent = self.block_indent;
391         let mut result = try_opt!(field.node
392                                        .attrs
393                                        .rewrite(&self.get_context(),
394                                                 self.config.max_width - indent.width(),
395                                                 indent));
396         if !result.is_empty() {
397             result.push('\n');
398             result.push_str(&indent.to_string(self.config));
399         }
400
401         let context = self.get_context();
402         let variant_body = match field.node.data {
403             ast::VariantData::Tuple(..) |
404             ast::VariantData::Struct(..) => {
405                 // FIXME: Should limit the width, as we have a trailing comma
406                 format_struct(&context,
407                               "",
408                               field.node.name,
409                               ast::Visibility::Inherited,
410                               &field.node.data,
411                               None,
412                               field.span,
413                               indent)
414             }
415             ast::VariantData::Unit(..) => {
416                 let tag = if let Some(ref expr) = field.node.disr_expr {
417                     format!("{} = {}", field.node.name, self.snippet(expr.span))
418                 } else {
419                     field.node.name.to_string()
420                 };
421
422                 wrap_str(tag,
423                          self.config.max_width,
424                          self.config.max_width - indent.width(),
425                          indent)
426             }
427         };
428
429         if let Some(variant_str) = variant_body {
430             result.push_str(&variant_str);
431             Some(result)
432         } else {
433             None
434         }
435     }
436 }
437
438 pub fn format_impl(context: &RewriteContext, item: &ast::Item, offset: Indent) -> Option<String> {
439     if let ast::Item_::ItemImpl(unsafety,
440                                 polarity,
441                                 ref generics,
442                                 ref trait_ref,
443                                 ref self_ty,
444                                 ref items) = item.node {
445         let mut result = String::new();
446         result.push_str(format_visibility(item.vis));
447         result.push_str(format_unsafety(unsafety));
448         result.push_str("impl");
449
450         let lo = span_after(item.span, "impl", context.codemap);
451         let hi = match *trait_ref {
452             Some(ref tr) => tr.path.span.lo,
453             None => self_ty.span.lo,
454         };
455         let generics_str = try_opt!(rewrite_generics(context,
456                                                      generics,
457                                                      offset,
458                                                      offset + result.len(),
459                                                      mk_sp(lo, hi)));
460         result.push_str(&generics_str);
461
462         // FIXME might need to linebreak in the impl header, here would be a
463         // good place.
464         result.push(' ');
465         if polarity == ast::ImplPolarity::Negative {
466             result.push_str("!");
467         }
468         if let &Some(ref trait_ref) = trait_ref {
469             let budget = try_opt!(context.config.max_width.checked_sub(result.len()));
470             let indent = offset + result.len();
471             result.push_str(&*try_opt!(trait_ref.rewrite(context, budget, indent)));
472             result.push_str(" for ");
473         }
474
475         let budget = try_opt!(context.config.max_width.checked_sub(result.len()));
476         let indent = offset + result.len();
477         result.push_str(&*try_opt!(self_ty.rewrite(context, budget, indent)));
478
479         let where_clause_str = try_opt!(rewrite_where_clause(context,
480                                                              &generics.where_clause,
481                                                              context.config,
482                                                              context.block_indent,
483                                                              context.config.where_density,
484                                                              "{",
485                                                              None));
486         if !where_clause_str.contains('\n') &&
487            result.len() + where_clause_str.len() + offset.width() > context.config.max_width {
488             result.push('\n');
489             let width = context.block_indent.width() + context.config.tab_spaces - 1;
490             let where_indent = Indent::new(0, width);
491             result.push_str(&where_indent.to_string(context.config));
492         }
493         result.push_str(&where_clause_str);
494
495         match context.config.item_brace_style {
496             BraceStyle::AlwaysNextLine => result.push('\n'),
497             BraceStyle::PreferSameLine => result.push(' '),
498             BraceStyle::SameLineWhere => {
499                 if where_clause_str.len() > 0 {
500                     result.push('\n')
501                 } else {
502                     result.push(' ')
503                 }
504             }
505         }
506         result.push('{');
507
508         if !items.is_empty() {
509             let mut visitor = FmtVisitor::from_codemap(context.parse_session, context.config, None);
510             visitor.block_indent = context.block_indent.block_indent(context.config);
511
512             let snippet = context.snippet(item.span);
513             let open_pos = try_opt!(snippet.find_uncommented("{")) + 1;
514             visitor.last_pos = item.span.lo + BytePos(open_pos as u32);
515
516             for item in items {
517                 visitor.visit_impl_item(&item);
518             }
519
520             result.push('\n');
521             result.push_str(trim_newlines(&visitor.buffer.to_string()));
522             result.push('\n');
523
524             let indent_str = context.block_indent.to_string(context.config);
525             result.push_str(&indent_str);
526         }
527         result.push('}');
528
529         Some(result)
530     } else {
531         unreachable!();
532     }
533 }
534
535 pub fn format_struct(context: &RewriteContext,
536                      item_name: &str,
537                      ident: ast::Ident,
538                      vis: ast::Visibility,
539                      struct_def: &ast::VariantData,
540                      generics: Option<&ast::Generics>,
541                      span: Span,
542                      offset: Indent)
543                      -> Option<String> {
544     match *struct_def {
545         ast::VariantData::Unit(..) => format_unit_struct(item_name, ident, vis),
546         ast::VariantData::Tuple(ref fields, _) => {
547             format_tuple_struct(context,
548                                 item_name,
549                                 ident,
550                                 vis,
551                                 fields,
552                                 generics,
553                                 span,
554                                 offset)
555         }
556         ast::VariantData::Struct(ref fields, _) => {
557             format_struct_struct(context,
558                                  item_name,
559                                  ident,
560                                  vis,
561                                  fields,
562                                  generics,
563                                  span,
564                                  offset)
565         }
566     }
567 }
568
569 fn format_unit_struct(item_name: &str, ident: ast::Ident, vis: ast::Visibility) -> Option<String> {
570     let mut result = String::with_capacity(1024);
571
572     let header_str = format_header(item_name, ident, vis);
573     result.push_str(&header_str);
574     result.push(';');
575
576     Some(result)
577 }
578
579 fn format_struct_struct(context: &RewriteContext,
580                         item_name: &str,
581                         ident: ast::Ident,
582                         vis: ast::Visibility,
583                         fields: &[ast::StructField],
584                         generics: Option<&ast::Generics>,
585                         span: Span,
586                         offset: Indent)
587                         -> Option<String> {
588     let mut result = String::with_capacity(1024);
589
590     let header_str = format_header(item_name, ident, vis);
591     result.push_str(&header_str);
592
593     let body_lo = span_after(span, "{", context.codemap);
594
595     let generics_str = match generics {
596         Some(g) => {
597             try_opt!(format_generics(context,
598                                      g,
599                                      "{",
600                                      "{",
601                                      context.config.item_brace_style,
602                                      fields.is_empty(),
603                                      offset,
604                                      offset + header_str.len(),
605                                      mk_sp(span.lo, body_lo)))
606         }
607         None => {
608             if context.config.item_brace_style == BraceStyle::AlwaysNextLine && !fields.is_empty() {
609                 format!("\n{}{{", context.block_indent.to_string(context.config))
610             } else {
611                 " {".to_owned()
612             }
613         }
614     };
615     result.push_str(&generics_str);
616
617     // FIXME: properly format empty structs and their comments.
618     if fields.is_empty() {
619         result.push_str(&context.snippet(mk_sp(body_lo, span.hi)));
620         return Some(result);
621     }
622
623     let item_indent = offset.block_indent(context.config);
624     // 2 = ","
625     let item_budget = try_opt!(context.config.max_width.checked_sub(item_indent.width() + 1));
626
627     let items = itemize_list(context.codemap,
628                              fields.iter(),
629                              "}",
630                              |field| {
631                                  // Include attributes and doc comments, if present
632                                  if !field.node.attrs.is_empty() {
633                                      field.node.attrs[0].span.lo
634                                  } else {
635                                      field.span.lo
636                                  }
637                              },
638                              |field| field.node.ty.span.hi,
639                              |field| field.rewrite(context, item_budget, item_indent),
640                              span_after(span, "{", context.codemap),
641                              span.hi);
642     // 1 = ,
643     let budget = context.config.max_width - offset.width() + context.config.tab_spaces - 1;
644     let fmt = ListFormatting {
645         tactic: DefinitiveListTactic::Vertical,
646         separator: ",",
647         trailing_separator: context.config.struct_trailing_comma,
648         indent: item_indent,
649         width: budget,
650         ends_with_newline: true,
651         config: context.config,
652     };
653     Some(format!("{}\n{}{}\n{}}}",
654                  result,
655                  offset.block_indent(context.config).to_string(context.config),
656                  try_opt!(write_list(items, &fmt)),
657                  offset.to_string(context.config)))
658 }
659
660 fn format_tuple_struct(context: &RewriteContext,
661                        item_name: &str,
662                        ident: ast::Ident,
663                        vis: ast::Visibility,
664                        fields: &[ast::StructField],
665                        generics: Option<&ast::Generics>,
666                        span: Span,
667                        offset: Indent)
668                        -> Option<String> {
669     assert!(!fields.is_empty(), "Tuple struct with no fields?");
670     let mut result = String::with_capacity(1024);
671
672     let header_str = format_header(item_name, ident, vis);
673     result.push_str(&header_str);
674
675     let body_lo = fields[0].span.lo;
676
677     let (generics_str, where_clause_str) = match generics {
678         Some(ref generics) => {
679             let generics_str = try_opt!(rewrite_generics(context,
680                                                          generics,
681                                                          offset,
682                                                          offset + header_str.len(),
683                                                          mk_sp(span.lo, body_lo)));
684
685             let where_clause_str = try_opt!(rewrite_where_clause(context,
686                                                                  &generics.where_clause,
687                                                                  context.config,
688                                                                  context.block_indent,
689                                                                  Density::Compressed,
690                                                                  ";",
691                                                                  None));
692
693             (generics_str, where_clause_str)
694         }
695         None => ("".to_owned(), "".to_owned()),
696     };
697     result.push_str(&generics_str);
698     result.push('(');
699
700     let item_indent = context.block_indent + result.len();
701     // 2 = ");"
702     let item_budget = try_opt!(context.config.max_width.checked_sub(item_indent.width() + 2));
703
704     let items = itemize_list(context.codemap,
705                              fields.iter(),
706                              ")",
707                              |field| {
708                                  // Include attributes and doc comments, if present
709                                  if !field.node.attrs.is_empty() {
710                                      field.node.attrs[0].span.lo
711                                  } else {
712                                      field.span.lo
713                                  }
714                              },
715                              |field| field.node.ty.span.hi,
716                              |field| field.rewrite(context, item_budget, item_indent),
717                              span_after(span, "(", context.codemap),
718                              span.hi);
719     let body = try_opt!(format_item_list(items, item_budget, item_indent, context.config));
720     result.push_str(&body);
721     result.push(')');
722
723     if where_clause_str.len() > 0 && !where_clause_str.contains('\n') &&
724        (result.contains('\n') ||
725         context.block_indent.width() + result.len() + where_clause_str.len() + 1 >
726         context.config.max_width) {
727         // We need to put the where clause on a new line, but we didn'to_string
728         // know that earlier, so the where clause will not be indented properly.
729         result.push('\n');
730         result.push_str(&(context.block_indent + (context.config.tab_spaces - 1))
731                              .to_string(context.config));
732     }
733     result.push_str(&where_clause_str);
734
735     Some(result)
736 }
737
738 impl Rewrite for ast::StructField {
739     fn rewrite(&self, context: &RewriteContext, width: usize, offset: Indent) -> Option<String> {
740         if contains_skip(&self.node.attrs) {
741             let span = context.snippet(mk_sp(self.node.attrs[0].span.lo, self.span.hi));
742             return wrap_str(span, context.config.max_width, width, offset);
743         }
744
745         let name = match self.node.kind {
746             ast::StructFieldKind::NamedField(ident, _) => Some(ident.to_string()),
747             ast::StructFieldKind::UnnamedField(_) => None,
748         };
749         let vis = match self.node.kind {
750             ast::StructFieldKind::NamedField(_, vis) |
751             ast::StructFieldKind::UnnamedField(vis) => format_visibility(vis),
752         };
753         let mut attr_str = try_opt!(self.node
754                                         .attrs
755                                         .rewrite(context,
756                                                  context.config.max_width - offset.width(),
757                                                  offset));
758         if !attr_str.is_empty() {
759             attr_str.push('\n');
760             attr_str.push_str(&offset.to_string(context.config));
761         }
762
763         let result = match name {
764             Some(name) => format!("{}{}{}: ", attr_str, vis, name),
765             None => format!("{}{}", attr_str, vis),
766         };
767
768         let last_line_width = last_line_width(&result);
769         let budget = try_opt!(width.checked_sub(last_line_width));
770         let rewrite = try_opt!(self.node.ty.rewrite(context, budget, offset + last_line_width));
771         Some(result + &rewrite)
772     }
773 }
774
775 pub fn rewrite_static(prefix: &str,
776                       vis: ast::Visibility,
777                       ident: ast::Ident,
778                       ty: &ast::Ty,
779                       mutability: ast::Mutability,
780                       expr: &ast::Expr,
781                       context: &RewriteContext)
782                       -> Option<String> {
783     let prefix = format!("{}{} {}{}: ",
784                          format_visibility(vis),
785                          prefix,
786                          format_mutability(mutability),
787                          ident);
788     // 2 = " =".len()
789     let ty_str = try_opt!(ty.rewrite(context,
790                                      context.config.max_width - context.block_indent.width() -
791                                      prefix.len() - 2,
792                                      context.block_indent));
793     let lhs = format!("{}{} =", prefix, ty_str);
794
795     // 1 = ;
796     let remaining_width = context.config.max_width - context.block_indent.width() - 1;
797     rewrite_assign_rhs(context, lhs, expr, remaining_width, context.block_indent).map(|s| s + ";")
798 }
799
800 impl Rewrite for ast::FunctionRetTy {
801     fn rewrite(&self, context: &RewriteContext, width: usize, offset: Indent) -> Option<String> {
802         match *self {
803             ast::FunctionRetTy::DefaultReturn(_) => Some(String::new()),
804             ast::FunctionRetTy::NoReturn(_) => {
805                 if width >= 4 {
806                     Some("-> !".to_owned())
807                 } else {
808                     None
809                 }
810             }
811             ast::FunctionRetTy::Return(ref ty) => {
812                 let inner_width = try_opt!(width.checked_sub(3));
813                 ty.rewrite(context, inner_width, offset + 3).map(|r| format!("-> {}", r))
814             }
815         }
816     }
817 }
818
819 impl Rewrite for ast::Arg {
820     fn rewrite(&self, context: &RewriteContext, width: usize, offset: Indent) -> Option<String> {
821         if is_named_arg(self) {
822             if let ast::Ty_::TyInfer = self.ty.node {
823                 wrap_str(pprust::pat_to_string(&self.pat),
824                          context.config.max_width,
825                          width,
826                          offset)
827             } else {
828                 let mut result = pprust::pat_to_string(&self.pat);
829                 result.push_str(": ");
830                 let max_width = try_opt!(width.checked_sub(result.len()));
831                 let ty_str = try_opt!(self.ty.rewrite(context, max_width, offset + result.len()));
832                 result.push_str(&ty_str);
833                 Some(result)
834             }
835         } else {
836             self.ty.rewrite(context, width, offset)
837         }
838     }
839 }
840
841 fn rewrite_explicit_self(explicit_self: &ast::ExplicitSelf, args: &[ast::Arg]) -> Option<String> {
842     match explicit_self.node {
843         ast::ExplicitSelf_::SelfRegion(lt, m, _) => {
844             let mut_str = format_mutability(m);
845             match lt {
846                 Some(ref l) => Some(format!("&{} {}self", pprust::lifetime_to_string(l), mut_str)),
847                 None => Some(format!("&{}self", mut_str)),
848             }
849         }
850         ast::ExplicitSelf_::SelfExplicit(ref ty, _) => {
851             Some(format!("self: {}", pprust::ty_to_string(ty)))
852         }
853         ast::ExplicitSelf_::SelfValue(_) => {
854             assert!(args.len() >= 1, "&[ast::Arg] shouldn't be empty.");
855
856             // this hacky solution caused by absence of `Mutability` in `SelfValue`.
857             let mut_str = {
858                 if let ast::Pat_::PatIdent(ast::BindingMode::BindByValue(mutability), _, _) =
859                        args[0].pat.node {
860                     format_mutability(mutability)
861                 } else {
862                     panic!("there is a bug or change in structure of AST, aborting.");
863                 }
864             };
865
866             Some(format!("{}self", mut_str))
867         }
868         _ => None,
869     }
870 }
871
872 pub fn span_lo_for_arg(arg: &ast::Arg) -> BytePos {
873     if is_named_arg(arg) {
874         arg.pat.span.lo
875     } else {
876         arg.ty.span.lo
877     }
878 }
879
880 pub fn span_hi_for_arg(arg: &ast::Arg) -> BytePos {
881     match arg.ty.node {
882         ast::Ty_::TyInfer if is_named_arg(arg) => arg.pat.span.hi,
883         _ => arg.ty.span.hi,
884     }
885 }
886
887 fn is_named_arg(arg: &ast::Arg) -> bool {
888     if let ast::Pat_::PatIdent(_, ident, _) = arg.pat.node {
889         ident.node != token::special_idents::invalid
890     } else {
891         true
892     }
893 }
894
895 fn span_for_return(ret: &ast::FunctionRetTy) -> Span {
896     match *ret {
897         ast::FunctionRetTy::NoReturn(ref span) |
898         ast::FunctionRetTy::DefaultReturn(ref span) => span.clone(),
899         ast::FunctionRetTy::Return(ref ty) => ty.span,
900     }
901 }
902
903 fn span_for_ty_param(ty: &ast::TyParam) -> Span {
904     // Note that ty.span is the span for ty.ident, not the whole item.
905     let lo = ty.span.lo;
906     if let Some(ref def) = ty.default {
907         return mk_sp(lo, def.span.hi);
908     }
909     if ty.bounds.is_empty() {
910         return ty.span;
911     }
912     let hi = match ty.bounds[ty.bounds.len() - 1] {
913         ast::TyParamBound::TraitTyParamBound(ref ptr, _) => ptr.span.hi,
914         ast::TyParamBound::RegionTyParamBound(ref l) => l.span.hi,
915     };
916     mk_sp(lo, hi)
917 }
918
919 fn span_for_where_pred(pred: &ast::WherePredicate) -> Span {
920     match *pred {
921         ast::WherePredicate::BoundPredicate(ref p) => p.span,
922         ast::WherePredicate::RegionPredicate(ref p) => p.span,
923         ast::WherePredicate::EqPredicate(ref p) => p.span,
924     }
925 }
926
927 // Return type is (result, force_new_line_for_brace)
928 fn rewrite_fn_base(context: &RewriteContext,
929                    indent: Indent,
930                    ident: ast::Ident,
931                    fd: &ast::FnDecl,
932                    explicit_self: Option<&ast::ExplicitSelf>,
933                    generics: &ast::Generics,
934                    unsafety: ast::Unsafety,
935                    constness: ast::Constness,
936                    abi: abi::Abi,
937                    vis: ast::Visibility,
938                    span: Span,
939                    newline_brace: bool,
940                    has_body: bool)
941                    -> Option<(String, bool)> {
942     let mut force_new_line_for_brace = false;
943     // FIXME we'll lose any comments in between parts of the function decl, but
944     // anyone who comments there probably deserves what they get.
945
946     let where_clause = &generics.where_clause;
947
948     let mut result = String::with_capacity(1024);
949     // Vis unsafety abi.
950     result.push_str(format_visibility(vis));
951     result.push_str(::utils::format_unsafety(unsafety));
952
953     if let ast::Constness::Const = constness {
954         result.push_str("const ");
955     }
956
957     if abi != abi::Rust {
958         result.push_str(&::utils::format_abi(abi));
959     }
960
961     // fn foo
962     result.push_str("fn ");
963     result.push_str(&ident.to_string());
964
965     // Generics.
966     let generics_indent = indent + result.len();
967     let generics_span = mk_sp(span.lo, span_for_return(&fd.output).lo);
968     let generics_str = try_opt!(rewrite_generics(context,
969                                                  generics,
970                                                  indent,
971                                                  generics_indent,
972                                                  generics_span));
973     result.push_str(&generics_str);
974
975     // Note that if the width and indent really matter, we'll re-layout the
976     // return type later anyway.
977     let ret_str = fd.output
978                     .rewrite(&context, context.config.max_width - indent.width(), indent)
979                     .unwrap();
980
981     let multi_line_ret_str = ret_str.contains('\n');
982     let ret_str_len = if multi_line_ret_str {
983         0
984     } else {
985         ret_str.len()
986     };
987
988     // Args.
989     let (mut one_line_budget, multi_line_budget, mut arg_indent) =
990         compute_budgets_for_args(context, &result, indent, ret_str_len, newline_brace);
991
992     debug!("rewrite_fn: one_line_budget: {}, multi_line_budget: {}, arg_indent: {:?}",
993            one_line_budget,
994            multi_line_budget,
995            arg_indent);
996
997     // Check if vertical layout was forced by compute_budget_for_args.
998     if one_line_budget <= 0 {
999         if context.config.fn_args_paren_newline {
1000             result.push('\n');
1001             result.push_str(&arg_indent.to_string(context.config));
1002             arg_indent = arg_indent + 1; // extra space for `(`
1003             result.push('(');
1004         } else {
1005             result.push_str("(\n");
1006             result.push_str(&arg_indent.to_string(context.config));
1007         }
1008     } else if context.config.fn_args_layout == StructLitStyle::Block {
1009         arg_indent = indent.block_indent(context.config);
1010         result.push_str("(\n");
1011         result.push_str(&arg_indent.to_string(context.config));
1012     } else {
1013         result.push('(');
1014     }
1015
1016     if multi_line_ret_str {
1017         one_line_budget = 0;
1018     }
1019
1020     // A conservative estimation, to goal is to be over all parens in generics
1021     let args_start = generics.ty_params
1022                              .last()
1023                              .map(|tp| end_typaram(tp))
1024                              .unwrap_or(span.lo);
1025     let args_span = mk_sp(span_after(mk_sp(args_start, span.hi), "(", context.codemap),
1026                           span_for_return(&fd.output).lo);
1027     let arg_str = try_opt!(rewrite_args(context,
1028                                         &fd.inputs,
1029                                         explicit_self,
1030                                         one_line_budget,
1031                                         multi_line_budget,
1032                                         indent,
1033                                         arg_indent,
1034                                         args_span,
1035                                         fd.variadic));
1036     result.push_str(&arg_str);
1037     if context.config.fn_args_layout == StructLitStyle::Block {
1038         result.push('\n');
1039     }
1040     result.push(')');
1041
1042     // Return type.
1043     if !ret_str.is_empty() {
1044         // If we've already gone multi-line, or the return type would push
1045         // over the max width, then put the return type on a new line.
1046         // Unless we are formatting args like a block, in which case there
1047         // should always be room for the return type.
1048         let ret_indent = if (result.contains("\n") || multi_line_ret_str ||
1049                              result.len() + indent.width() + ret_str_len >
1050                              context.config.max_width) &&
1051                             context.config.fn_args_layout != StructLitStyle::Block {
1052             let indent = match context.config.fn_return_indent {
1053                 ReturnIndent::WithWhereClause => indent + 4,
1054                 // Aligning with non-existent args looks silly.
1055                 _ if arg_str.len() == 0 => {
1056                     force_new_line_for_brace = true;
1057                     indent + 4
1058                 }
1059                 // FIXME: we might want to check that using the arg indent
1060                 // doesn't blow our budget, and if it does, then fallback to
1061                 // the where clause indent.
1062                 _ => arg_indent,
1063             };
1064
1065             result.push('\n');
1066             result.push_str(&indent.to_string(context.config));
1067             indent
1068         } else {
1069             result.push(' ');
1070             Indent::new(indent.width(), result.len())
1071         };
1072
1073         if multi_line_ret_str {
1074             // Now that we know the proper indent and width, we need to
1075             // re-layout the return type.
1076
1077             let budget = try_opt!(context.config.max_width.checked_sub(ret_indent.width()));
1078             let ret_str = fd.output
1079                             .rewrite(context, budget, ret_indent)
1080                             .unwrap();
1081             result.push_str(&ret_str);
1082         } else {
1083             result.push_str(&ret_str);
1084         }
1085
1086         // Comment between return type and the end of the decl.
1087         let snippet_lo = fd.output.span().hi;
1088         if where_clause.predicates.is_empty() {
1089             let snippet_hi = span.hi;
1090             let snippet = context.snippet(mk_sp(snippet_lo, snippet_hi));
1091             let snippet = snippet.trim();
1092             if !snippet.is_empty() {
1093                 result.push(' ');
1094                 result.push_str(snippet);
1095             }
1096         } else {
1097             // FIXME it would be nice to catch comments between the return type
1098             // and the where clause, but we don't have a span for the where
1099             // clause.
1100         }
1101     }
1102
1103     let where_density = if (context.config.where_density == Density::Compressed &&
1104                             (!result.contains('\n') ||
1105                              context.config.fn_args_layout == StructLitStyle::Block)) ||
1106                            (context.config.fn_args_layout == StructLitStyle::Block &&
1107                             ret_str.is_empty()) ||
1108                            (context.config.where_density == Density::CompressedIfEmpty &&
1109                             !has_body) {
1110         Density::Compressed
1111     } else {
1112         Density::Tall
1113     };
1114
1115     // Where clause.
1116     let where_clause_str = try_opt!(rewrite_where_clause(context,
1117                                                          where_clause,
1118                                                          context.config,
1119                                                          indent,
1120                                                          where_density,
1121                                                          "{",
1122                                                          Some(span.hi)));
1123     result.push_str(&where_clause_str);
1124
1125     Some((result, force_new_line_for_brace))
1126 }
1127
1128 fn rewrite_args(context: &RewriteContext,
1129                 args: &[ast::Arg],
1130                 explicit_self: Option<&ast::ExplicitSelf>,
1131                 one_line_budget: usize,
1132                 multi_line_budget: usize,
1133                 indent: Indent,
1134                 arg_indent: Indent,
1135                 span: Span,
1136                 variadic: bool)
1137                 -> Option<String> {
1138     let mut arg_item_strs = try_opt!(args.iter()
1139                                          .map(|arg| {
1140                                              arg.rewrite(&context, multi_line_budget, arg_indent)
1141                                          })
1142                                          .collect::<Option<Vec<_>>>());
1143
1144     // Account for sugary self.
1145     // FIXME: the comment for the self argument is dropped. This is blocked
1146     // on rust issue #27522.
1147     let min_args = explicit_self.and_then(|explicit_self| {
1148                                     rewrite_explicit_self(explicit_self, args)
1149                                 })
1150                                 .map(|self_str| {
1151                                     arg_item_strs[0] = self_str;
1152                                     2
1153                                 })
1154                                 .unwrap_or(1);
1155
1156     // Comments between args.
1157     let mut arg_items = Vec::new();
1158     if min_args == 2 {
1159         arg_items.push(ListItem::from_str(""));
1160     }
1161
1162     // FIXME(#21): if there are no args, there might still be a comment, but
1163     // without spans for the comment or parens, there is no chance of
1164     // getting it right. You also don't get to put a comment on self, unless
1165     // it is explicit.
1166     if args.len() >= min_args || variadic {
1167         let comment_span_start = if min_args == 2 {
1168             span_after(span, ",", context.codemap)
1169         } else {
1170             span.lo
1171         };
1172
1173         enum ArgumentKind<'a> {
1174             Regular(&'a ast::Arg),
1175             Variadic(BytePos),
1176         }
1177
1178         let variadic_arg = if variadic {
1179             let variadic_span = mk_sp(args.last().unwrap().ty.span.hi, span.hi);
1180             let variadic_start = span_after(variadic_span, "...", context.codemap) - BytePos(3);
1181             Some(ArgumentKind::Variadic(variadic_start))
1182         } else {
1183             None
1184         };
1185
1186         let more_items = itemize_list(context.codemap,
1187                                       args[min_args - 1..]
1188                                           .iter()
1189                                           .map(ArgumentKind::Regular)
1190                                           .chain(variadic_arg),
1191                                       ")",
1192                                       |arg| {
1193                                           match *arg {
1194                                               ArgumentKind::Regular(arg) => span_lo_for_arg(arg),
1195                                               ArgumentKind::Variadic(start) => start,
1196                                           }
1197                                       },
1198                                       |arg| {
1199                                           match *arg {
1200                                               ArgumentKind::Regular(arg) => arg.ty.span.hi,
1201                                               ArgumentKind::Variadic(start) => start + BytePos(3),
1202                                           }
1203                                       },
1204                                       |arg| {
1205                                           match *arg {
1206                                               ArgumentKind::Regular(..) => None,
1207                                               ArgumentKind::Variadic(..) => Some("...".to_owned()),
1208                                           }
1209                                       },
1210                                       comment_span_start,
1211                                       span.hi);
1212
1213         arg_items.extend(more_items);
1214     }
1215
1216     for (item, arg) in arg_items.iter_mut().zip(arg_item_strs) {
1217         item.item = Some(arg);
1218     }
1219
1220     let indent = match context.config.fn_arg_indent {
1221         BlockIndentStyle::Inherit => indent,
1222         BlockIndentStyle::Tabbed => indent.block_indent(context.config),
1223         BlockIndentStyle::Visual => arg_indent,
1224     };
1225
1226     let tactic = definitive_tactic(&arg_items,
1227                                    context.config.fn_args_density.to_list_tactic(),
1228                                    one_line_budget);
1229     let budget = match tactic {
1230         DefinitiveListTactic::Horizontal => one_line_budget,
1231         _ => multi_line_budget,
1232     };
1233
1234     let fmt = ListFormatting {
1235         tactic: tactic,
1236         separator: ",",
1237         trailing_separator: SeparatorTactic::Never,
1238         indent: indent,
1239         width: budget,
1240         ends_with_newline: false,
1241         config: context.config,
1242     };
1243
1244     write_list(&arg_items, &fmt)
1245 }
1246
1247 fn compute_budgets_for_args(context: &RewriteContext,
1248                             result: &str,
1249                             indent: Indent,
1250                             ret_str_len: usize,
1251                             newline_brace: bool)
1252                             -> (usize, usize, Indent) {
1253     // Try keeping everything on the same line
1254     if !result.contains("\n") {
1255         // 3 = `() `, space is before ret_string
1256         let mut used_space = indent.width() + result.len() + ret_str_len + 3;
1257         if !newline_brace {
1258             used_space += 2;
1259         }
1260         let one_line_budget = if used_space > context.config.max_width {
1261             0
1262         } else {
1263             context.config.max_width - used_space
1264         };
1265
1266         // 2 = `()`
1267         let used_space = indent.width() + result.len() + 2;
1268         let max_space = context.config.max_width;
1269         debug!("compute_budgets_for_args: used_space: {}, max_space: {}",
1270                used_space,
1271                max_space);
1272         if used_space < max_space {
1273             return (one_line_budget,
1274                     max_space - used_space,
1275                     indent + result.len() + 1);
1276         }
1277     }
1278
1279     // Didn't work. we must force vertical layout and put args on a newline.
1280     let new_indent = indent.block_indent(context.config);
1281     let used_space = new_indent.width() + 2; // account for `(` and `)`
1282     let max_space = context.config.max_width;
1283     if used_space <= max_space {
1284         (0, max_space - used_space, new_indent)
1285     } else {
1286         // Whoops! bankrupt.
1287         // FIXME: take evasive action, perhaps kill the indent or something.
1288         panic!("in compute_budgets_for_args");
1289     }
1290 }
1291
1292 fn newline_for_brace(config: &Config, where_clause: &ast::WhereClause) -> bool {
1293     match config.fn_brace_style {
1294         BraceStyle::AlwaysNextLine => true,
1295         BraceStyle::SameLineWhere if !where_clause.predicates.is_empty() => true,
1296         _ => false,
1297     }
1298 }
1299
1300 fn rewrite_generics(context: &RewriteContext,
1301                     generics: &ast::Generics,
1302                     offset: Indent,
1303                     generics_offset: Indent,
1304                     span: Span)
1305                     -> Option<String> {
1306     // FIXME: convert bounds to where clauses where they get too big or if
1307     // there is a where clause at all.
1308     let lifetimes: &[_] = &generics.lifetimes;
1309     let tys: &[_] = &generics.ty_params;
1310     if lifetimes.is_empty() && tys.is_empty() {
1311         return Some(String::new());
1312     }
1313
1314     let offset = match context.config.generics_indent {
1315         BlockIndentStyle::Inherit => offset,
1316         BlockIndentStyle::Tabbed => offset.block_indent(context.config),
1317         // 1 = <
1318         BlockIndentStyle::Visual => generics_offset + 1,
1319     };
1320
1321     let h_budget = context.config.max_width - generics_offset.width() - 2;
1322     // FIXME: might need to insert a newline if the generics are really long.
1323
1324     // Strings for the generics.
1325     let lt_strs = lifetimes.iter().map(|lt| lt.rewrite(&context, h_budget, offset));
1326     let ty_strs = tys.iter().map(|ty_param| ty_param.rewrite(&context, h_budget, offset));
1327
1328     // Extract comments between generics.
1329     let lt_spans = lifetimes.iter().map(|l| {
1330         let hi = if l.bounds.is_empty() {
1331             l.lifetime.span.hi
1332         } else {
1333             l.bounds[l.bounds.len() - 1].span.hi
1334         };
1335         mk_sp(l.lifetime.span.lo, hi)
1336     });
1337     let ty_spans = tys.iter().map(span_for_ty_param);
1338
1339     let items = itemize_list(context.codemap,
1340                              lt_spans.chain(ty_spans).zip(lt_strs.chain(ty_strs)),
1341                              ">",
1342                              |&(sp, _)| sp.lo,
1343                              |&(sp, _)| sp.hi,
1344                              // FIXME: don't clone
1345                              |&(_, ref str)| str.clone(),
1346                              span_after(span, "<", context.codemap),
1347                              span.hi);
1348     let list_str = try_opt!(format_item_list(items, h_budget, offset, context.config));
1349
1350     Some(format!("<{}>", list_str))
1351 }
1352
1353 fn rewrite_where_clause(context: &RewriteContext,
1354                         where_clause: &ast::WhereClause,
1355                         config: &Config,
1356                         indent: Indent,
1357                         density: Density,
1358                         terminator: &str,
1359                         span_end: Option<BytePos>)
1360                         -> Option<String> {
1361     if where_clause.predicates.is_empty() {
1362         return Some(String::new());
1363     }
1364
1365     let extra_indent = match context.config.where_indent {
1366         BlockIndentStyle::Inherit => Indent::empty(),
1367         BlockIndentStyle::Tabbed | BlockIndentStyle::Visual => Indent::new(config.tab_spaces, 0),
1368     };
1369
1370     let offset = match context.config.where_pred_indent {
1371         BlockIndentStyle::Inherit => indent + extra_indent,
1372         BlockIndentStyle::Tabbed => indent + extra_indent.block_indent(config),
1373         // 6 = "where ".len()
1374         BlockIndentStyle::Visual => indent + extra_indent + 6,
1375     };
1376     // FIXME: if where_pred_indent != Visual, then the budgets below might
1377     // be out by a char or two.
1378
1379     let budget = context.config.max_width - offset.width();
1380     let span_start = span_for_where_pred(&where_clause.predicates[0]).lo;
1381     // If we don't have the start of the next span, then use the end of the
1382     // predicates, but that means we miss comments.
1383     let len = where_clause.predicates.len();
1384     let end_of_preds = span_for_where_pred(&where_clause.predicates[len - 1]).hi;
1385     let span_end = span_end.unwrap_or(end_of_preds);
1386     let items = itemize_list(context.codemap,
1387                              where_clause.predicates.iter(),
1388                              terminator,
1389                              |pred| span_for_where_pred(pred).lo,
1390                              |pred| span_for_where_pred(pred).hi,
1391                              |pred| pred.rewrite(&context, budget, offset),
1392                              span_start,
1393                              span_end);
1394     let item_vec = items.collect::<Vec<_>>();
1395     // FIXME: we don't need to collect here if the where_layout isn't
1396     // HorizontalVertical.
1397     let tactic = definitive_tactic(&item_vec, context.config.where_layout, budget);
1398
1399     let fmt = ListFormatting {
1400         tactic: tactic,
1401         separator: ",",
1402         trailing_separator: SeparatorTactic::Never,
1403         indent: offset,
1404         width: budget,
1405         ends_with_newline: true,
1406         config: context.config,
1407     };
1408     let preds_str = try_opt!(write_list(&item_vec, &fmt));
1409
1410     // 9 = " where ".len() + " {".len()
1411     if density == Density::Tall || preds_str.contains('\n') ||
1412        indent.width() + 9 + preds_str.len() > context.config.max_width {
1413         Some(format!("\n{}where {}",
1414                      (indent + extra_indent).to_string(context.config),
1415                      preds_str))
1416     } else {
1417         Some(format!(" where {}", preds_str))
1418     }
1419 }
1420
1421 fn format_header(item_name: &str, ident: ast::Ident, vis: ast::Visibility) -> String {
1422     format!("{}{}{}", format_visibility(vis), item_name, ident)
1423 }
1424
1425 fn format_generics(context: &RewriteContext,
1426                    generics: &ast::Generics,
1427                    opener: &str,
1428                    terminator: &str,
1429                    brace_style: BraceStyle,
1430                    force_same_line_brace: bool,
1431                    offset: Indent,
1432                    generics_offset: Indent,
1433                    span: Span)
1434                    -> Option<String> {
1435     let mut result = try_opt!(rewrite_generics(context, generics, offset, generics_offset, span));
1436
1437     if !generics.where_clause.predicates.is_empty() || result.contains('\n') {
1438         let where_clause_str = try_opt!(rewrite_where_clause(context,
1439                                                              &generics.where_clause,
1440                                                              context.config,
1441                                                              context.block_indent,
1442                                                              Density::Tall,
1443                                                              terminator,
1444                                                              Some(span.hi)));
1445         result.push_str(&where_clause_str);
1446         if !force_same_line_brace &&
1447            (brace_style == BraceStyle::SameLineWhere || brace_style == BraceStyle::AlwaysNextLine) {
1448             result.push('\n');
1449             result.push_str(&context.block_indent.to_string(context.config));
1450         } else {
1451             result.push(' ');
1452         }
1453         result.push_str(opener);
1454     } else {
1455         if !force_same_line_brace && brace_style == BraceStyle::AlwaysNextLine {
1456             result.push('\n');
1457             result.push_str(&context.block_indent.to_string(context.config));
1458         } else {
1459             result.push(' ');
1460         }
1461         result.push_str(opener);
1462     }
1463
1464     Some(result)
1465 }