]> git.lizzy.rs Git - rust.git/blob - src/items.rs
Add --dump-default-config and --dump-minimal-config.
[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, Shape};
14 use codemap::SpanUtils;
15 use utils::{format_mutability, format_visibility, contains_skip, end_typaram, wrap_str,
16             last_line_width, format_unsafety, trim_newlines, stmt_expr, semicolon_for_expr,
17             trimmed_last_line_width};
18 use lists::{write_list, itemize_list, ListItem, ListFormatting, SeparatorTactic, list_helper,
19             DefinitiveListTactic, ListTactic, definitive_tactic, format_item_list};
20 use expr::{is_empty_block, is_simple_block_stmt, rewrite_assign_rhs, type_annotation_separator};
21 use comment::{FindUncommented, contains_comment};
22 use visitor::FmtVisitor;
23 use rewrite::{Rewrite, RewriteContext};
24 use config::{Config, IndentStyle, Density, ReturnIndent, BraceStyle, Style, TypeDensity};
25 use itertools::Itertools;
26
27 use syntax::{ast, abi, codemap, ptr, symbol};
28 use syntax::codemap::{Span, BytePos, mk_sp};
29 use syntax::ast::ImplItem;
30
31 // Statements of the form
32 // let pat: ty = init;
33 impl Rewrite for ast::Local {
34     fn rewrite(&self, context: &RewriteContext, shape: Shape) -> Option<String> {
35         debug!("Local::rewrite {:?} {} {:?}",
36                self,
37                shape.width,
38                shape.indent);
39         let mut result = "let ".to_owned();
40
41         // 4 = "let ".len()
42         let pat_shape = try_opt!(shape.offset_left(4));
43         // 1 = ;
44         let pat_shape = try_opt!(pat_shape.sub_width(1));
45         let pat_str = try_opt!(self.pat.rewrite(&context, pat_shape));
46         result.push_str(&pat_str);
47
48         // String that is placed within the assignment pattern and expression.
49         let infix = {
50             let mut infix = String::new();
51
52             if let Some(ref ty) = self.ty {
53                 let separator = type_annotation_separator(context.config);
54                 let indent = shape.indent + last_line_width(&result) + separator.len();
55                 // 1 = ;
56                 let budget = try_opt!(shape.width.checked_sub(indent.width() + 1));
57                 let rewrite = try_opt!(ty.rewrite(context, Shape::legacy(budget, indent)));
58
59                 infix.push_str(separator);
60                 infix.push_str(&rewrite);
61             }
62
63             if self.init.is_some() {
64                 infix.push_str(" =");
65             }
66
67             infix
68         };
69
70         result.push_str(&infix);
71
72         if let Some(ref ex) = self.init {
73             // 1 = trailing semicolon;
74             let nested_shape = try_opt!(shape.sub_width(1));
75
76             result = try_opt!(rewrite_assign_rhs(&context, result, ex, nested_shape));
77         }
78
79         result.push(';');
80         Some(result)
81     }
82 }
83
84 // TODO convert to using rewrite style rather than visitor
85 // TODO format modules in this style
86 #[allow(dead_code)]
87 struct Item<'a> {
88     keyword: &'static str,
89     abi: String,
90     vis: Option<&'a ast::Visibility>,
91     body: Vec<BodyElement<'a>>,
92     span: Span,
93 }
94
95 impl<'a> Item<'a> {
96     fn from_foreign_mod(fm: &'a ast::ForeignMod, span: Span, config: &Config) -> Item<'a> {
97         let abi = if fm.abi == abi::Abi::C && !config.force_explicit_abi() {
98             "extern".into()
99         } else {
100             format!("extern {}", fm.abi)
101         };
102         Item {
103             keyword: "",
104             abi: abi,
105             vis: None,
106             body: fm.items
107                 .iter()
108                 .map(|i| BodyElement::ForeignItem(i))
109                 .collect(),
110             span: span,
111         }
112     }
113 }
114
115 enum BodyElement<'a> {
116     // Stmt(&'a ast::Stmt),
117     // Field(&'a ast::Field),
118     // Variant(&'a ast::Variant),
119     // Item(&'a ast::Item),
120     ForeignItem(&'a ast::ForeignItem),
121 }
122
123 impl<'a> FmtVisitor<'a> {
124     fn format_item(&mut self, item: Item) {
125         self.buffer.push_str(&item.abi);
126         self.buffer.push_str(" ");
127
128         let snippet = self.snippet(item.span);
129         let brace_pos = snippet.find_uncommented("{").unwrap();
130
131         self.buffer.push_str("{");
132         if !item.body.is_empty() || contains_comment(&snippet[brace_pos..]) {
133             // FIXME: this skips comments between the extern keyword and the opening
134             // brace.
135             self.last_pos = item.span.lo + BytePos(brace_pos as u32 + 1);
136             self.block_indent = self.block_indent.block_indent(self.config);
137
138             if item.body.is_empty() {
139                 self.format_missing_no_indent(item.span.hi - BytePos(1));
140                 self.block_indent = self.block_indent.block_unindent(self.config);
141
142                 self.buffer
143                     .push_str(&self.block_indent.to_string(self.config));
144             } else {
145                 for item in &item.body {
146                     self.format_body_element(item);
147                 }
148
149                 self.block_indent = self.block_indent.block_unindent(self.config);
150                 self.format_missing_with_indent(item.span.hi - BytePos(1));
151             }
152         }
153
154         self.buffer.push_str("}");
155         self.last_pos = item.span.hi;
156     }
157
158     fn format_body_element(&mut self, element: &BodyElement) {
159         match *element {
160             BodyElement::ForeignItem(ref item) => self.format_foreign_item(item),
161         }
162     }
163
164     pub fn format_foreign_mod(&mut self, fm: &ast::ForeignMod, span: Span) {
165         let item = Item::from_foreign_mod(fm, span, self.config);
166         self.format_item(item);
167     }
168
169     fn format_foreign_item(&mut self, item: &ast::ForeignItem) {
170         self.format_missing_with_indent(item.span.lo);
171         // Drop semicolon or it will be interpreted as comment.
172         // FIXME: this may be a faulty span from libsyntax.
173         let span = mk_sp(item.span.lo, item.span.hi - BytePos(1));
174
175         match item.node {
176             ast::ForeignItemKind::Fn(ref fn_decl, ref generics) => {
177                 let indent = self.block_indent;
178                 let rewrite = rewrite_fn_base(&self.get_context(),
179                                               indent,
180                                               item.ident,
181                                               fn_decl,
182                                               generics,
183                                               ast::Unsafety::Normal,
184                                               ast::Constness::NotConst,
185                                               ast::Defaultness::Final,
186                                               // These are not actually rust functions,
187                                               // but we format them as such.
188                                               abi::Abi::Rust,
189                                               &item.vis,
190                                               span,
191                                               false,
192                                               false,
193                                               false);
194
195                 match rewrite {
196                     Some((new_fn, _)) => {
197                         self.buffer.push_str(&new_fn);
198                         self.buffer.push_str(";");
199                     }
200                     None => self.format_missing(item.span.hi),
201                 }
202             }
203             ast::ForeignItemKind::Static(ref ty, is_mutable) => {
204                 // FIXME(#21): we're dropping potential comments in between the
205                 // function keywords here.
206                 let vis = format_visibility(&item.vis);
207                 let mut_str = if is_mutable { "mut " } else { "" };
208                 let prefix = format!("{}static {}{}: ", vis, mut_str, item.ident);
209                 let offset = self.block_indent + prefix.len();
210                 // 1 = ;
211                 let shape = Shape::indented(offset, self.config).sub_width(1).unwrap();
212                 let rewrite = ty.rewrite(&self.get_context(), shape);
213
214                 match rewrite {
215                     Some(result) => {
216                         self.buffer.push_str(&prefix);
217                         self.buffer.push_str(&result);
218                         self.buffer.push_str(";");
219                     }
220                     None => self.format_missing(item.span.hi),
221                 }
222             }
223         }
224
225         self.last_pos = item.span.hi;
226     }
227
228     pub fn rewrite_fn(&mut self,
229                       indent: Indent,
230                       ident: ast::Ident,
231                       fd: &ast::FnDecl,
232                       generics: &ast::Generics,
233                       unsafety: ast::Unsafety,
234                       constness: ast::Constness,
235                       defaultness: ast::Defaultness,
236                       abi: abi::Abi,
237                       vis: &ast::Visibility,
238                       span: Span,
239                       block: &ast::Block)
240                       -> Option<String> {
241         let mut newline_brace = newline_for_brace(self.config, &generics.where_clause);
242         let context = self.get_context();
243
244         let block_snippet = self.snippet(codemap::mk_sp(block.span.lo, block.span.hi));
245         let has_body = !block_snippet[1..block_snippet.len() - 1].trim().is_empty() ||
246                        !context.config.fn_empty_single_line();
247
248         let (mut result, force_newline_brace) = try_opt!(rewrite_fn_base(&context,
249                                                                          indent,
250                                                                          ident,
251                                                                          fd,
252                                                                          generics,
253                                                                          unsafety,
254                                                                          constness,
255                                                                          defaultness,
256                                                                          abi,
257                                                                          vis,
258                                                                          span,
259                                                                          newline_brace,
260                                                                          has_body,
261                                                                          true));
262
263         if self.config.fn_brace_style() != BraceStyle::AlwaysNextLine && !result.contains('\n') {
264             newline_brace = false;
265         } else if force_newline_brace {
266             newline_brace = true;
267         }
268
269         // Prepare for the function body by possibly adding a newline and
270         // indent.
271         // FIXME we'll miss anything between the end of the signature and the
272         // start of the body, but we need more spans from the compiler to solve
273         // this.
274         if newline_brace {
275             result.push('\n');
276             result.push_str(&indent.to_string(self.config));
277         } else {
278             result.push(' ');
279         }
280
281         self.single_line_fn(&result, block).or_else(|| Some(result))
282     }
283
284     pub fn rewrite_required_fn(&mut self,
285                                indent: Indent,
286                                ident: ast::Ident,
287                                sig: &ast::MethodSig,
288                                span: Span)
289                                -> Option<String> {
290         // Drop semicolon or it will be interpreted as comment.
291         let span = mk_sp(span.lo, span.hi - BytePos(1));
292         let context = self.get_context();
293
294         let (mut result, _) = try_opt!(rewrite_fn_base(&context,
295                                                        indent,
296                                                        ident,
297                                                        &sig.decl,
298                                                        &sig.generics,
299                                                        sig.unsafety,
300                                                        sig.constness.node,
301                                                        ast::Defaultness::Final,
302                                                        sig.abi,
303                                                        &ast::Visibility::Inherited,
304                                                        span,
305                                                        false,
306                                                        false,
307                                                        false));
308
309         // Re-attach semicolon
310         result.push(';');
311
312         Some(result)
313     }
314
315     fn single_line_fn(&self, fn_str: &str, block: &ast::Block) -> Option<String> {
316         if fn_str.contains('\n') {
317             return None;
318         }
319
320         let codemap = self.get_context().codemap;
321
322         if self.config.fn_empty_single_line() && is_empty_block(block, codemap) &&
323            self.block_indent.width() + fn_str.len() + 2 <= self.config.max_width() {
324             return Some(format!("{}{{}}", fn_str));
325         }
326
327         if self.config.fn_single_line() && is_simple_block_stmt(block, codemap) {
328             let rewrite = {
329                 if let Some(ref stmt) = block.stmts.first() {
330                     match stmt_expr(stmt) {
331                         Some(e) => {
332                             let suffix = if semicolon_for_expr(e) { ";" } else { "" };
333
334                             e.rewrite(&self.get_context(),
335                                          Shape::indented(self.block_indent, self.config))
336                                 .map(|s| s + suffix)
337                                 .or_else(|| Some(self.snippet(e.span)))
338                         }
339                         None => {
340                             stmt.rewrite(&self.get_context(),
341                                          Shape::indented(self.block_indent, self.config))
342                         }
343                     }
344                 } else {
345                     None
346                 }
347             };
348
349             if let Some(res) = rewrite {
350                 let width = self.block_indent.width() + fn_str.len() + res.len() + 4;
351                 if !res.contains('\n') && width <= self.config.max_width() {
352                     return Some(format!("{}{{ {} }}", fn_str, res));
353                 }
354             }
355         }
356
357         None
358     }
359
360     pub fn visit_enum(&mut self,
361                       ident: ast::Ident,
362                       vis: &ast::Visibility,
363                       enum_def: &ast::EnumDef,
364                       generics: &ast::Generics,
365                       span: Span) {
366         self.buffer.push_str(&format_header("enum ", ident, vis));
367
368         let enum_snippet = self.snippet(span);
369         let brace_pos = enum_snippet.find_uncommented("{").unwrap();
370         let body_start = span.lo + BytePos(brace_pos as u32 + 1);
371         let generics_str = format_generics(&self.get_context(),
372                                            generics,
373                                            "{",
374                                            "{",
375                                            self.config.item_brace_style(),
376                                            enum_def.variants.is_empty(),
377                                            self.block_indent,
378                                            mk_sp(span.lo, body_start))
379                 .unwrap();
380         self.buffer.push_str(&generics_str);
381
382         self.last_pos = body_start;
383
384         self.block_indent = self.block_indent.block_indent(self.config);
385         let variant_list = self.format_variant_list(enum_def, body_start, span.hi - BytePos(1));
386         match variant_list {
387             Some(ref body_str) => self.buffer.push_str(body_str),
388             None => {
389                 if contains_comment(&enum_snippet[brace_pos..]) {
390                     self.format_missing_no_indent(span.hi - BytePos(1))
391                 } else {
392                     self.format_missing(span.hi - BytePos(1))
393                 }
394             }
395         }
396         self.block_indent = self.block_indent.block_unindent(self.config);
397
398         if variant_list.is_some() || contains_comment(&enum_snippet[brace_pos..]) {
399             self.buffer
400                 .push_str(&self.block_indent.to_string(self.config));
401         }
402         self.buffer.push_str("}");
403         self.last_pos = span.hi;
404     }
405
406     // Format the body of an enum definition
407     fn format_variant_list(&self,
408                            enum_def: &ast::EnumDef,
409                            body_lo: BytePos,
410                            body_hi: BytePos)
411                            -> Option<String> {
412         if enum_def.variants.is_empty() {
413             return None;
414         }
415         let mut result = String::with_capacity(1024);
416         result.push('\n');
417         let indentation = self.block_indent.to_string(self.config);
418         result.push_str(&indentation);
419
420         let items = itemize_list(self.codemap,
421                                  enum_def.variants.iter(),
422                                  "}",
423                                  |f| if !f.node.attrs.is_empty() {
424                                      f.node.attrs[0].span.lo
425                                  } else {
426                                      f.span.lo
427                                  },
428                                  |f| f.span.hi,
429                                  |f| self.format_variant(f),
430                                  body_lo,
431                                  body_hi);
432
433         let shape = Shape::indented(self.block_indent, self.config)
434             .sub_width(2)
435             .unwrap();
436         let fmt = ListFormatting {
437             tactic: DefinitiveListTactic::Vertical,
438             separator: ",",
439             trailing_separator: self.config.trailing_comma(),
440             shape: shape,
441             ends_with_newline: true,
442             config: self.config,
443         };
444
445         let list = try_opt!(write_list(items, &fmt));
446         result.push_str(&list);
447         result.push('\n');
448         Some(result)
449     }
450
451     // Variant of an enum.
452     fn format_variant(&self, field: &ast::Variant) -> Option<String> {
453         if contains_skip(&field.node.attrs) {
454             let lo = field.node.attrs[0].span.lo;
455             let span = mk_sp(lo, field.span.hi);
456             return Some(self.snippet(span));
457         }
458
459         let indent = self.block_indent;
460         let mut result = try_opt!(field
461                                       .node
462                                       .attrs
463                                       .rewrite(&self.get_context(),
464                                                Shape::indented(indent, self.config)));
465         if !result.is_empty() {
466             result.push('\n');
467             result.push_str(&indent.to_string(self.config));
468         }
469
470         let context = self.get_context();
471         let variant_body = match field.node.data {
472             ast::VariantData::Tuple(..) |
473             ast::VariantData::Struct(..) => {
474                 // FIXME: Should limit the width, as we have a trailing comma
475                 format_struct(&context,
476                               "",
477                               field.node.name,
478                               &ast::Visibility::Inherited,
479                               &field.node.data,
480                               None,
481                               field.span,
482                               indent,
483                               Some(self.config.struct_variant_width()))
484             }
485             ast::VariantData::Unit(..) => {
486                 let tag = if let Some(ref expr) = field.node.disr_expr {
487                     format!("{} = {}", field.node.name, self.snippet(expr.span))
488                 } else {
489                     field.node.name.to_string()
490                 };
491
492                 wrap_str(tag,
493                          self.config.max_width(),
494                          Shape::indented(indent, self.config))
495             }
496         };
497
498         if let Some(variant_str) = variant_body {
499             result.push_str(&variant_str);
500             Some(result)
501         } else {
502             None
503         }
504     }
505 }
506
507 pub fn format_impl(context: &RewriteContext, item: &ast::Item, offset: Indent) -> Option<String> {
508     if let ast::ItemKind::Impl(_, _, ref generics, ref trait_ref, _, ref items) = item.node {
509         let mut result = String::new();
510         // First try to format the ref and type without a split at the 'for'.
511         let mut ref_and_type = try_opt!(format_impl_ref_and_type(context, item, offset, false));
512
513         // If there is a line break present in the first result format it again
514         // with a split at the 'for'. Skip this if there is no trait ref and
515         // therefore no 'for'.
516         if ref_and_type.contains('\n') && trait_ref.is_some() {
517             ref_and_type = try_opt!(format_impl_ref_and_type(context, item, offset, true));
518         }
519         result.push_str(&ref_and_type);
520
521         let where_budget = try_opt!(context
522                                         .config
523                                         .max_width()
524                                         .checked_sub(last_line_width(&result)));
525         let where_clause_str = try_opt!(rewrite_where_clause(context,
526                                                              &generics.where_clause,
527                                                              context.config.item_brace_style(),
528                                                              Shape::legacy(where_budget,
529                                                                            offset.block_only()),
530                                                              context.config.where_density(),
531                                                              "{",
532                                                              false,
533                                                              last_line_width(&ref_and_type) == 1,
534                                                              None));
535
536         if try_opt!(is_impl_single_line(context, &items, &result, &where_clause_str, &item)) {
537             result.push_str(&where_clause_str);
538             if where_clause_str.contains('\n') {
539                 let white_space = offset.to_string(context.config);
540                 result.push_str(&format!("\n{}{{\n{}}}", &white_space, &white_space));
541             } else {
542                 result.push_str(" {}");
543             }
544             return Some(result);
545         }
546
547         if !where_clause_str.is_empty() && !where_clause_str.contains('\n') {
548             result.push('\n');
549             let width = offset.block_indent + context.config.tab_spaces() - 1;
550             let where_indent = Indent::new(0, width);
551             result.push_str(&where_indent.to_string(context.config));
552         }
553         result.push_str(&where_clause_str);
554
555         match context.config.item_brace_style() {
556             BraceStyle::AlwaysNextLine => {
557                 result.push('\n');
558                 result.push_str(&offset.to_string(context.config));
559             }
560             BraceStyle::PreferSameLine => result.push(' '),
561             BraceStyle::SameLineWhere => {
562                 if !where_clause_str.is_empty() {
563                     result.push('\n');
564                     result.push_str(&offset.to_string(context.config));
565                 } else {
566                     result.push(' ');
567                 }
568             }
569         }
570
571         result.push('{');
572
573         let snippet = context.snippet(item.span);
574         let open_pos = try_opt!(snippet.find_uncommented("{")) + 1;
575
576         if !items.is_empty() || contains_comment(&snippet[open_pos..]) {
577             let mut visitor = FmtVisitor::from_codemap(context.parse_session, context.config);
578             visitor.block_indent = offset.block_only().block_indent(context.config);
579             visitor.last_pos = item.span.lo + BytePos(open_pos as u32);
580
581             for item in items {
582                 visitor.visit_impl_item(item);
583             }
584
585             visitor.format_missing(item.span.hi - BytePos(1));
586
587             let inner_indent_str = visitor.block_indent.to_string(context.config);
588             let outer_indent_str = offset.block_only().to_string(context.config);
589
590             result.push('\n');
591             result.push_str(&inner_indent_str);
592             result.push_str(trim_newlines(visitor.buffer.to_string().trim()));
593             result.push('\n');
594             result.push_str(&outer_indent_str);
595         }
596
597         if result.chars().last().unwrap() == '{' {
598             result.push('\n');
599             result.push_str(&offset.to_string(context.config));
600         }
601         result.push('}');
602
603         Some(result)
604     } else {
605         unreachable!();
606     }
607 }
608
609 fn is_impl_single_line(context: &RewriteContext,
610                        items: &[ImplItem],
611                        result: &str,
612                        where_clause_str: &str,
613                        item: &ast::Item)
614                        -> Option<bool> {
615     let snippet = context.snippet(item.span);
616     let open_pos = try_opt!(snippet.find_uncommented("{")) + 1;
617
618     Some(context.config.impl_empty_single_line() && items.is_empty() &&
619          result.len() + where_clause_str.len() <= context.config.max_width() &&
620          !contains_comment(&snippet[open_pos..]))
621 }
622
623 fn format_impl_ref_and_type(context: &RewriteContext,
624                             item: &ast::Item,
625                             offset: Indent,
626                             split_at_for: bool)
627                             -> Option<String> {
628     if let ast::ItemKind::Impl(unsafety, polarity, ref generics, ref trait_ref, ref self_ty, _) =
629         item.node {
630         let mut result = String::new();
631
632         result.push_str(&format_visibility(&item.vis));
633         result.push_str(format_unsafety(unsafety));
634         result.push_str("impl");
635
636         let lo = context.codemap.span_after(item.span, "impl");
637         let hi = match *trait_ref {
638             Some(ref tr) => tr.path.span.lo,
639             None => self_ty.span.lo,
640         };
641         let generics_indent = offset + last_line_width(&result);
642         let shape = Shape::indented(generics_indent, context.config);
643         let generics_str = try_opt!(rewrite_generics(context, generics, shape, mk_sp(lo, hi)));
644         result.push_str(&generics_str);
645
646         if polarity == ast::ImplPolarity::Negative {
647             result.push_str(" !");
648         }
649         if let Some(ref trait_ref) = *trait_ref {
650             if polarity != ast::ImplPolarity::Negative {
651                 result.push_str(" ");
652             }
653             let used_space = last_line_width(&result);
654             let budget = try_opt!(context.config.max_width().checked_sub(used_space));
655             let indent = offset + used_space;
656             result.push_str(&*try_opt!(trait_ref.rewrite(context, Shape::legacy(budget, indent))));
657
658             if split_at_for {
659                 result.push('\n');
660
661                 // Add indentation of one additional tab.
662                 let width = offset.block_indent + context.config.tab_spaces();
663                 let for_indent = Indent::new(0, width);
664                 result.push_str(&for_indent.to_string(context.config));
665
666                 result.push_str("for");
667             } else {
668                 result.push_str(" for");
669             }
670         }
671
672         let mut used_space = last_line_width(&result);
673         if generics.where_clause.predicates.is_empty() {
674             // If there is no where clause adapt budget for type formatting to take space and curly
675             // brace into account.
676             match context.config.item_brace_style() {
677                 BraceStyle::AlwaysNextLine => {}
678                 BraceStyle::PreferSameLine => used_space += 2,
679                 BraceStyle::SameLineWhere => used_space += 2,
680             }
681         }
682
683         // 1 = space before the type.
684         let budget = try_opt!(context.config.max_width().checked_sub(used_space + 1));
685         let indent = offset + result.len() + 1;
686         let self_ty_str = self_ty.rewrite(context, Shape::legacy(budget, indent));
687         if let Some(self_ty_str) = self_ty_str {
688             result.push_str(" ");
689             result.push_str(&self_ty_str);
690             return Some(result);
691         }
692
693         // Can't fit the self type on what's left of the line, so start a new one.
694         let indent = offset.block_indent(context.config);
695         result.push_str(&format!("\n{}", indent.to_string(context.config)));
696         result.push_str(&*try_opt!(self_ty.rewrite(context,
697                                                    Shape::indented(indent, context.config))));
698         Some(result)
699     } else {
700         unreachable!();
701     }
702 }
703
704 pub fn format_struct(context: &RewriteContext,
705                      item_name: &str,
706                      ident: ast::Ident,
707                      vis: &ast::Visibility,
708                      struct_def: &ast::VariantData,
709                      generics: Option<&ast::Generics>,
710                      span: Span,
711                      offset: Indent,
712                      one_line_width: Option<usize>)
713                      -> Option<String> {
714     match *struct_def {
715         ast::VariantData::Unit(..) => Some(format_unit_struct(item_name, ident, vis)),
716         ast::VariantData::Tuple(ref fields, _) => {
717             format_tuple_struct(context,
718                                 item_name,
719                                 ident,
720                                 vis,
721                                 fields,
722                                 generics,
723                                 span,
724                                 offset)
725         }
726         ast::VariantData::Struct(ref fields, _) => {
727             format_struct_struct(context,
728                                  item_name,
729                                  ident,
730                                  vis,
731                                  fields,
732                                  generics,
733                                  span,
734                                  offset,
735                                  one_line_width)
736         }
737     }
738 }
739
740 pub fn format_trait(context: &RewriteContext, item: &ast::Item, offset: Indent) -> Option<String> {
741     if let ast::ItemKind::Trait(unsafety, ref generics, ref type_param_bounds, ref trait_items) =
742         item.node {
743         let mut result = String::new();
744         let header = format!("{}{}trait {}",
745                              format_visibility(&item.vis),
746                              format_unsafety(unsafety),
747                              item.ident);
748
749         result.push_str(&header);
750
751         let body_lo = context.codemap.span_after(item.span, "{");
752
753         let generics_indent = offset + last_line_width(&result);
754         let shape = Shape::indented(generics_indent, context.config);
755         let generics_str =
756             try_opt!(rewrite_generics(context, generics, shape, mk_sp(item.span.lo, body_lo)));
757         result.push_str(&generics_str);
758
759         let trait_bound_str =
760             try_opt!(rewrite_trait_bounds(context,
761                                           type_param_bounds,
762                                           Shape::legacy(context.config.max_width(), offset)));
763         // If the trait, generics, and trait bound cannot fit on the same line,
764         // put the trait bounds on an indented new line
765         if offset.width() + last_line_width(&result) + trait_bound_str.len() >
766            context.config.comment_width() {
767             result.push('\n');
768             let trait_indent = offset.block_only().block_indent(context.config);
769             result.push_str(&trait_indent.to_string(context.config));
770         }
771         result.push_str(&trait_bound_str);
772
773         let has_body = !trait_items.is_empty();
774
775         let where_density =
776             if (context.config.where_density() == Density::Compressed &&
777                 (!result.contains('\n') ||
778                  context.config.fn_args_layout() == IndentStyle::Block)) ||
779                (context.config.fn_args_layout() == IndentStyle::Block && result.is_empty()) ||
780                (context.config.where_density() == Density::CompressedIfEmpty && !has_body &&
781                 !result.contains('\n')) {
782                 Density::Compressed
783             } else {
784                 Density::Tall
785             };
786
787         let where_budget = try_opt!(context
788                                         .config
789                                         .max_width()
790                                         .checked_sub(last_line_width(&result)));
791         let where_clause_str = try_opt!(rewrite_where_clause(context,
792                                                              &generics.where_clause,
793                                                              context.config.item_brace_style(),
794                                                              Shape::legacy(where_budget,
795                                                                            offset.block_only()),
796                                                              where_density,
797                                                              "{",
798                                                              !has_body,
799                                                              trait_bound_str.is_empty() &&
800                                                              last_line_width(&generics_str) == 1,
801                                                              None));
802         // If the where clause cannot fit on the same line,
803         // put the where clause on a new line
804         if !where_clause_str.contains('\n') &&
805            last_line_width(&result) + where_clause_str.len() + offset.width() >
806            context.config.comment_width() {
807             result.push('\n');
808             let width = offset.block_indent + context.config.tab_spaces() - 1;
809             let where_indent = Indent::new(0, width);
810             result.push_str(&where_indent.to_string(context.config));
811         }
812         result.push_str(&where_clause_str);
813
814         match context.config.item_brace_style() {
815             BraceStyle::AlwaysNextLine => {
816                 result.push('\n');
817                 result.push_str(&offset.to_string(context.config));
818             }
819             BraceStyle::PreferSameLine => result.push(' '),
820             BraceStyle::SameLineWhere => {
821                 if !where_clause_str.is_empty() &&
822                    (!trait_items.is_empty() || result.contains('\n')) {
823                     result.push('\n');
824                     result.push_str(&offset.to_string(context.config));
825                 } else {
826                     result.push(' ');
827                 }
828             }
829         }
830         result.push('{');
831
832         let snippet = context.snippet(item.span);
833         let open_pos = try_opt!(snippet.find_uncommented("{")) + 1;
834
835         if !trait_items.is_empty() || contains_comment(&snippet[open_pos..]) {
836             let mut visitor = FmtVisitor::from_codemap(context.parse_session, context.config);
837             visitor.block_indent = offset.block_only().block_indent(context.config);
838             visitor.last_pos = item.span.lo + BytePos(open_pos as u32);
839
840             for item in trait_items {
841                 visitor.visit_trait_item(item);
842             }
843
844             visitor.format_missing(item.span.hi - BytePos(1));
845
846             let inner_indent_str = visitor.block_indent.to_string(context.config);
847             let outer_indent_str = offset.block_only().to_string(context.config);
848
849             result.push('\n');
850             result.push_str(&inner_indent_str);
851             result.push_str(trim_newlines(visitor.buffer.to_string().trim()));
852             result.push('\n');
853             result.push_str(&outer_indent_str);
854         } else if result.contains('\n') {
855             result.push('\n');
856         }
857
858         result.push('}');
859         Some(result)
860     } else {
861         unreachable!();
862     }
863 }
864
865 fn format_unit_struct(item_name: &str, ident: ast::Ident, vis: &ast::Visibility) -> String {
866     format!("{};", format_header(item_name, ident, vis))
867 }
868
869 fn format_struct_struct(context: &RewriteContext,
870                         item_name: &str,
871                         ident: ast::Ident,
872                         vis: &ast::Visibility,
873                         fields: &[ast::StructField],
874                         generics: Option<&ast::Generics>,
875                         span: Span,
876                         offset: Indent,
877                         one_line_width: Option<usize>)
878                         -> Option<String> {
879     let mut result = String::with_capacity(1024);
880
881     let header_str = format_header(item_name, ident, vis);
882     result.push_str(&header_str);
883
884     let body_lo = context.codemap.span_after(span, "{");
885
886     let generics_str = match generics {
887         Some(g) => {
888             try_opt!(format_generics(context,
889                                      g,
890                                      "{",
891                                      "{",
892                                      context.config.item_brace_style(),
893                                      fields.is_empty(),
894                                      offset,
895                                      mk_sp(span.lo, body_lo)))
896         }
897         None => {
898             if context.config.item_brace_style() == BraceStyle::AlwaysNextLine &&
899                !fields.is_empty() {
900                 format!("\n{}{{", offset.block_only().to_string(context.config))
901             } else {
902                 " {".to_owned()
903             }
904         }
905     };
906     result.push_str(&generics_str);
907
908     if fields.is_empty() {
909         let snippet = context.snippet(mk_sp(body_lo, span.hi - BytePos(1)));
910         if snippet.trim().is_empty() {
911             // `struct S {}`
912         } else if snippet.trim_right_matches(&[' ', '\t'][..]).ends_with('\n') {
913             // fix indent
914             result.push_str(&snippet.trim_right());
915             result.push('\n');
916             result.push_str(&offset.to_string(context.config));
917         } else {
918             result.push_str(&snippet);
919         }
920         result.push('}');
921         return Some(result);
922     }
923
924     let item_indent = offset.block_indent(context.config);
925     // 1 = ","
926     let item_budget = try_opt!(context
927                                    .config
928                                    .max_width()
929                                    .checked_sub(item_indent.width() + 1));
930
931     let items =
932         itemize_list(context.codemap,
933                      fields.iter(),
934                      "}",
935                      |field| {
936                          // Include attributes and doc comments, if present
937                          if !field.attrs.is_empty() {
938                              field.attrs[0].span.lo
939                          } else {
940                              field.span.lo
941                          }
942                      },
943                      |field| field.ty.span.hi,
944                      |field| field.rewrite(context, Shape::legacy(item_budget, item_indent)),
945                      context.codemap.span_after(span, "{"),
946                      span.hi)
947                 .collect::<Vec<_>>();
948     // 1 = ,
949     let budget = context.config.max_width() - offset.width() + context.config.tab_spaces() - 1;
950
951     let tactic = match one_line_width {
952         Some(w) => definitive_tactic(&items, ListTactic::LimitedHorizontalVertical(w), budget),
953         None => DefinitiveListTactic::Vertical,
954     };
955
956     let fmt = ListFormatting {
957         tactic: tactic,
958         separator: ",",
959         trailing_separator: context.config.trailing_comma(),
960         shape: Shape::legacy(budget, item_indent),
961         ends_with_newline: true,
962         config: context.config,
963     };
964     let items_str = try_opt!(write_list(&items, &fmt));
965     if one_line_width.is_some() && !items_str.contains('\n') {
966         Some(format!("{} {} }}", result, items_str))
967     } else {
968         Some(format!("{}\n{}{}\n{}}}",
969                      result,
970                      offset
971                          .block_indent(context.config)
972                          .to_string(context.config),
973                      items_str,
974                      offset.to_string(context.config)))
975     }
976 }
977
978 fn format_tuple_struct(context: &RewriteContext,
979                        item_name: &str,
980                        ident: ast::Ident,
981                        vis: &ast::Visibility,
982                        fields: &[ast::StructField],
983                        generics: Option<&ast::Generics>,
984                        span: Span,
985                        offset: Indent)
986                        -> Option<String> {
987     let mut result = String::with_capacity(1024);
988
989     let header_str = format_header(item_name, ident, vis);
990     result.push_str(&header_str);
991
992     let body_lo = if fields.is_empty() {
993         context.codemap.span_after(span, "(")
994     } else {
995         fields[0].span.lo
996     };
997
998     let where_clause_str = match generics {
999         Some(generics) => {
1000             let generics_indent = offset + last_line_width(&header_str);
1001             let shape = Shape::indented(generics_indent, context.config);
1002             let generics_str =
1003                 try_opt!(rewrite_generics(context, generics, shape, mk_sp(span.lo, body_lo)));
1004             result.push_str(&generics_str);
1005
1006             let where_budget = try_opt!(context
1007                                             .config
1008                                             .max_width()
1009                                             .checked_sub(last_line_width(&result)));
1010             try_opt!(rewrite_where_clause(context,
1011                                           &generics.where_clause,
1012                                           context.config.item_brace_style(),
1013                                           Shape::legacy(where_budget, offset.block_only()),
1014                                           Density::Compressed,
1015                                           ";",
1016                                           true,
1017                                           false,
1018                                           None))
1019         }
1020         None => "".to_owned(),
1021     };
1022
1023     if fields.is_empty() {
1024         result.push('(');
1025         let snippet = context.snippet(mk_sp(body_lo, context.codemap.span_before(span, ")")));
1026         if snippet.is_empty() {
1027             // `struct S ()`
1028         } else if snippet.trim_right_matches(&[' ', '\t'][..]).ends_with('\n') {
1029             result.push_str(&snippet.trim_right());
1030             result.push('\n');
1031             result.push_str(&offset.to_string(context.config));
1032         } else {
1033             result.push_str(&snippet);
1034         }
1035         result.push(')');
1036     } else {
1037         let (tactic, item_indent) = match context.config.fn_args_layout() {
1038             IndentStyle::Visual => {
1039                 // 1 = `(`
1040                 (ListTactic::HorizontalVertical, offset.block_only() + result.len() + 1)
1041             }
1042             IndentStyle::Block => {
1043                 (ListTactic::HorizontalVertical, offset.block_only().block_indent(&context.config))
1044             }
1045         };
1046         // 3 = `();`
1047         let item_budget = try_opt!(context
1048                                        .config
1049                                        .max_width()
1050                                        .checked_sub(item_indent.width() + 3));
1051
1052         let items =
1053             itemize_list(context.codemap,
1054                          fields.iter(),
1055                          ")",
1056                          |field| {
1057                              // Include attributes and doc comments, if present
1058                              if !field.attrs.is_empty() {
1059                                  field.attrs[0].span.lo
1060                              } else {
1061                                  field.span.lo
1062                              }
1063                          },
1064                          |field| field.ty.span.hi,
1065                          |field| field.rewrite(context, Shape::legacy(item_budget, item_indent)),
1066                          context.codemap.span_after(span, "("),
1067                          span.hi);
1068         let body_budget = try_opt!(context
1069                                        .config
1070                                        .max_width()
1071                                        .checked_sub(offset.block_only().width() + result.len() +
1072                                                     3));
1073         let body = try_opt!(list_helper(items,
1074                                         // TODO budget is wrong in block case
1075                                         Shape::legacy(body_budget, item_indent),
1076                                         context.config,
1077                                         tactic));
1078
1079         if context.config.fn_args_layout() == IndentStyle::Visual || !body.contains('\n') {
1080             result.push('(');
1081             if context.config.spaces_within_parens() && body.len() > 0 {
1082                 result.push(' ');
1083             }
1084
1085             result.push_str(&body);
1086
1087             if context.config.spaces_within_parens() && body.len() > 0 {
1088                 result.push(' ');
1089             }
1090             result.push(')');
1091         } else {
1092             result.push_str("(\n");
1093             result.push_str(&item_indent.to_string(&context.config));
1094             result.push_str(&body);
1095             result.push('\n');
1096             result.push_str(&offset.block_only().to_string(&context.config));
1097             result.push(')');
1098         }
1099     }
1100
1101     if !where_clause_str.is_empty() && !where_clause_str.contains('\n') &&
1102        (result.contains('\n') ||
1103         offset.block_indent + result.len() + where_clause_str.len() + 1 >
1104         context.config.max_width()) {
1105         // We need to put the where clause on a new line, but we didn't
1106         // know that earlier, so the where clause will not be indented properly.
1107         result.push('\n');
1108         result.push_str(&(offset.block_only() + (context.config.tab_spaces() - 1))
1109                             .to_string(context.config));
1110     }
1111     result.push_str(&where_clause_str);
1112
1113     Some(result)
1114 }
1115
1116 pub fn rewrite_type_alias(context: &RewriteContext,
1117                           indent: Indent,
1118                           ident: ast::Ident,
1119                           ty: &ast::Ty,
1120                           generics: &ast::Generics,
1121                           vis: &ast::Visibility,
1122                           span: Span)
1123                           -> Option<String> {
1124     let mut result = String::new();
1125
1126     result.push_str(&format_visibility(vis));
1127     result.push_str("type ");
1128     result.push_str(&ident.to_string());
1129
1130     let generics_indent = indent + result.len();
1131     let generics_span = mk_sp(context.codemap.span_after(span, "type"), ty.span.lo);
1132     let shape = try_opt!(Shape::indented(generics_indent, context.config)
1133                              .sub_width(" =".len()));
1134     let generics_str = try_opt!(rewrite_generics(context, generics, shape, generics_span));
1135
1136     result.push_str(&generics_str);
1137
1138     let where_budget = try_opt!(context
1139                                     .config
1140                                     .max_width()
1141                                     .checked_sub(last_line_width(&result)));
1142     let where_clause_str = try_opt!(rewrite_where_clause(context,
1143                                                          &generics.where_clause,
1144                                                          context.config.item_brace_style(),
1145                                                          Shape::legacy(where_budget, indent),
1146                                                          context.config.where_density(),
1147                                                          "=",
1148                                                          true,
1149                                                          true,
1150                                                          Some(span.hi)));
1151     result.push_str(&where_clause_str);
1152     result.push_str(" = ");
1153
1154     let line_width = last_line_width(&result);
1155     // This checked_sub may fail as the extra space after '=' is not taken into account
1156     // In that case the budget is set to 0 which will make ty.rewrite retry on a new line
1157     let budget = context
1158         .config
1159         .max_width()
1160         .checked_sub(indent.width() + line_width + ";".len())
1161         .unwrap_or(0);
1162     let type_indent = indent + line_width;
1163     // Try to fit the type on the same line
1164     let ty_str = try_opt!(ty.rewrite(context, Shape::legacy(budget, type_indent))
1165                               .or_else(|| {
1166         // The line was too short, try to put the type on the next line
1167
1168         // Remove the space after '='
1169         result.pop();
1170         let type_indent = indent.block_indent(context.config);
1171         result.push('\n');
1172         result.push_str(&type_indent.to_string(context.config));
1173         let budget = try_opt!(context
1174                                   .config
1175                                   .max_width()
1176                                   .checked_sub(type_indent.width() + ";".len()));
1177         ty.rewrite(context, Shape::legacy(budget, type_indent))
1178     }));
1179     result.push_str(&ty_str);
1180     result.push_str(";");
1181     Some(result)
1182 }
1183
1184 fn type_annotation_spacing(config: &Config) -> (&str, &str) {
1185     (if config.space_before_type_annotation() {
1186          " "
1187      } else {
1188          ""
1189      },
1190      if config.space_after_type_annotation_colon() {
1191          " "
1192      } else {
1193          ""
1194      })
1195 }
1196
1197 impl Rewrite for ast::StructField {
1198     fn rewrite(&self, context: &RewriteContext, shape: Shape) -> Option<String> {
1199         if contains_skip(&self.attrs) {
1200             let span = context.snippet(mk_sp(self.attrs[0].span.lo, self.span.hi));
1201             return wrap_str(span, context.config.max_width(), shape);
1202         }
1203
1204         let name = self.ident;
1205         let vis = format_visibility(&self.vis);
1206         let mut attr_str =
1207             try_opt!(self.attrs
1208                          .rewrite(context, Shape::indented(shape.indent, context.config)));
1209         if !attr_str.is_empty() {
1210             attr_str.push('\n');
1211             attr_str.push_str(&shape.indent.to_string(context.config));
1212         }
1213
1214         let type_annotation_spacing = type_annotation_spacing(context.config);
1215         let mut result = match name {
1216             Some(name) => format!("{}{}{}{}:", attr_str, vis, name, type_annotation_spacing.0),
1217             None => format!("{}{}", attr_str, vis),
1218         };
1219
1220         let type_offset = shape.indent.block_indent(context.config);
1221         let rewrite_type_in_next_line = || {
1222             self.ty
1223                 .rewrite(context, Shape::indented(type_offset, context.config))
1224         };
1225
1226         let last_line_width = last_line_width(&result) + type_annotation_spacing.1.len();
1227         let budget = try_opt!(shape.width.checked_sub(last_line_width));
1228         let ty_rewritten = self.ty
1229             .rewrite(context,
1230                      Shape::legacy(budget, shape.indent + last_line_width));
1231         match ty_rewritten {
1232             Some(ref ty) if ty.contains('\n') => {
1233                 let new_ty = rewrite_type_in_next_line();
1234                 match new_ty {
1235                     Some(ref new_ty) if !new_ty.contains('\n') &&
1236                                         new_ty.len() + type_offset.width() <=
1237                                         context.config.max_width() => {
1238                         Some(format!("{}\n{}{}",
1239                                      result,
1240                                      type_offset.to_string(&context.config),
1241                                      &new_ty))
1242                     }
1243                     _ => {
1244                         if name.is_some() {
1245                             result.push_str(type_annotation_spacing.1);
1246                         }
1247                         Some(result + &ty)
1248                     }
1249                 }
1250             }
1251             Some(ty) => {
1252                 if name.is_some() {
1253                     result.push_str(type_annotation_spacing.1);
1254                 }
1255                 Some(result + &ty)
1256             }
1257             None => {
1258                 let ty = try_opt!(rewrite_type_in_next_line());
1259                 Some(format!("{}\n{}{}",
1260                              result,
1261                              type_offset.to_string(&context.config),
1262                              &ty))
1263             }
1264         }
1265     }
1266 }
1267
1268 pub fn rewrite_static(prefix: &str,
1269                       vis: &ast::Visibility,
1270                       ident: ast::Ident,
1271                       ty: &ast::Ty,
1272                       mutability: ast::Mutability,
1273                       expr_opt: Option<&ptr::P<ast::Expr>>,
1274                       offset: Indent,
1275                       context: &RewriteContext)
1276                       -> Option<String> {
1277     let type_annotation_spacing = type_annotation_spacing(context.config);
1278     let prefix = format!("{}{} {}{}{}:{}",
1279                          format_visibility(vis),
1280                          prefix,
1281                          format_mutability(mutability),
1282                          ident,
1283                          type_annotation_spacing.0,
1284                          type_annotation_spacing.1);
1285     // 2 = " =".len()
1286     let ty_str = try_opt!(ty.rewrite(context,
1287                                      Shape::legacy(context.config.max_width() -
1288                                                    offset.block_indent -
1289                                                    prefix.len() -
1290                                                    2,
1291                                                    offset.block_only())));
1292
1293     if let Some(expr) = expr_opt {
1294         let lhs = format!("{}{} =", prefix, ty_str);
1295         // 1 = ;
1296         let remaining_width = context.config.max_width() - offset.block_indent - 1;
1297         rewrite_assign_rhs(context,
1298                            lhs,
1299                            expr,
1300                            Shape::legacy(remaining_width, offset.block_only()))
1301                 .map(|s| s + ";")
1302     } else {
1303         let lhs = format!("{}{};", prefix, ty_str);
1304         Some(lhs)
1305     }
1306 }
1307
1308 pub fn rewrite_associated_type(ident: ast::Ident,
1309                                ty_opt: Option<&ptr::P<ast::Ty>>,
1310                                ty_param_bounds_opt: Option<&ast::TyParamBounds>,
1311                                context: &RewriteContext,
1312                                indent: Indent)
1313                                -> Option<String> {
1314     let prefix = format!("type {}", ident);
1315
1316     let type_bounds_str =
1317         if let Some(ty_param_bounds) = ty_param_bounds_opt {
1318             let joiner = match context.config.type_punctuation_density() {
1319                 TypeDensity::Compressed => "+",
1320                 TypeDensity::Wide => " + ",
1321             };
1322             let bounds: &[_] = ty_param_bounds;
1323             let bound_str = try_opt!(bounds
1324                                          .iter()
1325                                          .map(|ty_bound| {
1326                 ty_bound.rewrite(context, Shape::legacy(context.config.max_width(), indent))
1327             })
1328                                          .intersperse(Some(joiner.to_string()))
1329                                          .collect::<Option<String>>());
1330             if bounds.len() > 0 {
1331                 format!(": {}", bound_str)
1332             } else {
1333                 String::new()
1334             }
1335         } else {
1336             String::new()
1337         };
1338
1339     if let Some(ty) = ty_opt {
1340         let ty_str = try_opt!(ty.rewrite(context,
1341                                          Shape::legacy(context.config.max_width() -
1342                                                        indent.block_indent -
1343                                                        prefix.len() -
1344                                                        2,
1345                                                        indent.block_only())));
1346         Some(format!("{} = {};", prefix, ty_str))
1347     } else {
1348         Some(format!("{}{};", prefix, type_bounds_str))
1349     }
1350 }
1351
1352 pub fn rewrite_associated_impl_type(ident: ast::Ident,
1353                                     defaultness: ast::Defaultness,
1354                                     ty_opt: Option<&ptr::P<ast::Ty>>,
1355                                     ty_param_bounds_opt: Option<&ast::TyParamBounds>,
1356                                     context: &RewriteContext,
1357                                     indent: Indent)
1358                                     -> Option<String> {
1359     let result =
1360         try_opt!(rewrite_associated_type(ident, ty_opt, ty_param_bounds_opt, context, indent));
1361
1362     match defaultness {
1363         ast::Defaultness::Default => Some(format!("default {}", result)),
1364         _ => Some(result),
1365     }
1366 }
1367
1368 impl Rewrite for ast::FunctionRetTy {
1369     fn rewrite(&self, context: &RewriteContext, shape: Shape) -> Option<String> {
1370         match *self {
1371             ast::FunctionRetTy::Default(_) => Some(String::new()),
1372             ast::FunctionRetTy::Ty(ref ty) => {
1373                 let inner_width = try_opt!(shape.width.checked_sub(3));
1374                 ty.rewrite(context, Shape::legacy(inner_width, shape.indent + 3))
1375                     .map(|r| format!("-> {}", r))
1376             }
1377         }
1378     }
1379 }
1380
1381 impl Rewrite for ast::Arg {
1382     fn rewrite(&self, context: &RewriteContext, shape: Shape) -> Option<String> {
1383         if is_named_arg(self) {
1384             let mut result = try_opt!(self.pat
1385                                           .rewrite(context,
1386                                                    Shape::legacy(shape.width, shape.indent)));
1387
1388             if self.ty.node != ast::TyKind::Infer {
1389                 if context.config.space_before_type_annotation() {
1390                     result.push_str(" ");
1391                 }
1392                 result.push_str(":");
1393                 if context.config.space_after_type_annotation_colon() {
1394                     result.push_str(" ");
1395                 }
1396                 let max_width = try_opt!(shape.width.checked_sub(result.len()));
1397                 let ty_str = try_opt!(self.ty
1398                                           .rewrite(context,
1399                                                    Shape::legacy(max_width,
1400                                                                  shape.indent + result.len())));
1401                 result.push_str(&ty_str);
1402             }
1403
1404             Some(result)
1405         } else {
1406             self.ty.rewrite(context, shape)
1407         }
1408     }
1409 }
1410
1411 fn rewrite_explicit_self(explicit_self: &ast::ExplicitSelf,
1412                          args: &[ast::Arg],
1413                          context: &RewriteContext)
1414                          -> Option<String> {
1415     match explicit_self.node {
1416         ast::SelfKind::Region(lt, m) => {
1417             let mut_str = format_mutability(m);
1418             match lt {
1419                 Some(ref l) => {
1420                     let lifetime_str = try_opt!(l.rewrite(context,
1421                                                           Shape::legacy(usize::max_value(),
1422                                                                         Indent::empty())));
1423                     Some(format!("&{} {}self", lifetime_str, mut_str))
1424                 }
1425                 None => Some(format!("&{}self", mut_str)),
1426             }
1427         }
1428         ast::SelfKind::Explicit(ref ty, _) => {
1429             assert!(!args.is_empty(), "&[ast::Arg] shouldn't be empty.");
1430
1431             let mutability = explicit_self_mutability(&args[0]);
1432             let type_str = try_opt!(ty.rewrite(context,
1433                                                Shape::legacy(usize::max_value(), Indent::empty())));
1434
1435             Some(format!("{}self: {}", format_mutability(mutability), type_str))
1436         }
1437         ast::SelfKind::Value(_) => {
1438             assert!(!args.is_empty(), "&[ast::Arg] shouldn't be empty.");
1439
1440             let mutability = explicit_self_mutability(&args[0]);
1441
1442             Some(format!("{}self", format_mutability(mutability)))
1443         }
1444     }
1445 }
1446
1447 // Hacky solution caused by absence of `Mutability` in `SelfValue` and
1448 // `SelfExplicit` variants of `ast::ExplicitSelf_`.
1449 fn explicit_self_mutability(arg: &ast::Arg) -> ast::Mutability {
1450     if let ast::PatKind::Ident(ast::BindingMode::ByValue(mutability), _, _) = arg.pat.node {
1451         mutability
1452     } else {
1453         unreachable!()
1454     }
1455 }
1456
1457 pub fn span_lo_for_arg(arg: &ast::Arg) -> BytePos {
1458     if is_named_arg(arg) {
1459         arg.pat.span.lo
1460     } else {
1461         arg.ty.span.lo
1462     }
1463 }
1464
1465 pub fn span_hi_for_arg(arg: &ast::Arg) -> BytePos {
1466     match arg.ty.node {
1467         ast::TyKind::Infer if is_named_arg(arg) => arg.pat.span.hi,
1468         _ => arg.ty.span.hi,
1469     }
1470 }
1471
1472 pub fn is_named_arg(arg: &ast::Arg) -> bool {
1473     if let ast::PatKind::Ident(_, ident, _) = arg.pat.node {
1474         ident.node != symbol::keywords::Invalid.ident()
1475     } else {
1476         true
1477     }
1478 }
1479
1480 fn span_for_return(ret: &ast::FunctionRetTy) -> Span {
1481     match *ret {
1482         ast::FunctionRetTy::Default(ref span) => span.clone(),
1483         ast::FunctionRetTy::Ty(ref ty) => ty.span,
1484     }
1485 }
1486
1487 fn span_for_ty_param(ty: &ast::TyParam) -> Span {
1488     // Note that ty.span is the span for ty.ident, not the whole item.
1489     let lo = ty.span.lo;
1490     if let Some(ref def) = ty.default {
1491         return mk_sp(lo, def.span.hi);
1492     }
1493     if ty.bounds.is_empty() {
1494         return ty.span;
1495     }
1496     let hi = match ty.bounds[ty.bounds.len() - 1] {
1497         ast::TyParamBound::TraitTyParamBound(ref ptr, _) => ptr.span.hi,
1498         ast::TyParamBound::RegionTyParamBound(ref l) => l.span.hi,
1499     };
1500     mk_sp(lo, hi)
1501 }
1502
1503 fn span_for_where_pred(pred: &ast::WherePredicate) -> Span {
1504     match *pred {
1505         ast::WherePredicate::BoundPredicate(ref p) => p.span,
1506         ast::WherePredicate::RegionPredicate(ref p) => p.span,
1507         ast::WherePredicate::EqPredicate(ref p) => p.span,
1508     }
1509 }
1510
1511 // Return type is (result, force_new_line_for_brace)
1512 fn rewrite_fn_base(context: &RewriteContext,
1513                    indent: Indent,
1514                    ident: ast::Ident,
1515                    fd: &ast::FnDecl,
1516                    generics: &ast::Generics,
1517                    unsafety: ast::Unsafety,
1518                    constness: ast::Constness,
1519                    defaultness: ast::Defaultness,
1520                    abi: abi::Abi,
1521                    vis: &ast::Visibility,
1522                    span: Span,
1523                    newline_brace: bool,
1524                    has_body: bool,
1525                    has_braces: bool)
1526                    -> Option<(String, bool)> {
1527     let mut force_new_line_for_brace = false;
1528
1529     let where_clause = &generics.where_clause;
1530
1531     let mut result = String::with_capacity(1024);
1532     // Vis unsafety abi.
1533     result.push_str(&*format_visibility(vis));
1534
1535     if let ast::Defaultness::Default = defaultness {
1536         result.push_str("default ");
1537     }
1538
1539     if let ast::Constness::Const = constness {
1540         result.push_str("const ");
1541     }
1542
1543     result.push_str(::utils::format_unsafety(unsafety));
1544
1545     if abi != abi::Abi::Rust {
1546         result.push_str(&::utils::format_abi(abi, context.config.force_explicit_abi()));
1547     }
1548
1549     // fn foo
1550     result.push_str("fn ");
1551     result.push_str(&ident.to_string());
1552
1553     // Generics.
1554     let generics_indent = indent + last_line_width(&result);
1555     let generics_span = mk_sp(span.lo, span_for_return(&fd.output).lo);
1556     let shape = Shape::indented(generics_indent, context.config);
1557     let generics_str = try_opt!(rewrite_generics(context, generics, shape, generics_span));
1558     result.push_str(&generics_str);
1559
1560     let snuggle_angle_bracket = last_line_width(&generics_str) == 1;
1561
1562     // Note that the width and indent don't really matter, we'll re-layout the
1563     // return type later anyway.
1564     let ret_str = try_opt!(fd.output
1565                                .rewrite(&context, Shape::indented(indent, context.config)));
1566
1567     let multi_line_ret_str = ret_str.contains('\n');
1568     let ret_str_len = if multi_line_ret_str { 0 } else { ret_str.len() };
1569
1570     // Args.
1571     let (mut one_line_budget, mut multi_line_budget, mut arg_indent) =
1572         try_opt!(compute_budgets_for_args(context, &result, indent, ret_str_len, newline_brace));
1573
1574     if context.config.fn_args_layout() == IndentStyle::Block {
1575         arg_indent = indent.block_indent(context.config);
1576         multi_line_budget = context.config.max_width() - arg_indent.width();
1577     }
1578
1579     debug!("rewrite_fn_base: one_line_budget: {}, multi_line_budget: {}, arg_indent: {:?}",
1580            one_line_budget,
1581            multi_line_budget,
1582            arg_indent);
1583
1584     // Check if vertical layout was forced.
1585     if one_line_budget == 0 {
1586         if snuggle_angle_bracket {
1587             result.push_str("(");
1588         } else if context.config.fn_args_paren_newline() {
1589             result.push('\n');
1590             result.push_str(&arg_indent.to_string(context.config));
1591             arg_indent = arg_indent + 1; // extra space for `(`
1592             result.push('(');
1593             if context.config.spaces_within_parens() && fd.inputs.len() > 0 {
1594                 result.push(' ')
1595             }
1596         } else {
1597             result.push_str("(\n");
1598             result.push_str(&arg_indent.to_string(context.config));
1599         }
1600     } else {
1601         result.push('(');
1602         if context.config.spaces_within_parens() && fd.inputs.len() > 0 {
1603             result.push(' ')
1604         }
1605     }
1606
1607     if multi_line_ret_str {
1608         one_line_budget = 0;
1609     }
1610
1611     // A conservative estimation, to goal is to be over all parens in generics
1612     let args_start = generics
1613         .ty_params
1614         .last()
1615         .map_or(span.lo, |tp| end_typaram(tp));
1616     let args_span = mk_sp(context.codemap.span_after(mk_sp(args_start, span.hi), "("),
1617                           span_for_return(&fd.output).lo);
1618     let arg_str = try_opt!(rewrite_args(context,
1619                                         &fd.inputs,
1620                                         fd.get_self().as_ref(),
1621                                         one_line_budget,
1622                                         multi_line_budget,
1623                                         indent,
1624                                         arg_indent,
1625                                         args_span,
1626                                         fd.variadic,
1627                                         generics_str.contains('\n')));
1628
1629     let multi_line_arg_str = arg_str.contains('\n');
1630
1631     let put_args_in_block = match context.config.fn_args_layout() {
1632         IndentStyle::Block => multi_line_arg_str || generics_str.contains('\n'),
1633         _ => false,
1634     } && !fd.inputs.is_empty();
1635
1636     if put_args_in_block {
1637         arg_indent = indent.block_indent(context.config);
1638         result.push('\n');
1639         result.push_str(&arg_indent.to_string(context.config));
1640         result.push_str(&arg_str);
1641         result.push('\n');
1642         result.push_str(&indent.to_string(context.config));
1643         result.push(')');
1644     } else {
1645         result.push_str(&arg_str);
1646         if context.config.spaces_within_parens() && fd.inputs.len() > 0 {
1647             result.push(' ')
1648         }
1649         result.push(')');
1650     }
1651
1652     // Return type.
1653     if !ret_str.is_empty() {
1654         let ret_should_indent = match context.config.fn_args_layout() {
1655             // If our args are block layout then we surely must have space.
1656             IndentStyle::Block if put_args_in_block => false,
1657             _ => {
1658                 // If we've already gone multi-line, or the return type would push over the max
1659                 // width, then put the return type on a new line. With the +1 for the signature
1660                 // length an additional space between the closing parenthesis of the argument and
1661                 // the arrow '->' is considered.
1662                 let mut sig_length = result.len() + indent.width() + ret_str_len + 1;
1663
1664                 // If there is no where clause, take into account the space after the return type
1665                 // and the brace.
1666                 if where_clause.predicates.is_empty() {
1667                     sig_length += 2;
1668                 }
1669
1670                 let overlong_sig = sig_length > context.config.max_width();
1671
1672                 result.contains('\n') || multi_line_ret_str || overlong_sig
1673             }
1674         };
1675         let ret_indent = if ret_should_indent {
1676             let indent = match context.config.fn_return_indent() {
1677                 ReturnIndent::WithWhereClause => indent + 4,
1678                 // Aligning with non-existent args looks silly.
1679                 _ if arg_str.is_empty() => {
1680                     force_new_line_for_brace = true;
1681                     indent + 4
1682                 }
1683                 // FIXME: we might want to check that using the arg indent
1684                 // doesn't blow our budget, and if it does, then fallback to
1685                 // the where clause indent.
1686                 _ => arg_indent,
1687             };
1688
1689             result.push('\n');
1690             result.push_str(&indent.to_string(context.config));
1691             indent
1692         } else {
1693             result.push(' ');
1694             Indent::new(indent.width(), result.len())
1695         };
1696
1697         if multi_line_ret_str || ret_should_indent {
1698             // Now that we know the proper indent and width, we need to
1699             // re-layout the return type.
1700             let ret_str = try_opt!(fd.output
1701                                        .rewrite(context,
1702                                                 Shape::indented(ret_indent, context.config)));
1703             result.push_str(&ret_str);
1704         } else {
1705             result.push_str(&ret_str);
1706         }
1707
1708         // Comment between return type and the end of the decl.
1709         let snippet_lo = fd.output.span().hi;
1710         if where_clause.predicates.is_empty() {
1711             let snippet_hi = span.hi;
1712             let snippet = context.snippet(mk_sp(snippet_lo, snippet_hi));
1713             let snippet = snippet.trim();
1714             if !snippet.is_empty() {
1715                 result.push(' ');
1716                 result.push_str(snippet);
1717             }
1718         } else {
1719             // FIXME it would be nice to catch comments between the return type
1720             // and the where clause, but we don't have a span for the where
1721             // clause.
1722         }
1723     }
1724
1725     let should_compress_where = match context.config.where_density() {
1726         Density::Compressed => !result.contains('\n') || put_args_in_block,
1727         Density::CompressedIfEmpty => !has_body && !result.contains('\n'),
1728         _ => false,
1729     } || (put_args_in_block && ret_str.is_empty());
1730
1731     if where_clause.predicates.len() == 1 && should_compress_where {
1732         let budget = try_opt!(context
1733                                   .config
1734                                   .max_width()
1735                                   .checked_sub(last_line_width(&result)));
1736         if let Some(where_clause_str) =
1737             rewrite_where_clause(context,
1738                                  where_clause,
1739                                  context.config.fn_brace_style(),
1740                                  Shape::legacy(budget, indent),
1741                                  Density::Compressed,
1742                                  "{",
1743                                  !has_braces,
1744                                  put_args_in_block && ret_str.is_empty(),
1745                                  Some(span.hi)) {
1746             if !where_clause_str.contains('\n') {
1747                 if last_line_width(&result) + where_clause_str.len() > context.config.max_width() {
1748                     result.push('\n');
1749                 }
1750
1751                 result.push_str(&where_clause_str);
1752
1753                 return Some((result, force_new_line_for_brace));
1754             }
1755         }
1756     }
1757
1758     let where_clause_str = try_opt!(rewrite_where_clause(context,
1759                                                          where_clause,
1760                                                          context.config.fn_brace_style(),
1761                                                          Shape::indented(indent, context.config),
1762                                                          Density::Tall,
1763                                                          "{",
1764                                                          !has_braces,
1765                                                          put_args_in_block && ret_str.is_empty(),
1766                                                          Some(span.hi)));
1767
1768     result.push_str(&where_clause_str);
1769
1770     Some((result, force_new_line_for_brace))
1771 }
1772
1773 fn rewrite_args(context: &RewriteContext,
1774                 args: &[ast::Arg],
1775                 explicit_self: Option<&ast::ExplicitSelf>,
1776                 one_line_budget: usize,
1777                 multi_line_budget: usize,
1778                 indent: Indent,
1779                 arg_indent: Indent,
1780                 span: Span,
1781                 variadic: bool,
1782                 generics_str_contains_newline: bool)
1783                 -> Option<String> {
1784     let mut arg_item_strs =
1785         try_opt!(args.iter()
1786                      .map(|arg| {
1787                               arg.rewrite(&context, Shape::legacy(multi_line_budget, arg_indent))
1788                           })
1789                      .collect::<Option<Vec<_>>>());
1790
1791     // Account for sugary self.
1792     // FIXME: the comment for the self argument is dropped. This is blocked
1793     // on rust issue #27522.
1794     let min_args = explicit_self
1795         .and_then(|explicit_self| rewrite_explicit_self(explicit_self, args, context))
1796         .map_or(1, |self_str| {
1797             arg_item_strs[0] = self_str;
1798             2
1799         });
1800
1801     // Comments between args.
1802     let mut arg_items = Vec::new();
1803     if min_args == 2 {
1804         arg_items.push(ListItem::from_str(""));
1805     }
1806
1807     // FIXME(#21): if there are no args, there might still be a comment, but
1808     // without spans for the comment or parens, there is no chance of
1809     // getting it right. You also don't get to put a comment on self, unless
1810     // it is explicit.
1811     if args.len() >= min_args || variadic {
1812         let comment_span_start = if min_args == 2 {
1813             let second_arg_start = if arg_has_pattern(&args[1]) {
1814                 args[1].pat.span.lo
1815             } else {
1816                 args[1].ty.span.lo
1817             };
1818             let reduced_span = mk_sp(span.lo, second_arg_start);
1819
1820             context.codemap.span_after_last(reduced_span, ",")
1821         } else {
1822             span.lo
1823         };
1824
1825         enum ArgumentKind<'a> {
1826             Regular(&'a ast::Arg),
1827             Variadic(BytePos),
1828         }
1829
1830         let variadic_arg = if variadic {
1831             let variadic_span = mk_sp(args.last().unwrap().ty.span.hi, span.hi);
1832             let variadic_start = context.codemap.span_after(variadic_span, "...") - BytePos(3);
1833             Some(ArgumentKind::Variadic(variadic_start))
1834         } else {
1835             None
1836         };
1837
1838         let more_items = itemize_list(context.codemap,
1839                                       args[min_args - 1..]
1840                                           .iter()
1841                                           .map(ArgumentKind::Regular)
1842                                           .chain(variadic_arg),
1843                                       ")",
1844                                       |arg| match *arg {
1845                                           ArgumentKind::Regular(arg) => span_lo_for_arg(arg),
1846                                           ArgumentKind::Variadic(start) => start,
1847                                       },
1848                                       |arg| match *arg {
1849                                           ArgumentKind::Regular(arg) => arg.ty.span.hi,
1850                                           ArgumentKind::Variadic(start) => start + BytePos(3),
1851                                       },
1852                                       |arg| match *arg {
1853                                           ArgumentKind::Regular(..) => None,
1854                                           ArgumentKind::Variadic(..) => Some("...".to_owned()),
1855                                       },
1856                                       comment_span_start,
1857                                       span.hi);
1858
1859         arg_items.extend(more_items);
1860     }
1861
1862     for (item, arg) in arg_items.iter_mut().zip(arg_item_strs) {
1863         item.item = Some(arg);
1864     }
1865
1866     let (indent, trailing_comma, end_with_newline) = match context.config.fn_args_layout() {
1867         IndentStyle::Block if !generics_str_contains_newline && arg_items.len() <= 1 => {
1868             (indent.block_indent(context.config), SeparatorTactic::Never, true)
1869         }
1870         IndentStyle::Block => {
1871             (indent.block_indent(context.config), SeparatorTactic::Vertical, true)
1872         }
1873         IndentStyle::Visual => (arg_indent, SeparatorTactic::Never, false),
1874     };
1875
1876     let tactic = definitive_tactic(&arg_items,
1877                                    context.config.fn_args_density().to_list_tactic(),
1878                                    one_line_budget);
1879     let budget = match tactic {
1880         DefinitiveListTactic::Horizontal => one_line_budget,
1881         _ => multi_line_budget,
1882     };
1883
1884     debug!("rewrite_args: budget: {}, tactic: {:?}", budget, tactic);
1885
1886     let fmt = ListFormatting {
1887         tactic: tactic,
1888         separator: ",",
1889         trailing_separator: trailing_comma,
1890         shape: Shape::legacy(budget, indent),
1891         ends_with_newline: end_with_newline,
1892         config: context.config,
1893     };
1894
1895     write_list(&arg_items, &fmt)
1896 }
1897
1898 fn arg_has_pattern(arg: &ast::Arg) -> bool {
1899     if let ast::PatKind::Ident(_, ident, _) = arg.pat.node {
1900         ident.node != symbol::keywords::Invalid.ident()
1901     } else {
1902         true
1903     }
1904 }
1905
1906 fn compute_budgets_for_args(context: &RewriteContext,
1907                             result: &str,
1908                             indent: Indent,
1909                             ret_str_len: usize,
1910                             newline_brace: bool)
1911                             -> Option<((usize, usize, Indent))> {
1912     debug!("compute_budgets_for_args {} {:?}, {}, {}",
1913            result.len(),
1914            indent,
1915            ret_str_len,
1916            newline_brace);
1917     // Try keeping everything on the same line.
1918     if !result.contains('\n') {
1919         // 3 = `() `, space is before ret_string.
1920         let mut used_space = indent.width() + result.len() + ret_str_len + 3;
1921         if !newline_brace {
1922             used_space += 2;
1923         }
1924         let one_line_budget = context
1925             .config
1926             .max_width()
1927             .checked_sub(used_space)
1928             .unwrap_or(0);
1929
1930         if one_line_budget > 0 {
1931             // 4 = "() {".len()
1932             let multi_line_budget = try_opt!(context
1933                                                  .config
1934                                                  .max_width()
1935                                                  .checked_sub(indent.width() + result.len() +
1936                                                               4));
1937
1938             return Some((one_line_budget, multi_line_budget, indent + result.len() + 1));
1939         }
1940     }
1941
1942     // Didn't work. we must force vertical layout and put args on a newline.
1943     let new_indent = indent.block_indent(context.config);
1944     let used_space = new_indent.width() + 4; // Account for `(` and `)` and possibly ` {`.
1945     let max_space = context.config.max_width();
1946     if used_space <= max_space {
1947         Some((0, max_space - used_space, new_indent))
1948     } else {
1949         // Whoops! bankrupt.
1950         None
1951     }
1952 }
1953
1954 fn newline_for_brace(config: &Config, where_clause: &ast::WhereClause) -> bool {
1955     match config.fn_brace_style() {
1956         BraceStyle::AlwaysNextLine => true,
1957         BraceStyle::SameLineWhere if !where_clause.predicates.is_empty() => true,
1958         _ => false,
1959     }
1960 }
1961
1962 fn rewrite_generics(context: &RewriteContext,
1963                     generics: &ast::Generics,
1964                     shape: Shape,
1965                     span: Span)
1966                     -> Option<String> {
1967     // FIXME: convert bounds to where clauses where they get too big or if
1968     // there is a where clause at all.
1969     let lifetimes: &[_] = &generics.lifetimes;
1970     let tys: &[_] = &generics.ty_params;
1971     if lifetimes.is_empty() && tys.is_empty() {
1972         return Some(String::new());
1973     }
1974
1975     let offset = match context.config.generics_indent() {
1976         IndentStyle::Block => shape.indent.block_only().block_indent(context.config),
1977         // 1 = <
1978         IndentStyle::Visual => shape.indent + 1,
1979     };
1980
1981     let h_budget = try_opt!(shape.width.checked_sub(2));
1982     // FIXME: might need to insert a newline if the generics are really long.
1983
1984     // Strings for the generics.
1985     let lt_strs = lifetimes
1986         .iter()
1987         .map(|lt| lt.rewrite(context, Shape::legacy(h_budget, offset)));
1988     let ty_strs = tys.iter()
1989         .map(|ty_param| ty_param.rewrite(context, Shape::legacy(h_budget, offset)));
1990
1991     // Extract comments between generics.
1992     let lt_spans = lifetimes
1993         .iter()
1994         .map(|l| {
1995                  let hi = if l.bounds.is_empty() {
1996                      l.lifetime.span.hi
1997                  } else {
1998                      l.bounds[l.bounds.len() - 1].span.hi
1999                  };
2000                  mk_sp(l.lifetime.span.lo, hi)
2001              });
2002     let ty_spans = tys.iter().map(span_for_ty_param);
2003
2004     let items = itemize_list(context.codemap,
2005                              lt_spans.chain(ty_spans).zip(lt_strs.chain(ty_strs)),
2006                              ">",
2007                              |&(sp, _)| sp.lo,
2008                              |&(sp, _)| sp.hi,
2009                              // FIXME: don't clone
2010                              |&(_, ref str)| str.clone(),
2011                              context.codemap.span_after(span, "<"),
2012                              span.hi);
2013     let list_str =
2014         try_opt!(format_item_list(items, Shape::legacy(h_budget, offset), context.config));
2015
2016     let result = if context.config.generics_indent() != IndentStyle::Visual &&
2017                     list_str.contains('\n') {
2018         format!("<\n{}{}\n{}>",
2019                 offset.to_string(context.config),
2020                 list_str,
2021                 shape.indent.block_only().to_string(context.config))
2022     } else if context.config.spaces_within_angle_brackets() {
2023         format!("< {} >", list_str)
2024     } else {
2025         format!("<{}>", list_str)
2026     };
2027     Some(result)
2028 }
2029
2030 fn rewrite_trait_bounds(context: &RewriteContext,
2031                         type_param_bounds: &ast::TyParamBounds,
2032                         shape: Shape)
2033                         -> Option<String> {
2034     let bounds: &[_] = type_param_bounds;
2035
2036     if bounds.is_empty() {
2037         return Some(String::new());
2038     }
2039     let joiner = match context.config.type_punctuation_density() {
2040         TypeDensity::Compressed => "+",
2041         TypeDensity::Wide => " + ",
2042     };
2043     let bound_str = try_opt!(bounds
2044                                  .iter()
2045                                  .map(|ty_bound| ty_bound.rewrite(&context, shape))
2046                                  .intersperse(Some(joiner.to_string()))
2047                                  .collect::<Option<String>>());
2048
2049     let mut result = String::new();
2050     result.push_str(": ");
2051     result.push_str(&bound_str);
2052     Some(result)
2053 }
2054
2055 //   fn reflow_list_node_with_rule(
2056 //        &self,
2057 //        node: &CompoundNode,
2058 //        rule: &Rule,
2059 //        args: &[Arg],
2060 //        shape: &Shape
2061 //    ) -> Result<String, ()>
2062 //    where
2063 //        T: Foo,
2064 //    {
2065
2066
2067 fn rewrite_where_clause_rfc_style(context: &RewriteContext,
2068                                   where_clause: &ast::WhereClause,
2069                                   shape: Shape,
2070                                   terminator: &str,
2071                                   suppress_comma: bool,
2072                                   // where clause can be kept on the current line.
2073                                   snuggle: bool,
2074                                   span_end: Option<BytePos>)
2075                                   -> Option<String> {
2076     let block_shape = shape.block();
2077
2078     let starting_newline = if snuggle {
2079         " ".to_owned()
2080     } else {
2081         "\n".to_owned() + &block_shape.indent.to_string(context.config)
2082     };
2083
2084     let clause_shape = block_shape.block_indent(context.config.tab_spaces());
2085     // each clause on one line, trailing comma (except if suppress_comma)
2086     let span_start = span_for_where_pred(&where_clause.predicates[0]).lo;
2087     // If we don't have the start of the next span, then use the end of the
2088     // predicates, but that means we miss comments.
2089     let len = where_clause.predicates.len();
2090     let end_of_preds = span_for_where_pred(&where_clause.predicates[len - 1]).hi;
2091     let span_end = span_end.unwrap_or(end_of_preds);
2092     let items = itemize_list(context.codemap,
2093                              where_clause.predicates.iter(),
2094                              terminator,
2095                              |pred| span_for_where_pred(pred).lo,
2096                              |pred| span_for_where_pred(pred).hi,
2097                              |pred| pred.rewrite(context, clause_shape),
2098                              span_start,
2099                              span_end);
2100     let comma_tactic = if suppress_comma {
2101         SeparatorTactic::Never
2102     } else {
2103         SeparatorTactic::Always
2104     };
2105
2106     let fmt = ListFormatting {
2107         tactic: DefinitiveListTactic::Vertical,
2108         separator: ",",
2109         trailing_separator: comma_tactic,
2110         shape: clause_shape,
2111         ends_with_newline: true,
2112         config: context.config,
2113     };
2114     let preds_str = try_opt!(write_list(items, &fmt));
2115
2116     Some(format!("{}where\n{}{}",
2117                  starting_newline,
2118                  clause_shape.indent.to_string(context.config),
2119                  preds_str))
2120 }
2121
2122 fn rewrite_where_clause(context: &RewriteContext,
2123                         where_clause: &ast::WhereClause,
2124                         brace_style: BraceStyle,
2125                         shape: Shape,
2126                         density: Density,
2127                         terminator: &str,
2128                         suppress_comma: bool,
2129                         snuggle: bool,
2130                         span_end: Option<BytePos>)
2131                         -> Option<String> {
2132     if where_clause.predicates.is_empty() {
2133         return Some(String::new());
2134     }
2135
2136     if context.config.where_style() == Style::Rfc {
2137         return rewrite_where_clause_rfc_style(context,
2138                                               where_clause,
2139                                               shape,
2140                                               terminator,
2141                                               suppress_comma,
2142                                               snuggle,
2143                                               span_end);
2144     }
2145
2146     let extra_indent = Indent::new(context.config.tab_spaces(), 0);
2147
2148     let offset = match context.config.where_pred_indent() {
2149         IndentStyle::Block => shape.indent + extra_indent.block_indent(context.config),
2150         // 6 = "where ".len()
2151         IndentStyle::Visual => shape.indent + extra_indent + 6,
2152     };
2153     // FIXME: if where_pred_indent != Visual, then the budgets below might
2154     // be out by a char or two.
2155
2156     let budget = context.config.max_width() - offset.width();
2157     let span_start = span_for_where_pred(&where_clause.predicates[0]).lo;
2158     // If we don't have the start of the next span, then use the end of the
2159     // predicates, but that means we miss comments.
2160     let len = where_clause.predicates.len();
2161     let end_of_preds = span_for_where_pred(&where_clause.predicates[len - 1]).hi;
2162     let span_end = span_end.unwrap_or(end_of_preds);
2163     let items = itemize_list(context.codemap,
2164                              where_clause.predicates.iter(),
2165                              terminator,
2166                              |pred| span_for_where_pred(pred).lo,
2167                              |pred| span_for_where_pred(pred).hi,
2168                              |pred| pred.rewrite(context, Shape::legacy(budget, offset)),
2169                              span_start,
2170                              span_end);
2171     let item_vec = items.collect::<Vec<_>>();
2172     // FIXME: we don't need to collect here if the where_layout isn't
2173     // HorizontalVertical.
2174     let tactic = definitive_tactic(&item_vec, context.config.where_layout(), budget);
2175
2176     let mut comma_tactic = context.config.trailing_comma();
2177     // Kind of a hack because we don't usually have trailing commas in where clauses.
2178     if comma_tactic == SeparatorTactic::Vertical || suppress_comma {
2179         comma_tactic = SeparatorTactic::Never;
2180     }
2181
2182     let fmt = ListFormatting {
2183         tactic: tactic,
2184         separator: ",",
2185         trailing_separator: comma_tactic,
2186         shape: Shape::legacy(budget, offset),
2187         ends_with_newline: true,
2188         config: context.config,
2189     };
2190     let preds_str = try_opt!(write_list(&item_vec, &fmt));
2191
2192     let end_length = if terminator == "{" {
2193         // If the brace is on the next line we don't need to count it otherwise it needs two
2194         // characters " {"
2195         match brace_style {
2196             BraceStyle::AlwaysNextLine |
2197             BraceStyle::SameLineWhere => 0,
2198             BraceStyle::PreferSameLine => 2,
2199         }
2200     } else if terminator == "=" {
2201         2
2202     } else {
2203         terminator.len()
2204     };
2205     if density == Density::Tall || preds_str.contains('\n') ||
2206        shape.indent.width() + " where ".len() + preds_str.len() + end_length > shape.width {
2207         Some(format!("\n{}where {}",
2208                      (shape.indent + extra_indent).to_string(context.config),
2209                      preds_str))
2210     } else {
2211         Some(format!(" where {}", preds_str))
2212     }
2213 }
2214
2215 fn format_header(item_name: &str, ident: ast::Ident, vis: &ast::Visibility) -> String {
2216     format!("{}{}{}", format_visibility(vis), item_name, ident)
2217 }
2218
2219 fn format_generics(context: &RewriteContext,
2220                    generics: &ast::Generics,
2221                    opener: &str,
2222                    terminator: &str,
2223                    brace_style: BraceStyle,
2224                    force_same_line_brace: bool,
2225                    offset: Indent,
2226                    span: Span)
2227                    -> Option<String> {
2228     let shape = Shape::indented(offset, context.config);
2229     let mut result = try_opt!(rewrite_generics(context, generics, shape, span));
2230
2231     if !generics.where_clause.predicates.is_empty() || result.contains('\n') {
2232         let budget = try_opt!(context
2233                                   .config
2234                                   .max_width()
2235                                   .checked_sub(last_line_width(&result)));
2236         let where_clause_str =
2237             try_opt!(rewrite_where_clause(context,
2238                                           &generics.where_clause,
2239                                           brace_style,
2240                                           Shape::legacy(budget, offset.block_only()),
2241                                           Density::Tall,
2242                                           terminator,
2243                                           false,
2244                                           trimmed_last_line_width(&result) == 1,
2245                                           Some(span.hi)));
2246         result.push_str(&where_clause_str);
2247         let same_line_brace = force_same_line_brace ||
2248                               (generics.where_clause.predicates.is_empty() &&
2249                                trimmed_last_line_width(&result) == 1);
2250         if !same_line_brace &&
2251            (brace_style == BraceStyle::SameLineWhere || brace_style == BraceStyle::AlwaysNextLine) {
2252             result.push('\n');
2253             result.push_str(&offset.block_only().to_string(context.config));
2254         } else {
2255             result.push(' ');
2256         }
2257         result.push_str(opener);
2258     } else {
2259         if force_same_line_brace || trimmed_last_line_width(&result) == 1 ||
2260            brace_style != BraceStyle::AlwaysNextLine {
2261             result.push(' ');
2262         } else {
2263             result.push('\n');
2264             result.push_str(&offset.block_only().to_string(context.config));
2265         }
2266         result.push_str(opener);
2267     }
2268
2269     Some(result)
2270 }