]> git.lizzy.rs Git - rust.git/blob - src/items.rs
Add comma after struct-like enum variant
[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 {ReturnIndent, BraceStyle};
14 use utils::{format_visibility, make_indent, contains_skip, span_after, end_typaram};
15 use lists::{write_list, itemize_list, ListItem, ListFormatting, SeparatorTactic, ListTactic};
16 use comment::FindUncommented;
17 use visitor::FmtVisitor;
18
19 use syntax::{ast, abi};
20 use syntax::codemap::{self, Span, BytePos};
21 use syntax::print::pprust;
22 use syntax::parse::token;
23
24 impl<'a> FmtVisitor<'a> {
25     pub fn rewrite_fn(&mut self,
26                       indent: usize,
27                       ident: ast::Ident,
28                       fd: &ast::FnDecl,
29                       explicit_self: Option<&ast::ExplicitSelf>,
30                       generics: &ast::Generics,
31                       unsafety: &ast::Unsafety,
32                       constness: &ast::Constness,
33                       abi: &abi::Abi,
34                       vis: ast::Visibility,
35                       span: Span)
36         -> String
37     {
38         let newline_brace = self.newline_for_brace(&generics.where_clause);
39
40         let mut result = self.rewrite_fn_base(indent,
41                                               ident,
42                                               fd,
43                                               explicit_self,
44                                               generics,
45                                               unsafety,
46                                               constness,
47                                               abi,
48                                               vis,
49                                               span,
50                                               newline_brace);
51
52         // Prepare for the function body by possibly adding a newline and indent.
53         // FIXME we'll miss anything between the end of the signature and the start
54         // of the body, but we need more spans from the compiler to solve this.
55         if newline_brace {
56             result.push('\n');
57             result.push_str(&make_indent(indent));
58         } else {
59             result.push(' ');
60         }
61
62         result
63     }
64
65     pub fn rewrite_required_fn(&mut self,
66                                indent: usize,
67                                ident: ast::Ident,
68                                sig: &ast::MethodSig,
69                                span: Span)
70         -> String
71     {
72         // Drop semicolon or it will be interpreted as comment
73         let span = codemap::mk_sp(span.lo, span.hi - BytePos(1));
74
75         let mut result = self.rewrite_fn_base(indent,
76                                               ident,
77                                               &sig.decl,
78                                               Some(&sig.explicit_self),
79                                               &sig.generics,
80                                               &sig.unsafety,
81                                               &sig.constness,
82                                               &sig.abi,
83                                               ast::Visibility::Inherited,
84                                               span,
85                                               false);
86
87         // Re-attach semicolon
88         result.push(';');
89
90         result
91     }
92
93     fn rewrite_fn_base(&mut self,
94                        indent: usize,
95                        ident: ast::Ident,
96                        fd: &ast::FnDecl,
97                        explicit_self: Option<&ast::ExplicitSelf>,
98                        generics: &ast::Generics,
99                        unsafety: &ast::Unsafety,
100                        constness: &ast::Constness,
101                        abi: &abi::Abi,
102                        vis: ast::Visibility,
103                        span: Span,
104                        newline_brace: bool)
105         -> String
106     {
107         // FIXME we'll lose any comments in between parts of the function decl, but anyone
108         // who comments there probably deserves what they get.
109
110         let where_clause = &generics.where_clause;
111
112         let mut result = String::with_capacity(1024);
113         // Vis unsafety abi.
114         result.push_str(format_visibility(vis));
115
116         if let &ast::Unsafety::Unsafe = unsafety {
117             result.push_str("unsafe ");
118         }
119         if let &ast::Constness::Const = constness {
120             result.push_str("const ");
121         }
122         if *abi != abi::Rust {
123             result.push_str("extern ");
124             result.push_str(&abi.to_string());
125             result.push(' ');
126         }
127
128         // fn foo
129         result.push_str("fn ");
130         result.push_str(&token::get_ident(ident));
131
132         // Generics.
133         let generics_indent = indent + result.len();
134         result.push_str(&self.rewrite_generics(generics,
135                                                generics_indent,
136                                                codemap::mk_sp(span.lo,
137                                                               span_for_return(&fd.output).lo)));
138
139         let ret_str = self.rewrite_return(&fd.output);
140
141         // Args.
142         let (one_line_budget, multi_line_budget, mut arg_indent) =
143             self.compute_budgets_for_args(&result, indent, ret_str.len(), newline_brace);
144
145         debug!("rewrite_fn: one_line_budget: {}, multi_line_budget: {}, arg_indent: {}",
146                one_line_budget, multi_line_budget, arg_indent);
147
148         // Check if vertical layout was forced by compute_budget_for_args.
149         if one_line_budget <= 0 {
150             if self.config.fn_args_paren_newline {
151                 result.push('\n');
152                 result.push_str(&make_indent(arg_indent));
153                 arg_indent = arg_indent + 1; // extra space for `(`
154                 result.push('(');
155             } else {
156                 result.push_str("(\n");
157                 result.push_str(&make_indent(arg_indent));
158             }
159         } else {
160             result.push('(');
161         }
162
163         // A conservative estimation, to goal is to be over all parens in generics
164         let args_start = generics.ty_params
165                                  .last()
166                                  .map(|tp| end_typaram(tp))
167                                  .unwrap_or(span.lo);
168         let args_span = codemap::mk_sp(
169             span_after(codemap::mk_sp(args_start, span.hi), "(", self.codemap),
170             span_for_return(&fd.output).lo);
171         result.push_str(&self.rewrite_args(&fd.inputs,
172                                            explicit_self,
173                                            one_line_budget,
174                                            multi_line_budget,
175                                            arg_indent,
176                                            args_span));
177         result.push(')');
178
179         // Return type.
180         if ret_str.len() > 0 {
181             // If we've already gone multi-line, or the return type would push
182             // over the max width, then put the return type on a new line.
183             if result.contains("\n") ||
184                result.len() + indent + ret_str.len() > self.config.max_width {
185                 let indent = match self.config.fn_return_indent {
186                     ReturnIndent::WithWhereClause => indent + 4,
187                     // TODO we might want to check that using the arg indent doesn't
188                     // blow our budget, and if it does, then fallback to the where
189                     // clause indent.
190                     _ => arg_indent,
191                 };
192
193                 result.push('\n');
194                 result.push_str(&make_indent(indent));
195             } else {
196                 result.push(' ');
197             }
198             result.push_str(&ret_str);
199
200             // Comment between return type and the end of the decl.
201             let snippet_lo = fd.output.span().hi;
202             if where_clause.predicates.len() == 0 {
203                 let snippet_hi = span.hi;
204                 let snippet = self.snippet(codemap::mk_sp(snippet_lo, snippet_hi));
205                 let snippet = snippet.trim();
206                 if snippet.len() > 0 {
207                     result.push(' ');
208                     result.push_str(snippet);
209                 }
210             } else {
211                 // FIXME it would be nice to catch comments between the return type
212                 // and the where clause, but we don't have a span for the where
213                 // clause.
214             }
215         }
216
217         // Where clause.
218         result.push_str(&self.rewrite_where_clause(where_clause,
219                                                    indent,
220                                                    span.hi));
221
222         result
223     }
224
225     fn rewrite_args(&self,
226                     args: &[ast::Arg],
227                     explicit_self: Option<&ast::ExplicitSelf>,
228                     one_line_budget: usize,
229                     multi_line_budget: usize,
230                     arg_indent: usize,
231                     span: Span)
232         -> String
233     {
234         let mut arg_item_strs: Vec<_> = args.iter().map(|a| self.rewrite_fn_input(a)).collect();
235         // Account for sugary self.
236         let mut min_args = 1;
237         if let Some(explicit_self) = explicit_self {
238             match explicit_self.node {
239                 ast::ExplicitSelf_::SelfRegion(ref lt, ref m, _) => {
240                     let lt_str = match lt {
241                         &Some(ref l) => format!("{} ", pprust::lifetime_to_string(l)),
242                         &None => String::new(),
243                     };
244                     let mut_str = match m {
245                         &ast::Mutability::MutMutable => "mut ".to_owned(),
246                         &ast::Mutability::MutImmutable => String::new(),
247                     };
248                     arg_item_strs[0] = format!("&{}{}self", lt_str, mut_str);
249                     min_args = 2;
250                 }
251                 ast::ExplicitSelf_::SelfExplicit(ref ty, _) => {
252                     arg_item_strs[0] = format!("self: {}", pprust::ty_to_string(ty));
253                 }
254                 ast::ExplicitSelf_::SelfValue(_) => {
255                     assert!(args.len() >= 1, "&[ast::Arg] shouldn't be empty.");
256
257                     // this hacky solution caused by absence of `Mutability` in `SelfValue`.
258                     let mut_str = {
259                         if let ast::Pat_::PatIdent(ast::BindingMode::BindByValue(mutability), _, _)
260                                 = args[0].pat.node {
261                             match mutability {
262                                 ast::Mutability::MutMutable => "mut ",
263                                 ast::Mutability::MutImmutable => "",
264                             }
265                         } else {
266                             panic!("there is a bug or change in structure of AST, aborting.");
267                         }
268                     };
269
270                     arg_item_strs[0] = format!("{}self", mut_str);
271                     min_args = 2;
272                 }
273                 _ => {}
274             }
275         }
276
277         // Comments between args
278         let mut arg_items = Vec::new();
279         if min_args == 2 {
280             arg_items.push(ListItem::from_str(""));
281         }
282
283         // TODO if there are no args, there might still be a comment, but without
284         // spans for the comment or parens, there is no chance of getting it right.
285         // You also don't get to put a comment on self, unless it is explicit.
286         if args.len() >= min_args {
287             let comment_span_start = if min_args == 2 {
288                 span_after(span, ",", self.codemap)
289             } else {
290                 span.lo
291             };
292
293             arg_items = itemize_list(self.codemap,
294                                      arg_items,
295                                      args[min_args-1..].iter(),
296                                      ",",
297                                      ")",
298                                      |arg| arg.pat.span.lo,
299                                      |arg| arg.ty.span.hi,
300                                      |_| String::new(),
301                                      comment_span_start,
302                                      span.hi);
303         }
304
305         assert_eq!(arg_item_strs.len(), arg_items.len());
306
307         for (item, arg) in arg_items.iter_mut().zip(arg_item_strs) {
308             item.item = arg;
309         }
310
311         let fmt = ListFormatting {
312             tactic: ListTactic::HorizontalVertical,
313             separator: ",",
314             trailing_separator: SeparatorTactic::Never,
315             indent: arg_indent,
316             h_width: one_line_budget,
317             v_width: multi_line_budget,
318             ends_with_newline: true,
319         };
320
321         write_list(&arg_items, &fmt)
322     }
323
324     fn compute_budgets_for_args(&self,
325                                 result: &str,
326                                 indent: usize,
327                                 ret_str_len: usize,
328                                 newline_brace: bool)
329         -> (usize, usize, usize)
330     {
331         let mut budgets = None;
332
333         // Try keeping everything on the same line
334         if !result.contains("\n") {
335             // 3 = `() `, space is before ret_string
336             let mut used_space = indent + result.len() + ret_str_len + 3;
337             if !newline_brace {
338                 used_space += 2;
339             }
340             let one_line_budget = if used_space > self.config.max_width {
341                 0
342             } else {
343                 self.config.max_width - used_space
344             };
345
346             // 2 = `()`
347             let used_space = indent + result.len() + 2;
348             let max_space = self.config.ideal_width + self.config.leeway;
349             debug!("compute_budgets_for_args: used_space: {}, max_space: {}",
350                    used_space, max_space);
351             if used_space < max_space {
352                 budgets = Some((one_line_budget,
353                                 max_space - used_space,
354                                 indent + result.len() + 1));
355             }
356         }
357
358         // Didn't work. we must force vertical layout and put args on a newline.
359         if let None = budgets {
360             let new_indent = indent + self.config.tab_spaces;
361             let used_space = new_indent + 2; // account for `(` and `)`
362             let max_space = self.config.ideal_width + self.config.leeway;
363             if used_space > max_space {
364                 // Whoops! bankrupt.
365                 // TODO take evasive action, perhaps kill the indent or something.
366             } else {
367                 budgets = Some((0, max_space - used_space, new_indent));
368             }
369         }
370
371         budgets.unwrap()
372     }
373
374     fn newline_for_brace(&self, where_clause: &ast::WhereClause) -> bool {
375         match self.config.fn_brace_style {
376             BraceStyle::AlwaysNextLine => true,
377             BraceStyle::SameLineWhere if where_clause.predicates.len() > 0 => true,
378             _ => false,
379         }
380     }
381
382     pub fn visit_enum(&mut self,
383                       ident: ast::Ident,
384                       vis: ast::Visibility,
385                       enum_def: &ast::EnumDef,
386                       generics: &ast::Generics,
387                       span: Span)
388     {
389         let header_str = self.format_header("enum ", ident, vis);
390         self.changes.push_str_span(span, &header_str);
391
392         let enum_snippet = self.snippet(span);
393         let body_start = span.lo + BytePos(enum_snippet.find_uncommented("{").unwrap() as u32 + 1);
394         let generics_str = self.format_generics(generics,
395                                                 " {",
396                                                 self.block_indent + self.config.tab_spaces,
397                                                 codemap::mk_sp(span.lo,
398                                                                body_start));
399         self.changes.push_str_span(span, &generics_str);
400
401         self.last_pos = body_start;
402         self.block_indent += self.config.tab_spaces;
403         for (i, f) in enum_def.variants.iter().enumerate() {
404             let next_span_start: BytePos = if i == enum_def.variants.len() - 1 {
405                 span.hi
406             } else {
407                 enum_def.variants[i + 1].span.lo
408             };
409
410             self.visit_variant(f, i == enum_def.variants.len() - 1, next_span_start);
411         }
412         self.block_indent -= self.config.tab_spaces;
413
414         self.format_missing_with_indent(span.lo + BytePos(enum_snippet.rfind('}').unwrap() as u32));
415         self.changes.push_str_span(span, "}");
416     }
417
418     // Variant of an enum
419     fn visit_variant(&mut self,
420                      field: &ast::Variant,
421                      last_field: bool,
422                      next_span_start: BytePos)
423     {
424         if self.visit_attrs(&field.node.attrs) {
425             return;
426         }
427
428         self.format_missing_with_indent(field.span.lo);
429
430         let result = match field.node.kind {
431             ast::VariantKind::TupleVariantKind(ref types) => {
432                 let vis = format_visibility(field.node.vis);
433                 self.changes.push_str_span(field.span, vis);
434                 let name = field.node.name.to_string();
435                 self.changes.push_str_span(field.span, &name);
436
437                 let mut result = String::new();
438
439                 if types.len() > 0 {
440                     let items = itemize_list(self.codemap,
441                                              Vec::new(),
442                                              types.iter(),
443                                              ",",
444                                              ")",
445                                              |arg| arg.ty.span.lo,
446                                              |arg| arg.ty.span.hi,
447                                              |arg| pprust::ty_to_string(&arg.ty),
448                                              span_after(field.span, "(", self.codemap),
449                                              next_span_start);
450
451                     result.push('(');
452
453                     let indent = self.block_indent
454                                  + vis.len()
455                                  + field.node.name.to_string().len()
456                                  + 1; // Open paren
457
458                     let comma_cost = if self.config.enum_trailing_comma { 1 } else { 0 };
459                     let budget = self.config.ideal_width - indent - comma_cost - 1; // 1 = )
460
461                     let fmt = ListFormatting {
462                         tactic: ListTactic::HorizontalVertical,
463                         separator: ",",
464                         trailing_separator: SeparatorTactic::Never,
465                         indent: indent,
466                         h_width: budget,
467                         v_width: budget,
468                         ends_with_newline: false,
469                     };
470                     result.push_str(&write_list(&items, &fmt));
471                     result.push(')');
472                 }
473
474                 if let Some(ref expr) = field.node.disr_expr {
475                     result.push_str(" = ");
476                     let expr_snippet = self.snippet(expr.span);
477                     result.push_str(&expr_snippet);
478
479                     // Make sure we do not exceed column limit
480                     // 4 = " = ,"
481                     assert!(self.config.max_width >= vis.len() + name.len() + expr_snippet.len() + 4,
482                             "Enum variant exceeded column limit");
483                 }
484
485                 result
486             },
487             ast::VariantKind::StructVariantKind(ref struct_def) => {
488                 // TODO Should limit the width, as we have a trailing comma
489                 self.format_struct("",
490                                    field.node.name,
491                                    field.node.vis,
492                                    struct_def,
493                                    None,
494                                    field.span,
495                                    self.block_indent)
496             }
497         };
498         self.changes.push_str_span(field.span, &result);
499
500         if !last_field || self.config.enum_trailing_comma {
501             self.changes.push_str_span(field.span, ",");
502         }
503
504         self.last_pos = field.span.hi + BytePos(1);
505     }
506
507     fn format_struct(&self,
508                      item_name: &str,
509                      ident: ast::Ident,
510                      vis: ast::Visibility,
511                      struct_def: &ast::StructDef,
512                      generics: Option<&ast::Generics>,
513                      span: Span,
514                      offset: usize) -> String
515     {
516         let mut result = String::with_capacity(1024);
517
518         let header_str = self.format_header(item_name, ident, vis);
519         result.push_str(&header_str);
520
521         if struct_def.fields.len() == 0 {
522             result.push(';');
523             return result;
524         }
525
526         let is_tuple = match struct_def.fields[0].node.kind {
527             ast::StructFieldKind::NamedField(..) => false,
528             ast::StructFieldKind::UnnamedField(..) => true
529         };
530
531         let (opener, terminator) = if is_tuple { ("(", ")") } else { (" {", "}") };
532
533         let generics_str = match generics {
534             Some(g) => self.format_generics(g,
535                                             opener,
536                                             offset + header_str.len(),
537                                             codemap::mk_sp(span.lo,
538                                                            struct_def.fields[0].span.lo)),
539             None => opener.to_owned()
540         };
541         result.push_str(&generics_str);
542
543         let items = itemize_list(self.codemap,
544                                  Vec::new(),
545                                  struct_def.fields.iter(),
546                                  ",",
547                                  terminator,
548                                  |field| {
549                                       // Include attributes and doc comments,
550                                       // if present
551                                       if field.node.attrs.len() > 0 {
552                                           field.node.attrs[0].span.lo
553                                       } else {
554                                           field.span.lo
555                                       }
556                                  },
557                                  |field| field.node.ty.span.hi,
558                                  |field| self.format_field(field),
559                                  span_after(span, opener.trim(), self.codemap),
560                                  span.hi);
561
562         // 2 terminators and a semicolon
563         let used_budget = offset + header_str.len() + generics_str.len() + 3;
564
565         // Conservative approximation
566         let single_line_cost = (span.hi - struct_def.fields[0].span.lo).0;
567         let break_line = !is_tuple ||
568                          generics_str.contains('\n') ||
569                          single_line_cost as usize + used_budget > self.config.max_width;
570
571         if break_line {
572             let indentation = make_indent(offset + self.config.tab_spaces);
573             result.push('\n');
574             result.push_str(&indentation);
575         }
576
577         let tactic = if break_line { ListTactic::Vertical } else { ListTactic::Horizontal };
578
579         // 1 = ,
580         let budget = self.config.ideal_width - offset + self.config.tab_spaces - 1;
581         let fmt = ListFormatting {
582             tactic: tactic,
583             separator: ",",
584             trailing_separator: self.config.struct_trailing_comma,
585             indent: offset + self.config.tab_spaces,
586             h_width: self.config.max_width,
587             v_width: budget,
588             ends_with_newline: false,
589         };
590
591         result.push_str(&write_list(&items, &fmt));
592
593         if break_line {
594             result.push('\n');
595             result.push_str(&make_indent(offset));
596         }
597
598         result.push_str(terminator);
599
600         if is_tuple {
601             result.push(';');
602         }
603
604         result
605     }
606
607     pub fn visit_struct(&mut self,
608                         ident: ast::Ident,
609                         vis: ast::Visibility,
610                         struct_def: &ast::StructDef,
611                         generics: &ast::Generics,
612                         span: Span)
613     {
614         let indent = self.block_indent;
615         let result = self.format_struct("struct ",
616                                         ident,
617                                         vis,
618                                         struct_def,
619                                         Some(generics),
620                                         span,
621                                         indent);
622         self.changes.push_str_span(span, &result);
623         self.last_pos = span.hi;
624     }
625
626     fn format_header(&self,
627                      item_name: &str,
628                      ident: ast::Ident,
629                      vis: ast::Visibility)
630         -> String
631     {
632         format!("{}{}{}", format_visibility(vis), item_name, &token::get_ident(ident))
633     }
634
635     fn format_generics(&self,
636                        generics: &ast::Generics,
637                        opener: &str,
638                        offset: usize,
639                        span: Span)
640         -> String
641     {
642         let mut result = self.rewrite_generics(generics, offset, span);
643
644         if generics.where_clause.predicates.len() > 0 || result.contains('\n') {
645             result.push_str(&self.rewrite_where_clause(&generics.where_clause,
646                                                        self.block_indent,
647                                                        span.hi));
648             result.push_str(&make_indent(self.block_indent));
649             result.push('\n');
650             result.push_str(opener.trim());
651         } else {
652             result.push_str(opener);
653         }
654
655         result
656     }
657
658     // Field of a struct
659     fn format_field(&self, field: &ast::StructField) -> String {
660         if contains_skip(&field.node.attrs) {
661             return self.snippet(codemap::mk_sp(field.node.attrs[0].span.lo, field.span.hi));
662         }
663
664         let name = match field.node.kind {
665             ast::StructFieldKind::NamedField(ident, _) => Some(token::get_ident(ident)),
666             ast::StructFieldKind::UnnamedField(_) => None,
667         };
668         let vis = match field.node.kind {
669             ast::StructFieldKind::NamedField(_, vis) |
670             ast::StructFieldKind::UnnamedField(vis) => format_visibility(vis)
671         };
672         let typ = pprust::ty_to_string(&field.node.ty);
673
674         let indent = self.block_indent + self.config.tab_spaces;
675         let mut attr_str = self.rewrite_attrs(&field.node.attrs, indent);
676         if attr_str.len() > 0 {
677             attr_str.push('\n');
678             attr_str.push_str(&make_indent(indent));
679         }
680
681         match name {
682             Some(name) => format!("{}{}{}: {}", attr_str, vis, name, typ),
683             None => format!("{}{}{}", attr_str, vis, typ)
684         }
685     }
686
687     fn rewrite_generics(&self, generics: &ast::Generics, offset: usize, span: Span) -> String {
688         // FIXME convert bounds to where clauses where they get too big or if
689         // there is a where clause at all.
690         let mut result = String::new();
691         let lifetimes: &[_] = &generics.lifetimes;
692         let tys: &[_] = &generics.ty_params;
693         if lifetimes.len() + tys.len() == 0 {
694             return result;
695         }
696
697         let budget = self.config.max_width - offset - 2;
698         // TODO might need to insert a newline if the generics are really long
699         result.push('<');
700
701         // Strings for the generics.
702         let lt_strs = lifetimes.iter().map(|l| self.rewrite_lifetime_def(l));
703         let ty_strs = tys.iter().map(|ty| self.rewrite_ty_param(ty));
704
705         // Extract comments between generics.
706         let lt_spans = lifetimes.iter().map(|l| {
707             let hi = if l.bounds.len() == 0 {
708                 l.lifetime.span.hi
709             } else {
710                 l.bounds[l.bounds.len() - 1].span.hi
711             };
712             codemap::mk_sp(l.lifetime.span.lo, hi)
713         });
714         let ty_spans = tys.iter().map(span_for_ty_param);
715
716         let mut items = itemize_list(self.codemap,
717                                      Vec::new(),
718                                      lt_spans.chain(ty_spans),
719                                      ",",
720                                      ">",
721                                      |sp| sp.lo,
722                                      |sp| sp.hi,
723                                      |_| String::new(),
724                                      span_after(span, "<", self.codemap),
725                                      span.hi);
726
727         for (item, ty) in items.iter_mut().zip(lt_strs.chain(ty_strs)) {
728             item.item = ty;
729         }
730
731         let fmt = ListFormatting {
732             tactic: ListTactic::HorizontalVertical,
733             separator: ",",
734             trailing_separator: SeparatorTactic::Never,
735             indent: offset + 1,
736             h_width: budget,
737             v_width: budget,
738             ends_with_newline: true,
739         };
740         result.push_str(&write_list(&items, &fmt));
741
742         result.push('>');
743
744         result
745     }
746
747     fn rewrite_where_clause(&self,
748                             where_clause: &ast::WhereClause,
749                             indent: usize,
750                             span_end: BytePos)
751         -> String
752     {
753         let mut result = String::new();
754         if where_clause.predicates.len() == 0 {
755             return result;
756         }
757
758         result.push('\n');
759         result.push_str(&make_indent(indent + 4));
760         result.push_str("where ");
761
762         let span_start = span_for_where_pred(&where_clause.predicates[0]).lo;
763         let items = itemize_list(self.codemap,
764                                  Vec::new(),
765                                  where_clause.predicates.iter(),
766                                  ",",
767                                  "{",
768                                  |pred| span_for_where_pred(pred).lo,
769                                  |pred| span_for_where_pred(pred).hi,
770                                  |pred| self.rewrite_pred(pred),
771                                  span_start,
772                                  span_end);
773
774         let budget = self.config.ideal_width + self.config.leeway - indent - 10;
775         let fmt = ListFormatting {
776             tactic: ListTactic::Vertical,
777             separator: ",",
778             trailing_separator: SeparatorTactic::Never,
779             indent: indent + 10,
780             h_width: budget,
781             v_width: budget,
782             ends_with_newline: true,
783         };
784         result.push_str(&write_list(&items, &fmt));
785
786         result
787     }
788
789     fn rewrite_return(&self, ret: &ast::FunctionRetTy) -> String {
790         match *ret {
791             ast::FunctionRetTy::DefaultReturn(_) => String::new(),
792             ast::FunctionRetTy::NoReturn(_) => "-> !".to_owned(),
793             ast::FunctionRetTy::Return(ref ty) => "-> ".to_owned() + &pprust::ty_to_string(ty),
794         }
795     }
796
797     // TODO we farm this out, but this could spill over the column limit, so we ought to handle it properly
798     fn rewrite_fn_input(&self, arg: &ast::Arg) -> String {
799         format!("{}: {}",
800                 pprust::pat_to_string(&arg.pat),
801                 pprust::ty_to_string(&arg.ty))
802     }
803 }
804
805 fn span_for_return(ret: &ast::FunctionRetTy) -> Span {
806     match *ret {
807         ast::FunctionRetTy::NoReturn(ref span) |
808         ast::FunctionRetTy::DefaultReturn(ref span) => span.clone(),
809         ast::FunctionRetTy::Return(ref ty) => ty.span,
810     }
811 }
812
813 fn span_for_ty_param(ty: &ast::TyParam) -> Span {
814     // Note that ty.span is the span for ty.ident, not the whole item.
815     let lo = ty.span.lo;
816     if let Some(ref def) = ty.default {
817         return codemap::mk_sp(lo, def.span.hi);
818     }
819     if ty.bounds.len() == 0 {
820         return ty.span;
821     }
822     let hi = match ty.bounds[ty.bounds.len() - 1] {
823         ast::TyParamBound::TraitTyParamBound(ref ptr, _) => ptr.span.hi,
824         ast::TyParamBound::RegionTyParamBound(ref l) => l.span.hi,
825     };
826     codemap::mk_sp(lo, hi)
827 }
828
829 fn span_for_where_pred(pred: &ast::WherePredicate) -> Span {
830     match *pred {
831         ast::WherePredicate::BoundPredicate(ref p) => p.span,
832         ast::WherePredicate::RegionPredicate(ref p) => p.span,
833         ast::WherePredicate::EqPredicate(ref p) => p.span,
834     }
835 }