]> git.lizzy.rs Git - rust.git/blobdiff - src/items.rs
Remove BlockIndentStyle::Inherit
[rust.git] / src / items.rs
index 457c6749520f8706240aa4d5f96f3b4adf3ec411..445959f63b0a004f65b1b20b4bae1655e3edb911 100644 (file)
 use {Indent, Shape};
 use codemap::SpanUtils;
 use utils::{format_mutability, format_visibility, contains_skip, end_typaram, wrap_str,
-            last_line_width, format_unsafety, trim_newlines, stmt_expr, semicolon_for_expr};
-use lists::{write_list, itemize_list, ListItem, ListFormatting, SeparatorTactic,
+            last_line_width, format_unsafety, trim_newlines, stmt_expr, semicolon_for_expr,
+            trimmed_last_line_width};
+use lists::{write_list, itemize_list, ListItem, ListFormatting, SeparatorTactic, list_helper,
             DefinitiveListTactic, ListTactic, definitive_tactic, format_item_list};
 use expr::{is_empty_block, is_simple_block_stmt, rewrite_assign_rhs, type_annotation_separator};
 use comment::{FindUncommented, contains_comment};
 use visitor::FmtVisitor;
 use rewrite::{Rewrite, RewriteContext};
-use config::{Config, BlockIndentStyle, Density, ReturnIndent, BraceStyle, FnArgLayoutStyle};
+use config::{Config, BlockIndentStyle, Density, ReturnIndent, BraceStyle, FnArgLayoutStyle, Style};
 use itertools::Itertools;
 
 use syntax::{ast, abi, codemap, ptr, symbol};
@@ -40,9 +41,8 @@ fn rewrite(&self, context: &RewriteContext, shape: Shape) -> Option<String> {
         // 1 = ;
         let pattern_width = try_opt!(shape.width.checked_sub(pattern_offset.width() + 1));
 
-        let pat_str = try_opt!(self.pat
-                                   .rewrite(&context,
-                                            Shape::legacy(pattern_width, pattern_offset)));
+        let pat_str = try_opt!(self.pat.rewrite(&context,
+                                                Shape::legacy(pattern_width, pattern_offset)));
         result.push_str(&pat_str);
 
         // String that is placed within the assignment pattern and expression.
@@ -106,7 +106,10 @@ fn from_foreign_mod(fm: &'a ast::ForeignMod, span: Span, config: &Config) -> Ite
             keyword: "",
             abi: abi,
             vis: None,
-            body: fm.items.iter().map(|i| BodyElement::ForeignItem(i)).collect(),
+            body: fm.items
+                .iter()
+                .map(|i| BodyElement::ForeignItem(i))
+                .collect(),
             span: span,
         }
     }
@@ -188,6 +191,7 @@ fn format_foreign_item(&mut self, item: &ast::ForeignItem) {
                                               &item.vis,
                                               span,
                                               false,
+                                              false,
                                               false);
 
                 match rewrite {
@@ -255,7 +259,8 @@ pub fn rewrite_fn(&mut self,
                                                                          vis,
                                                                          span,
                                                                          newline_brace,
-                                                                         has_body));
+                                                                         has_body,
+                                                                         true));
 
         if self.config.fn_brace_style != BraceStyle::AlwaysNextLine && !result.contains('\n') {
             newline_brace = false;
@@ -300,6 +305,7 @@ pub fn rewrite_required_fn(&mut self,
                                                        &ast::Visibility::Inherited,
                                                        span,
                                                        false,
+                                                       false,
                                                        false));
 
         // Re-attach semicolon
@@ -434,7 +440,7 @@ fn format_variant_list(&self,
         let fmt = ListFormatting {
             tactic: DefinitiveListTactic::Vertical,
             separator: ",",
-            trailing_separator: SeparatorTactic::from_bool(self.config.enum_trailing_comma),
+            trailing_separator: self.config.trailing_comma,
             shape: Shape::legacy(budget, self.block_indent),
             ends_with_newline: true,
             config: self.config,
@@ -455,12 +461,10 @@ fn format_variant(&self, field: &ast::Variant) -> Option<String> {
         }
 
         let indent = self.block_indent;
-        let mut result = try_opt!(field.node
-                                      .attrs
-                                      .rewrite(&self.get_context(),
-                                               Shape::legacy(self.config.max_width -
-                                                             indent.width(),
-                                                             indent)));
+        let mut result = try_opt!(field.node.attrs.rewrite(&self.get_context(),
+                                                           Shape::legacy(self.config.max_width -
+                                                                         indent.width(),
+                                                                         indent)));
         if !result.is_empty() {
             result.push('\n');
             result.push_str(&indent.to_string(self.config));
@@ -520,13 +524,13 @@ pub fn format_impl(context: &RewriteContext, item: &ast::Item, offset: Indent) -
         let where_budget = try_opt!(context.config.max_width.checked_sub(last_line_width(&result)));
         let where_clause_str = try_opt!(rewrite_where_clause(context,
                                                              &generics.where_clause,
-                                                             context.config,
                                                              context.config.item_brace_style,
                                                              Shape::legacy(where_budget,
                                                                            offset.block_only()),
                                                              context.config.where_density,
                                                              "{",
-                                                             true,
+                                                             false,
+                                                             last_line_width(&ref_and_type) == 1,
                                                              None));
 
         if try_opt!(is_impl_single_line(context, &items, &result, &where_clause_str, &item)) {
@@ -625,7 +629,7 @@ fn format_impl_ref_and_type(context: &RewriteContext,
         item.node {
         let mut result = String::new();
 
-        result.push_str(&*format_visibility(&item.vis));
+        result.push_str(&format_visibility(&item.vis));
         result.push_str(format_unsafety(unsafety));
         result.push_str("impl");
 
@@ -649,8 +653,9 @@ fn format_impl_ref_and_type(context: &RewriteContext,
             if polarity != ast::ImplPolarity::Negative {
                 result.push_str(" ");
             }
-            let budget = try_opt!(context.config.max_width.checked_sub(result.len()));
-            let indent = offset + result.len();
+            let used_space = last_line_width(&result);
+            let budget = try_opt!(context.config.max_width.checked_sub(used_space));
+            let indent = offset + used_space;
             result.push_str(&*try_opt!(trait_ref.rewrite(context, Shape::legacy(budget, indent))));
 
             if split_at_for {
@@ -763,7 +768,7 @@ pub fn format_trait(context: &RewriteContext, item: &ast::Item, offset: Indent)
         // If the trait, generics, and trait bound cannot fit on the same line,
         // put the trait bounds on an indented new line
         if offset.width() + last_line_width(&result) + trait_bound_str.len() >
-           context.config.ideal_width {
+           context.config.comment_width {
             result.push('\n');
             let trait_indent = offset.block_only().block_indent(context.config);
             result.push_str(&trait_indent.to_string(context.config));
@@ -784,24 +789,23 @@ pub fn format_trait(context: &RewriteContext, item: &ast::Item, offset: Indent)
                 Density::Tall
             };
 
-        let where_budget = try_opt!(context.config
-                                        .max_width
-                                        .checked_sub(last_line_width(&result)));
+        let where_budget = try_opt!(context.config.max_width.checked_sub(last_line_width(&result)));
         let where_clause_str = try_opt!(rewrite_where_clause(context,
                                                              &generics.where_clause,
-                                                             context.config,
                                                              context.config.item_brace_style,
                                                              Shape::legacy(where_budget,
                                                                            offset.block_only()),
                                                              where_density,
                                                              "{",
-                                                             has_body,
+                                                             !has_body,
+                                                             trait_bound_str.is_empty() &&
+                                                             last_line_width(&generics_str) == 1,
                                                              None));
         // If the where clause cannot fit on the same line,
         // put the where clause on a new line
         if !where_clause_str.contains('\n') &&
            last_line_width(&result) + where_clause_str.len() + offset.width() >
-           context.config.ideal_width {
+           context.config.comment_width {
             result.push('\n');
             let width = offset.block_indent + context.config.tab_spaces - 1;
             let where_indent = Indent::new(0, width);
@@ -952,7 +956,7 @@ fn format_struct_struct(context: &RewriteContext,
     let fmt = ListFormatting {
         tactic: tactic,
         separator: ",",
-        trailing_separator: context.config.struct_trailing_comma,
+        trailing_separator: context.config.trailing_comma,
         shape: Shape::legacy(budget, item_indent),
         ends_with_newline: true,
         config: context.config,
@@ -1000,26 +1004,33 @@ fn format_tuple_struct(context: &RewriteContext,
                                                          mk_sp(span.lo, body_lo)));
             result.push_str(&generics_str);
 
-            let where_budget = try_opt!(context.config
-                                            .max_width
-                                            .checked_sub(last_line_width(&result)));
+            let where_budget =
+                try_opt!(context.config.max_width.checked_sub(last_line_width(&result)));
             try_opt!(rewrite_where_clause(context,
                                           &generics.where_clause,
-                                          context.config,
                                           context.config.item_brace_style,
                                           Shape::legacy(where_budget, offset.block_only()),
                                           Density::Compressed,
                                           ";",
+                                          true,
                                           false,
                                           None))
         }
         None => "".to_owned(),
     };
-    result.push('(');
 
-    let item_indent = offset.block_only() + result.len();
-    // 2 = ");"
-    let item_budget = try_opt!(context.config.max_width.checked_sub(item_indent.width() + 2));
+    let (tactic, item_indent) = match context.config.fn_args_layout {
+        FnArgLayoutStyle::Visual => {
+            // 1 = `(`
+            (ListTactic::HorizontalVertical, offset.block_only() + result.len() + 1)
+        }
+        FnArgLayoutStyle::Block |
+        FnArgLayoutStyle::BlockAlways => {
+            (ListTactic::HorizontalVertical, offset.block_only().block_indent(&context.config))
+        }
+    };
+    // 3 = `();`
+    let item_budget = try_opt!(context.config.max_width.checked_sub(item_indent.width() + 3));
 
     let items =
         itemize_list(context.codemap,
@@ -1037,27 +1048,41 @@ fn format_tuple_struct(context: &RewriteContext,
                      |field| field.rewrite(context, Shape::legacy(item_budget, item_indent)),
                      context.codemap.span_after(span, "("),
                      span.hi);
-    let body = try_opt!(format_item_list(items,
-                                         Shape::legacy(item_budget, item_indent),
-                                         context.config));
-
-    if context.config.spaces_within_parens && body.len() > 0 {
-        result.push(' ');
-    }
+    let body_budget = try_opt!(context.config.max_width.checked_sub(offset.block_only().width() +
+                                                                    result.len() +
+                                                                    3));
+    let body = try_opt!(list_helper(items,
+                                    // TODO budget is wrong in block case
+                                    Shape::legacy(body_budget, item_indent),
+                                    context.config,
+                                    tactic));
+
+    if context.config.fn_args_layout == FnArgLayoutStyle::Visual || !body.contains('\n') {
+        result.push('(');
+        if context.config.spaces_within_parens && body.len() > 0 {
+            result.push(' ');
+        }
 
-    result.push_str(&body);
+        result.push_str(&body);
 
-    if context.config.spaces_within_parens && body.len() > 0 {
-        result.push(' ');
+        if context.config.spaces_within_parens && body.len() > 0 {
+            result.push(' ');
+        }
+        result.push(')');
+    } else {
+        result.push_str("(\n");
+        result.push_str(&item_indent.to_string(&context.config));
+        result.push_str(&body);
+        result.push('\n');
+        result.push_str(&offset.block_only().to_string(&context.config));
+        result.push(')');
     }
 
-    result.push(')');
-
     if !where_clause_str.is_empty() && !where_clause_str.contains('\n') &&
        (result.contains('\n') ||
         offset.block_indent + result.len() + where_clause_str.len() + 1 >
         context.config.max_width) {
-        // We need to put the where clause on a new line, but we didn'to_string
+        // We need to put the where clause on a new line, but we didn't
         // know that earlier, so the where clause will not be indented properly.
         result.push('\n');
         result.push_str(&(offset.block_only() + (context.config.tab_spaces - 1))
@@ -1093,17 +1118,15 @@ pub fn rewrite_type_alias(context: &RewriteContext,
 
     result.push_str(&generics_str);
 
-    let where_budget = try_opt!(context.config
-                                    .max_width
-                                    .checked_sub(last_line_width(&result)));
+    let where_budget = try_opt!(context.config.max_width.checked_sub(last_line_width(&result)));
     let where_clause_str = try_opt!(rewrite_where_clause(context,
                                                          &generics.where_clause,
-                                                         context.config,
                                                          context.config.item_brace_style,
                                                          Shape::legacy(where_budget, indent),
                                                          context.config.where_density,
                                                          "=",
-                                                         false,
+                                                         true,
+                                                         true,
                                                          Some(span.hi)));
     result.push_str(&where_clause_str);
     result.push_str(" = ");
@@ -1117,8 +1140,7 @@ pub fn rewrite_type_alias(context: &RewriteContext,
         .unwrap_or(0);
     let type_indent = indent + line_width;
     // Try to fit the type on the same line
-    let ty_str = try_opt!(ty.rewrite(context, Shape::legacy(budget, type_indent))
-                              .or_else(|| {
+    let ty_str = try_opt!(ty.rewrite(context, Shape::legacy(budget, type_indent)).or_else(|| {
         // The line was too short, try to put the type on the next line
 
         // Remove the space after '='
@@ -1126,9 +1148,8 @@ pub fn rewrite_type_alias(context: &RewriteContext,
         let type_indent = indent.block_indent(context.config);
         result.push('\n');
         result.push_str(&type_indent.to_string(context.config));
-        let budget = try_opt!(context.config
-                                  .max_width
-                                  .checked_sub(type_indent.width() + ";".len()));
+        let budget = try_opt!(context.config.max_width.checked_sub(type_indent.width() +
+                                                                   ";".len()));
         ty.rewrite(context, Shape::legacy(budget, type_indent))
     }));
     result.push_str(&ty_str);
@@ -1158,11 +1179,10 @@ fn rewrite(&self, context: &RewriteContext, shape: Shape) -> Option<String> {
 
         let name = self.ident;
         let vis = format_visibility(&self.vis);
-        let mut attr_str = try_opt!(self.attrs
-                                        .rewrite(context,
-                                                 Shape::legacy(context.config.max_width -
-                                                               shape.indent.width(),
-                                                               shape.indent)));
+        let mut attr_str = try_opt!(self.attrs.rewrite(context,
+                                                       Shape::legacy(context.config.max_width -
+                                                                     shape.indent.width(),
+                                                                     shape.indent)));
         if !attr_str.is_empty() {
             attr_str.push('\n');
             attr_str.push_str(&shape.indent.to_string(context.config));
@@ -1289,8 +1309,9 @@ fn rewrite(&self, context: &RewriteContext, shape: Shape) -> Option<String> {
             ast::FunctionRetTy::Default(_) => Some(String::new()),
             ast::FunctionRetTy::Ty(ref ty) => {
                 let inner_width = try_opt!(shape.width.checked_sub(3));
-                ty.rewrite(context, Shape::legacy(inner_width, shape.indent + 3))
-                    .map(|r| format!("-> {}", r))
+                ty.rewrite(context, Shape::legacy(inner_width, shape.indent + 3)).map(|r| {
+                    format!("-> {}", r)
+                })
             }
         }
     }
@@ -1299,9 +1320,8 @@ fn rewrite(&self, context: &RewriteContext, shape: Shape) -> Option<String> {
 impl Rewrite for ast::Arg {
     fn rewrite(&self, context: &RewriteContext, shape: Shape) -> Option<String> {
         if is_named_arg(self) {
-            let mut result = try_opt!(self.pat
-                                          .rewrite(context,
-                                                   Shape::legacy(shape.width, shape.indent)));
+            let mut result = try_opt!(self.pat.rewrite(context,
+                                                       Shape::legacy(shape.width, shape.indent)));
 
             if self.ty.node != ast::TyKind::Infer {
                 if context.config.space_before_type_annotation {
@@ -1438,7 +1458,8 @@ fn rewrite_fn_base(context: &RewriteContext,
                    vis: &ast::Visibility,
                    span: Span,
                    newline_brace: bool,
-                   has_body: bool)
+                   has_body: bool,
+                   has_braces: bool)
                    -> Option<(String, bool)> {
     let mut force_new_line_for_brace = false;
 
@@ -1476,13 +1497,14 @@ fn rewrite_fn_base(context: &RewriteContext,
                                                  generics_span));
     result.push_str(&generics_str);
 
-    // Note that if the width and indent really matter, we'll re-layout the
+    let snuggle_angle_bracket = last_line_width(&generics_str) == 1;
+
+    // Note that the width and indent don't really matter, we'll re-layout the
     // return type later anyway.
-    let ret_str = try_opt!(fd.output
-                               .rewrite(&context,
-                                        Shape::legacy(context.config.max_width -
-                                                      indent.width(),
-                                                      indent)));
+    let ret_str = try_opt!(fd.output.rewrite(&context,
+                                             Shape::legacy(context.config.max_width -
+                                                           indent.width(),
+                                                           indent)));
 
     let multi_line_ret_str = ret_str.contains('\n');
     let ret_str_len = if multi_line_ret_str { 0 } else { ret_str.len() };
@@ -1504,7 +1526,9 @@ fn rewrite_fn_base(context: &RewriteContext,
 
     // Check if vertical layout was forced.
     if one_line_budget == 0 {
-        if context.config.fn_args_paren_newline {
+        if snuggle_angle_bracket {
+            result.push_str("(");
+        } else if context.config.fn_args_paren_newline {
             result.push('\n');
             result.push_str(&arg_indent.to_string(context.config));
             arg_indent = arg_indent + 1; // extra space for `(`
@@ -1528,9 +1552,7 @@ fn rewrite_fn_base(context: &RewriteContext,
     }
 
     // A conservative estimation, to goal is to be over all parens in generics
-    let args_start = generics.ty_params
-        .last()
-        .map_or(span.lo, |tp| end_typaram(tp));
+    let args_start = generics.ty_params.last().map_or(span.lo, |tp| end_typaram(tp));
     let args_span = mk_sp(context.codemap.span_after(mk_sp(args_start, span.hi), "("),
                           span_for_return(&fd.output).lo);
     let arg_str = try_opt!(rewrite_args(context,
@@ -1546,7 +1568,7 @@ fn rewrite_fn_base(context: &RewriteContext,
     let multi_line_arg_str = arg_str.contains('\n');
 
     let put_args_in_block = match context.config.fn_args_layout {
-        FnArgLayoutStyle::Block => multi_line_arg_str,
+        FnArgLayoutStyle::Block => multi_line_arg_str || generics_str.contains('\n'),
         FnArgLayoutStyle::BlockAlways => true,
         _ => false,
     } && !fd.inputs.is_empty();
@@ -1613,7 +1635,7 @@ fn rewrite_fn_base(context: &RewriteContext,
             Indent::new(indent.width(), result.len())
         };
 
-        if multi_line_ret_str {
+        if multi_line_ret_str || ret_should_indent {
             // Now that we know the proper indent and width, we need to
             // re-layout the return type.
             let budget = try_opt!(context.config.max_width.checked_sub(ret_indent.width()));
@@ -1646,29 +1668,41 @@ fn rewrite_fn_base(context: &RewriteContext,
         _ => false,
     } || (put_args_in_block && ret_str.is_empty());
 
-    let where_density = if should_compress_where {
-        Density::Compressed
-    } else {
-        Density::Tall
-    };
+    if where_clause.predicates.len() == 1 && should_compress_where {
+        let budget = try_opt!(context.config.max_width.checked_sub(last_line_width(&result)));
+        if let Some(where_clause_str) =
+            rewrite_where_clause(context,
+                                 where_clause,
+                                 context.config.fn_brace_style,
+                                 Shape::legacy(budget, indent),
+                                 Density::Compressed,
+                                 "{",
+                                 !has_braces,
+                                 put_args_in_block && ret_str.is_empty(),
+                                 Some(span.hi)) {
+            if !where_clause_str.contains('\n') {
+                if last_line_width(&result) + where_clause_str.len() > context.config.max_width {
+                    result.push('\n');
+                }
 
-    // Where clause.
-    let where_budget = try_opt!(context.config.max_width.checked_sub(last_line_width(&result)));
+                result.push_str(&where_clause_str);
+
+                return Some((result, force_new_line_for_brace));
+            }
+        }
+    }
+
+    let budget = try_opt!(context.config.max_width.checked_sub(indent.block_indent));
     let where_clause_str = try_opt!(rewrite_where_clause(context,
                                                          where_clause,
-                                                         context.config,
                                                          context.config.fn_brace_style,
-                                                         Shape::legacy(where_budget, indent),
-                                                         where_density,
+                                                         Shape::legacy(budget, indent),
+                                                         Density::Tall,
                                                          "{",
-                                                         has_body,
+                                                         !has_braces,
+                                                         put_args_in_block && ret_str.is_empty(),
                                                          Some(span.hi)));
 
-    if last_line_width(&result) + where_clause_str.len() > context.config.max_width &&
-       !where_clause_str.contains('\n') {
-        result.push('\n');
-    }
-
     result.push_str(&where_clause_str);
 
     Some((result, force_new_line_for_brace))
@@ -1731,7 +1765,12 @@ enum ArgumentKind<'a> {
         }
 
         let variadic_arg = if variadic {
-            let variadic_span = mk_sp(args.last().unwrap().ty.span.hi, span.hi);
+            let variadic_span = mk_sp(args.last()
+                                          .unwrap()
+                                          .ty
+                                          .span
+                                          .hi,
+                                      span.hi);
             let variadic_start = context.codemap.span_after(variadic_span, "...") - BytePos(3);
             Some(ArgumentKind::Variadic(variadic_start))
         } else {
@@ -1767,7 +1806,6 @@ enum ArgumentKind<'a> {
     }
 
     let indent = match context.config.fn_arg_indent {
-        BlockIndentStyle::Inherit => indent,
         BlockIndentStyle::Tabbed => indent.block_indent(context.config),
         BlockIndentStyle::Visual => arg_indent,
     };
@@ -1782,16 +1820,16 @@ enum ArgumentKind<'a> {
 
     debug!("rewrite_args: budget: {}, tactic: {:?}", budget, tactic);
 
-    let end_with_newline = match context.config.fn_args_layout {
-        FnArgLayoutStyle::Block |
-        FnArgLayoutStyle::BlockAlways => true,
-        _ => false,
+    let (trailing_comma, end_with_newline) = match context.config.fn_args_layout {
+        FnArgLayoutStyle::Block => (SeparatorTactic::Vertical, true),
+        FnArgLayoutStyle::BlockAlways => (SeparatorTactic::Always, true),
+        _ => (SeparatorTactic::Never, false),
     };
 
     let fmt = ListFormatting {
         tactic: tactic,
         separator: ",",
-        trailing_separator: SeparatorTactic::Never,
+        trailing_separator: trailing_comma,
         shape: Shape::legacy(budget, indent),
         ends_with_newline: end_with_newline,
         config: context.config,
@@ -1826,7 +1864,10 @@ fn compute_budgets_for_args(context: &RewriteContext,
         if !newline_brace {
             used_space += 2;
         }
-        let one_line_budget = context.config.max_width.checked_sub(used_space).unwrap_or(0);
+        let one_line_budget = context.config
+            .max_width
+            .checked_sub(used_space)
+            .unwrap_or(0);
 
         if one_line_budget > 0 {
             // 4 = "() {".len()
@@ -1873,7 +1914,6 @@ fn rewrite_generics(context: &RewriteContext,
     }
 
     let offset = match context.config.generics_indent {
-        BlockIndentStyle::Inherit => shape.indent,
         BlockIndentStyle::Tabbed => shape.indent.block_indent(context.config),
         // 1 = <
         BlockIndentStyle::Visual => generics_offset + 1,
@@ -1884,8 +1924,8 @@ fn rewrite_generics(context: &RewriteContext,
 
     // Strings for the generics.
     let lt_strs = lifetimes.iter().map(|lt| lt.rewrite(context, Shape::legacy(h_budget, offset)));
-    let ty_strs = tys.iter()
-        .map(|ty_param| ty_param.rewrite(context, Shape::legacy(h_budget, offset)));
+    let ty_strs =
+        tys.iter().map(|ty_param| ty_param.rewrite(context, Shape::legacy(h_budget, offset)));
 
     // Extract comments between generics.
     let lt_spans = lifetimes.iter().map(|l| {
@@ -1910,11 +1950,18 @@ fn rewrite_generics(context: &RewriteContext,
     let list_str =
         try_opt!(format_item_list(items, Shape::legacy(h_budget, offset), context.config));
 
-    Some(if context.config.spaces_within_angle_brackets {
-             format!("< {} >", list_str)
-         } else {
-             format!("<{}>", list_str)
-         })
+    let result = if context.config.generics_indent != BlockIndentStyle::Visual &&
+                    list_str.contains('\n') {
+        format!("<\n{}{}\n{}>",
+                offset.to_string(context.config),
+                list_str,
+                shape.indent.to_string(context.config))
+    } else if context.config.spaces_within_angle_brackets {
+        format!("< {} >", list_str)
+    } else {
+        format!("<{}>", list_str)
+    };
+    Some(result)
 }
 
 fn rewrite_trait_bounds(context: &RewriteContext,
@@ -1938,28 +1985,101 @@ fn rewrite_trait_bounds(context: &RewriteContext,
     Some(result)
 }
 
+//   fn reflow_list_node_with_rule(
+//        &self,
+//        node: &CompoundNode,
+//        rule: &Rule,
+//        args: &[Arg],
+//        shape: &Shape
+//    ) -> Result<String, ()>
+//    where
+//        T: Foo,
+//    {
+
+
+fn rewrite_where_clause_rfc_style(context: &RewriteContext,
+                                  where_clause: &ast::WhereClause,
+                                  shape: Shape,
+                                  terminator: &str,
+                                  suppress_comma: bool,
+                                  // where clause can be kept on the current line.
+                                  snuggle: bool,
+                                  span_end: Option<BytePos>)
+                                  -> Option<String> {
+    let block_shape = shape.block();
+
+    let starting_newline = if snuggle {
+        " ".to_owned()
+    } else {
+        "\n".to_owned() + &block_shape.indent.to_string(context.config)
+    };
+
+    let clause_shape = block_shape.block_indent(context.config.tab_spaces);
+    // each clause on one line, trailing comma (except if suppress_comma)
+    let span_start = span_for_where_pred(&where_clause.predicates[0]).lo;
+    // If we don't have the start of the next span, then use the end of the
+    // predicates, but that means we miss comments.
+    let len = where_clause.predicates.len();
+    let end_of_preds = span_for_where_pred(&where_clause.predicates[len - 1]).hi;
+    let span_end = span_end.unwrap_or(end_of_preds);
+    let items = itemize_list(context.codemap,
+                             where_clause.predicates.iter(),
+                             terminator,
+                             |pred| span_for_where_pred(pred).lo,
+                             |pred| span_for_where_pred(pred).hi,
+                             |pred| pred.rewrite(context, clause_shape),
+                             span_start,
+                             span_end);
+    let comma_tactic = if suppress_comma {
+        SeparatorTactic::Never
+    } else {
+        SeparatorTactic::Always
+    };
+
+    let fmt = ListFormatting {
+        tactic: DefinitiveListTactic::Vertical,
+        separator: ",",
+        trailing_separator: comma_tactic,
+        shape: clause_shape,
+        ends_with_newline: true,
+        config: context.config,
+    };
+    let preds_str = try_opt!(write_list(items, &fmt));
+
+    Some(format!("{}where\n{}{}",
+                 starting_newline,
+                 clause_shape.indent.to_string(context.config),
+                 preds_str))
+}
+
 fn rewrite_where_clause(context: &RewriteContext,
                         where_clause: &ast::WhereClause,
-                        config: &Config,
                         brace_style: BraceStyle,
                         shape: Shape,
                         density: Density,
                         terminator: &str,
-                        allow_trailing_comma: bool,
+                        suppress_comma: bool,
+                        snuggle: bool,
                         span_end: Option<BytePos>)
                         -> Option<String> {
     if where_clause.predicates.is_empty() {
         return Some(String::new());
     }
 
-    let extra_indent = match context.config.where_indent {
-        BlockIndentStyle::Inherit => Indent::empty(),
-        BlockIndentStyle::Tabbed | BlockIndentStyle::Visual => Indent::new(config.tab_spaces, 0),
-    };
+    if context.config.where_style == Style::Rfc {
+        return rewrite_where_clause_rfc_style(context,
+                                              where_clause,
+                                              shape,
+                                              terminator,
+                                              suppress_comma,
+                                              snuggle,
+                                              span_end);
+    }
+
+    let extra_indent = Indent::new(context.config.tab_spaces, 0);
 
     let offset = match context.config.where_pred_indent {
-        BlockIndentStyle::Inherit => shape.indent + extra_indent,
-        BlockIndentStyle::Tabbed => shape.indent + extra_indent.block_indent(config),
+        BlockIndentStyle::Tabbed => shape.indent + extra_indent.block_indent(context.config),
         // 6 = "where ".len()
         BlockIndentStyle::Visual => shape.indent + extra_indent + 6,
     };
@@ -1985,12 +2105,17 @@ fn rewrite_where_clause(context: &RewriteContext,
     // FIXME: we don't need to collect here if the where_layout isn't
     // HorizontalVertical.
     let tactic = definitive_tactic(&item_vec, context.config.where_layout, budget);
-    let use_trailing_comma = allow_trailing_comma && context.config.where_trailing_comma;
+
+    let mut comma_tactic = context.config.trailing_comma;
+    // Kind of a hack because we don't usually have trailing commas in where clauses.
+    if comma_tactic == SeparatorTactic::Vertical || suppress_comma {
+        comma_tactic = SeparatorTactic::Never;
+    }
 
     let fmt = ListFormatting {
         tactic: tactic,
         separator: ",",
-        trailing_separator: SeparatorTactic::from_bool(use_trailing_comma),
+        trailing_separator: comma_tactic,
         shape: Shape::legacy(budget, offset),
         ends_with_newline: true,
         config: context.config,
@@ -2042,18 +2167,21 @@ fn format_generics(context: &RewriteContext,
 
     if !generics.where_clause.predicates.is_empty() || result.contains('\n') {
         let budget = try_opt!(context.config.max_width.checked_sub(last_line_width(&result)));
-        let where_clause_str = try_opt!(rewrite_where_clause(context,
-                                                             &generics.where_clause,
-                                                             context.config,
-                                                             brace_style,
-                                                             Shape::legacy(budget,
-                                                                           offset.block_only()),
-                                                             Density::Tall,
-                                                             terminator,
-                                                             true,
-                                                             Some(span.hi)));
+        let where_clause_str =
+            try_opt!(rewrite_where_clause(context,
+                                          &generics.where_clause,
+                                          brace_style,
+                                          Shape::legacy(budget, offset.block_only()),
+                                          Density::Tall,
+                                          terminator,
+                                          false,
+                                          trimmed_last_line_width(&result) == 1,
+                                          Some(span.hi)));
         result.push_str(&where_clause_str);
-        if !force_same_line_brace &&
+        let same_line_brace = force_same_line_brace ||
+                              (generics.where_clause.predicates.is_empty() &&
+                               trimmed_last_line_width(&result) == 1);
+        if !same_line_brace &&
            (brace_style == BraceStyle::SameLineWhere || brace_style == BraceStyle::AlwaysNextLine) {
             result.push('\n');
             result.push_str(&offset.block_only().to_string(context.config));
@@ -2062,11 +2190,12 @@ fn format_generics(context: &RewriteContext,
         }
         result.push_str(opener);
     } else {
-        if !force_same_line_brace && brace_style == BraceStyle::AlwaysNextLine {
+        if force_same_line_brace || trimmed_last_line_width(&result) == 1 ||
+           brace_style != BraceStyle::AlwaysNextLine {
+            result.push(' ');
+        } else {
             result.push('\n');
             result.push_str(&offset.block_only().to_string(context.config));
-        } else {
-            result.push(' ');
         }
         result.push_str(opener);
     }