]> git.lizzy.rs Git - rust.git/blob - src/expr.rs
Merge pull request #1568 from mathstuf/suffixes-typo
[rust.git] / src / expr.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 use std::cmp::{Ordering, min};
12 use std::mem::swap;
13 use std::ops::Deref;
14 use std::iter::ExactSizeIterator;
15 use std::fmt::Write;
16
17 use {Indent, Shape, Spanned};
18 use codemap::SpanUtils;
19 use rewrite::{Rewrite, RewriteContext};
20 use lists::{write_list, itemize_list, ListFormatting, SeparatorTactic, ListTactic,
21             DefinitiveListTactic, definitive_tactic, ListItem, format_item_list, struct_lit_shape,
22             struct_lit_tactic, shape_for_tactic, struct_lit_formatting};
23 use string::{StringFormat, rewrite_string};
24 use utils::{extra_offset, last_line_width, wrap_str, binary_search, first_line_width,
25             semicolon_for_stmt, trimmed_last_line_width, left_most_sub_expr, stmt_expr,
26             colon_spaces};
27 use visitor::FmtVisitor;
28 use config::{Config, IndentStyle, MultilineStyle, ControlBraceStyle, Style};
29 use comment::{FindUncommented, rewrite_comment, contains_comment, recover_comment_removed};
30 use types::{rewrite_path, PathContext};
31 use items::{span_lo_for_arg, span_hi_for_arg};
32 use chains::rewrite_chain;
33 use macros::{rewrite_macro, MacroPosition};
34
35 use syntax::{ast, ptr};
36 use syntax::codemap::{CodeMap, Span, BytePos, mk_sp};
37 use syntax::parse::classify;
38
39 impl Rewrite for ast::Expr {
40     fn rewrite(&self, context: &RewriteContext, shape: Shape) -> Option<String> {
41         format_expr(self, ExprType::SubExpression, context, shape)
42     }
43 }
44
45 #[derive(PartialEq)]
46 enum ExprType {
47     Statement,
48     SubExpression,
49 }
50
51 fn format_expr(expr: &ast::Expr,
52                expr_type: ExprType,
53                context: &RewriteContext,
54                shape: Shape)
55                -> Option<String> {
56     let result = match expr.node {
57         ast::ExprKind::Array(ref expr_vec) => {
58             rewrite_array(expr_vec.iter().map(|e| &**e),
59                           mk_sp(context.codemap.span_after(expr.span, "["), expr.span.hi),
60                           context,
61                           shape)
62         }
63         ast::ExprKind::Lit(ref l) => {
64             match l.node {
65                 ast::LitKind::Str(_, ast::StrStyle::Cooked) => {
66                     rewrite_string_lit(context, l.span, shape)
67                 }
68                 _ => wrap_str(context.snippet(expr.span), context.config.max_width, shape),
69             }
70         }
71         ast::ExprKind::Call(ref callee, ref args) => {
72             let inner_span = mk_sp(callee.span.hi, expr.span.hi);
73             rewrite_call(context, &**callee, args, inner_span, shape)
74         }
75         ast::ExprKind::Paren(ref subexpr) => rewrite_paren(context, subexpr, shape),
76         ast::ExprKind::Binary(ref op, ref lhs, ref rhs) => {
77             // FIXME: format comments between operands and operator
78             rewrite_pair(&**lhs,
79                          &**rhs,
80                          "",
81                          &format!(" {} ", context.snippet(op.span)),
82                          "",
83                          context,
84                          shape)
85         }
86         ast::ExprKind::Unary(ref op, ref subexpr) => rewrite_unary_op(context, op, subexpr, shape),
87         ast::ExprKind::Struct(ref path, ref fields, ref base) => {
88             rewrite_struct_lit(context,
89                                path,
90                                fields,
91                                base.as_ref().map(|e| &**e),
92                                expr.span,
93                                shape)
94         }
95         ast::ExprKind::Tup(ref items) => {
96             rewrite_tuple(context, items.iter().map(|x| &**x), expr.span, shape)
97         }
98         ast::ExprKind::While(ref cond, ref block, label) => {
99             ControlFlow::new_while(None, cond, block, label, expr.span).rewrite(context, shape)
100         }
101         ast::ExprKind::WhileLet(ref pat, ref cond, ref block, label) => {
102             ControlFlow::new_while(Some(pat), cond, block, label, expr.span).rewrite(context, shape)
103         }
104         ast::ExprKind::ForLoop(ref pat, ref cond, ref block, label) => {
105             ControlFlow::new_for(pat, cond, block, label, expr.span).rewrite(context, shape)
106         }
107         ast::ExprKind::Loop(ref block, label) => {
108             ControlFlow::new_loop(block, label, expr.span).rewrite(context, shape)
109         }
110         ast::ExprKind::Block(ref block) => block.rewrite(context, shape),
111         ast::ExprKind::If(ref cond, ref if_block, ref else_block) => {
112             ControlFlow::new_if(cond,
113                                 None,
114                                 if_block,
115                                 else_block.as_ref().map(|e| &**e),
116                                 expr_type == ExprType::SubExpression,
117                                 false,
118                                 expr.span)
119                     .rewrite(context, shape)
120         }
121         ast::ExprKind::IfLet(ref pat, ref cond, ref if_block, ref else_block) => {
122             ControlFlow::new_if(cond,
123                                 Some(pat),
124                                 if_block,
125                                 else_block.as_ref().map(|e| &**e),
126                                 expr_type == ExprType::SubExpression,
127                                 false,
128                                 expr.span)
129                     .rewrite(context, shape)
130         }
131         ast::ExprKind::Match(ref cond, ref arms) => {
132             rewrite_match(context, cond, arms, shape, expr.span)
133         }
134         ast::ExprKind::Path(ref qself, ref path) => {
135             rewrite_path(context, PathContext::Expr, qself.as_ref(), path, shape)
136         }
137         ast::ExprKind::Assign(ref lhs, ref rhs) => {
138             rewrite_assignment(context, lhs, rhs, None, shape)
139         }
140         ast::ExprKind::AssignOp(ref op, ref lhs, ref rhs) => {
141             rewrite_assignment(context, lhs, rhs, Some(op), shape)
142         }
143         ast::ExprKind::Continue(ref opt_ident) => {
144             let id_str = match *opt_ident {
145                 Some(ident) => format!(" {}", ident.node),
146                 None => String::new(),
147             };
148             wrap_str(format!("continue{}", id_str),
149                      context.config.max_width,
150                      shape)
151         }
152         ast::ExprKind::Break(ref opt_ident, ref opt_expr) => {
153             let id_str = match *opt_ident {
154                 Some(ident) => format!(" {}", ident.node),
155                 None => String::new(),
156             };
157
158             if let Some(ref expr) = *opt_expr {
159                 rewrite_unary_prefix(context, &format!("break{} ", id_str), &**expr, shape)
160             } else {
161                 wrap_str(format!("break{}", id_str), context.config.max_width, shape)
162             }
163         }
164         ast::ExprKind::Closure(capture, ref fn_decl, ref body, _) => {
165             rewrite_closure(capture, fn_decl, body, expr.span, context, shape)
166         }
167         ast::ExprKind::Try(..) |
168         ast::ExprKind::Field(..) |
169         ast::ExprKind::TupField(..) |
170         ast::ExprKind::MethodCall(..) => rewrite_chain(expr, context, shape),
171         ast::ExprKind::Mac(ref mac) => {
172             // Failure to rewrite a marco should not imply failure to
173             // rewrite the expression.
174             rewrite_macro(mac, None, context, shape, MacroPosition::Expression)
175                 .or_else(|| wrap_str(context.snippet(expr.span), context.config.max_width, shape))
176         }
177         ast::ExprKind::Ret(None) => wrap_str("return".to_owned(), context.config.max_width, shape),
178         ast::ExprKind::Ret(Some(ref expr)) => {
179             rewrite_unary_prefix(context, "return ", &**expr, shape)
180         }
181         ast::ExprKind::Box(ref expr) => rewrite_unary_prefix(context, "box ", &**expr, shape),
182         ast::ExprKind::AddrOf(mutability, ref expr) => {
183             rewrite_expr_addrof(context, mutability, expr, shape)
184         }
185         ast::ExprKind::Cast(ref expr, ref ty) => {
186             rewrite_pair(&**expr, &**ty, "", " as ", "", context, shape)
187         }
188         ast::ExprKind::Type(ref expr, ref ty) => {
189             rewrite_pair(&**expr, &**ty, "", ": ", "", context, shape)
190         }
191         ast::ExprKind::Index(ref expr, ref index) => {
192             rewrite_index(&**expr, &**index, context, shape)
193         }
194         ast::ExprKind::Repeat(ref expr, ref repeats) => {
195             let (lbr, rbr) = if context.config.spaces_within_square_brackets {
196                 ("[ ", " ]")
197             } else {
198                 ("[", "]")
199             };
200             rewrite_pair(&**expr, &**repeats, lbr, "; ", rbr, context, shape)
201         }
202         ast::ExprKind::Range(ref lhs, ref rhs, limits) => {
203             let delim = match limits {
204                 ast::RangeLimits::HalfOpen => "..",
205                 ast::RangeLimits::Closed => "...",
206             };
207
208             match (lhs.as_ref().map(|x| &**x), rhs.as_ref().map(|x| &**x)) {
209                 (Some(ref lhs), Some(ref rhs)) => {
210                     let sp_delim = if context.config.spaces_around_ranges {
211                         format!(" {} ", delim)
212                     } else {
213                         delim.into()
214                     };
215                     rewrite_pair(&**lhs, &**rhs, "", &sp_delim, "", context, shape)
216                 }
217                 (None, Some(ref rhs)) => {
218                     let sp_delim = if context.config.spaces_around_ranges {
219                         format!("{} ", delim)
220                     } else {
221                         delim.into()
222                     };
223                     rewrite_unary_prefix(context, &sp_delim, &**rhs, shape)
224                 }
225                 (Some(ref lhs), None) => {
226                     let sp_delim = if context.config.spaces_around_ranges {
227                         format!(" {}", delim)
228                     } else {
229                         delim.into()
230                     };
231                     rewrite_unary_suffix(context, &sp_delim, &**lhs, shape)
232                 }
233                 (None, None) => wrap_str(delim.into(), context.config.max_width, shape),
234             }
235         }
236         // We do not format these expressions yet, but they should still
237         // satisfy our width restrictions.
238         ast::ExprKind::InPlace(..) |
239         ast::ExprKind::InlineAsm(..) => {
240             wrap_str(context.snippet(expr.span), context.config.max_width, shape)
241         }
242     };
243     result.and_then(|res| recover_comment_removed(res, expr.span, context, shape))
244 }
245
246 pub fn rewrite_pair<LHS, RHS>(lhs: &LHS,
247                               rhs: &RHS,
248                               prefix: &str,
249                               infix: &str,
250                               suffix: &str,
251                               context: &RewriteContext,
252                               shape: Shape)
253                               -> Option<String>
254     where LHS: Rewrite,
255           RHS: Rewrite
256 {
257     // Get "full width" rhs and see if it fits on the current line. This
258     // usually works fairly well since it tends to place operands of
259     // operations with high precendence close together.
260     // Note that this is non-conservative, but its just to see if it's even
261     // worth trying to put everything on one line.
262     let rhs_shape = try_opt!(shape.sub_width(suffix.len()));
263     let rhs_result = rhs.rewrite(context, rhs_shape);
264
265     if let Some(rhs_result) = rhs_result {
266         // This is needed in case of line break not caused by a
267         // shortage of space, but by end-of-line comments, for example.
268         if !rhs_result.contains('\n') {
269             let lhs_shape = try_opt!(shape.sub_width(prefix.len() + infix.len()));
270             let lhs_result = lhs.rewrite(context, lhs_shape);
271             if let Some(lhs_result) = lhs_result {
272                 let mut result = format!("{}{}{}", prefix, lhs_result, infix);
273
274                 let remaining_width = shape
275                     .width
276                     .checked_sub(last_line_width(&result))
277                     .unwrap_or(0);
278
279                 if rhs_result.len() <= remaining_width {
280                     result.push_str(&rhs_result);
281                     result.push_str(suffix);
282                     return Some(result);
283                 }
284
285                 // Try rewriting the rhs into the remaining space.
286                 let rhs_shape = shape.shrink_left(last_line_width(&result) + suffix.len());
287                 if let Some(rhs_shape) = rhs_shape {
288                     if let Some(rhs_result) = rhs.rewrite(context, rhs_shape) {
289                         // FIXME this should always hold.
290                         if rhs_result.len() <= remaining_width {
291                             result.push_str(&rhs_result);
292                             result.push_str(suffix);
293                             return Some(result);
294                         }
295                     }
296                 }
297             }
298         }
299     }
300
301     // We have to use multiple lines.
302
303     // Re-evaluate the rhs because we have more space now:
304     let infix = infix.trim_right();
305     let lhs_budget = try_opt!(context
306                                   .config
307                                   .max_width
308                                   .checked_sub(shape.used_width() + prefix.len() +
309                                                infix.len()));
310     let rhs_shape = match context.config.control_style {
311         Style::Default => {
312             try_opt!(shape.sub_width(suffix.len() + prefix.len())).visual_indent(prefix.len())
313         }
314         Style::Rfc => try_opt!(shape.block_left(context.config.tab_spaces)),
315     };
316
317     let rhs_result = try_opt!(rhs.rewrite(context, rhs_shape));
318     let lhs_result = try_opt!(lhs.rewrite(context,
319                                           Shape {
320                                               width: lhs_budget,
321                                               ..shape
322                                           }));
323     Some(format!("{}{}{}\n{}{}{}",
324                  prefix,
325                  lhs_result,
326                  infix,
327                  rhs_shape.indent.to_string(context.config),
328                  rhs_result,
329                  suffix))
330 }
331
332 pub fn rewrite_array<'a, I>(expr_iter: I,
333                             span: Span,
334                             context: &RewriteContext,
335                             shape: Shape)
336                             -> Option<String>
337     where I: Iterator<Item = &'a ast::Expr>
338 {
339     let bracket_size = if context.config.spaces_within_square_brackets {
340         2 // "[ "
341     } else {
342         1 // "["
343     };
344
345     let nested_shape = match context.config.array_layout {
346         IndentStyle::Block => shape.block().block_indent(context.config.tab_spaces),
347         IndentStyle::Visual => {
348             try_opt!(shape
349                          .visual_indent(bracket_size)
350                          .sub_width(bracket_size * 2))
351         }
352     };
353
354     let items = itemize_list(context.codemap,
355                              expr_iter,
356                              "]",
357                              |item| item.span.lo,
358                              |item| item.span.hi,
359                              |item| item.rewrite(context, nested_shape),
360                              span.lo,
361                              span.hi)
362             .collect::<Vec<_>>();
363
364     if items.is_empty() {
365         if context.config.spaces_within_square_brackets {
366             return Some("[ ]".to_string());
367         } else {
368             return Some("[]".to_string());
369         }
370     }
371
372     let has_long_item = try_opt!(items
373                                      .iter()
374                                      .map(|li| li.item.as_ref().map(|s| s.len() > 10))
375                                      .fold(Some(false),
376                                            |acc, x| acc.and_then(|y| x.map(|x| x || y))));
377
378     let tactic = match context.config.array_layout {
379         IndentStyle::Block => {
380             // FIXME wrong shape in one-line case
381             match shape.width.checked_sub(2 * bracket_size) {
382                 Some(width) => {
383                     let tactic = ListTactic::LimitedHorizontalVertical(context.config.array_width);
384                     definitive_tactic(&items, tactic, width)
385                 }
386                 None => DefinitiveListTactic::Vertical,
387             }
388         }
389         IndentStyle::Visual => {
390             if has_long_item || items.iter().any(ListItem::is_multiline) {
391                 definitive_tactic(&items,
392                                   ListTactic::LimitedHorizontalVertical(context.config.array_width),
393                                   nested_shape.width)
394             } else {
395                 DefinitiveListTactic::Mixed
396             }
397         }
398     };
399
400     let fmt = ListFormatting {
401         tactic: tactic,
402         separator: ",",
403         trailing_separator: SeparatorTactic::Never,
404         shape: nested_shape,
405         ends_with_newline: false,
406         config: context.config,
407     };
408     let list_str = try_opt!(write_list(&items, &fmt));
409
410     let result = if context.config.array_layout == IndentStyle::Visual ||
411                     tactic != DefinitiveListTactic::Vertical {
412         if context.config.spaces_within_square_brackets && list_str.len() > 0 {
413             format!("[ {} ]", list_str)
414         } else {
415             format!("[{}]", list_str)
416         }
417     } else {
418         format!("[\n{}{},\n{}]",
419                 nested_shape.indent.to_string(context.config),
420                 list_str,
421                 shape.block().indent.to_string(context.config))
422     };
423
424     Some(result)
425 }
426
427 // This functions is pretty messy because of the rules around closures and blocks:
428 // FIXME - the below is probably no longer true in full.
429 //   * if there is a return type, then there must be braces,
430 //   * given a closure with braces, whether that is parsed to give an inner block
431 //     or not depends on if there is a return type and if there are statements
432 //     in that block,
433 //   * if the first expression in the body ends with a block (i.e., is a
434 //     statement without needing a semi-colon), then adding or removing braces
435 //     can change whether it is treated as an expression or statement.
436 fn rewrite_closure(capture: ast::CaptureBy,
437                    fn_decl: &ast::FnDecl,
438                    body: &ast::Expr,
439                    span: Span,
440                    context: &RewriteContext,
441                    shape: Shape)
442                    -> Option<String> {
443     let mover = if capture == ast::CaptureBy::Value {
444         "move "
445     } else {
446         ""
447     };
448     // 4 = "|| {".len(), which is overconservative when the closure consists of
449     // a single expression.
450     let nested_shape = try_opt!(try_opt!(shape.shrink_left(mover.len())).sub_width(4));
451
452     // 1 = |
453     let argument_offset = nested_shape.indent + 1;
454     let arg_shape = try_opt!(nested_shape.shrink_left(1)).visual_indent(0);
455     let ret_str = try_opt!(fn_decl.output.rewrite(context, arg_shape));
456
457     let arg_items = itemize_list(context.codemap,
458                                  fn_decl.inputs.iter(),
459                                  "|",
460                                  |arg| span_lo_for_arg(arg),
461                                  |arg| span_hi_for_arg(arg),
462                                  |arg| arg.rewrite(context, arg_shape),
463                                  context.codemap.span_after(span, "|"),
464                                  body.span.lo);
465     let item_vec = arg_items.collect::<Vec<_>>();
466     // 1 = space between arguments and return type.
467     let horizontal_budget = nested_shape
468         .width
469         .checked_sub(ret_str.len() + 1)
470         .unwrap_or(0);
471     let tactic = definitive_tactic(&item_vec, ListTactic::HorizontalVertical, horizontal_budget);
472     let arg_shape = match tactic {
473         DefinitiveListTactic::Horizontal => try_opt!(arg_shape.sub_width(ret_str.len() + 1)),
474         _ => arg_shape,
475     };
476
477     let fmt = ListFormatting {
478         tactic: tactic,
479         separator: ",",
480         trailing_separator: SeparatorTactic::Never,
481         shape: arg_shape,
482         ends_with_newline: false,
483         config: context.config,
484     };
485     let list_str = try_opt!(write_list(&item_vec, &fmt));
486     let mut prefix = format!("{}|{}|", mover, list_str);
487
488     if !ret_str.is_empty() {
489         if prefix.contains('\n') {
490             prefix.push('\n');
491             prefix.push_str(&argument_offset.to_string(context.config));
492         } else {
493             prefix.push(' ');
494         }
495         prefix.push_str(&ret_str);
496     }
497
498     // 1 = space between `|...|` and body.
499     let extra_offset = extra_offset(&prefix, shape) + 1;
500     let body_shape = try_opt!(shape.sub_width(extra_offset)).add_offset(extra_offset);
501
502     if let ast::ExprKind::Block(ref block) = body.node {
503         // The body of the closure is an empty block.
504         if block.stmts.is_empty() && !block_contains_comment(block, context.codemap) {
505             return Some(format!("{} {{}}", prefix));
506         }
507
508         // Figure out if the block is necessary.
509         let needs_block = block.rules != ast::BlockCheckMode::Default ||
510                           block.stmts.len() > 1 || context.inside_macro ||
511                           block_contains_comment(block, context.codemap) ||
512                           prefix.contains('\n');
513
514         if ret_str.is_empty() && !needs_block {
515             // lock.stmts.len() == 1
516             if let Some(ref expr) = stmt_expr(&block.stmts[0]) {
517                 if let Some(rw) = rewrite_closure_expr(expr, &prefix, context, body_shape) {
518                     return Some(rw);
519                 }
520             }
521         }
522
523         if !needs_block {
524             // We need braces, but we might still prefer a one-liner.
525             let stmt = &block.stmts[0];
526             // 4 = braces and spaces.
527             if let Some(body_shape) = body_shape.sub_width(4) {
528                 // Checks if rewrite succeeded and fits on a single line.
529                 if let Some(rewrite) = and_one_line(stmt.rewrite(context, body_shape)) {
530                     return Some(format!("{} {{ {} }}", prefix, rewrite));
531                 }
532             }
533         }
534
535         // Either we require a block, or tried without and failed.
536         return rewrite_closure_block(&block, prefix, context, body_shape);
537     }
538
539     if let Some(rw) = rewrite_closure_expr(body, &prefix, context, body_shape) {
540         return Some(rw);
541     }
542
543     // The closure originally had a non-block expression, but we can't fit on
544     // one line, so we'll insert a block.
545     let block = ast::Block {
546         stmts: vec![ast::Stmt {
547                         id: ast::NodeId::new(0),
548                         node: ast::StmtKind::Expr(ptr::P(body.clone())),
549                         span: body.span,
550                     }],
551         id: ast::NodeId::new(0),
552         rules: ast::BlockCheckMode::Default,
553         span: body.span,
554     };
555     return rewrite_closure_block(&block, prefix, context, body_shape);
556
557     fn rewrite_closure_expr(expr: &ast::Expr,
558                             prefix: &str,
559                             context: &RewriteContext,
560                             shape: Shape)
561                             -> Option<String> {
562         let mut rewrite = expr.rewrite(context, shape);
563         if classify::expr_requires_semi_to_be_stmt(left_most_sub_expr(expr)) {
564             rewrite = and_one_line(rewrite);
565         }
566         rewrite.map(|rw| format!("{} {}", prefix, rw))
567     }
568
569     fn rewrite_closure_block(block: &ast::Block,
570                              prefix: String,
571                              context: &RewriteContext,
572                              shape: Shape)
573                              -> Option<String> {
574         // Start with visual indent, then fall back to block indent if the
575         // closure is large.
576         if let Some(block_str) = block.rewrite(&context, shape) {
577             let block_threshold = context.config.closure_block_indent_threshold;
578             if block_threshold < 0 || block_str.matches('\n').count() <= block_threshold as usize {
579                 if let Some(block_str) = block_str.rewrite(context, shape) {
580                     return Some(format!("{} {}", prefix, block_str));
581                 }
582             }
583         }
584
585         // The body of the closure is big enough to be block indented, that
586         // means we must re-format.
587         let block_shape = shape.block().with_max_width(context.config);
588         let block_str = try_opt!(block.rewrite(&context, block_shape));
589         Some(format!("{} {}",
590                      prefix,
591                      try_opt!(block_str.rewrite(context, block_shape))))
592     }
593 }
594
595 fn and_one_line(x: Option<String>) -> Option<String> {
596     x.and_then(|x| if x.contains('\n') { None } else { Some(x) })
597 }
598
599 fn nop_block_collapse(block_str: Option<String>, budget: usize) -> Option<String> {
600     debug!("nop_block_collapse {:?} {}", block_str, budget);
601     block_str.map(|block_str| if block_str.starts_with('{') && budget >= 2 &&
602                                  (block_str[1..].find(|c: char| !c.is_whitespace()).unwrap() ==
603                                   block_str.len() - 2) {
604                       "{}".to_owned()
605                   } else {
606                       block_str.to_owned()
607                   })
608 }
609
610 impl Rewrite for ast::Block {
611     fn rewrite(&self, context: &RewriteContext, shape: Shape) -> Option<String> {
612         // shape.width is used only for the single line case: either the empty block `{}`,
613         // or an unsafe expression `unsafe { e }`.
614
615         if self.stmts.is_empty() && !block_contains_comment(self, context.codemap) &&
616            shape.width >= 2 {
617             return Some("{}".to_owned());
618         }
619
620         // If a block contains only a single-line comment, then leave it on one line.
621         let user_str = context.snippet(self.span);
622         let user_str = user_str.trim();
623         if user_str.starts_with('{') && user_str.ends_with('}') {
624             let comment_str = user_str[1..user_str.len() - 1].trim();
625             if self.stmts.is_empty() && !comment_str.contains('\n') &&
626                !comment_str.starts_with("//") &&
627                comment_str.len() + 4 <= shape.width {
628                 return Some(format!("{{ {} }}", comment_str));
629             }
630         }
631
632         let mut visitor = FmtVisitor::from_codemap(context.parse_session, context.config);
633         visitor.block_indent = shape.indent;
634
635         let prefix = match self.rules {
636             ast::BlockCheckMode::Unsafe(..) => {
637                 let snippet = context.snippet(self.span);
638                 let open_pos = try_opt!(snippet.find_uncommented("{"));
639                 visitor.last_pos = self.span.lo + BytePos(open_pos as u32);
640
641                 // Extract comment between unsafe and block start.
642                 let trimmed = &snippet[6..open_pos].trim();
643
644                 let prefix = if !trimmed.is_empty() {
645                     // 9 = "unsafe  {".len(), 7 = "unsafe ".len()
646                     let budget = try_opt!(shape.width.checked_sub(9));
647                     format!("unsafe {} ",
648                             try_opt!(rewrite_comment(trimmed,
649                                                      true,
650                                                      Shape::legacy(budget, shape.indent + 7),
651                                                      context.config)))
652                 } else {
653                     "unsafe ".to_owned()
654                 };
655
656                 if is_simple_block(self, context.codemap) && prefix.len() < shape.width {
657                     let expr_str =
658                         self.stmts[0].rewrite(context,
659                                               Shape::legacy(shape.width - prefix.len(),
660                                                             shape.indent));
661                     let expr_str = try_opt!(expr_str);
662                     let result = format!("{}{{ {} }}", prefix, expr_str);
663                     if result.len() <= shape.width && !result.contains('\n') {
664                         return Some(result);
665                     }
666                 }
667
668                 prefix
669             }
670             ast::BlockCheckMode::Default => {
671                 visitor.last_pos = self.span.lo;
672
673                 String::new()
674             }
675         };
676
677         visitor.visit_block(self);
678         if visitor.failed && shape.indent.alignment != 0 {
679             self.rewrite(context,
680                          Shape::indented(shape.indent.block_only(), context.config))
681         } else {
682             Some(format!("{}{}", prefix, visitor.buffer))
683         }
684     }
685 }
686
687 impl Rewrite for ast::Stmt {
688     fn rewrite(&self, context: &RewriteContext, shape: Shape) -> Option<String> {
689         let result = match self.node {
690             ast::StmtKind::Local(ref local) => local.rewrite(context, shape),
691             ast::StmtKind::Expr(ref ex) |
692             ast::StmtKind::Semi(ref ex) => {
693                 let suffix = if semicolon_for_stmt(self) { ";" } else { "" };
694
695                 format_expr(ex,
696                             match self.node {
697                                 ast::StmtKind::Expr(_) => ExprType::SubExpression,
698                                 ast::StmtKind::Semi(_) => ExprType::Statement,
699                                 _ => unreachable!(),
700                             },
701                             context,
702                             try_opt!(shape.sub_width(suffix.len())))
703                         .map(|s| s + suffix)
704             }
705             ast::StmtKind::Mac(..) |
706             ast::StmtKind::Item(..) => None,
707         };
708         result.and_then(|res| recover_comment_removed(res, self.span, context, shape))
709     }
710 }
711
712 // Abstraction over control flow expressions
713 #[derive(Debug)]
714 struct ControlFlow<'a> {
715     cond: Option<&'a ast::Expr>,
716     block: &'a ast::Block,
717     else_block: Option<&'a ast::Expr>,
718     label: Option<ast::SpannedIdent>,
719     pat: Option<&'a ast::Pat>,
720     keyword: &'a str,
721     matcher: &'a str,
722     connector: &'a str,
723     allow_single_line: bool,
724     // True if this is an `if` expression in an `else if` :-( hacky
725     nested_if: bool,
726     span: Span,
727 }
728
729 impl<'a> ControlFlow<'a> {
730     fn new_if(cond: &'a ast::Expr,
731               pat: Option<&'a ast::Pat>,
732               block: &'a ast::Block,
733               else_block: Option<&'a ast::Expr>,
734               allow_single_line: bool,
735               nested_if: bool,
736               span: Span)
737               -> ControlFlow<'a> {
738         ControlFlow {
739             cond: Some(cond),
740             block: block,
741             else_block: else_block,
742             label: None,
743             pat: pat,
744             keyword: "if",
745             matcher: match pat {
746                 Some(..) => "let",
747                 None => "",
748             },
749             connector: " =",
750             allow_single_line: allow_single_line,
751             nested_if: nested_if,
752             span: span,
753         }
754     }
755
756     fn new_loop(block: &'a ast::Block,
757                 label: Option<ast::SpannedIdent>,
758                 span: Span)
759                 -> ControlFlow<'a> {
760         ControlFlow {
761             cond: None,
762             block: block,
763             else_block: None,
764             label: label,
765             pat: None,
766             keyword: "loop",
767             matcher: "",
768             connector: "",
769             allow_single_line: false,
770             nested_if: false,
771             span: span,
772         }
773     }
774
775     fn new_while(pat: Option<&'a ast::Pat>,
776                  cond: &'a ast::Expr,
777                  block: &'a ast::Block,
778                  label: Option<ast::SpannedIdent>,
779                  span: Span)
780                  -> ControlFlow<'a> {
781         ControlFlow {
782             cond: Some(cond),
783             block: block,
784             else_block: None,
785             label: label,
786             pat: pat,
787             keyword: "while",
788             matcher: match pat {
789                 Some(..) => "let",
790                 None => "",
791             },
792             connector: " =",
793             allow_single_line: false,
794             nested_if: false,
795             span: span,
796         }
797     }
798
799     fn new_for(pat: &'a ast::Pat,
800                cond: &'a ast::Expr,
801                block: &'a ast::Block,
802                label: Option<ast::SpannedIdent>,
803                span: Span)
804                -> ControlFlow<'a> {
805         ControlFlow {
806             cond: Some(cond),
807             block: block,
808             else_block: None,
809             label: label,
810             pat: Some(pat),
811             keyword: "for",
812             matcher: "",
813             connector: " in",
814             allow_single_line: false,
815             nested_if: false,
816             span: span,
817         }
818     }
819
820     fn rewrite_single_line(&self,
821                            pat_expr_str: &str,
822                            context: &RewriteContext,
823                            width: usize)
824                            -> Option<String> {
825         assert!(self.allow_single_line);
826         let else_block = try_opt!(self.else_block);
827         let fixed_cost = self.keyword.len() + "  {  } else {  }".len();
828
829         if let ast::ExprKind::Block(ref else_node) = else_block.node {
830             if !is_simple_block(self.block, context.codemap) ||
831                !is_simple_block(else_node, context.codemap) ||
832                pat_expr_str.contains('\n') {
833                 return None;
834             }
835
836             let new_width = try_opt!(width.checked_sub(pat_expr_str.len() + fixed_cost));
837             let expr = &self.block.stmts[0];
838             let if_str = try_opt!(expr.rewrite(context, Shape::legacy(new_width, Indent::empty())));
839
840             let new_width = try_opt!(new_width.checked_sub(if_str.len()));
841             let else_expr = &else_node.stmts[0];
842             let else_str = try_opt!(else_expr.rewrite(context,
843                                                       Shape::legacy(new_width, Indent::empty())));
844
845             if if_str.contains('\n') || else_str.contains('\n') {
846                 return None;
847             }
848
849             let result = format!("{} {} {{ {} }} else {{ {} }}",
850                                  self.keyword,
851                                  pat_expr_str,
852                                  if_str,
853                                  else_str);
854
855             if result.len() <= width {
856                 return Some(result);
857             }
858         }
859
860         None
861     }
862 }
863
864 impl<'a> Rewrite for ControlFlow<'a> {
865     fn rewrite(&self, context: &RewriteContext, shape: Shape) -> Option<String> {
866         debug!("ControlFlow::rewrite {:?} {:?}", self, shape);
867         let constr_shape = if self.nested_if {
868             // We are part of an if-elseif-else chain. Our constraints are tightened.
869             // 7 = "} else " .len()
870             try_opt!(shape.shrink_left(7))
871         } else {
872             shape
873         };
874
875         let label_string = rewrite_label(self.label);
876         // 1 = space after keyword.
877         let add_offset = self.keyword.len() + label_string.len() + 1;
878
879         let pat_expr_string = match self.cond {
880             Some(cond) => {
881                 let mut cond_shape = match context.config.control_style {
882                     Style::Default => try_opt!(constr_shape.shrink_left(add_offset)),
883                     Style::Rfc => constr_shape,
884                 };
885                 if context.config.control_brace_style != ControlBraceStyle::AlwaysNextLine {
886                     // 2 = " {".len()
887                     cond_shape = try_opt!(cond_shape.sub_width(2));
888                 }
889
890                 try_opt!(rewrite_pat_expr(context,
891                                           self.pat,
892                                           cond,
893                                           self.matcher,
894                                           self.connector,
895                                           cond_shape))
896             }
897             None => String::new(),
898         };
899
900         let force_newline_brace = context.config.control_style == Style::Rfc &&
901                                   pat_expr_string.contains('\n');
902
903         // Try to format if-else on single line.
904         if self.allow_single_line && context.config.single_line_if_else_max_width > 0 {
905             let trial = self.rewrite_single_line(&pat_expr_string, context, shape.width);
906
907             if trial.is_some() &&
908                trial.as_ref().unwrap().len() <= context.config.single_line_if_else_max_width {
909                 return trial;
910             }
911         }
912
913         let used_width = if pat_expr_string.contains('\n') {
914             last_line_width(&pat_expr_string)
915         } else {
916             // 2 = spaces after keyword and condition.
917             label_string.len() + self.keyword.len() + pat_expr_string.len() + 2
918         };
919
920         let block_width = shape.width.checked_sub(used_width).unwrap_or(0);
921         // This is used only for the empty block case: `{}`. So, we use 1 if we know
922         // we should avoid the single line case.
923         let block_width = if self.else_block.is_some() || self.nested_if {
924             min(1, block_width)
925         } else {
926             block_width
927         };
928
929         let block_shape = Shape {
930             width: block_width,
931             ..shape
932         };
933         let block_str = try_opt!(self.block.rewrite(context, block_shape));
934
935         let cond_span = if let Some(cond) = self.cond {
936             cond.span
937         } else {
938             mk_sp(self.block.span.lo, self.block.span.lo)
939         };
940
941         // for event in event
942         let between_kwd_cond =
943             mk_sp(context.codemap.span_after(self.span, self.keyword.trim()),
944                   self.pat
945                       .map_or(cond_span.lo, |p| if self.matcher.is_empty() {
946                 p.span.lo
947             } else {
948                 context.codemap.span_before(self.span, self.matcher.trim())
949             }));
950
951         let between_kwd_cond_comment = extract_comment(between_kwd_cond, context, shape);
952
953         let after_cond_comment =
954             extract_comment(mk_sp(cond_span.hi, self.block.span.lo), context, shape);
955
956         let alt_block_sep = String::from("\n") +
957                             &shape.indent.block_only().to_string(context.config);
958         let block_sep = if self.cond.is_none() && between_kwd_cond_comment.is_some() {
959             ""
960         } else if context.config.control_brace_style == ControlBraceStyle::AlwaysNextLine ||
961                   force_newline_brace {
962             alt_block_sep.as_str()
963         } else {
964             " "
965         };
966
967         let mut result = format!("{}{}{}{}{}{}",
968                                  label_string,
969                                  self.keyword,
970                                  between_kwd_cond_comment
971                                      .as_ref()
972                                      .map_or(if pat_expr_string.is_empty() ||
973                                                 pat_expr_string.starts_with('\n') {
974                                                  ""
975                                              } else {
976                                                  " "
977                                              },
978                                              |s| &**s),
979                                  pat_expr_string,
980                                  after_cond_comment.as_ref().map_or(block_sep, |s| &**s),
981                                  block_str);
982
983         if let Some(else_block) = self.else_block {
984             let shape = Shape::indented(shape.indent, context.config);
985             let mut last_in_chain = false;
986             let rewrite = match else_block.node {
987                 // If the else expression is another if-else expression, prevent it
988                 // from being formatted on a single line.
989                 // Note how we're passing the original shape, as the
990                 // cost of "else" should not cascade.
991                 ast::ExprKind::IfLet(ref pat, ref cond, ref if_block, ref next_else_block) => {
992                     ControlFlow::new_if(cond,
993                                         Some(pat),
994                                         if_block,
995                                         next_else_block.as_ref().map(|e| &**e),
996                                         false,
997                                         true,
998                                         mk_sp(else_block.span.lo, self.span.hi))
999                             .rewrite(context, shape)
1000                 }
1001                 ast::ExprKind::If(ref cond, ref if_block, ref next_else_block) => {
1002                     ControlFlow::new_if(cond,
1003                                         None,
1004                                         if_block,
1005                                         next_else_block.as_ref().map(|e| &**e),
1006                                         false,
1007                                         true,
1008                                         mk_sp(else_block.span.lo, self.span.hi))
1009                             .rewrite(context, shape)
1010                 }
1011                 _ => {
1012                     last_in_chain = true;
1013                     // When rewriting a block, the width is only used for single line
1014                     // blocks, passing 1 lets us avoid that.
1015                     let else_shape = Shape {
1016                         width: min(1, shape.width),
1017                         ..shape
1018                     };
1019                     else_block.rewrite(context, else_shape)
1020                 }
1021             };
1022
1023             let between_kwd_else_block =
1024                 mk_sp(self.block.span.hi,
1025                       context
1026                           .codemap
1027                           .span_before(mk_sp(self.block.span.hi, else_block.span.lo), "else"));
1028             let between_kwd_else_block_comment =
1029                 extract_comment(between_kwd_else_block, context, shape);
1030
1031             let after_else = mk_sp(context.codemap.span_after(mk_sp(self.block.span.hi,
1032                                                                     else_block.span.lo),
1033                                                               "else"),
1034                                    else_block.span.lo);
1035             let after_else_comment = extract_comment(after_else, context, shape);
1036
1037             let between_sep = match context.config.control_brace_style {
1038                 ControlBraceStyle::AlwaysNextLine |
1039                 ControlBraceStyle::ClosingNextLine => &*alt_block_sep,
1040                 ControlBraceStyle::AlwaysSameLine => " ",
1041             };
1042             let after_sep = match context.config.control_brace_style {
1043                 ControlBraceStyle::AlwaysNextLine if last_in_chain => &*alt_block_sep,
1044                 _ => " ",
1045             };
1046             try_opt!(write!(&mut result,
1047                             "{}else{}",
1048                             between_kwd_else_block_comment
1049                                 .as_ref()
1050                                 .map_or(between_sep, |s| &**s),
1051                             after_else_comment.as_ref().map_or(after_sep, |s| &**s))
1052                              .ok());
1053             result.push_str(&try_opt!(rewrite));
1054         }
1055
1056         Some(result)
1057     }
1058 }
1059
1060 fn rewrite_label(label: Option<ast::SpannedIdent>) -> String {
1061     match label {
1062         Some(ident) => format!("{}: ", ident.node),
1063         None => "".to_owned(),
1064     }
1065 }
1066
1067 fn extract_comment(span: Span, context: &RewriteContext, shape: Shape) -> Option<String> {
1068     let comment_str = context.snippet(span);
1069     if contains_comment(&comment_str) {
1070         let comment = try_opt!(rewrite_comment(comment_str.trim(), false, shape, context.config));
1071         Some(format!("\n{indent}{}\n{indent}",
1072                      comment,
1073                      indent = shape.indent.to_string(context.config)))
1074     } else {
1075         None
1076     }
1077 }
1078
1079 fn block_contains_comment(block: &ast::Block, codemap: &CodeMap) -> bool {
1080     let snippet = codemap.span_to_snippet(block.span).unwrap();
1081     contains_comment(&snippet)
1082 }
1083
1084 // Checks that a block contains no statements, an expression and no comments.
1085 // FIXME: incorrectly returns false when comment is contained completely within
1086 // the expression.
1087 pub fn is_simple_block(block: &ast::Block, codemap: &CodeMap) -> bool {
1088     (block.stmts.len() == 1 && stmt_is_expr(&block.stmts[0]) &&
1089      !block_contains_comment(block, codemap))
1090 }
1091
1092 /// Checks whether a block contains at most one statement or expression, and no comments.
1093 pub fn is_simple_block_stmt(block: &ast::Block, codemap: &CodeMap) -> bool {
1094     block.stmts.len() <= 1 && !block_contains_comment(block, codemap)
1095 }
1096
1097 /// Checks whether a block contains no statements, expressions, or comments.
1098 pub fn is_empty_block(block: &ast::Block, codemap: &CodeMap) -> bool {
1099     block.stmts.is_empty() && !block_contains_comment(block, codemap)
1100 }
1101
1102 pub fn stmt_is_expr(stmt: &ast::Stmt) -> bool {
1103     match stmt.node {
1104         ast::StmtKind::Expr(..) => true,
1105         _ => false,
1106     }
1107 }
1108
1109 fn is_unsafe_block(block: &ast::Block) -> bool {
1110     if let ast::BlockCheckMode::Unsafe(..) = block.rules {
1111         true
1112     } else {
1113         false
1114     }
1115 }
1116
1117 // inter-match-arm-comment-rules:
1118 //  - all comments following a match arm before the start of the next arm
1119 //    are about the second arm
1120 fn rewrite_match_arm_comment(context: &RewriteContext,
1121                              missed_str: &str,
1122                              shape: Shape,
1123                              arm_indent_str: &str)
1124                              -> Option<String> {
1125     // The leading "," is not part of the arm-comment
1126     let missed_str = match missed_str.find_uncommented(",") {
1127         Some(n) => &missed_str[n + 1..],
1128         None => &missed_str[..],
1129     };
1130
1131     let mut result = String::new();
1132     // any text not preceeded by a newline is pushed unmodified to the block
1133     let first_brk = missed_str.find(|c: char| c == '\n').unwrap_or(0);
1134     result.push_str(&missed_str[..first_brk]);
1135     let missed_str = &missed_str[first_brk..]; // If missed_str had one newline, it starts with it
1136
1137     let first = missed_str
1138         .find(|c: char| !c.is_whitespace())
1139         .unwrap_or(missed_str.len());
1140     if missed_str[..first].chars().filter(|c| c == &'\n').count() >= 2 {
1141         // Excessive vertical whitespace before comment should be preserved
1142         // FIXME handle vertical whitespace better
1143         result.push('\n');
1144     }
1145     let missed_str = missed_str[first..].trim();
1146     if !missed_str.is_empty() {
1147         let comment = try_opt!(rewrite_comment(&missed_str, false, shape, context.config));
1148         result.push('\n');
1149         result.push_str(arm_indent_str);
1150         result.push_str(&comment);
1151     }
1152
1153     Some(result)
1154 }
1155
1156 fn rewrite_match(context: &RewriteContext,
1157                  cond: &ast::Expr,
1158                  arms: &[ast::Arm],
1159                  shape: Shape,
1160                  span: Span)
1161                  -> Option<String> {
1162     if arms.is_empty() {
1163         return None;
1164     }
1165
1166     // `match `cond` {`
1167     let cond_shape = try_opt!(shape.shrink_left(6));
1168     let cond_shape = try_opt!(cond_shape.sub_width(2));
1169     let cond_str = try_opt!(cond.rewrite(context, cond_shape));
1170     let alt_block_sep = String::from("\n") + &shape.indent.block_only().to_string(context.config);
1171     let block_sep = match context.config.control_brace_style {
1172         ControlBraceStyle::AlwaysSameLine => " ",
1173         _ => alt_block_sep.as_str(),
1174     };
1175     let mut result = format!("match {}{}{{", cond_str, block_sep);
1176
1177     let arm_shape = if context.config.indent_match_arms {
1178         shape.block_indent(context.config.tab_spaces)
1179     } else {
1180         shape.block_indent(0)
1181     };
1182
1183     let arm_indent_str = arm_shape.indent.to_string(context.config);
1184
1185     let open_brace_pos = context
1186         .codemap
1187         .span_after(mk_sp(cond.span.hi, arm_start_pos(&arms[0])), "{");
1188
1189     for (i, arm) in arms.iter().enumerate() {
1190         // Make sure we get the stuff between arms.
1191         let missed_str = if i == 0 {
1192             context.snippet(mk_sp(open_brace_pos, arm_start_pos(arm)))
1193         } else {
1194             context.snippet(mk_sp(arm_end_pos(&arms[i - 1]), arm_start_pos(arm)))
1195         };
1196         let comment =
1197             try_opt!(rewrite_match_arm_comment(context, &missed_str, arm_shape, &arm_indent_str));
1198         result.push_str(&comment);
1199         result.push('\n');
1200         result.push_str(&arm_indent_str);
1201
1202         let arm_str = arm.rewrite(&context, arm_shape.with_max_width(context.config));
1203         if let Some(ref arm_str) = arm_str {
1204             result.push_str(arm_str);
1205         } else {
1206             // We couldn't format the arm, just reproduce the source.
1207             let snippet = context.snippet(mk_sp(arm_start_pos(arm), arm_end_pos(arm)));
1208             result.push_str(&snippet);
1209             result.push_str(arm_comma(context.config, &arm.body));
1210         }
1211     }
1212     // BytePos(1) = closing match brace.
1213     let last_span = mk_sp(arm_end_pos(&arms[arms.len() - 1]), span.hi - BytePos(1));
1214     let last_comment = context.snippet(last_span);
1215     let comment =
1216         try_opt!(rewrite_match_arm_comment(context, &last_comment, arm_shape, &arm_indent_str));
1217     result.push_str(&comment);
1218     result.push('\n');
1219     result.push_str(&shape.indent.to_string(context.config));
1220     result.push('}');
1221     Some(result)
1222 }
1223
1224 fn arm_start_pos(arm: &ast::Arm) -> BytePos {
1225     let &ast::Arm {
1226         ref attrs,
1227         ref pats,
1228         ..
1229     } = arm;
1230     if !attrs.is_empty() {
1231         return attrs[0].span.lo;
1232     }
1233
1234     pats[0].span.lo
1235 }
1236
1237 fn arm_end_pos(arm: &ast::Arm) -> BytePos {
1238     arm.body.span.hi
1239 }
1240
1241 fn arm_comma(config: &Config, body: &ast::Expr) -> &'static str {
1242     if config.match_block_trailing_comma {
1243         ","
1244     } else if let ast::ExprKind::Block(ref block) = body.node {
1245         if let ast::BlockCheckMode::Default = block.rules {
1246             ""
1247         } else {
1248             ","
1249         }
1250     } else {
1251         ","
1252     }
1253 }
1254
1255 // Match arms.
1256 impl Rewrite for ast::Arm {
1257     fn rewrite(&self, context: &RewriteContext, shape: Shape) -> Option<String> {
1258         debug!("Arm::rewrite {:?} {:?}", self, shape);
1259         let &ast::Arm {
1260             ref attrs,
1261             ref pats,
1262             ref guard,
1263             ref body,
1264         } = self;
1265
1266         // FIXME this is all a bit grotty, would be nice to abstract out the
1267         // treatment of attributes.
1268         let attr_str = if !attrs.is_empty() {
1269             // We only use this visitor for the attributes, should we use it for
1270             // more?
1271             let mut attr_visitor = FmtVisitor::from_codemap(context.parse_session, context.config);
1272             attr_visitor.block_indent = shape.indent.block_only();
1273             attr_visitor.last_pos = attrs[0].span.lo;
1274             if attr_visitor.visit_attrs(attrs) {
1275                 // Attributes included a skip instruction.
1276                 return None;
1277             }
1278             attr_visitor.format_missing(pats[0].span.lo);
1279             attr_visitor.buffer.to_string()
1280         } else {
1281             String::new()
1282         };
1283
1284         // Patterns
1285         // 5 = ` => {`
1286         let pat_shape = try_opt!(shape.sub_width(5));
1287
1288         let pat_strs = try_opt!(pats.iter()
1289                                     .map(|p| p.rewrite(context, pat_shape))
1290                                     .collect::<Option<Vec<_>>>());
1291
1292         let all_simple = pat_strs.iter().all(|p| pat_is_simple(p));
1293         let items: Vec<_> = pat_strs.into_iter().map(ListItem::from_str).collect();
1294         let fmt = ListFormatting {
1295             tactic: if all_simple {
1296                 DefinitiveListTactic::Mixed
1297             } else {
1298                 DefinitiveListTactic::Vertical
1299             },
1300             separator: " |",
1301             trailing_separator: SeparatorTactic::Never,
1302             shape: pat_shape,
1303             ends_with_newline: false,
1304             config: context.config,
1305         };
1306         let pats_str = try_opt!(write_list(items, &fmt));
1307
1308         let guard_shape = if pats_str.contains('\n') {
1309             shape.with_max_width(context.config)
1310         } else {
1311             shape
1312         };
1313
1314         let guard_str = try_opt!(rewrite_guard(context,
1315                                                guard,
1316                                                guard_shape,
1317                                                trimmed_last_line_width(&pats_str)));
1318
1319         let pats_str = format!("{}{}", pats_str, guard_str);
1320
1321         let body = match body.node {
1322             ast::ExprKind::Block(ref block) if !is_unsafe_block(block) &&
1323                                                is_simple_block(block, context.codemap) &&
1324                                                context.config.wrap_match_arms => {
1325                 if let ast::StmtKind::Expr(ref expr) = block.stmts[0].node {
1326                     expr
1327                 } else {
1328                     &**body
1329                 }
1330             }
1331             _ => &**body,
1332         };
1333
1334         let comma = arm_comma(&context.config, body);
1335         let alt_block_sep = String::from("\n") +
1336                             &shape.indent.block_only().to_string(context.config);
1337
1338         let pat_width = extra_offset(&pats_str, shape);
1339         // Let's try and get the arm body on the same line as the condition.
1340         // 4 = ` => `.len()
1341         if shape.width > pat_width + comma.len() + 4 {
1342             let arm_shape = shape
1343                 .offset_left(pat_width + 4)
1344                 .unwrap()
1345                 .sub_width(comma.len())
1346                 .unwrap();
1347             let rewrite = nop_block_collapse(body.rewrite(context, arm_shape), arm_shape.width);
1348             let is_block = if let ast::ExprKind::Block(..) = body.node {
1349                 true
1350             } else {
1351                 false
1352             };
1353
1354             match rewrite {
1355                 Some(ref body_str) if (!body_str.contains('\n') &&
1356                                        body_str.len() <= arm_shape.width) ||
1357                                       !context.config.wrap_match_arms ||
1358                                       is_block => {
1359                     let block_sep = match context.config.control_brace_style {
1360                         ControlBraceStyle::AlwaysNextLine if is_block => alt_block_sep.as_str(),
1361                         _ => " ",
1362                     };
1363
1364                     return Some(format!("{}{} =>{}{}{}",
1365                                         attr_str.trim_left(),
1366                                         pats_str,
1367                                         block_sep,
1368                                         body_str,
1369                                         comma));
1370                 }
1371                 _ => {}
1372             }
1373         }
1374
1375         // FIXME: we're doing a second rewrite of the expr; This may not be
1376         // necessary.
1377         let body_shape = try_opt!(shape.sub_width(context.config.tab_spaces))
1378             .block_indent(context.config.tab_spaces);
1379         let next_line_body = try_opt!(nop_block_collapse(body.rewrite(context, body_shape),
1380                                                          body_shape.width));
1381         let indent_str = shape
1382             .indent
1383             .block_indent(context.config)
1384             .to_string(context.config);
1385         let (body_prefix, body_suffix) = if context.config.wrap_match_arms {
1386             if context.config.match_block_trailing_comma {
1387                 ("{", "},")
1388             } else {
1389                 ("{", "}")
1390             }
1391         } else {
1392             ("", ",")
1393         };
1394
1395
1396         let block_sep = match context.config.control_brace_style {
1397             ControlBraceStyle::AlwaysNextLine => alt_block_sep + body_prefix + "\n",
1398             _ if body_prefix.is_empty() => "\n".to_owned(),
1399             _ => " ".to_owned() + body_prefix + "\n",
1400         };
1401
1402         if context.config.wrap_match_arms {
1403             Some(format!("{}{} =>{}{}{}\n{}{}",
1404                          attr_str.trim_left(),
1405                          pats_str,
1406                          block_sep,
1407                          indent_str,
1408                          next_line_body,
1409                          shape.indent.to_string(context.config),
1410                          body_suffix))
1411         } else {
1412             Some(format!("{}{} =>{}{}{}{}",
1413                          attr_str.trim_left(),
1414                          pats_str,
1415                          block_sep,
1416                          indent_str,
1417                          next_line_body,
1418                          body_suffix))
1419         }
1420     }
1421 }
1422
1423 // A pattern is simple if it is very short or it is short-ish and just a path.
1424 // E.g. `Foo::Bar` is simple, but `Foo(..)` is not.
1425 fn pat_is_simple(pat_str: &str) -> bool {
1426     pat_str.len() <= 16 ||
1427     (pat_str.len() <= 24 && pat_str.chars().all(|c| c.is_alphabetic() || c == ':'))
1428 }
1429
1430 // The `if ...` guard on a match arm.
1431 fn rewrite_guard(context: &RewriteContext,
1432                  guard: &Option<ptr::P<ast::Expr>>,
1433                  shape: Shape,
1434                  // The amount of space used up on this line for the pattern in
1435                  // the arm (excludes offset).
1436                  pattern_width: usize)
1437                  -> Option<String> {
1438     if let Some(ref guard) = *guard {
1439         // First try to fit the guard string on the same line as the pattern.
1440         // 4 = ` if `, 5 = ` => {`
1441         let overhead = pattern_width + 4 + 5;
1442         if overhead < shape.width {
1443             let cond_shape = shape
1444                 .shrink_left(pattern_width + 4)
1445                 .unwrap()
1446                 .sub_width(5)
1447                 .unwrap();
1448             let cond_str = guard.rewrite(context, cond_shape);
1449             if let Some(cond_str) = cond_str {
1450                 return Some(format!(" if {}", cond_str));
1451             }
1452         }
1453
1454         // Not enough space to put the guard after the pattern, try a newline.
1455         let overhead = shape.indent.block_indent(context.config).width() + 4 + 5;
1456         if overhead < shape.width {
1457             let cond_str = guard.rewrite(context,
1458                                          Shape::legacy(shape.width - overhead,
1459                                                        // 3 == `if `
1460                                                        shape.indent.block_indent(context.config) +
1461                                                        3));
1462             if let Some(cond_str) = cond_str {
1463                 return Some(format!("\n{}if {}",
1464                                     shape
1465                                         .indent
1466                                         .block_indent(context.config)
1467                                         .to_string(context.config),
1468                                     cond_str));
1469             }
1470         }
1471
1472         None
1473     } else {
1474         Some(String::new())
1475     }
1476 }
1477
1478 fn rewrite_pat_expr(context: &RewriteContext,
1479                     pat: Option<&ast::Pat>,
1480                     expr: &ast::Expr,
1481                     matcher: &str,
1482                     // Connecting piece between pattern and expression,
1483                     // *without* trailing space.
1484                     connector: &str,
1485                     shape: Shape)
1486                     -> Option<String> {
1487     debug!("rewrite_pat_expr {:?} {:?} {:?}", shape, pat, expr);
1488     let mut pat_string = String::new();
1489     let mut result = match pat {
1490         Some(pat) => {
1491             let matcher = if matcher.is_empty() {
1492                 matcher.to_owned()
1493             } else {
1494                 format!("{} ", matcher)
1495             };
1496             let pat_shape = try_opt!(try_opt!(shape.shrink_left(matcher.len()))
1497                                          .sub_width(connector.len()));
1498             pat_string = try_opt!(pat.rewrite(context, pat_shape));
1499             format!("{}{}{}", matcher, pat_string, connector)
1500         }
1501         None => String::new(),
1502     };
1503
1504     // Consider only the last line of the pat string.
1505     let extra_offset = extra_offset(&result, shape);
1506
1507     // The expression may (partially) fit on the current line.
1508     if shape.width > extra_offset + 1 {
1509         let spacer = if pat.is_some() { " " } else { "" };
1510
1511         let expr_shape = try_opt!(shape.offset_left(extra_offset + spacer.len()));
1512         let expr_rewrite = expr.rewrite(context, expr_shape);
1513
1514         if let Some(expr_string) = expr_rewrite {
1515             if pat.is_none() || pat_is_simple(&pat_string) || !expr_string.contains('\n') {
1516                 result.push_str(spacer);
1517                 result.push_str(&expr_string);
1518                 return Some(result);
1519             }
1520         }
1521     }
1522
1523     let nested_indent = shape.indent.block_only().block_indent(context.config);
1524
1525     // The expression won't fit on the current line, jump to next.
1526     result.push('\n');
1527     result.push_str(&nested_indent.to_string(context.config));
1528
1529     let expr_rewrite = expr.rewrite(&context, Shape::indented(nested_indent, context.config));
1530     result.push_str(&try_opt!(expr_rewrite));
1531
1532     Some(result)
1533 }
1534
1535 fn rewrite_string_lit(context: &RewriteContext, span: Span, shape: Shape) -> Option<String> {
1536     let string_lit = context.snippet(span);
1537
1538     if !context.config.format_strings && !context.config.force_format_strings {
1539         return Some(string_lit);
1540     }
1541
1542     if !context.config.force_format_strings &&
1543        !string_requires_rewrite(context, span, &string_lit, shape) {
1544         return Some(string_lit);
1545     }
1546
1547     let fmt = StringFormat {
1548         opener: "\"",
1549         closer: "\"",
1550         line_start: " ",
1551         line_end: "\\",
1552         shape: shape,
1553         trim_end: false,
1554         config: context.config,
1555     };
1556
1557     // Remove the quote characters.
1558     let str_lit = &string_lit[1..string_lit.len() - 1];
1559
1560     rewrite_string(str_lit, &fmt)
1561 }
1562
1563 fn string_requires_rewrite(context: &RewriteContext,
1564                            span: Span,
1565                            string: &str,
1566                            shape: Shape)
1567                            -> bool {
1568     if context.codemap.lookup_char_pos(span.lo).col.0 != shape.indent.width() {
1569         return true;
1570     }
1571
1572     for (i, line) in string.lines().enumerate() {
1573         if i == 0 {
1574             if line.len() > shape.width {
1575                 return true;
1576             }
1577         } else {
1578             if line.len() > shape.width + shape.indent.width() {
1579                 return true;
1580             }
1581         }
1582     }
1583
1584     false
1585 }
1586
1587 pub fn rewrite_call<R>(context: &RewriteContext,
1588                        callee: &R,
1589                        args: &[ptr::P<ast::Expr>],
1590                        span: Span,
1591                        shape: Shape)
1592                        -> Option<String>
1593     where R: Rewrite
1594 {
1595     let closure =
1596         |callee_max_width| rewrite_call_inner(context, callee, callee_max_width, args, span, shape);
1597
1598     // 2 is for parens
1599     let max_width = try_opt!(shape.width.checked_sub(2));
1600     binary_search(1, max_width, closure)
1601 }
1602
1603 fn rewrite_call_inner<R>(context: &RewriteContext,
1604                          callee: &R,
1605                          max_callee_width: usize,
1606                          args: &[ptr::P<ast::Expr>],
1607                          span: Span,
1608                          shape: Shape)
1609                          -> Result<String, Ordering>
1610     where R: Rewrite
1611 {
1612     // FIXME using byte lens instead of char lens (and probably all over the
1613     // place too)
1614     let callee_shape = Shape {
1615         width: max_callee_width,
1616         ..shape
1617     };
1618     let callee_str = callee
1619         .rewrite(context, callee_shape)
1620         .ok_or(Ordering::Greater)?;
1621
1622     // 4 = `(  )`, 2 = `()`
1623     let paren_overhead = if context.config.spaces_within_parens {
1624         4
1625     } else {
1626         2
1627     };
1628     let used_width = extra_offset(&callee_str, shape);
1629     let one_line_width = shape
1630         .width
1631         .checked_sub(used_width + paren_overhead)
1632         .ok_or(Ordering::Greater)?;
1633
1634     let nested_shape = match context.config.fn_call_style {
1635             IndentStyle::Block => shape.block().block_left(context.config.tab_spaces),
1636             // 1 = (
1637             IndentStyle::Visual => {
1638                 shape
1639                     .visual_indent(used_width + 1)
1640                     .sub_width(used_width + paren_overhead)
1641             }
1642         }
1643         .ok_or(Ordering::Greater)?;
1644
1645     let span_lo = context.codemap.span_after(span, "(");
1646     let span = mk_sp(span_lo, span.hi);
1647
1648     let list_str = rewrite_call_args(context, args, span, nested_shape, one_line_width)
1649         .ok_or(Ordering::Less)?;
1650
1651     let result = if context.config.fn_call_style == IndentStyle::Visual ||
1652                     (!list_str.contains('\n') && list_str.chars().last().unwrap_or(' ') != ',') {
1653         if context.config.spaces_within_parens && list_str.len() > 0 {
1654             format!("{}( {} )", callee_str, list_str)
1655         } else {
1656             format!("{}({})", callee_str, list_str)
1657         }
1658     } else {
1659         format!("{}(\n{}{}\n{})",
1660                 callee_str,
1661                 nested_shape.indent.to_string(context.config),
1662                 list_str,
1663                 shape.block().indent.to_string(context.config))
1664     };
1665
1666     Ok(result)
1667 }
1668
1669 fn rewrite_call_args(context: &RewriteContext,
1670                      args: &[ptr::P<ast::Expr>],
1671                      span: Span,
1672                      shape: Shape,
1673                      one_line_width: usize)
1674                      -> Option<String> {
1675     let arg_count = args.len();
1676
1677     let items = itemize_list(context.codemap,
1678                              args.iter(),
1679                              ")",
1680                              |item| item.span.lo,
1681                              |item| item.span.hi,
1682                              |item| item.rewrite(context, shape),
1683                              span.lo,
1684                              span.hi);
1685     let mut item_vec: Vec<_> = items.collect();
1686
1687     // Try letting the last argument overflow to the next line with block
1688     // indentation. If its first line fits on one line with the other arguments,
1689     // we format the function arguments horizontally.
1690     let overflow_last = match args.last().map(|x| &x.node) {
1691         Some(&ast::ExprKind::Closure(..)) |
1692         Some(&ast::ExprKind::Block(..)) |
1693         Some(&ast::ExprKind::Match(..)) if arg_count > 1 => true,
1694         _ => false,
1695     };
1696
1697     let mut orig_last = None;
1698     let mut placeholder = None;
1699
1700     // Replace the last item with its first line to see if it fits with
1701     // first arguments.
1702     if overflow_last {
1703         let nested_shape = Shape {
1704             indent: shape.indent.block_only(),
1705             ..shape
1706         };
1707         let rewrite = args.last().unwrap().rewrite(context, nested_shape);
1708
1709         if let Some(rewrite) = rewrite {
1710             let rewrite_first_line = Some(rewrite[..first_line_width(&rewrite)].to_owned());
1711             placeholder = Some(rewrite);
1712
1713             swap(&mut item_vec[arg_count - 1].item, &mut orig_last);
1714             item_vec[arg_count - 1].item = rewrite_first_line;
1715         }
1716     }
1717
1718     let one_line_shape = Shape {
1719         width: one_line_width,
1720         ..shape
1721     };
1722
1723     let tactic =
1724         definitive_tactic(&item_vec,
1725                           ListTactic::LimitedHorizontalVertical(context.config.fn_call_width),
1726                           one_line_width);
1727
1728     // Replace the stub with the full overflowing last argument if the rewrite
1729     // succeeded and its first line fits with the other arguments.
1730     match (overflow_last, tactic, placeholder) {
1731         (true, DefinitiveListTactic::Horizontal, placeholder @ Some(..)) => {
1732             item_vec[arg_count - 1].item = placeholder;
1733         }
1734         (true, _, _) => {
1735             item_vec[arg_count - 1].item = orig_last;
1736         }
1737         (false, _, _) => {}
1738     }
1739
1740     let mut fmt = ListFormatting {
1741         tactic: tactic,
1742         separator: ",",
1743         trailing_separator: if context.inside_macro ||
1744                                context.config.fn_call_style == IndentStyle::Visual ||
1745                                arg_count <= 1 {
1746             SeparatorTactic::Never
1747         } else {
1748             context.config.trailing_comma
1749         },
1750         shape: one_line_shape,
1751         ends_with_newline: false,
1752         config: context.config,
1753     };
1754
1755     match write_list(&item_vec, &fmt) {
1756         // If arguments do not fit in a single line and do not contain newline,
1757         // try to put it on the next line. Try this only when we are in block mode
1758         // and not rewriting macro.
1759         Some(ref s) if context.config.fn_call_style == IndentStyle::Block &&
1760                        !context.inside_macro &&
1761                        (!s.contains('\n') &&
1762                         (s.len() > one_line_width || s.len() > context.config.fn_call_width)) => {
1763             fmt.trailing_separator = SeparatorTactic::Vertical;
1764             write_list(&item_vec, &fmt)
1765         }
1766         rewrite @ _ => rewrite,
1767     }
1768 }
1769
1770 fn rewrite_paren(context: &RewriteContext, subexpr: &ast::Expr, shape: Shape) -> Option<String> {
1771     debug!("rewrite_paren, shape: {:?}", shape);
1772     // 1 is for opening paren, 2 is for opening+closing, we want to keep the closing
1773     // paren on the same line as the subexpr.
1774     let sub_shape = try_opt!(shape.sub_width(2)).visual_indent(1);
1775     let subexpr_str = subexpr.rewrite(context, sub_shape);
1776     debug!("rewrite_paren, subexpr_str: `{:?}`", subexpr_str);
1777
1778     subexpr_str.map(|s| if context.config.spaces_within_parens && s.len() > 0 {
1779                         format!("( {} )", s)
1780                     } else {
1781                         format!("({})", s)
1782                     })
1783 }
1784
1785 fn rewrite_index(expr: &ast::Expr,
1786                  index: &ast::Expr,
1787                  context: &RewriteContext,
1788                  shape: Shape)
1789                  -> Option<String> {
1790     let expr_str = try_opt!(expr.rewrite(context, shape));
1791
1792     let (lbr, rbr) = if context.config.spaces_within_square_brackets {
1793         ("[ ", " ]")
1794     } else {
1795         ("[", "]")
1796     };
1797
1798     let budget = shape
1799         .width
1800         .checked_sub(expr_str.len() + lbr.len() + rbr.len())
1801         .unwrap_or(0);
1802     let index_str = index.rewrite(context, Shape::legacy(budget, shape.indent));
1803     if let Some(index_str) = index_str {
1804         return Some(format!("{}{}{}{}", expr_str, lbr, index_str, rbr));
1805     }
1806
1807     let indent = shape.indent.block_indent(&context.config);
1808     let indent = indent.to_string(&context.config);
1809     // FIXME this is not right, since we don't take into account that shape.width
1810     // might be reduced from max_width by something on the right.
1811     let budget = try_opt!(context
1812                               .config
1813                               .max_width
1814                               .checked_sub(indent.len() + lbr.len() + rbr.len()));
1815     let index_str = try_opt!(index.rewrite(context, Shape::legacy(budget, shape.indent)));
1816     Some(format!("{}\n{}{}{}{}", expr_str, indent, lbr, index_str, rbr))
1817 }
1818
1819 fn rewrite_struct_lit<'a>(context: &RewriteContext,
1820                           path: &ast::Path,
1821                           fields: &'a [ast::Field],
1822                           base: Option<&'a ast::Expr>,
1823                           span: Span,
1824                           shape: Shape)
1825                           -> Option<String> {
1826     debug!("rewrite_struct_lit: shape {:?}", shape);
1827
1828     enum StructLitField<'a> {
1829         Regular(&'a ast::Field),
1830         Base(&'a ast::Expr),
1831     }
1832
1833     // 2 = " {".len()
1834     let path_shape = try_opt!(shape.sub_width(2));
1835     let path_str = try_opt!(rewrite_path(context, PathContext::Expr, None, path, path_shape));
1836
1837     if fields.len() == 0 && base.is_none() {
1838         return Some(format!("{} {{}}", path_str));
1839     }
1840
1841     let field_iter = fields
1842         .into_iter()
1843         .map(StructLitField::Regular)
1844         .chain(base.into_iter().map(StructLitField::Base));
1845
1846     // Foo { a: Foo } - indent is +3, width is -5.
1847     let (h_shape, v_shape) = try_opt!(struct_lit_shape(shape, context, path_str.len() + 3, 2));
1848
1849     let span_lo = |item: &StructLitField| match *item {
1850         StructLitField::Regular(field) => field.span.lo,
1851         StructLitField::Base(expr) => {
1852             let last_field_hi = fields.last().map_or(span.lo, |field| field.span.hi);
1853             let snippet = context.snippet(mk_sp(last_field_hi, expr.span.lo));
1854             let pos = snippet.find_uncommented("..").unwrap();
1855             last_field_hi + BytePos(pos as u32)
1856         }
1857     };
1858     let span_hi = |item: &StructLitField| match *item {
1859         StructLitField::Regular(field) => field.span.hi,
1860         StructLitField::Base(expr) => expr.span.hi,
1861     };
1862     let rewrite = |item: &StructLitField| match *item {
1863         StructLitField::Regular(field) => {
1864             // The 1 taken from the v_budget is for the comma.
1865             rewrite_field(context, field, try_opt!(v_shape.sub_width(1)))
1866         }
1867         StructLitField::Base(expr) => {
1868             // 2 = ..
1869             expr.rewrite(context, try_opt!(v_shape.shrink_left(2)))
1870                 .map(|s| format!("..{}", s))
1871         }
1872     };
1873
1874     let items = itemize_list(context.codemap,
1875                              field_iter,
1876                              "}",
1877                              span_lo,
1878                              span_hi,
1879                              rewrite,
1880                              context.codemap.span_after(span, "{"),
1881                              span.hi);
1882     let item_vec = items.collect::<Vec<_>>();
1883
1884     let tactic = struct_lit_tactic(h_shape, context, &item_vec);
1885     let nested_shape = shape_for_tactic(tactic, h_shape, v_shape);
1886     let fmt = struct_lit_formatting(nested_shape, tactic, context, base.is_some());
1887
1888     let fields_str = try_opt!(write_list(&item_vec, &fmt));
1889     let fields_str = if context.config.struct_lit_style == IndentStyle::Block &&
1890                         (fields_str.contains('\n') ||
1891                          context.config.struct_lit_multiline_style == MultilineStyle::ForceMulti ||
1892                          fields_str.len() > h_shape.map(|s| s.width).unwrap_or(0)) {
1893         format!("\n{}{}\n{}",
1894                 v_shape.indent.to_string(context.config),
1895                 fields_str,
1896                 shape.indent.to_string(context.config))
1897     } else {
1898         // One liner or visual indent.
1899         format!(" {} ", fields_str)
1900     };
1901
1902     Some(format!("{} {{{}}}", path_str, fields_str))
1903
1904     // FIXME if context.config.struct_lit_style == Visual, but we run out
1905     // of space, we should fall back to BlockIndent.
1906 }
1907
1908 pub fn type_annotation_separator(config: &Config) -> &str {
1909     colon_spaces(config.space_before_type_annotation,
1910                  config.space_after_type_annotation_colon)
1911 }
1912
1913 fn rewrite_field(context: &RewriteContext, field: &ast::Field, shape: Shape) -> Option<String> {
1914     let name = &field.ident.node.to_string();
1915     if field.is_shorthand {
1916         Some(name.to_string())
1917     } else {
1918         let separator = type_annotation_separator(context.config);
1919         let overhead = name.len() + separator.len();
1920         let mut expr_shape = try_opt!(shape.sub_width(overhead));
1921         expr_shape.offset += overhead;
1922         let expr = field.expr.rewrite(context, expr_shape);
1923
1924         let mut attrs_str = try_opt!((*field.attrs).rewrite(context, shape));
1925         if !attrs_str.is_empty() {
1926             attrs_str.push_str(&format!("\n{}", shape.indent.to_string(context.config)));
1927         };
1928
1929         match expr {
1930             Some(e) => Some(format!("{}{}{}{}", attrs_str, name, separator, e)),
1931             None => {
1932                 let expr_offset = shape.indent.block_indent(context.config);
1933                 let expr = field
1934                     .expr
1935                     .rewrite(context, Shape::indented(expr_offset, context.config));
1936                 expr.map(|s| {
1937                              format!("{}{}:\n{}{}",
1938                                      attrs_str,
1939                                      name,
1940                                      expr_offset.to_string(&context.config),
1941                                      s)
1942                          })
1943             }
1944         }
1945     }
1946 }
1947
1948 pub fn rewrite_tuple<'a, I>(context: &RewriteContext,
1949                             mut items: I,
1950                             span: Span,
1951                             shape: Shape)
1952                             -> Option<String>
1953     where I: ExactSizeIterator,
1954           <I as Iterator>::Item: Deref,
1955           <I::Item as Deref>::Target: Rewrite + Spanned + 'a
1956 {
1957     debug!("rewrite_tuple {:?}", shape);
1958     // In case of length 1, need a trailing comma
1959     if items.len() == 1 {
1960         // 3 = "(" + ",)"
1961         let nested_shape = try_opt!(shape.sub_width(3)).visual_indent(1);
1962         return items
1963             .next()
1964             .unwrap()
1965             .rewrite(context, nested_shape)
1966             .map(|s| if context.config.spaces_within_parens {
1967                      format!("( {}, )", s)
1968                  } else {
1969                      format!("({},)", s)
1970                  });
1971     }
1972
1973     let list_lo = context.codemap.span_after(span, "(");
1974     let nested_shape = try_opt!(shape.sub_width(2)).visual_indent(1);
1975     let items = itemize_list(context.codemap,
1976                              items,
1977                              ")",
1978                              |item| item.span().lo,
1979                              |item| item.span().hi,
1980                              |item| item.rewrite(context, nested_shape),
1981                              list_lo,
1982                              span.hi - BytePos(1));
1983     let list_str = try_opt!(format_item_list(items, nested_shape, context.config));
1984
1985     if context.config.spaces_within_parens && list_str.len() > 0 {
1986         Some(format!("( {} )", list_str))
1987     } else {
1988         Some(format!("({})", list_str))
1989     }
1990 }
1991
1992 pub fn rewrite_unary_prefix<R: Rewrite>(context: &RewriteContext,
1993                                         prefix: &str,
1994                                         rewrite: &R,
1995                                         shape: Shape)
1996                                         -> Option<String> {
1997     rewrite
1998         .rewrite(context, try_opt!(shape.offset_left(prefix.len())))
1999         .map(|r| format!("{}{}", prefix, r))
2000 }
2001
2002 // FIXME: this is probably not correct for multi-line Rewrites. we should
2003 // subtract suffix.len() from the last line budget, not the first!
2004 pub fn rewrite_unary_suffix<R: Rewrite>(context: &RewriteContext,
2005                                         suffix: &str,
2006                                         rewrite: &R,
2007                                         shape: Shape)
2008                                         -> Option<String> {
2009     rewrite
2010         .rewrite(context, try_opt!(shape.sub_width(suffix.len())))
2011         .map(|mut r| {
2012                  r.push_str(suffix);
2013                  r
2014              })
2015 }
2016
2017 fn rewrite_unary_op(context: &RewriteContext,
2018                     op: &ast::UnOp,
2019                     expr: &ast::Expr,
2020                     shape: Shape)
2021                     -> Option<String> {
2022     // For some reason, an UnOp is not spanned like BinOp!
2023     let operator_str = match *op {
2024         ast::UnOp::Deref => "*",
2025         ast::UnOp::Not => "!",
2026         ast::UnOp::Neg => "-",
2027     };
2028     rewrite_unary_prefix(context, operator_str, expr, shape)
2029 }
2030
2031 fn rewrite_assignment(context: &RewriteContext,
2032                       lhs: &ast::Expr,
2033                       rhs: &ast::Expr,
2034                       op: Option<&ast::BinOp>,
2035                       shape: Shape)
2036                       -> Option<String> {
2037     let operator_str = match op {
2038         Some(op) => context.snippet(op.span),
2039         None => "=".to_owned(),
2040     };
2041
2042     // 1 = space between lhs and operator.
2043     let lhs_shape = try_opt!(shape.sub_width(operator_str.len() + 1));
2044     let lhs_str = format!("{} {}",
2045                           try_opt!(lhs.rewrite(context, lhs_shape)),
2046                           operator_str);
2047
2048     rewrite_assign_rhs(context, lhs_str, rhs, shape)
2049 }
2050
2051 // The left hand side must contain everything up to, and including, the
2052 // assignment operator.
2053 pub fn rewrite_assign_rhs<S: Into<String>>(context: &RewriteContext,
2054                                            lhs: S,
2055                                            ex: &ast::Expr,
2056                                            shape: Shape)
2057                                            -> Option<String> {
2058     let mut result = lhs.into();
2059     let last_line_width = last_line_width(&result) -
2060                           if result.contains('\n') {
2061                               shape.indent.width()
2062                           } else {
2063                               0
2064                           };
2065     // 1 = space between operator and rhs.
2066     let max_width = try_opt!(shape.width.checked_sub(last_line_width + 1));
2067     let rhs = ex.rewrite(context,
2068                          Shape::offset(max_width,
2069                                        shape.indent,
2070                                        shape.indent.alignment + last_line_width + 1));
2071
2072     fn count_line_breaks(src: &str) -> usize {
2073         src.chars().filter(|&x| x == '\n').count()
2074     }
2075
2076     match rhs {
2077         Some(ref new_str) if count_line_breaks(new_str) < 2 => {
2078             result.push(' ');
2079             result.push_str(new_str);
2080         }
2081         _ => {
2082             // Expression did not fit on the same line as the identifier or is
2083             // at least three lines big. Try splitting the line and see
2084             // if that works better.
2085             let new_offset = shape.indent.block_indent(context.config);
2086             let max_width = try_opt!((shape.width + shape.indent.width())
2087                                          .checked_sub(new_offset.width()));
2088             let new_shape = Shape::legacy(max_width, new_offset);
2089             let new_rhs = ex.rewrite(context, new_shape);
2090
2091             // FIXME: DRY!
2092             match (rhs, new_rhs) {
2093                 (Some(ref orig_rhs), Some(ref replacement_rhs))
2094                     if count_line_breaks(orig_rhs) > count_line_breaks(replacement_rhs) + 1 ||
2095                        (orig_rhs.rewrite(context, shape).is_none() &&
2096                         replacement_rhs.rewrite(context, new_shape).is_some()) => {
2097                     result.push_str(&format!("\n{}", new_offset.to_string(context.config)));
2098                     result.push_str(replacement_rhs);
2099                 }
2100                 (None, Some(ref final_rhs)) => {
2101                     result.push_str(&format!("\n{}", new_offset.to_string(context.config)));
2102                     result.push_str(final_rhs);
2103                 }
2104                 (None, None) => return None,
2105                 (Some(ref orig_rhs), _) => {
2106                     result.push(' ');
2107                     result.push_str(orig_rhs);
2108                 }
2109             }
2110         }
2111     }
2112
2113     Some(result)
2114 }
2115
2116 fn rewrite_expr_addrof(context: &RewriteContext,
2117                        mutability: ast::Mutability,
2118                        expr: &ast::Expr,
2119                        shape: Shape)
2120                        -> Option<String> {
2121     let operator_str = match mutability {
2122         ast::Mutability::Immutable => "&",
2123         ast::Mutability::Mutable => "&mut ",
2124     };
2125     rewrite_unary_prefix(context, operator_str, expr, shape)
2126 }