]> git.lizzy.rs Git - rust.git/blobdiff - src/expr.rs
Handle special-case macros
[rust.git] / src / expr.rs
index 6cbbcc5c466e7932fe281dc9b666be309150a5c8..70363f7dd23115be4f6a1ed1a1f5d5b04fab6fa0 100644 (file)
 
 use syntax::{ast, ptr};
 use syntax::codemap::{BytePos, CodeMap, Span};
-use syntax::parse::classify;
 
 use spanned::Spanned;
 use chains::rewrite_chain;
+use closures;
 use codemap::{LineRangeUtils, SpanUtils};
 use comment::{combine_strs_with_missing_comments, contains_comment, recover_comment_removed,
               rewrite_comment, rewrite_missing_comment, FindUncommented};
-use config::{Config, ControlBraceStyle, IndentStyle, MultilineStyle, Style};
-use items::{span_hi_for_arg, span_lo_for_arg};
+use config::{Config, ControlBraceStyle, IndentStyle};
 use lists::{definitive_tactic, itemize_list, shape_for_tactic, struct_lit_formatting,
             struct_lit_shape, struct_lit_tactic, write_list, DefinitiveListTactic, ListFormatting,
             ListItem, ListTactic, Separator, SeparatorPlace, SeparatorTactic};
@@ -33,9 +32,8 @@
 use string::{rewrite_string, StringFormat};
 use types::{can_be_overflowed_type, rewrite_path, PathContext};
 use utils::{colon_spaces, contains_skip, extra_offset, first_line_width, inner_attributes,
-            last_line_extendable, last_line_width, left_most_sub_expr, mk_sp, outer_attributes,
-            paren_overhead, ptr_vec_to_ref_vec, semicolon_for_stmt, stmt_expr,
-            trimmed_last_line_width, wrap_str};
+            last_line_extendable, last_line_width, mk_sp, outer_attributes, paren_overhead,
+            ptr_vec_to_ref_vec, semicolon_for_stmt, trimmed_last_line_width, wrap_str};
 use vertical::rewrite_with_alignment;
 use visitor::FmtVisitor;
 
@@ -65,7 +63,7 @@ pub fn format_expr(
 
     let expr_rw = match expr.node {
         ast::ExprKind::Array(ref expr_vec) => rewrite_array(
-            expr_vec.iter().map(|e| &**e),
+            &ptr_vec_to_ref_vec(expr_vec),
             mk_sp(context.codemap.span_after(expr.span, "["), expr.span.hi()),
             context,
             shape,
@@ -101,12 +99,12 @@ pub fn format_expr(
         ast::ExprKind::Tup(ref items) => {
             rewrite_tuple(context, &ptr_vec_to_ref_vec(items), expr.span, shape)
         }
-        ast::ExprKind::If(..) |
-        ast::ExprKind::IfLet(..) |
-        ast::ExprKind::ForLoop(..) |
-        ast::ExprKind::Loop(..) |
-        ast::ExprKind::While(..) |
-        ast::ExprKind::WhileLet(..) => to_control_flow(expr, expr_type)
+        ast::ExprKind::If(..)
+        | ast::ExprKind::IfLet(..)
+        | ast::ExprKind::ForLoop(..)
+        | ast::ExprKind::Loop(..)
+        | ast::ExprKind::While(..)
+        ast::ExprKind::WhileLet(..) => to_control_flow(expr, expr_type)
             .and_then(|control_flow| control_flow.rewrite(context, shape)),
         ast::ExprKind::Block(ref block) => {
             match expr_type {
@@ -118,7 +116,7 @@ pub fn format_expr(
                         rw
                     } else {
                         let prefix = block_prefix(context, block, shape)?;
-                        rewrite_block_with_visitor(context, &prefix, block, shape)
+                        rewrite_block_with_visitor(context, &prefix, block, shape, true)
                     }
                 }
                 ExprType::SubExpression => block.rewrite(context, shape),
@@ -161,12 +159,12 @@ pub fn format_expr(
             Some("yield".to_string())
         },
         ast::ExprKind::Closure(capture, ref fn_decl, ref body, _) => {
-            rewrite_closure(capture, fn_decl, body, expr.span, context, shape)
+            closures::rewrite_closure(capture, fn_decl, body, expr.span, context, shape)
         }
-        ast::ExprKind::Try(..) |
-        ast::ExprKind::Field(..) |
-        ast::ExprKind::TupField(..) |
-        ast::ExprKind::MethodCall(..) => rewrite_chain(expr, context, shape),
+        ast::ExprKind::Try(..)
+        | ast::ExprKind::Field(..)
+        | ast::ExprKind::TupField(..)
+        ast::ExprKind::MethodCall(..) => rewrite_chain(expr, context, shape),
         ast::ExprKind::Mac(ref mac) => {
             rewrite_macro(mac, None, context, shape, MacroPosition::Expression).or_else(|| {
                 wrap_str(
@@ -204,7 +202,7 @@ pub fn format_expr(
             rewrite_index(&**expr, &**index, context, shape)
         }
         ast::ExprKind::Repeat(ref expr, ref repeats) => {
-            let (lbr, rbr) = if context.config.spaces_within_square_brackets() {
+            let (lbr, rbr) = if context.config.spaces_within_parens_and_brackets() {
                 ("[ ", " ]")
             } else {
                 ("[", "]")
@@ -294,9 +292,7 @@ fn needs_space_before_range(context: &RewriteContext, lhs: &ast::Expr) -> bool {
     };
 
     expr_rw
-        .and_then(|expr_str| {
-            recover_comment_removed(expr_str, expr.span, context)
-        })
+        .and_then(|expr_str| recover_comment_removed(expr_str, expr.span, context))
         .and_then(|expr_str| {
             let attrs = outer_attributes(&expr.attrs);
             let attrs_str = attrs.rewrite(context, shape)?;
@@ -368,11 +364,11 @@ pub fn rewrite_pair<LHS, RHS>(
 
     // We have to use multiple lines.
     // Re-evaluate the rhs because we have more space now:
-    let mut rhs_shape = match context.config.control_style() {
-        Style::Legacy => shape
+    let mut rhs_shape = match context.config.indent_style() {
+        IndentStyle::Visual => shape
             .sub_width(pp.suffix.len() + pp.prefix.len())?
             .visual_indent(pp.prefix.len()),
-        Style::Rfc => {
+        IndentStyle::Block => {
             // Try to calculate the initial constraint on the right hand side.
             let rhs_overhead = shape.rhs_overhead(context.config);
             Shape::indented(shape.indent.block_indent(context.config), context.config)
@@ -401,23 +397,20 @@ pub fn rewrite_pair<LHS, RHS>(
     ))
 }
 
-pub fn rewrite_array<'a, I>(
-    expr_iter: I,
+pub fn rewrite_array<T: Rewrite + Spanned + ToExpr>(
+    exprs: &[&T],
     span: Span,
     context: &RewriteContext,
     shape: Shape,
     trailing_comma: bool,
-) -> Option<String>
-where
-    I: Iterator<Item = &'a ast::Expr>,
-{
-    let bracket_size = if context.config.spaces_within_square_brackets() {
+) -> Option<String> {
+    let bracket_size = if context.config.spaces_within_parens_and_brackets() {
         2 // "[ "
     } else {
         1 // "["
     };
 
-    let nested_shape = match context.config.array_indent() {
+    let nested_shape = match context.config.indent_style() {
         IndentStyle::Block => shape
             .block()
             .block_indent(context.config.tab_spaces())
@@ -430,10 +423,11 @@ pub fn rewrite_array<'a, I>(
 
     let items = itemize_list(
         context.codemap,
-        expr_iter,
+        exprs.iter(),
         "]",
-        |item| item.span.lo(),
-        |item| item.span.hi(),
+        ",",
+        |item| item.span().lo(),
+        |item| item.span().hi(),
         |item| item.rewrite(context, nested_shape),
         span.lo(),
         span.hi(),
@@ -441,7 +435,7 @@ pub fn rewrite_array<'a, I>(
     ).collect::<Vec<_>>();
 
     if items.is_empty() {
-        if context.config.spaces_within_square_brackets() {
+        if context.config.spaces_within_parens_and_brackets() {
             return Some("[ ]".to_string());
         } else {
             return Some("[]".to_string());
@@ -452,42 +446,52 @@ pub fn rewrite_array<'a, I>(
         .iter()
         .any(|li| li.item.as_ref().map(|s| s.len() > 10).unwrap_or(false));
 
-    let mut tactic = match context.config.array_indent() {
+    let tactic = match context.config.indent_style() {
         IndentStyle::Block => {
             // FIXME wrong shape in one-line case
             match shape.width.checked_sub(2 * bracket_size) {
                 Some(width) => {
-                    let tactic =
-                        ListTactic::LimitedHorizontalVertical(context.config.array_width());
+                    let tactic = ListTactic::LimitedHorizontalVertical(
+                        context.config.width_heuristics().array_width,
+                    );
                     definitive_tactic(&items, tactic, Separator::Comma, width)
                 }
                 None => DefinitiveListTactic::Vertical,
             }
         }
-        IndentStyle::Visual => if has_long_item || items.iter().any(ListItem::is_multiline) {
-            definitive_tactic(
-                &items,
-                ListTactic::LimitedHorizontalVertical(context.config.array_width()),
-                Separator::Comma,
-                nested_shape.width,
-            )
-        } else {
-            DefinitiveListTactic::Mixed
-        },
+        IndentStyle::Visual => {
+            if has_long_item || items.iter().any(ListItem::is_multiline) {
+                definitive_tactic(
+                    &items,
+                    ListTactic::LimitedHorizontalVertical(
+                        context.config.width_heuristics().array_width,
+                    ),
+                    Separator::Comma,
+                    nested_shape.width,
+                )
+            } else {
+                DefinitiveListTactic::Mixed
+            }
+        }
     };
-    let ends_with_newline = tactic.ends_with_newline(context.config.array_indent());
-    if context.config.array_horizontal_layout_threshold() > 0
-        && items.len() > context.config.array_horizontal_layout_threshold()
-    {
-        tactic = DefinitiveListTactic::Mixed;
-    }
+    let ends_with_newline = tactic.ends_with_newline(context.config.indent_style());
 
     let fmt = ListFormatting {
         tactic: tactic,
         separator: ",",
         trailing_separator: if trailing_comma {
             SeparatorTactic::Always
-        } else if context.inside_macro || context.config.array_indent() == IndentStyle::Visual {
+        } else if context.inside_macro && !exprs.is_empty() {
+            let ends_with_bracket = context.snippet(span).ends_with(']');
+            let bracket_offset = if ends_with_bracket { 1 } else { 0 };
+            let snippet = context.snippet(mk_sp(span.lo(), span.hi() - BytePos(bracket_offset)));
+            let last_char_index = snippet.rfind(|c: char| !c.is_whitespace())?;
+            if &snippet[last_char_index..last_char_index + 1] == "," {
+                SeparatorTactic::Always
+            } else {
+                SeparatorTactic::Never
+            }
+        } else if context.config.indent_style() == IndentStyle::Visual {
             SeparatorTactic::Never
         } else {
             SeparatorTactic::Vertical
@@ -500,10 +504,10 @@ pub fn rewrite_array<'a, I>(
     };
     let list_str = write_list(&items, &fmt)?;
 
-    let result = if context.config.array_indent() == IndentStyle::Visual
+    let result = if context.config.indent_style() == IndentStyle::Visual
         || tactic == DefinitiveListTactic::Horizontal
     {
-        if context.config.spaces_within_square_brackets() && !list_str.is_empty() {
+        if context.config.spaces_within_parens_and_brackets() && !list_str.is_empty() {
             format!("[ {} ]", list_str)
         } else {
             format!("[{}]", list_str)
@@ -520,221 +524,6 @@ pub fn rewrite_array<'a, I>(
     Some(result)
 }
 
-// Return type is (prefix, extra_offset)
-fn rewrite_closure_fn_decl(
-    capture: ast::CaptureBy,
-    fn_decl: &ast::FnDecl,
-    body: &ast::Expr,
-    span: Span,
-    context: &RewriteContext,
-    shape: Shape,
-) -> Option<(String, usize)> {
-    let mover = if capture == ast::CaptureBy::Value {
-        "move "
-    } else {
-        ""
-    };
-    // 4 = "|| {".len(), which is overconservative when the closure consists of
-    // a single expression.
-    let nested_shape = shape.shrink_left(mover.len())?.sub_width(4)?;
-
-    // 1 = |
-    let argument_offset = nested_shape.indent + 1;
-    let arg_shape = nested_shape.offset_left(1)?.visual_indent(0);
-    let ret_str = fn_decl.output.rewrite(context, arg_shape)?;
-
-    let arg_items = itemize_list(
-        context.codemap,
-        fn_decl.inputs.iter(),
-        "|",
-        |arg| span_lo_for_arg(arg),
-        |arg| span_hi_for_arg(context, arg),
-        |arg| arg.rewrite(context, arg_shape),
-        context.codemap.span_after(span, "|"),
-        body.span.lo(),
-        false,
-    );
-    let item_vec = arg_items.collect::<Vec<_>>();
-    // 1 = space between arguments and return type.
-    let horizontal_budget = nested_shape
-        .width
-        .checked_sub(ret_str.len() + 1)
-        .unwrap_or(0);
-    let tactic = definitive_tactic(
-        &item_vec,
-        ListTactic::HorizontalVertical,
-        Separator::Comma,
-        horizontal_budget,
-    );
-    let arg_shape = match tactic {
-        DefinitiveListTactic::Horizontal => arg_shape.sub_width(ret_str.len() + 1)?,
-        _ => arg_shape,
-    };
-
-    let fmt = ListFormatting {
-        tactic: tactic,
-        separator: ",",
-        trailing_separator: SeparatorTactic::Never,
-        separator_place: SeparatorPlace::Back,
-        shape: arg_shape,
-        ends_with_newline: false,
-        preserve_newline: true,
-        config: context.config,
-    };
-    let list_str = write_list(&item_vec, &fmt)?;
-    let mut prefix = format!("{}|{}|", mover, list_str);
-
-    if !ret_str.is_empty() {
-        if prefix.contains('\n') {
-            prefix.push('\n');
-            prefix.push_str(&argument_offset.to_string(context.config));
-        } else {
-            prefix.push(' ');
-        }
-        prefix.push_str(&ret_str);
-    }
-    // 1 = space between `|...|` and body.
-    let extra_offset = last_line_width(&prefix) + 1;
-
-    Some((prefix, extra_offset))
-}
-
-// This functions is pretty messy because of the rules around closures and blocks:
-// FIXME - the below is probably no longer true in full.
-//   * if there is a return type, then there must be braces,
-//   * given a closure with braces, whether that is parsed to give an inner block
-//     or not depends on if there is a return type and if there are statements
-//     in that block,
-//   * if the first expression in the body ends with a block (i.e., is a
-//     statement without needing a semi-colon), then adding or removing braces
-//     can change whether it is treated as an expression or statement.
-fn rewrite_closure(
-    capture: ast::CaptureBy,
-    fn_decl: &ast::FnDecl,
-    body: &ast::Expr,
-    span: Span,
-    context: &RewriteContext,
-    shape: Shape,
-) -> Option<String> {
-    let (prefix, extra_offset) =
-        rewrite_closure_fn_decl(capture, fn_decl, body, span, context, shape)?;
-    // 1 = space between `|...|` and body.
-    let body_shape = shape.offset_left(extra_offset)?;
-
-    if let ast::ExprKind::Block(ref block) = body.node {
-        // The body of the closure is an empty block.
-        if block.stmts.is_empty() && !block_contains_comment(block, context.codemap) {
-            return Some(format!("{} {{}}", prefix));
-        }
-
-        // Figure out if the block is necessary.
-        let needs_block = is_unsafe_block(block) || block.stmts.len() > 1 || context.inside_macro
-            || block_contains_comment(block, context.codemap)
-            || prefix.contains('\n');
-
-        let no_return_type = if let ast::FunctionRetTy::Default(_) = fn_decl.output {
-            true
-        } else {
-            false
-        };
-        if no_return_type && !needs_block {
-            // block.stmts.len() == 1
-            if let Some(expr) = stmt_expr(&block.stmts[0]) {
-                if let Some(rw) = if is_block_closure_forced(expr) {
-                    rewrite_closure_with_block(context, shape, &prefix, expr)
-                } else {
-                    rewrite_closure_expr(expr, &prefix, context, body_shape)
-                } {
-                    return Some(rw);
-                }
-            }
-        }
-
-        // Either we require a block, or tried without and failed.
-        rewrite_closure_block(block, &prefix, context, body_shape)
-    } else {
-        rewrite_closure_expr(body, &prefix, context, body_shape).or_else(|| {
-            // The closure originally had a non-block expression, but we can't fit on
-            // one line, so we'll insert a block.
-            rewrite_closure_with_block(context, body_shape, &prefix, body)
-        })
-    }
-}
-
-// Rewrite closure with a single expression wrapping its body with block.
-fn rewrite_closure_with_block(
-    context: &RewriteContext,
-    shape: Shape,
-    prefix: &str,
-    body: &ast::Expr,
-) -> Option<String> {
-    let block = ast::Block {
-        stmts: vec![
-            ast::Stmt {
-                id: ast::NodeId::new(0),
-                node: ast::StmtKind::Expr(ptr::P(body.clone())),
-                span: body.span,
-            },
-        ],
-        id: ast::NodeId::new(0),
-        rules: ast::BlockCheckMode::Default,
-        span: body.span,
-    };
-    rewrite_closure_block(&block, prefix, context, shape)
-}
-
-// Rewrite closure with a single expression without wrapping its body with block.
-fn rewrite_closure_expr(
-    expr: &ast::Expr,
-    prefix: &str,
-    context: &RewriteContext,
-    shape: Shape,
-) -> Option<String> {
-    let mut rewrite = expr.rewrite(context, shape);
-    if classify::expr_requires_semi_to_be_stmt(left_most_sub_expr(expr)) {
-        rewrite = and_one_line(rewrite);
-    }
-    rewrite = rewrite.and_then(|rw| {
-        if context.config.multiline_closure_forces_block() && rw.contains('\n') {
-            None
-        } else {
-            Some(rw)
-        }
-    });
-    rewrite.map(|rw| format!("{} {}", prefix, rw))
-}
-
-// Rewrite closure whose body is block.
-fn rewrite_closure_block(
-    block: &ast::Block,
-    prefix: &str,
-    context: &RewriteContext,
-    shape: Shape,
-) -> Option<String> {
-    // Start with visual indent, then fall back to block indent if the
-    // closure is large.
-    let block_threshold = context.config.closure_block_indent_threshold();
-    if block_threshold >= 0 {
-        if let Some(block_str) = block.rewrite(context, shape) {
-            if block_str.matches('\n').count() <= block_threshold as usize
-                && !need_block_indent(&block_str, shape)
-            {
-                return Some(format!("{} {}", prefix, block_str));
-            }
-        }
-    }
-
-    // The body of the closure is big enough to be block indented, that
-    // means we must re-format.
-    let block_shape = shape.block();
-    let block_str = block.rewrite(context, block_shape)?;
-    Some(format!("{} {}", prefix, block_str))
-}
-
-fn and_one_line(x: Option<String>) -> Option<String> {
-    x.and_then(|x| if x.contains('\n') { None } else { Some(x) })
-}
-
 fn nop_block_collapse(block_str: Option<String>, budget: usize) -> Option<String> {
     debug!("nop_block_collapse {:?} {}", block_str, budget);
     block_str.map(|block_str| {
@@ -818,11 +607,12 @@ fn rewrite_single_line_block(
     None
 }
 
-fn rewrite_block_with_visitor(
+pub fn rewrite_block_with_visitor(
     context: &RewriteContext,
     prefix: &str,
     block: &ast::Block,
     shape: Shape,
+    has_braces: bool,
 ) -> Option<String> {
     if let rw @ Some(_) = rewrite_empty_block(context, block, shape) {
         return rw;
@@ -840,7 +630,7 @@ fn rewrite_block_with_visitor(
         ast::BlockCheckMode::Default => visitor.last_pos = block.span.lo(),
     }
 
-    visitor.visit_block(block, None);
+    visitor.visit_block(block, None, has_braces);
     Some(format!("{}{}", prefix, visitor.buffer))
 }
 
@@ -853,8 +643,9 @@ fn rewrite(&self, context: &RewriteContext, shape: Shape) -> Option<String> {
         }
 
         let prefix = block_prefix(context, self, shape)?;
+        let shape = shape.offset_left(last_line_width(&prefix))?;
 
-        let result = rewrite_block_with_visitor(context, &prefix, self, shape);
+        let result = rewrite_block_with_visitor(context, &prefix, self, shape, true);
         if let Some(ref result_str) = result {
             if result_str.lines().count() <= 3 {
                 if let rw @ Some(_) = rewrite_single_line_block(context, &prefix, self, shape) {
@@ -890,13 +681,13 @@ fn rewrite(&self, context: &RewriteContext, shape: Shape) -> Option<String> {
 }
 
 // Rewrite condition if the given expression has one.
-fn rewrite_cond(context: &RewriteContext, expr: &ast::Expr, shape: Shape) -> Option<String> {
+pub fn rewrite_cond(context: &RewriteContext, expr: &ast::Expr, shape: Shape) -> Option<String> {
     match expr.node {
         ast::ExprKind::Match(ref cond, _) => {
             // `match `cond` {`
-            let cond_shape = match context.config.control_style() {
-                Style::Legacy => shape.shrink_left(6).and_then(|s| s.sub_width(2))?,
-                Style::Rfc => shape.offset_left(8)?,
+            let cond_shape = match context.config.indent_style() {
+                IndentStyle::Visual => shape.shrink_left(6).and_then(|s| s.sub_width(2))?,
+                IndentStyle::Block => shape.offset_left(8)?,
             };
             cond.rewrite(context, cond_shape)
         }
@@ -1139,9 +930,9 @@ fn rewrite_cond(
 
         let pat_expr_string = match self.cond {
             Some(cond) => {
-                let cond_shape = match context.config.control_style() {
-                    Style::Legacy => constr_shape.shrink_left(offset)?,
-                    Style::Rfc => constr_shape.offset_left(offset)?,
+                let cond_shape = match context.config.indent_style() {
+                    IndentStyle::Visual => constr_shape.shrink_left(offset)?,
+                    IndentStyle::Block => constr_shape.offset_left(offset)?,
                 };
                 rewrite_pat_expr(
                     context,
@@ -1168,16 +959,26 @@ fn rewrite_cond(
             .max_width()
             .checked_sub(constr_shape.used_width() + offset + brace_overhead)
             .unwrap_or(0);
-        let force_newline_brace = context.config.control_style() == Style::Rfc
+        let force_newline_brace = context.config.indent_style() == IndentStyle::Block
             && (pat_expr_string.contains('\n') || pat_expr_string.len() > one_line_budget)
             && !last_line_extendable(&pat_expr_string);
 
         // Try to format if-else on single line.
-        if self.allow_single_line && context.config.single_line_if_else_max_width() > 0 {
+        if self.allow_single_line
+            && context
+                .config
+                .width_heuristics()
+                .single_line_if_else_max_width > 0
+        {
             let trial = self.rewrite_single_line(&pat_expr_string, context, shape.width);
 
             if let Some(cond_str) = trial {
-                if cond_str.len() <= context.config.single_line_if_else_max_width() {
+                if cond_str.len()
+                    <= context
+                        .config
+                        .width_heuristics()
+                        .single_line_if_else_max_width
+                {
                     return Some((cond_str, 0));
                 }
             }
@@ -1274,7 +1075,8 @@ fn rewrite(&self, context: &RewriteContext, shape: Shape) -> Option<String> {
         };
         let mut block_context = context.clone();
         block_context.is_if_else_block = self.else_block.is_some();
-        let block_str = rewrite_block_with_visitor(&block_context, "", self.block, block_shape)?;
+        let block_str =
+            rewrite_block_with_visitor(&block_context, "", self.block, block_shape, true)?;
 
         let mut result = format!("{}{}", cond_str, block_str);
 
@@ -1380,7 +1182,7 @@ fn extract_comment(span: Span, context: &RewriteContext, shape: Shape) -> Option
     }
 }
 
-fn block_contains_comment(block: &ast::Block, codemap: &CodeMap) -> bool {
+pub fn block_contains_comment(block: &ast::Block, codemap: &CodeMap) -> bool {
     let snippet = codemap.span_to_snippet(block.span).unwrap();
     contains_comment(&snippet)
 }
@@ -1410,7 +1212,7 @@ pub fn stmt_is_expr(stmt: &ast::Stmt) -> bool {
     }
 }
 
-fn is_unsafe_block(block: &ast::Block) -> bool {
+pub fn is_unsafe_block(block: &ast::Block) -> bool {
     if let ast::BlockCheckMode::Unsafe(..) = block.rules {
         true
     } else {
@@ -1453,9 +1255,9 @@ fn rewrite_match(
         ..shape
     };
     // 6 = `match `
-    let cond_shape = match context.config.control_style() {
-        Style::Legacy => cond_shape.shrink_left(6)?,
-        Style::Rfc => cond_shape.offset_left(6)?,
+    let cond_shape = match context.config.indent_style() {
+        IndentStyle::Visual => cond_shape.shrink_left(6)?,
+        IndentStyle::Block => cond_shape.offset_left(6)?,
     };
     let cond_str = cond.rewrite(context, cond_shape)?;
     let alt_block_sep = String::from("\n") + &shape.indent.block_only().to_string(context.config);
@@ -1492,12 +1294,6 @@ fn rewrite_match(
         inner_attrs[inner_attrs.len() - 1].span().hi()
     };
 
-    let arm_indent_str = if context.config.indent_match_arms() {
-        nested_indent_str
-    } else {
-        shape.indent.to_string(context.config)
-    };
-
     if arms.is_empty() {
         let snippet = context.snippet(mk_sp(open_brace_pos, span.hi() - BytePos(1)));
         if snippet.trim().is_empty() {
@@ -1512,7 +1308,7 @@ fn rewrite_match(
             cond_str,
             block_sep,
             inner_attrs_str,
-            arm_indent_str,
+            nested_indent_str,
             rewrite_match_arms(context, arms, shape, span, open_brace_pos)?,
             shape.indent.to_string(context.config),
         ))
@@ -1542,11 +1338,9 @@ fn rewrite_match_arms(
     span: Span,
     open_brace_pos: BytePos,
 ) -> Option<String> {
-    let arm_shape = if context.config.indent_match_arms() {
-        shape.block_indent(context.config.tab_spaces())
-    } else {
-        shape.block_indent(0)
-    }.with_max_width(context.config);
+    let arm_shape = shape
+        .block_indent(context.config.tab_spaces())
+        .with_max_width(context.config);
 
     let arm_len = arms.len();
     let is_last_iter = repeat(false)
@@ -1558,6 +1352,7 @@ fn rewrite_match_arms(
             .zip(is_last_iter)
             .map(|(arm, is_last)| ArmWrapper::new(arm, is_last)),
         "}",
+        "|",
         |arm| arm.arm.span().lo(),
         |arm| arm.arm.span().hi(),
         |arm| arm.rewrite(context, arm_shape),
@@ -1597,13 +1392,11 @@ fn rewrite_match_arm(
                 arm_comma(context.config, body, is_last),
             ));
         }
-        (
-            mk_sp(
-                arm.attrs[arm.attrs.len() - 1].span.hi(),
-                arm.pats[0].span.lo(),
-            ),
-            arm.attrs.rewrite(context, shape)?,
-        )
+        let missing_span = mk_sp(
+            arm.attrs[arm.attrs.len() - 1].span.hi(),
+            arm.pats[0].span.lo(),
+        );
+        (missing_span, arm.attrs.rewrite(context, shape)?)
     } else {
         (mk_sp(arm.span().lo(), arm.span().lo()), String::new())
     };
@@ -1628,6 +1421,38 @@ fn rewrite_match_arm(
     )
 }
 
+/// Returns true if the given pattern is short. A short pattern is defined by the following grammer:
+///
+/// [small, ntp]:
+///     - single token
+///     - `&[single-line, ntp]`
+///
+/// [small]:
+///     - `[small, ntp]`
+///     - unary tuple constructor `([small, ntp])`
+///     - `&[small]`
+fn is_short_pattern(pat: &ast::Pat, pat_str: &str) -> bool {
+    // We also require that the pattern is reasonably 'small' with its literal width.
+    pat_str.len() <= 20 && !pat_str.contains('\n') && is_short_pattern_inner(pat)
+}
+
+fn is_short_pattern_inner(pat: &ast::Pat) -> bool {
+    match pat.node {
+        ast::PatKind::Wild | ast::PatKind::Lit(_) => true,
+        ast::PatKind::Ident(_, _, ref pat) => pat.is_none(),
+        ast::PatKind::Struct(..)
+        | ast::PatKind::Mac(..)
+        | ast::PatKind::Slice(..)
+        | ast::PatKind::Path(..)
+        | ast::PatKind::Range(..) => false,
+        ast::PatKind::Tuple(ref subpats, _) => subpats.len() <= 1,
+        ast::PatKind::TupleStruct(ref path, ref subpats, _) => {
+            path.segments.len() <= 1 && subpats.len() <= 1
+        }
+        ast::PatKind::Box(ref p) | ast::PatKind::Ref(ref p, _) => is_short_pattern_inner(&*p),
+    }
+}
+
 fn rewrite_match_pattern(
     context: &RewriteContext,
     pats: &[ptr::P<ast::Pat>],
@@ -1642,18 +1467,25 @@ fn rewrite_match_pattern(
         .map(|p| p.rewrite(context, pat_shape))
         .collect::<Option<Vec<_>>>()?;
 
+    let use_mixed_layout = pats.iter()
+        .zip(pat_strs.iter())
+        .all(|(pat, pat_str)| is_short_pattern(pat, pat_str));
     let items: Vec<_> = pat_strs.into_iter().map(ListItem::from_str).collect();
-    let tactic = definitive_tactic(
-        &items,
-        ListTactic::HorizontalVertical,
-        Separator::VerticalBar,
-        pat_shape.width,
-    );
+    let tactic = if use_mixed_layout {
+        DefinitiveListTactic::Mixed
+    } else {
+        definitive_tactic(
+            &items,
+            ListTactic::HorizontalVertical,
+            Separator::VerticalBar,
+            pat_shape.width,
+        )
+    };
     let fmt = ListFormatting {
         tactic: tactic,
         separator: " |",
         trailing_separator: SeparatorTactic::Never,
-        separator_place: context.config.match_pattern_separator_break_point(),
+        separator_place: context.config.binop_separator(),
         shape: pat_shape,
         ends_with_newline: false,
         preserve_newline: false,
@@ -1677,17 +1509,15 @@ fn flatten_arm_body<'a>(context: &'a RewriteContext, body: &'a ast::Expr) -> (bo
         {
             if let ast::StmtKind::Expr(ref expr) = block.stmts[0].node {
                 (
-                    !context.config.multiline_match_arm_forces_block()
-                        && expr.can_be_overflowed(context, 1),
-                    &**expr,
+                    !context.config.force_multiline_blocks() && can_extend_match_arm_body(expr),
+                    &*expr,
                 )
             } else {
                 (false, &*body)
             }
         }
         _ => (
-            !context.config.multiline_match_arm_forces_block()
-                && body.can_be_overflowed(context, 1),
+            !context.config.force_multiline_blocks() && body.can_be_overflowed(context, 1),
             &*body,
         ),
     }
@@ -1707,11 +1537,6 @@ fn rewrite_match_body(
     } else {
         (false, false)
     };
-    let extend = if context.config.match_arm_forces_newline() {
-        is_block
-    } else {
-        extend
-    };
 
     let comma = arm_comma(context.config, body, is_last);
     let alt_block_sep = String::from("\n") + &shape.indent.block_only().to_string(context.config);
@@ -1727,14 +1552,10 @@ fn rewrite_match_body(
     };
 
     let forbid_same_line = has_guard && pats_str.contains('\n') && !is_empty_block;
-    let next_line_indent = if is_block {
-        if is_empty_block {
-            shape.indent.block_indent(context.config)
-        } else {
-            shape.indent
-        }
-    } else {
+    let next_line_indent = if !is_block || is_empty_block {
         shape.indent.block_indent(context.config)
+    } else {
+        shape.indent
     };
     let combine_next_line_body = |body_str: &str| {
         if is_block {
@@ -1748,7 +1569,7 @@ fn rewrite_match_body(
 
         let indent_str = shape.indent.to_string(context.config);
         let nested_indent_str = next_line_indent.to_string(context.config);
-        let (body_prefix, body_suffix) = if context.config.wrap_match_arms() {
+        let (body_prefix, body_suffix) = if context.config.match_arm_blocks() {
             let comma = if context.config.match_block_trailing_comma() {
                 ","
             } else {
@@ -1788,7 +1609,7 @@ fn rewrite_match_body(
 
         match rewrite {
             Some(ref body_str)
-                if !forbid_same_line && !context.config.match_arm_forces_newline()
+                if !forbid_same_line
                     && (is_block
                         || (!body_str.contains('\n') && body_str.len() <= body_shape.width)) =>
             {
@@ -1911,17 +1732,44 @@ fn rewrite_pat_expr(
         .map(|expr_rw| format!("\n{}{}", nested_indent_str, expr_rw))
 }
 
+fn can_extend_match_arm_body(body: &ast::Expr) -> bool {
+    match body.node {
+        // We do not allow `if` to stay on the same line, since we could easily mistake
+        // `pat => if cond { ... }` and `pat if cond => { ... }`.
+        ast::ExprKind::If(..) | ast::ExprKind::IfLet(..) => false,
+        ast::ExprKind::ForLoop(..)
+        | ast::ExprKind::Loop(..)
+        | ast::ExprKind::While(..)
+        | ast::ExprKind::WhileLet(..)
+        | ast::ExprKind::Match(..)
+        | ast::ExprKind::Block(..)
+        | ast::ExprKind::Closure(..)
+        | ast::ExprKind::Array(..)
+        | ast::ExprKind::Call(..)
+        | ast::ExprKind::MethodCall(..)
+        | ast::ExprKind::Mac(..)
+        | ast::ExprKind::Struct(..)
+        | ast::ExprKind::Tup(..) => true,
+        ast::ExprKind::AddrOf(_, ref expr)
+        | ast::ExprKind::Box(ref expr)
+        | ast::ExprKind::Try(ref expr)
+        | ast::ExprKind::Unary(_, ref expr)
+        | ast::ExprKind::Cast(ref expr, _) => can_extend_match_arm_body(expr),
+        _ => false,
+    }
+}
+
 pub fn rewrite_literal(context: &RewriteContext, l: &ast::Lit, shape: Shape) -> Option<String> {
     match l.node {
         ast::LitKind::Str(_, ast::StrStyle::Cooked) => rewrite_string_lit(context, l.span, shape),
-        _ => Some(context.snippet(l.span)),
+        _ => wrap_str(context.snippet(l.span), context.config.max_width(), shape),
     }
 }
 
 fn rewrite_string_lit(context: &RewriteContext, span: Span, shape: Shape) -> Option<String> {
     let string_lit = context.snippet(span);
 
-    if !context.config.format_strings() && !context.config.force_format_strings() {
+    if !context.config.format_strings() {
         if string_lit
             .lines()
             .rev()
@@ -1929,7 +1777,7 @@ fn rewrite_string_lit(context: &RewriteContext, span: Span, shape: Shape) -> Opt
             .all(|line| line.ends_with('\\'))
         {
             let new_indent = shape.visual_indent(1).indent;
-            return Some(String::from(
+            let indented_string_lit = String::from(
                 string_lit
                     .lines()
                     .map(|line| {
@@ -1942,18 +1790,13 @@ fn rewrite_string_lit(context: &RewriteContext, span: Span, shape: Shape) -> Opt
                     .collect::<Vec<_>>()
                     .join("\n")
                     .trim_left(),
-            ));
+            );
+            return wrap_str(indented_string_lit, context.config.max_width(), shape);
         } else {
-            return Some(string_lit);
+            return wrap_str(string_lit, context.config.max_width(), shape);
         }
     }
 
-    if !context.config.force_format_strings()
-        && !string_requires_rewrite(context, span, &string_lit, shape)
-    {
-        return Some(string_lit);
-    }
-
     // Remove the quote characters.
     let str_lit = &string_lit[1..string_lit.len() - 1];
 
@@ -1964,28 +1807,17 @@ fn rewrite_string_lit(context: &RewriteContext, span: Span, shape: Shape) -> Opt
     )
 }
 
-fn string_requires_rewrite(
-    context: &RewriteContext,
-    span: Span,
-    string: &str,
-    shape: Shape,
-) -> bool {
-    if context.codemap.lookup_char_pos(span.lo()).col.0 != shape.indent.width() {
-        return true;
-    }
+const FORMAT_LIKE_WHITELIST: &[&str] = &[
+    "eprint!",
+    "eprintln!",
+    "format!",
+    "format_args!",
+    "panic!",
+    "println!",
+    "unreachable!",
+];
 
-    for (i, line) in string.lines().enumerate() {
-        if i == 0 {
-            if line.len() > shape.width {
-                return true;
-            }
-        } else if line.len() > shape.width + shape.indent.width() {
-            return true;
-        }
-    }
-
-    false
-}
+const WRITE_LIKE_WHITELIST: &[&str] = &["assert!", "write!", "writeln!"];
 
 pub fn rewrite_call(
     context: &RewriteContext,
@@ -2005,7 +1837,7 @@ pub fn rewrite_call(
         &ptr_vec_to_ref_vec(args),
         span,
         shape,
-        context.config.fn_call_width(),
+        context.config.width_heuristics().fn_call_width,
         force_trailing_comma,
     )
 }
@@ -2023,7 +1855,7 @@ pub fn rewrite_call_inner<'a, T>(
     T: Rewrite + Spanned + ToExpr + 'a,
 {
     // 2 = `( `, 1 = `(`
-    let paren_overhead = if context.config.spaces_within_parens() {
+    let paren_overhead = if context.config.spaces_within_parens_and_brackets() {
         2
     } else {
         1
@@ -2031,7 +1863,11 @@ pub fn rewrite_call_inner<'a, T>(
     let used_width = extra_offset(callee_str, shape);
     let one_line_width = shape.width.checked_sub(used_width + 2 * paren_overhead)?;
 
-    let nested_shape = shape_from_fn_call_indent(
+    // 1 = "(" or ")"
+    let one_line_shape = shape
+        .offset_left(last_line_width(callee_str) + 1)?
+        .sub_width(1)?;
+    let nested_shape = shape_from_indent_style(
         context,
         shape,
         used_width + 2 * paren_overhead,
@@ -2045,10 +1881,12 @@ pub fn rewrite_call_inner<'a, T>(
         context,
         args,
         args_span,
+        one_line_shape,
         nested_shape,
         one_line_width,
         args_max_width,
         force_trailing_comma,
+        callee_str,
     )?;
 
     if !context.use_block_indent() && need_block_indent(&list_str, nested_shape) && !extendable {
@@ -2084,10 +1922,12 @@ fn rewrite_call_args<'a, T>(
     context: &RewriteContext,
     args: &[&T],
     span: Span,
-    shape: Shape,
+    one_line_shape: Shape,
+    nested_shape: Shape,
     one_line_width: usize,
     args_max_width: usize,
     force_trailing_comma: bool,
+    callee_str: &str,
 ) -> Option<(bool, String)>
 where
     T: Rewrite + Spanned + ToExpr + 'a,
@@ -2096,9 +1936,10 @@ fn rewrite_call_args<'a, T>(
         context.codemap,
         args.iter(),
         ")",
+        ",",
         |item| item.span().lo(),
         |item| item.span().hi(),
-        |item| item.rewrite(context, shape),
+        |item| item.rewrite(context, nested_shape),
         span.lo(),
         span.hi(),
         true,
@@ -2112,9 +1953,11 @@ fn rewrite_call_args<'a, T>(
         context,
         &mut item_vec,
         &args[..],
-        shape,
+        one_line_shape,
+        nested_shape,
         one_line_width,
         args_max_width,
+        callee_str,
     );
 
     let fmt = ListFormatting {
@@ -2128,40 +1971,46 @@ fn rewrite_call_args<'a, T>(
             context.config.trailing_comma()
         },
         separator_place: SeparatorPlace::Back,
-        shape: shape,
+        shape: nested_shape,
         ends_with_newline: context.use_block_indent() && tactic == DefinitiveListTactic::Vertical,
         preserve_newline: false,
         config: context.config,
     };
 
-    write_list(&item_vec, &fmt).map(|args_str| {
-        (tactic != DefinitiveListTactic::Vertical, args_str)
-    })
+    write_list(&item_vec, &fmt)
+        .map(|args_str| (tactic == DefinitiveListTactic::Horizontal, args_str))
 }
 
 fn try_overflow_last_arg<'a, T>(
     context: &RewriteContext,
     item_vec: &mut Vec<ListItem>,
     args: &[&T],
-    shape: Shape,
+    one_line_shape: Shape,
+    nested_shape: Shape,
     one_line_width: usize,
     args_max_width: usize,
+    callee_str: &str,
 ) -> DefinitiveListTactic
 where
     T: Rewrite + Spanned + ToExpr + 'a,
 {
-    let overflow_last = can_be_overflowed(context, args);
+    // 1 = "("
+    let combine_arg_with_callee =
+        callee_str.len() + 1 <= context.config.tab_spaces() && args.len() == 1;
+    let overflow_last = combine_arg_with_callee || can_be_overflowed(context, args);
 
     // Replace the last item with its first line to see if it fits with
     // first arguments.
     let placeholder = if overflow_last {
         let mut context = context.clone();
-        if let Some(expr) = args[args.len() - 1].to_expr() {
-            if let ast::ExprKind::MethodCall(..) = expr.node {
-                context.force_one_line_chain = true;
+        if !combine_arg_with_callee {
+            if let Some(expr) = args[args.len() - 1].to_expr() {
+                if let ast::ExprKind::MethodCall(..) = expr.node {
+                    context.force_one_line_chain = true;
+                }
             }
         }
-        last_arg_shape(&context, item_vec, shape, args_max_width).and_then(|arg_shape| {
+        last_arg_shape(args, item_vec, one_line_shape, args_max_width).and_then(|arg_shape| {
             rewrite_last_arg_with_overflow(&context, args, &mut item_vec[args.len() - 1], arg_shape)
         })
     } else {
@@ -2183,7 +2032,17 @@ fn try_overflow_last_arg<'a, T>(
         }
         _ if args.len() >= 1 => {
             item_vec[args.len() - 1].item = args.last()
-                .and_then(|last_arg| last_arg.rewrite(context, shape));
+                .and_then(|last_arg| last_arg.rewrite(context, nested_shape));
+
+            let default_tactic = || {
+                definitive_tactic(
+                    &*item_vec,
+                    ListTactic::LimitedHorizontalVertical(args_max_width),
+                    Separator::Comma,
+                    one_line_width,
+                )
+            };
+
             // Use horizontal layout for a function with a single argument as long as
             // everything fits in a single line.
             if args.len() == 1
@@ -2194,12 +2053,44 @@ fn try_overflow_last_arg<'a, T>(
             {
                 tactic = DefinitiveListTactic::Horizontal;
             } else {
-                tactic = definitive_tactic(
-                    &*item_vec,
-                    ListTactic::LimitedHorizontalVertical(args_max_width),
-                    Separator::Comma,
-                    one_line_width,
-                );
+                tactic = default_tactic();
+                let is_simple_enough =
+                    tactic == DefinitiveListTactic::Vertical && is_every_args_simple(args);
+                if is_simple_enough
+                    && FORMAT_LIKE_WHITELIST
+                        .iter()
+                        .find(|s| **s == callee_str)
+                        .is_some()
+                {
+                    let args_tactic = definitive_tactic(
+                        &item_vec[1..],
+                        ListTactic::HorizontalVertical,
+                        Separator::Comma,
+                        nested_shape.width,
+                    );
+                    tactic = if args_tactic == DefinitiveListTactic::Horizontal {
+                        DefinitiveListTactic::FormatCall
+                    } else {
+                        default_tactic()
+                    };
+                } else if is_simple_enough && item_vec.len() >= 2
+                    && WRITE_LIKE_WHITELIST
+                        .iter()
+                        .find(|s| **s == callee_str)
+                        .is_some()
+                {
+                    let args_tactic = definitive_tactic(
+                        &item_vec[2..],
+                        ListTactic::HorizontalVertical,
+                        Separator::Comma,
+                        nested_shape.width,
+                    );
+                    tactic = if args_tactic == DefinitiveListTactic::Horizontal {
+                        DefinitiveListTactic::WriteCall
+                    } else {
+                        default_tactic()
+                    };
+                }
             }
         }
         _ => (),
@@ -2208,106 +2099,56 @@ fn try_overflow_last_arg<'a, T>(
     tactic
 }
 
-fn last_arg_shape(
-    context: &RewriteContext,
-    items: &[ListItem],
-    shape: Shape,
-    args_max_width: usize,
-) -> Option<Shape> {
-    let overhead = items.iter().rev().skip(1).fold(0, |acc, i| {
-        acc + i.item.as_ref().map_or(0, |s| first_line_width(s))
-    });
-    let max_width = min(args_max_width, shape.width);
-    let arg_indent = if context.use_block_indent() {
-        shape.block().indent.block_unindent(context.config)
-    } else {
-        shape.block().indent
-    };
-    Some(Shape {
-        width: max_width.checked_sub(overhead)?,
-        indent: arg_indent,
-        offset: 0,
-    })
-}
-
-// Rewriting closure which is placed at the end of the function call's arg.
-// Returns `None` if the reformatted closure 'looks bad'.
-fn rewrite_last_closure(
-    context: &RewriteContext,
-    expr: &ast::Expr,
-    shape: Shape,
-) -> Option<String> {
-    if let ast::ExprKind::Closure(capture, ref fn_decl, ref body, _) = expr.node {
-        let body = match body.node {
-            ast::ExprKind::Block(ref block) if is_simple_block(block, context.codemap) => {
-                stmt_expr(&block.stmts[0]).unwrap_or(body)
-            }
-            _ => body,
-        };
-        let (prefix, extra_offset) =
-            rewrite_closure_fn_decl(capture, fn_decl, body, expr.span, context, shape)?;
-        // If the closure goes multi line before its body, do not overflow the closure.
-        if prefix.contains('\n') {
-            return None;
-        }
-        // If we are inside macro, we do not want to add or remove block from closure body.
-        if context.inside_macro {
-            return expr.rewrite(context, shape);
-        }
-
-        let body_shape = shape.offset_left(extra_offset)?;
-
-        // We force to use block for the body of the closure for certain kinds of expressions.
-        if is_block_closure_forced(body) {
-            return rewrite_closure_with_block(context, body_shape, &prefix, body).and_then(
-                |body_str| {
-                    // If the expression can fit in a single line, we need not force block closure.
-                    if body_str.lines().count() <= 7 {
-                        match rewrite_closure_expr(body, &prefix, context, shape) {
-                            Some(ref single_line_body_str)
-                                if !single_line_body_str.contains('\n') =>
-                            {
-                                Some(single_line_body_str.clone())
-                            }
-                            _ => Some(body_str),
-                        }
-                    } else {
-                        Some(body_str)
-                    }
-                },
-            );
-        }
-
-        // When overflowing the closure which consists of a single control flow expression,
-        // force to use block if its condition uses multi line.
-        let is_multi_lined_cond = rewrite_cond(context, body, body_shape)
-            .map(|cond| cond.contains('\n') || cond.len() > body_shape.width)
-            .unwrap_or(false);
-        if is_multi_lined_cond {
-            return rewrite_closure_with_block(context, body_shape, &prefix, body);
+fn is_simple_arg(expr: &ast::Expr) -> bool {
+    match expr.node {
+        ast::ExprKind::Lit(..) => true,
+        ast::ExprKind::Path(ref qself, ref path) => qself.is_none() && path.segments.len() <= 1,
+        ast::ExprKind::AddrOf(_, ref expr)
+        | ast::ExprKind::Box(ref expr)
+        | ast::ExprKind::Cast(ref expr, _)
+        | ast::ExprKind::Field(ref expr, _)
+        | ast::ExprKind::Try(ref expr)
+        | ast::ExprKind::TupField(ref expr, _)
+        | ast::ExprKind::Unary(_, ref expr) => is_simple_arg(expr),
+        ast::ExprKind::Index(ref lhs, ref rhs) | ast::ExprKind::Repeat(ref lhs, ref rhs) => {
+            is_simple_arg(lhs) && is_simple_arg(rhs)
         }
-
-        // Seems fine, just format the closure in usual manner.
-        return expr.rewrite(context, shape);
+        _ => false,
     }
-    None
 }
 
-fn is_block_closure_forced(expr: &ast::Expr) -> bool {
-    match expr.node {
-        ast::ExprKind::If(..) |
-        ast::ExprKind::IfLet(..) |
-        ast::ExprKind::Loop(..) |
-        ast::ExprKind::While(..) |
-        ast::ExprKind::WhileLet(..) |
-        ast::ExprKind::ForLoop(..) => true,
-        ast::ExprKind::AddrOf(_, ref expr) |
-        ast::ExprKind::Box(ref expr) |
-        ast::ExprKind::Try(ref expr) |
-        ast::ExprKind::Unary(_, ref expr) |
-        ast::ExprKind::Cast(ref expr, _) => is_block_closure_forced(expr),
-        _ => false,
-    }
+fn is_every_args_simple<T: ToExpr>(lists: &[&T]) -> bool {
+    lists
+        .iter()
+        .all(|arg| arg.to_expr().map_or(false, is_simple_arg))
+}
+
+/// Returns a shape for the last argument which is going to be overflowed.
+fn last_arg_shape<T>(
+    lists: &[&T],
+    items: &[ListItem],
+    shape: Shape,
+    args_max_width: usize,
+) -> Option<Shape>
+where
+    T: Rewrite + Spanned + ToExpr,
+{
+    let is_nested_call = lists
+        .iter()
+        .next()
+        .and_then(|item| item.to_expr())
+        .map_or(false, is_nested_call);
+    if items.len() == 1 && !is_nested_call {
+        return Some(shape);
+    }
+    let offset = items.iter().rev().skip(1).fold(0, |acc, i| {
+        // 2 = ", "
+        acc + 2 + i.inner_as_ref().len()
+    });
+    Shape {
+        width: min(args_max_width, shape.width),
+        ..shape
+    }.offset_left(offset)
 }
 
 fn rewrite_last_arg_with_overflow<'a, T>(
@@ -2327,10 +2168,10 @@ fn rewrite_last_arg_with_overflow<'a, T>(
             ast::ExprKind::Closure(..) => {
                 // If the argument consists of multiple closures, we do not overflow
                 // the last closure.
-                if args_have_many_closure(args) {
+                if closures::args_have_many_closure(args) {
                     None
                 } else {
-                    rewrite_last_closure(context, expr, shape)
+                    closures::rewrite_last_closure(context, expr, shape)
                 }
             }
             _ => expr.rewrite(context, shape),
@@ -2348,23 +2189,6 @@ fn rewrite_last_arg_with_overflow<'a, T>(
     }
 }
 
-/// Returns true if the given vector of arguments has more than one `ast::ExprKind::Closure`.
-fn args_have_many_closure<T>(args: &[&T]) -> bool
-where
-    T: ToExpr,
-{
-    args.iter()
-        .filter(|arg| {
-            arg.to_expr()
-                .map(|e| match e.node {
-                    ast::ExprKind::Closure(..) => true,
-                    _ => false,
-                })
-                .unwrap_or(false)
-        })
-        .count() > 1
-}
-
 fn can_be_overflowed<'a, T>(context: &RewriteContext, args: &[&T]) -> bool
 where
     T: Rewrite + Spanned + ToExpr + 'a,
@@ -2377,31 +2201,43 @@ pub fn can_be_overflowed_expr(context: &RewriteContext, expr: &ast::Expr, args_l
     match expr.node {
         ast::ExprKind::Match(..) => {
             (context.use_block_indent() && args_len == 1)
-                || (context.config.fn_call_indent() == IndentStyle::Visual && args_len > 1)
-        }
-        ast::ExprKind::If(..) |
-        ast::ExprKind::IfLet(..) |
-        ast::ExprKind::ForLoop(..) |
-        ast::ExprKind::Loop(..) |
-        ast::ExprKind::While(..) |
-        ast::ExprKind::WhileLet(..) => {
+                || (context.config.indent_style() == IndentStyle::Visual && args_len > 1)
+        }
+        ast::ExprKind::If(..)
+        | ast::ExprKind::IfLet(..)
+        | ast::ExprKind::ForLoop(..)
+        | ast::ExprKind::Loop(..)
+        | ast::ExprKind::While(..)
+        ast::ExprKind::WhileLet(..) => {
             context.config.combine_control_expr() && context.use_block_indent() && args_len == 1
         }
         ast::ExprKind::Block(..) | ast::ExprKind::Closure(..) => {
             context.use_block_indent()
-                || context.config.fn_call_indent() == IndentStyle::Visual && args_len > 1
-        }
-        ast::ExprKind::Array(..) |
-        ast::ExprKind::Call(..) |
-        ast::ExprKind::Mac(..) |
-        ast::ExprKind::MethodCall(..) |
-        ast::ExprKind::Struct(..) |
-        ast::ExprKind::Tup(..) => context.use_block_indent() && args_len == 1,
-        ast::ExprKind::AddrOf(_, ref expr) |
-        ast::ExprKind::Box(ref expr) |
-        ast::ExprKind::Try(ref expr) |
-        ast::ExprKind::Unary(_, ref expr) |
-        ast::ExprKind::Cast(ref expr, _) => can_be_overflowed_expr(context, expr, args_len),
+                || context.config.indent_style() == IndentStyle::Visual && args_len > 1
+        }
+        ast::ExprKind::Array(..)
+        | ast::ExprKind::Call(..)
+        | ast::ExprKind::Mac(..)
+        | ast::ExprKind::MethodCall(..)
+        | ast::ExprKind::Struct(..)
+        | ast::ExprKind::Tup(..) => context.use_block_indent() && args_len == 1,
+        ast::ExprKind::AddrOf(_, ref expr)
+        | ast::ExprKind::Box(ref expr)
+        | ast::ExprKind::Try(ref expr)
+        | ast::ExprKind::Unary(_, ref expr)
+        | ast::ExprKind::Cast(ref expr, _) => can_be_overflowed_expr(context, expr, args_len),
+        _ => false,
+    }
+}
+
+fn is_nested_call(expr: &ast::Expr) -> bool {
+    match expr.node {
+        ast::ExprKind::Call(..) | ast::ExprKind::Mac(..) => true,
+        ast::ExprKind::AddrOf(_, ref expr)
+        | ast::ExprKind::Box(ref expr)
+        | ast::ExprKind::Try(ref expr)
+        | ast::ExprKind::Unary(_, ref expr)
+        | ast::ExprKind::Cast(ref expr, _) => is_nested_call(expr),
         _ => false,
     }
 }
@@ -2417,7 +2253,7 @@ pub fn wrap_args_with_parens(
         || (context.inside_macro && !args_str.contains('\n')
             && args_str.len() + paren_overhead(context) <= shape.width) || is_extendable
     {
-        if context.config.spaces_within_parens() && !args_str.is_empty() {
+        if context.config.spaces_within_parens_and_brackets() && !args_str.is_empty() {
             format!("( {} )", args_str)
         } else {
             format!("({})", args_str)
@@ -2460,11 +2296,12 @@ fn rewrite_paren(context: &RewriteContext, subexpr: &ast::Expr, shape: Shape) ->
         .offset_left(paren_overhead)
         .and_then(|s| s.sub_width(paren_overhead))?;
 
-    let paren_wrapper = |s: &str| if context.config.spaces_within_parens() && !s.is_empty() {
-        format!("( {} )", s)
-    } else {
-        format!("({})", s)
-    };
+    let paren_wrapper =
+        |s: &str| if context.config.spaces_within_parens_and_brackets() && !s.is_empty() {
+            format!("( {} )", s)
+        } else {
+            format!("({})", s)
+        };
 
     let subexpr_str = subexpr.rewrite(context, sub_shape)?;
     debug!("rewrite_paren, subexpr_str: `{:?}`", subexpr_str);
@@ -2486,7 +2323,7 @@ fn rewrite_index(
 ) -> Option<String> {
     let expr_str = expr.rewrite(context, shape)?;
 
-    let (lbr, rbr) = if context.config.spaces_within_square_brackets() {
+    let (lbr, rbr) = if context.config.spaces_within_parens_and_brackets() {
         ("[ ", " ]")
     } else {
         ("[", "]")
@@ -2619,6 +2456,7 @@ enum StructLitField<'a> {
             context.codemap,
             field_iter,
             "}",
+            ",",
             span_lo,
             span_hi,
             rewrite,
@@ -2638,7 +2476,7 @@ enum StructLitField<'a> {
     let fields_str = wrap_struct_field(context, &fields_str, shape, v_shape, one_line_width);
     Some(format!("{} {{{}}}", path_str, fields_str))
 
-    // FIXME if context.config.struct_lit_indent() == Visual, but we run out
+    // FIXME if context.config.indent_style() == Visual, but we run out
     // of space, we should fall back to BlockIndent.
 }
 
@@ -2649,9 +2487,8 @@ pub fn wrap_struct_field(
     nested_shape: Shape,
     one_line_width: usize,
 ) -> String {
-    if context.config.struct_lit_indent() == IndentStyle::Block
-        && (fields_str.contains('\n')
-            || context.config.struct_lit_multiline_style() == MultilineStyle::ForceMulti
+    if context.config.indent_style() == IndentStyle::Block
+        && (fields_str.contains('\n') || !context.config.struct_lit_single_line()
             || fields_str.len() > one_line_width)
     {
         format!(
@@ -2667,10 +2504,7 @@ pub fn wrap_struct_field(
 }
 
 pub fn struct_lit_field_separator(config: &Config) -> &str {
-    colon_spaces(
-        config.space_before_struct_lit_field_colon(),
-        config.space_after_struct_lit_field_colon(),
-    )
+    colon_spaces(config.space_before_colon(), config.space_after_colon())
 }
 
 pub fn rewrite_field(
@@ -2720,7 +2554,7 @@ pub fn rewrite_field(
     }
 }
 
-fn shape_from_fn_call_indent(
+fn shape_from_indent_style(
     context: &RewriteContext,
     shape: Shape,
     overhead: usize,
@@ -2758,7 +2592,7 @@ fn rewrite_tuple_in_visual_indent_style<'a, T>(
             .unwrap()
             .rewrite(context, nested_shape)
             .map(|s| {
-                if context.config.spaces_within_parens() {
+                if context.config.spaces_within_parens_and_brackets() {
                     format!("( {}, )", s)
                 } else {
                     format!("({},)", s)
@@ -2772,6 +2606,7 @@ fn rewrite_tuple_in_visual_indent_style<'a, T>(
         context.codemap,
         items,
         ")",
+        ",",
         |item| item.span().lo(),
         |item| item.span().hi(),
         |item| item.rewrite(context, nested_shape),
@@ -2798,7 +2633,7 @@ fn rewrite_tuple_in_visual_indent_style<'a, T>(
     };
     let list_str = write_list(&item_vec, &fmt)?;
 
-    if context.config.spaces_within_parens() && !list_str.is_empty() {
+    if context.config.spaces_within_parens_and_brackets() && !list_str.is_empty() {
         Some(format!("( {} )", list_str))
     } else {
         Some(format!("({})", list_str))
@@ -2828,7 +2663,7 @@ pub fn rewrite_tuple<'a, T>(
             items,
             span,
             shape,
-            context.config.fn_call_width(),
+            context.config.width_heuristics().fn_call_width,
             force_trailing_comma,
         )
     } else {
@@ -2899,10 +2734,10 @@ fn rewrite_assignment(
 
 // The left hand side must contain everything up to, and including, the
 // assignment operator.
-pub fn rewrite_assign_rhs<S: Into<String>>(
+pub fn rewrite_assign_rhs<S: Into<String>, R: Rewrite>(
     context: &RewriteContext,
     lhs: S,
-    ex: &ast::Expr,
+    ex: &R,
     shape: Shape,
 ) -> Option<String> {
     let lhs = lhs.into();
@@ -2917,9 +2752,9 @@ pub fn rewrite_assign_rhs<S: Into<String>>(
     Some(lhs + &rhs)
 }
 
-fn choose_rhs(
+pub fn choose_rhs<R: Rewrite>(
     context: &RewriteContext,
-    expr: &ast::Expr,
+    expr: &R,
     shape: Shape,
     orig_rhs: Option<String>,
 ) -> Option<String> {
@@ -2938,6 +2773,12 @@ fn choose_rhs(
             let new_indent_str = &new_shape.indent.to_string(context.config);
 
             match (orig_rhs, new_rhs) {
+                (Some(ref orig_rhs), Some(ref new_rhs))
+                    if wrap_str(new_rhs.clone(), context.config.max_width(), new_shape)
+                        .is_none() =>
+                {
+                    Some(format!(" {}", orig_rhs))
+                }
                 (Some(ref orig_rhs), Some(ref new_rhs)) if prefer_next_line(orig_rhs, new_rhs) => {
                     Some(format!("\n{}{}", new_indent_str, new_rhs))
                 }