From 9eefc6fc8d113e80f92de53ae756cb5203e173b1 Mon Sep 17 00:00:00 2001 From: topecongiro Date: Sat, 10 Jun 2017 18:24:23 +0900 Subject: [PATCH 01/12] Share codes when rewriting generics --- src/items.rs | 75 ++++++++++++++----- src/types.rs | 25 +++---- tests/target/configs-generics_indent-block.rs | 2 +- tests/target/fn-custom-2.rs | 6 +- tests/target/fn-custom-3.rs | 6 +- 5 files changed, 72 insertions(+), 42 deletions(-) diff --git a/src/items.rs b/src/items.rs index bbbe75ddf780..03ca6f608325 100644 --- a/src/items.rs +++ b/src/items.rs @@ -16,7 +16,7 @@ use utils::{format_mutability, format_visibility, contains_skip, end_typaram, wr last_line_width, format_unsafety, trim_newlines, stmt_expr, semicolon_for_expr, trimmed_last_line_width, colon_spaces, mk_sp}; use lists::{write_list, itemize_list, ListItem, ListFormatting, SeparatorTactic, list_helper, - DefinitiveListTactic, ListTactic, definitive_tactic, format_item_list}; + DefinitiveListTactic, ListTactic, definitive_tactic}; use expr::{is_empty_block, is_simple_block_stmt, rewrite_assign_rhs}; use comment::{FindUncommented, contains_comment, rewrite_comment, recover_comment_removed}; use visitor::FmtVisitor; @@ -2111,21 +2111,13 @@ fn rewrite_generics(context: &RewriteContext, return Some(String::new()); } - let offset = match context.config.generics_indent() { - IndentStyle::Block => shape.indent.block_only().block_indent(context.config), - // 1 = < - IndentStyle::Visual => shape.indent + 1, - }; - - let h_budget = try_opt!(shape.width.checked_sub(2)); - // FIXME: might need to insert a newline if the generics are really long. - + let generics_shape = generics_shape_from_config(context.config, shape, 0); // Strings for the generics. let lt_strs = lifetimes .iter() - .map(|lt| lt.rewrite(context, Shape::legacy(h_budget, offset))); + .map(|lt| lt.rewrite(context, generics_shape)); let ty_strs = tys.iter() - .map(|ty_param| ty_param.rewrite(context, Shape::legacy(h_budget, offset))); + .map(|ty_param| ty_param.rewrite(context, generics_shape)); // Extract comments between generics. let lt_spans = lifetimes.iter().map(|l| { @@ -2147,21 +2139,64 @@ fn rewrite_generics(context: &RewriteContext, |&(_, ref str)| str.clone(), context.codemap.span_after(span, "<"), span.hi); - let list_str = - try_opt!(format_item_list(items, Shape::legacy(h_budget, offset), context.config)); + format_generics_item_list(context, items, generics_shape, generics_shape.width) +} - let result = if context.config.generics_indent() != IndentStyle::Visual && - list_str.contains('\n') { +pub fn generics_shape_from_config(config: &Config, shape: Shape, offset: usize) -> Shape { + Shape { + // 2 = `<>` + width: shape.width.checked_sub(offset + 2).unwrap_or(0), + ..match config.generics_indent() { + IndentStyle::Visual => shape.visual_indent(1 + offset), + IndentStyle::Block => shape.block().block_indent(config.tab_spaces()), + } + } +} + +pub fn format_generics_item_list(context: &RewriteContext, + items: I, + shape: Shape, + one_line_budget: usize) + -> Option + where I: Iterator +{ + let item_vec = items.collect::>(); + + let fmt = ListFormatting { + tactic: definitive_tactic(&item_vec, ListTactic::HorizontalVertical, one_line_budget), + separator: ",", + trailing_separator: if context.config.generics_indent() == IndentStyle::Visual { + SeparatorTactic::Never + } else { + context.config.trailing_comma() + }, + shape: shape, + ends_with_newline: false, + config: context.config, + }; + + let list_str = try_opt!(write_list(&item_vec, &fmt)); + + Some(wrap_generics_with_angle_brackets(context, &list_str, shape.indent)) +} + +pub fn wrap_generics_with_angle_brackets(context: &RewriteContext, + list_str: &str, + list_offset: Indent) + -> String { + if context.config.generics_indent() == IndentStyle::Block && + (list_str.contains('\n') || list_str.ends_with(',')) { format!("<\n{}{}\n{}>", - offset.to_string(context.config), + list_offset.to_string(context.config), list_str, - shape.indent.block_only().to_string(context.config)) + list_offset + .block_unindent(context.config) + .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, diff --git a/src/types.rs b/src/types.rs index 7dfc43371789..4e74ea8213f1 100644 --- a/src/types.rs +++ b/src/types.rs @@ -19,7 +19,8 @@ use syntax::symbol::keywords; use {Shape, Spanned}; use codemap::SpanUtils; -use lists::{format_item_list, itemize_list, format_fn_args}; +use items::{format_generics_item_list, generics_shape_from_config}; +use lists::{itemize_list, format_fn_args}; use rewrite::{Rewrite, RewriteContext}; use utils::{extra_offset, format_mutability, colon_spaces, wrap_str, mk_sp}; use expr::{rewrite_unary_prefix, rewrite_pair, rewrite_tuple_type}; @@ -213,31 +214,25 @@ fn rewrite_segment(path_context: PathContext, "" }; - // 1 for < - let extra_offset = 1 + separator.len(); - // 1 for > - // TODO bad visual indent - let list_shape = try_opt!(try_opt!(shape.shrink_left(extra_offset)).sub_width(1)) - .visual_indent(0); - + let generics_shape = + generics_shape_from_config(context.config, shape, separator.len()); let items = itemize_list(context.codemap, param_list.into_iter(), ">", |param| param.get_span().lo, |param| param.get_span().hi, - |seg| seg.rewrite(context, list_shape), + |seg| seg.rewrite(context, generics_shape), list_lo, span_hi); - let list_str = try_opt!(format_item_list(items, list_shape, context.config)); + let generics_str = try_opt!(format_generics_item_list(context, + items, + generics_shape, + generics_shape.width)); // Update position of last bracket. *span_lo = next_span_lo; - if context.config.spaces_within_angle_brackets() && list_str.len() > 0 { - format!("{}< {} >", separator, list_str) - } else { - format!("{}<{}>", separator, list_str) - } + format!("{}{}", separator, generics_str) } ast::PathParameters::Parenthesized(ref data) => { let output = match data.output { diff --git a/tests/target/configs-generics_indent-block.rs b/tests/target/configs-generics_indent-block.rs index 789243c02c30..848e59c7c0ae 100644 --- a/tests/target/configs-generics_indent-block.rs +++ b/tests/target/configs-generics_indent-block.rs @@ -8,7 +8,7 @@ fn lorem< Amet: Eq = usize, Adipiscing: Eq = usize, Consectetur: Eq = usize, - Elit: Eq = usize + Elit: Eq = usize, >(ipsum: Ipsum, dolor: Dolor, sit: Sit, diff --git a/tests/target/fn-custom-2.rs b/tests/target/fn-custom-2.rs index e9ba39f666cb..f0923bd1a853 100644 --- a/tests/target/fn-custom-2.rs +++ b/tests/target/fn-custom-2.rs @@ -16,7 +16,7 @@ fn foo( fn bar< 'a: 'bbbbbbbbbbbbbbbbbbbbbbbbbbb, TTTTTTTTTTTTT, - UUUUUUUUUUUUUUUUUUUU: WWWWWWWWWWWWWWWWWWWWWWWW + UUUUUUUUUUUUUUUUUUUU: WWWWWWWWWWWWWWWWWWWWWWWW, >( a: Aaaaaaaaaaaaaaa, ) { @@ -51,7 +51,7 @@ impl Foo { fn bar< 'a: 'bbbbbbbbbbbbbbbbbbbbbbbbbbb, TTTTTTTTTTTTT, - UUUUUUUUUUUUUUUUUUUU: WWWWWWWWWWWWWWWWWWWWWWWW + UUUUUUUUUUUUUUUUUUUU: WWWWWWWWWWWWWWWWWWWWWWWW, >( a: Aaaaaaaaaaaaaaa, ) { @@ -69,7 +69,7 @@ struct Foo< TTTTTTTTTTTTTTTTTTTTTTTTTTTT, UUUUUUUUUUUUUUUUUUUUUU, VVVVVVVVVVVVVVVVVVVVVVVVVVV, - WWWWWWWWWWWWWWWWWWWWWWWW + WWWWWWWWWWWWWWWWWWWWWWWW, > { foo: Foo, } diff --git a/tests/target/fn-custom-3.rs b/tests/target/fn-custom-3.rs index a29aac411ba9..4d26c9b69519 100644 --- a/tests/target/fn-custom-3.rs +++ b/tests/target/fn-custom-3.rs @@ -16,7 +16,7 @@ fn foo( fn bar< 'a: 'bbbbbbbbbbbbbbbbbbbbbbbbbbb, TTTTTTTTTTTTT, - UUUUUUUUUUUUUUUUUUUU: WWWWWWWWWWWWWWWWWWWWWWWW + UUUUUUUUUUUUUUUUUUUU: WWWWWWWWWWWWWWWWWWWWWWWW, >( a: Aaaaaaaaaaaaaaa, ) { @@ -53,7 +53,7 @@ impl Foo { fn bar< 'a: 'bbbbbbbbbbbbbbbbbbbbbbbbbbb, TTTTTTTTTTTTT, - UUUUUUUUUUUUUUUUUUUU: WWWWWWWWWWWWWWWWWWWWWWWW + UUUUUUUUUUUUUUUUUUUU: WWWWWWWWWWWWWWWWWWWWWWWW, >( a: Aaaaaaaaaaaaaaa, ) { @@ -65,7 +65,7 @@ struct Foo< TTTTTTTTTTTTTTTTTTTTTTTTTTTT, UUUUUUUUUUUUUUUUUUUUUU, VVVVVVVVVVVVVVVVVVVVVVVVVVV, - WWWWWWWWWWWWWWWWWWWWWWWW + WWWWWWWWWWWWWWWWWWWWWWWW, > { foo: Foo, } From 88e522f921dad2f50b78f16dcd24ac256c8bf7c8 Mon Sep 17 00:00:00 2001 From: topecongiro Date: Sat, 10 Jun 2017 19:45:23 +0900 Subject: [PATCH 02/12] Use multiline in generics rather than fail --- src/items.rs | 169 +++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 124 insertions(+), 45 deletions(-) diff --git a/src/items.rs b/src/items.rs index 03ca6f608325..f228bdf9d08e 100644 --- a/src/items.rs +++ b/src/items.rs @@ -530,7 +530,9 @@ pub fn format_impl(context: &RewriteContext, if let ast::ItemKind::Impl(_, _, _, ref generics, ref trait_ref, _, ref items) = item.node { let mut result = String::new(); // First try to format the ref and type without a split at the 'for'. - let mut ref_and_type = try_opt!(format_impl_ref_and_type(context, item, offset, false)); + let mut ref_and_type = + format_impl_ref_and_type(context, item, offset, false) + .unwrap_or(try_opt!(format_impl_ref_and_type(context, item, offset, true))); // If there is a line break present in the first result format it again // with a split at the 'for'. Skip this if there is no trait ref and @@ -540,10 +542,15 @@ pub fn format_impl(context: &RewriteContext, } result.push_str(&ref_and_type); - let where_budget = try_opt!(context - .config - .max_width() - .checked_sub(last_line_width(&result))); + let where_budget = if result.contains('\n') { + context.config.max_width() + } else { + context + .config + .max_width() + .checked_sub(last_line_width(&result)) + .unwrap_or(0) + }; let where_clause_str = try_opt!(rewrite_where_clause(context, &generics.where_clause, context.config.item_brace_style(), @@ -666,34 +673,89 @@ fn format_impl_ref_and_type(context: &RewriteContext, None => self_ty.span.lo, }; let generics_indent = offset + last_line_width(&result); - let shape = Shape::indented(generics_indent, context.config); - let generics_str = try_opt!(rewrite_generics(context, generics, shape, mk_sp(lo, hi))); - result.push_str(&generics_str); + let shape = generics_shape_from_config(context.config, + Shape::indented(generics_indent, context.config), + 0); + let mut generics_str = + try_opt!(rewrite_generics(context, generics, shape, shape.width, mk_sp(lo, hi))); if polarity == ast::ImplPolarity::Negative { - result.push_str(" !"); + generics_str.push_str(" !"); } + + let mut retry_with_multiline = true; if let Some(ref trait_ref) = *trait_ref { if polarity != ast::ImplPolarity::Negative { - result.push_str(" "); + generics_str.push_str(" "); } - 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 { - result.push('\n'); - - // Add indentation of one additional tab. - let width = offset.block_indent + context.config.tab_spaces(); - let for_indent = Indent::new(0, width); - result.push_str(&for_indent.to_string(context.config)); - - result.push_str("for"); + let used_space = if generics_str.contains('\n') { + last_line_width(&generics_str) } else { - result.push_str(" for"); + result.len() + generics_str.len() + }; + let budget = context + .config + .max_width() + .checked_sub(used_space) + .unwrap_or(0); + let indent = offset + used_space; + if let Some(trait_ref_str) = trait_ref.rewrite(context, Shape::legacy(budget, indent)) { + if !trait_ref_str.contains('\n') { + result.push_str(&generics_str); + result.push_str(&trait_ref_str); + if split_at_for { + result.push('\n'); + // Add indentation of one additional tab. + result.push_str(&offset + .block_indent(context.config) + .to_string(context.config)); + result.push_str("for"); + } else { + result.push_str(" for"); + } + retry_with_multiline = false; + } } + if retry_with_multiline { + let mut generics_str = + try_opt!(rewrite_generics(context, generics, shape, 0, mk_sp(lo, hi))); + if polarity == ast::ImplPolarity::Negative { + generics_str.push_str(" !"); + } else { + generics_str.push_str(" "); + } + let used_space = if generics_str.contains('\n') { + last_line_width(&generics_str) + } else { + result.len() + generics_str.len() + }; + let budget = context + .config + .max_width() + .checked_sub(used_space) + .unwrap_or(0); + let indent = offset + used_space; + if let Some(trait_ref_str) = + trait_ref.rewrite(context, Shape::legacy(budget, indent)) { + result.push_str(&generics_str); + result.push_str(&trait_ref_str); + if split_at_for { + result.push('\n'); + // Add indentation of one additional tab. + result.push_str(&offset + .block_indent(context.config) + .to_string(context.config)); + result.push_str("for"); + } else { + result.push_str(" for"); + } + } + } + } else { + if polarity == ast::ImplPolarity::Negative { + generics_str.push_str(" "); + } + result.push_str(&generics_str); } let mut used_space = last_line_width(&result); @@ -709,7 +771,7 @@ fn format_impl_ref_and_type(context: &RewriteContext, // 1 = space before the type. let budget = try_opt!(context.config.max_width().checked_sub(used_space + 1)); - let indent = offset + result.len() + 1; + let indent = offset + last_line_width(&result) + 1; let self_ty_str = self_ty.rewrite(context, Shape::legacy(budget, indent)); if let Some(self_ty_str) = self_ty_str { result.push_str(" "); @@ -778,9 +840,14 @@ pub fn format_trait(context: &RewriteContext, item: &ast::Item, offset: Indent) let body_lo = context.codemap.span_after(item.span, "{"); let generics_indent = offset + last_line_width(&result); - let shape = Shape::indented(generics_indent, context.config); - let generics_str = - try_opt!(rewrite_generics(context, generics, shape, mk_sp(item.span.lo, body_lo))); + let shape = generics_shape_from_config(context.config, + Shape::indented(generics_indent, context.config), + 0); + let generics_str = try_opt!(rewrite_generics(context, + generics, + shape, + shape.width, + mk_sp(item.span.lo, body_lo))); result.push_str(&generics_str); let trait_bound_str = @@ -1025,9 +1092,15 @@ fn format_tuple_struct(context: &RewriteContext, let where_clause_str = match generics { Some(generics) => { let generics_indent = offset + last_line_width(&header_str); - let shape = Shape::indented(generics_indent, context.config); - let generics_str = - try_opt!(rewrite_generics(context, generics, shape, mk_sp(span.lo, body_lo))); + let shape = generics_shape_from_config(context.config, + Shape::indented(generics_indent, + context.config), + 0); + let generics_str = try_opt!(rewrite_generics(context, + generics, + shape, + shape.width, + mk_sp(span.lo, body_lo))); result.push_str(&generics_str); let where_budget = try_opt!(context @@ -1156,8 +1229,13 @@ pub fn rewrite_type_alias(context: &RewriteContext, let generics_indent = indent + result.len(); let generics_span = mk_sp(context.codemap.span_after(span, "type"), ty.span.lo); - let shape = try_opt!(Shape::indented(generics_indent, context.config).sub_width(" =".len())); - let generics_str = try_opt!(rewrite_generics(context, generics, shape, generics_span)); + let shape = generics_shape_from_config(context.config, + try_opt!(Shape::indented(generics_indent, + context.config) + .sub_width(" =".len())), + 0); + let generics_str = + try_opt!(rewrite_generics(context, generics, shape, shape.width, generics_span)); result.push_str(&generics_str); @@ -1635,8 +1713,11 @@ fn rewrite_fn_base(context: &RewriteContext, // Generics. let generics_indent = indent + last_line_width(&result); let generics_span = mk_sp(span.lo, span_for_return(&fd.output).lo); - let shape = Shape::indented(generics_indent, context.config); - let generics_str = try_opt!(rewrite_generics(context, generics, shape, generics_span)); + let shape = generics_shape_from_config(context.config, + Shape::indented(generics_indent, context.config), + 0); + let generics_str = + try_opt!(rewrite_generics(context, generics, shape, shape.width, generics_span)); result.push_str(&generics_str); let snuggle_angle_bracket = generics_str @@ -2101,6 +2182,7 @@ fn newline_for_brace(config: &Config, where_clause: &ast::WhereClause) -> bool { fn rewrite_generics(context: &RewriteContext, generics: &ast::Generics, shape: Shape, + one_line_width: usize, span: Span) -> Option { // FIXME: convert bounds to where clauses where they get too big or if @@ -2111,13 +2193,9 @@ fn rewrite_generics(context: &RewriteContext, return Some(String::new()); } - let generics_shape = generics_shape_from_config(context.config, shape, 0); // Strings for the generics. - let lt_strs = lifetimes - .iter() - .map(|lt| lt.rewrite(context, generics_shape)); - let ty_strs = tys.iter() - .map(|ty_param| ty_param.rewrite(context, generics_shape)); + let lt_strs = lifetimes.iter().map(|lt| lt.rewrite(context, shape)); + let ty_strs = tys.iter().map(|ty_param| ty_param.rewrite(context, shape)); // Extract comments between generics. let lt_spans = lifetimes.iter().map(|l| { @@ -2139,7 +2217,7 @@ fn rewrite_generics(context: &RewriteContext, |&(_, ref str)| str.clone(), context.codemap.span_after(span, "<"), span.hi); - format_generics_item_list(context, items, generics_shape, generics_shape.width) + format_generics_item_list(context, items, shape, one_line_width) } pub fn generics_shape_from_config(config: &Config, shape: Shape, offset: usize) -> Shape { @@ -2385,8 +2463,9 @@ fn format_generics(context: &RewriteContext, offset: Indent, span: Span) -> Option { - let shape = Shape::indented(offset, context.config); - let mut result = try_opt!(rewrite_generics(context, generics, shape, span)); + let shape = + generics_shape_from_config(context.config, Shape::indented(offset, context.config), 0); + let mut result = try_opt!(rewrite_generics(context, generics, shape, shape.width, span)); if !generics.where_clause.predicates.is_empty() || result.contains('\n') { let budget = try_opt!(context From bd80077be89b3e8584d8c93af263e38c0e156d5b Mon Sep 17 00:00:00 2001 From: topecongiro Date: Sat, 10 Jun 2017 20:37:34 +0900 Subject: [PATCH 03/12] Add format_trait_ref_then_update_result --- src/items.rs | 136 +++++++++++++++++------------------ tests/source/big-impl-rfc.rs | 114 +++++++++++++++++++++++++++++ tests/target/big-impl-rfc.rs | 65 +++++++++++++++++ 3 files changed, 245 insertions(+), 70 deletions(-) create mode 100644 tests/source/big-impl-rfc.rs create mode 100644 tests/target/big-impl-rfc.rs diff --git a/src/items.rs b/src/items.rs index f228bdf9d08e..a0b50bd50b71 100644 --- a/src/items.rs +++ b/src/items.rs @@ -678,83 +678,30 @@ fn format_impl_ref_and_type(context: &RewriteContext, 0); let mut generics_str = try_opt!(rewrite_generics(context, generics, shape, shape.width, mk_sp(lo, hi))); + add_polarity(&mut generics_str, &polarity, trait_ref.is_some()); - if polarity == ast::ImplPolarity::Negative { - generics_str.push_str(" !"); - } - - let mut retry_with_multiline = true; if let Some(ref trait_ref) = *trait_ref { - if polarity != ast::ImplPolarity::Negative { - generics_str.push_str(" "); - } - let used_space = if generics_str.contains('\n') { - last_line_width(&generics_str) - } else { - result.len() + generics_str.len() - }; - let budget = context - .config - .max_width() - .checked_sub(used_space) - .unwrap_or(0); - let indent = offset + used_space; - if let Some(trait_ref_str) = trait_ref.rewrite(context, Shape::legacy(budget, indent)) { - if !trait_ref_str.contains('\n') { - result.push_str(&generics_str); - result.push_str(&trait_ref_str); - if split_at_for { - result.push('\n'); - // Add indentation of one additional tab. - result.push_str(&offset - .block_indent(context.config) - .to_string(context.config)); - result.push_str("for"); - } else { - result.push_str(" for"); - } - retry_with_multiline = false; - } - } - if retry_with_multiline { + let success = format_trait_ref_then_update_result(context, + &trait_ref, + offset, + &generics_str, + split_at_for, + &mut result); + if !success { let mut generics_str = try_opt!(rewrite_generics(context, generics, shape, 0, mk_sp(lo, hi))); - if polarity == ast::ImplPolarity::Negative { - generics_str.push_str(" !"); - } else { - generics_str.push_str(" "); - } - let used_space = if generics_str.contains('\n') { - last_line_width(&generics_str) - } else { - result.len() + generics_str.len() - }; - let budget = context - .config - .max_width() - .checked_sub(used_space) - .unwrap_or(0); - let indent = offset + used_space; - if let Some(trait_ref_str) = - trait_ref.rewrite(context, Shape::legacy(budget, indent)) { - result.push_str(&generics_str); - result.push_str(&trait_ref_str); - if split_at_for { - result.push('\n'); - // Add indentation of one additional tab. - result.push_str(&offset - .block_indent(context.config) - .to_string(context.config)); - result.push_str("for"); - } else { - result.push_str(" for"); - } + add_polarity(&mut generics_str, &polarity, true); + if !format_trait_ref_then_update_result(context, + &trait_ref, + offset, + &generics_str, + split_at_for, + &mut result) { + // FIXME: should be unreachable + return None; } } } else { - if polarity == ast::ImplPolarity::Negative { - generics_str.push_str(" "); - } result.push_str(&generics_str); } @@ -790,6 +737,55 @@ fn format_impl_ref_and_type(context: &RewriteContext, } } +// Returns false if failed to update result: then, try using multiline. +fn format_trait_ref_then_update_result(context: &RewriteContext, + trait_ref: &ast::TraitRef, + offset: Indent, + generics_str: &str, + split_at_for: bool, + result: &mut String) + -> bool { + let used_space = if generics_str.contains('\n') { + last_line_width(&generics_str) + } else { + result.len() + generics_str.len() + }; + let budget = context + .config + .max_width() + .checked_sub(used_space) + .unwrap_or(0); + let indent = offset + used_space; + if let Some(trait_ref_str) = trait_ref.rewrite(context, Shape::legacy(budget, indent)) { + if !trait_ref_str.contains('\n') { + result.push_str(&generics_str); + result.push_str(&trait_ref_str); + if split_at_for { + result.push('\n'); + // Add indentation of one additional tab. + let for_offset = match context.config.where_style() { + Style::Legacy => offset.block_indent(context.config), + Style::Rfc => offset, + }; + result.push_str(&for_offset.to_string(context.config)); + result.push_str("for"); + } else { + result.push_str(" for"); + } + return true; + } + } + false +} + +fn add_polarity(s: &mut String, polarity: &ast::ImplPolarity, has_trait_ref: bool) { + if polarity == &ast::ImplPolarity::Negative { + s.push_str(" !") + } else if has_trait_ref { + s.push(' ') + } +} + pub fn format_struct(context: &RewriteContext, item_name: &str, ident: ast::Ident, diff --git a/tests/source/big-impl-rfc.rs b/tests/source/big-impl-rfc.rs new file mode 100644 index 000000000000..167f654cc439 --- /dev/null +++ b/tests/source/big-impl-rfc.rs @@ -0,0 +1,114 @@ +// rustfmt-fn_args_layout: Block +// rustfmt-fn_call_style: Block +// rustfmt-generics_indent: Block +// rustfmt-where_style: Rfc + +// #1357 +impl< + 'a, + Select, + From, + Distinct, + Where, + Order, + Limit, + Offset, + Groupby, + DB, +> InternalBoxedDsl<'a, DB> + for SelectStatement< + Select, + From, + Distinct, + Where, + Order, + Limit, + Offset, + GroupBy, + > where + DB: Backend, + Select: QueryFragment + SelectableExpression + 'a, + Distinct: QueryFragment + 'a, + Where: Into + 'a>>>, + Order: QueryFragment + 'a, + Limit: QueryFragment + 'a, + Offset: QueryFragment + 'a, +{ + type Output = BoxedSelectStatement<'a, Select::SqlTypeForSelect, From, DB>; + + fn internal_into_boxed(self) -> Self::Output { + BoxedSelectStatement::new( + Box::new(self.select), + self.from, + Box::new(self.distinct), + self.where_clause.into(), + Box::new(self.order), + Box::new(self.limit), + Box::new(self.offset), + ) + } +} + +// #1369 +impl< + ExcessivelyLongGenericName, + ExcessivelyLongGenericName, + AnotherExcessivelyLongGenericName, +> Foo for Bar { + fn foo() {} +} +impl Foo< + ExcessivelyLongGenericName, + ExcessivelyLongGenericName, + AnotherExcessivelyLongGenericName, +> for Bar { + fn foo() {} +} +impl< + ExcessivelyLongGenericName, + ExcessivelyLongGenericName, + AnotherExcessivelyLongGenericName, +> Foo< + ExcessivelyLongGenericName, + ExcessivelyLongGenericName, + AnotherExcessivelyLongGenericName, +> for Bar { + fn foo() {} +} +impl< + ExcessivelyLongGenericName, + ExcessivelyLongGenericName, + AnotherExcessivelyLongGenericName, +> Foo for Bar< + ExcessivelyLongGenericName, + ExcessivelyLongGenericName, + AnotherExcessivelyLongGenericName, +> { + fn foo() {} +} +impl Foo< + ExcessivelyLongGenericName, + ExcessivelyLongGenericName, + AnotherExcessivelyLongGenericName, +> for Bar< + ExcessivelyLongGenericName, + ExcessivelyLongGenericName, + AnotherExcessivelyLongGenericName, +> { + fn foo() {} +} +impl< + ExcessivelyLongGenericName, + ExcessivelyLongGenericName, + AnotherExcessivelyLongGenericName, +> Foo< + ExcessivelyLongGenericName, + ExcessivelyLongGenericName, + AnotherExcessivelyLongGenericName, +> for Bar< + ExcessivelyLongGenericName, + ExcessivelyLongGenericName, + AnotherExcessivelyLongGenericName, +> { + fn foo() {} +} diff --git a/tests/target/big-impl-rfc.rs b/tests/target/big-impl-rfc.rs new file mode 100644 index 000000000000..18fa59cb5a0e --- /dev/null +++ b/tests/target/big-impl-rfc.rs @@ -0,0 +1,65 @@ +// rustfmt-fn_args_layout: Block +// rustfmt-fn_call_style: Block +// rustfmt-generics_indent: Block +// rustfmt-where_style: Rfc + +// #1357 +impl<'a, Select, From, Distinct, Where, Order, Limit, Offset, Groupby, DB> InternalBoxedDsl<'a, DB> +for SelectStatement +where + DB: Backend, + Select: QueryFragment + SelectableExpression + 'a, + Distinct: QueryFragment + 'a, + Where: Into + 'a>>>, + Order: QueryFragment + 'a, + Limit: QueryFragment + 'a, + Offset: QueryFragment + 'a, +{ + type Output = BoxedSelectStatement<'a, Select::SqlTypeForSelect, From, DB>; + + fn internal_into_boxed(self) -> Self::Output { + BoxedSelectStatement::new( + Box::new(self.select), + self.from, + Box::new(self.distinct), + self.where_clause.into(), + Box::new(self.order), + Box::new(self.limit), + Box::new(self.offset), + ) + } +} + +// #1369 +impl Foo +for Bar { + fn foo() {} +} +impl Foo +for Bar { + fn foo() {} +} +impl< + ExcessivelyLongGenericName, + ExcessivelyLongGenericName, + AnotherExcessivelyLongGenericName, +> Foo +for Bar { + fn foo() {} +} +impl Foo +for Bar { + fn foo() {} +} +impl Foo +for Bar { + fn foo() {} +} +impl< + ExcessivelyLongGenericName, + ExcessivelyLongGenericName, + AnotherExcessivelyLongGenericName, +> Foo +for Bar { + fn foo() {} +} From 9b195ae228be1c74b2ccdc83697219e35439b01f Mon Sep 17 00:00:00 2001 From: topecongiro Date: Sun, 11 Jun 2017 14:32:44 +0900 Subject: [PATCH 04/12] Refactor format_impl --- src/items.rs | 160 ++++++++++++++++++++++++++------------------------- 1 file changed, 82 insertions(+), 78 deletions(-) diff --git a/src/items.rs b/src/items.rs index a0b50bd50b71..10ab6fe72dfe 100644 --- a/src/items.rs +++ b/src/items.rs @@ -527,19 +527,9 @@ pub fn format_impl(context: &RewriteContext, offset: Indent, where_span_end: Option) -> Option { - if let ast::ItemKind::Impl(_, _, _, ref generics, ref trait_ref, _, ref items) = item.node { + if let ast::ItemKind::Impl(_, _, _, ref generics, _, _, ref items) = item.node { let mut result = String::new(); - // First try to format the ref and type without a split at the 'for'. - let mut ref_and_type = - format_impl_ref_and_type(context, item, offset, false) - .unwrap_or(try_opt!(format_impl_ref_and_type(context, item, offset, true))); - - // If there is a line break present in the first result format it again - // with a split at the 'for'. Skip this if there is no trait ref and - // therefore no 'for'. - if ref_and_type.contains('\n') && trait_ref.is_some() { - ref_and_type = try_opt!(format_impl_ref_and_type(context, item, offset, true)); - } + let ref_and_type = try_opt!(format_impl_ref_and_type(context, item, offset)); result.push_str(&ref_and_type); let where_budget = if result.contains('\n') { @@ -651,8 +641,7 @@ fn is_impl_single_line(context: &RewriteContext, fn format_impl_ref_and_type(context: &RewriteContext, item: &ast::Item, - offset: Indent, - split_at_for: bool) + offset: Indent) -> Option { if let ast::ItemKind::Impl(unsafety, polarity, @@ -672,32 +661,37 @@ fn format_impl_ref_and_type(context: &RewriteContext, Some(ref tr) => tr.path.span.lo, None => self_ty.span.lo, }; - let generics_indent = offset + last_line_width(&result); let shape = generics_shape_from_config(context.config, - Shape::indented(generics_indent, context.config), + Shape::indented(offset + last_line_width(&result), + context.config), 0); - let mut generics_str = + let generics_str = try_opt!(rewrite_generics(context, generics, shape, shape.width, mk_sp(lo, hi))); - add_polarity(&mut generics_str, &polarity, trait_ref.is_some()); + + let polarity_str = if polarity == ast::ImplPolarity::Negative { + "!" + } else { + "" + }; if let Some(ref trait_ref) = *trait_ref { let success = format_trait_ref_then_update_result(context, &trait_ref, offset, &generics_str, - split_at_for, + true, + polarity_str, &mut result); if !success { - let mut generics_str = + let generics_str = try_opt!(rewrite_generics(context, generics, shape, 0, mk_sp(lo, hi))); - add_polarity(&mut generics_str, &polarity, true); if !format_trait_ref_then_update_result(context, &trait_ref, offset, &generics_str, - split_at_for, + false, + polarity_str, &mut result) { - // FIXME: should be unreachable return None; } } @@ -705,32 +699,52 @@ fn format_impl_ref_and_type(context: &RewriteContext, result.push_str(&generics_str); } - let mut used_space = last_line_width(&result); - if generics.where_clause.predicates.is_empty() { + // Try to put the self type in a single line. + // ` for` + let trait_ref_overhead = if trait_ref.is_some() { 4 } else { 0 }; + let curly_brace_overhead = if generics.where_clause.predicates.is_empty() { // If there is no where clause adapt budget for type formatting to take space and curly // brace into account. match context.config.item_brace_style() { - BraceStyle::AlwaysNextLine => {} - BraceStyle::PreferSameLine => used_space += 2, - BraceStyle::SameLineWhere => used_space += 2, + BraceStyle::AlwaysNextLine => 0, + _ => 2, + } + } else { + 0 + }; + let used_space = last_line_width(&result) + trait_ref_overhead + curly_brace_overhead; + // 1 = space before the type. + let budget = context + .config + .max_width() + .checked_sub(used_space + 1) + .unwrap_or(0); + if let Some(self_ty_str) = self_ty.rewrite(context, Shape::legacy(budget, offset)) { + if !self_ty_str.contains('\n') { + if trait_ref.is_some() { + result.push_str(" for "); + } else { + result.push(' '); + } + result.push_str(&self_ty_str); + return Some(result); } } - // 1 = space before the type. - let budget = try_opt!(context.config.max_width().checked_sub(used_space + 1)); - let indent = offset + last_line_width(&result) + 1; - let self_ty_str = self_ty.rewrite(context, Shape::legacy(budget, indent)); - if let Some(self_ty_str) = self_ty_str { - result.push_str(" "); - result.push_str(&self_ty_str); - return Some(result); + // Couldn't fit the self type on a single line, put it on a new line. + result.push('\n'); + // Add indentation of one additional tab. + let new_line_offset = offset.block_indent(context.config); + result.push_str(&new_line_offset.to_string(context.config)); + if trait_ref.is_some() { + result.push_str("for "); } - - // Can't fit the self type on what's left of the line, so start a new one. - let indent = offset.block_indent(context.config); - result.push_str(&format!("\n{}", indent.to_string(context.config))); - result.push_str(&*try_opt!(self_ty.rewrite(context, - Shape::indented(indent, context.config)))); + let budget = context.config.max_width() - last_line_width(&result); + let type_offset = match context.config.where_style() { + Style::Legacy => new_line_offset + trait_ref_overhead, + Style::Rfc => new_line_offset, + }; + result.push_str(&*try_opt!(self_ty.rewrite(context, Shape::legacy(budget, type_offset)))); Some(result) } else { unreachable!(); @@ -742,50 +756,40 @@ fn format_trait_ref_then_update_result(context: &RewriteContext, trait_ref: &ast::TraitRef, offset: Indent, generics_str: &str, - split_at_for: bool, + retry: bool, + polarity_str: &str, result: &mut String) -> bool { - let used_space = if generics_str.contains('\n') { - last_line_width(&generics_str) - } else { - result.len() + generics_str.len() - }; - let budget = context - .config - .max_width() - .checked_sub(used_space) - .unwrap_or(0); - let indent = offset + used_space; - if let Some(trait_ref_str) = trait_ref.rewrite(context, Shape::legacy(budget, indent)) { - if !trait_ref_str.contains('\n') { - result.push_str(&generics_str); - result.push_str(&trait_ref_str); - if split_at_for { - result.push('\n'); - // Add indentation of one additional tab. - let for_offset = match context.config.where_style() { - Style::Legacy => offset.block_indent(context.config), - Style::Rfc => offset, - }; - result.push_str(&for_offset.to_string(context.config)); - result.push_str("for"); - } else { - result.push_str(" for"); - } + // 1 = space between generics and trait_ref + let used_space = 1 + polarity_str.len() + + if generics_str.contains('\n') { + last_line_width(&generics_str) + } else { + result.len() + generics_str.len() + }; + let shape = Shape::indented(offset + used_space, context.config); + if let Some(trait_ref_str) = trait_ref.rewrite(context, shape) { + if !(retry && trait_ref_str.contains('\n')) { + result.push_str(&format!("{} {}{}", generics_str, polarity_str, &trait_ref_str)); + return true; + } + } + // We could not make enough space for trait_ref, so put it on new line. + if !retry { + let offset = offset.block_indent(context.config); + let shape = Shape::indented(offset, context.config); + if let Some(trait_ref_str) = trait_ref.rewrite(context, shape) { + result.push_str(&format!("{}\n{}{}{}", + generics_str, + &offset.to_string(context.config), + polarity_str, + &trait_ref_str)); return true; } } false } -fn add_polarity(s: &mut String, polarity: &ast::ImplPolarity, has_trait_ref: bool) { - if polarity == &ast::ImplPolarity::Negative { - s.push_str(" !") - } else if has_trait_ref { - s.push(' ') - } -} - pub fn format_struct(context: &RewriteContext, item_name: &str, ident: ast::Ident, From f135641cc873c21ea8768a78534efc9ff3f4bb82 Mon Sep 17 00:00:00 2001 From: topecongiro Date: Sun, 11 Jun 2017 23:26:49 +0900 Subject: [PATCH 05/12] Use multi line when type bounds does not fit in a single line --- src/expr.rs | 2 +- src/items.rs | 107 ++++++++++++++++++--------------------------------- src/types.rs | 100 +++++++++++++++++++++-------------------------- 3 files changed, 82 insertions(+), 127 deletions(-) diff --git a/src/expr.rs b/src/expr.rs index aa5913e5f0fa..04778b6ddcab 100644 --- a/src/expr.rs +++ b/src/expr.rs @@ -2063,12 +2063,12 @@ fn rewrite_struct_lit<'a>(context: &RewriteContext, // FIXME if context.config.struct_lit_style() == Visual, but we run out // of space, we should fall back to BlockIndent. } + 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()) } - fn rewrite_field(context: &RewriteContext, field: &ast::Field, shape: Shape) -> Option { let name = &field.ident.node.to_string(); if field.is_shorthand { diff --git a/src/items.rs b/src/items.rs index 10ab6fe72dfe..78226624c4f0 100644 --- a/src/items.rs +++ b/src/items.rs @@ -21,7 +21,8 @@ use expr::{is_empty_block, is_simple_block_stmt, rewrite_assign_rhs}; use comment::{FindUncommented, contains_comment, rewrite_comment, recover_comment_removed}; use visitor::FmtVisitor; use rewrite::{Rewrite, RewriteContext}; -use config::{Config, IndentStyle, Density, ReturnIndent, BraceStyle, Style, TypeDensity}; +use config::{Config, IndentStyle, Density, ReturnIndent, BraceStyle, Style}; +use types::join_bounds; use syntax::{ast, abi, ptr, symbol}; use syntax::codemap::{Span, BytePos}; @@ -666,7 +667,7 @@ fn format_impl_ref_and_type(context: &RewriteContext, context.config), 0); let generics_str = - try_opt!(rewrite_generics(context, generics, shape, shape.width, mk_sp(lo, hi))); + try_opt!(rewrite_generics_inner(context, generics, shape, shape.width, mk_sp(lo, hi))); let polarity_str = if polarity == ast::ImplPolarity::Negative { "!" @@ -684,7 +685,7 @@ fn format_impl_ref_and_type(context: &RewriteContext, &mut result); if !success { let generics_str = - try_opt!(rewrite_generics(context, generics, shape, 0, mk_sp(lo, hi))); + try_opt!(rewrite_generics_inner(context, generics, shape, 0, mk_sp(lo, hi))); if !format_trait_ref_then_update_result(context, &trait_ref, offset, @@ -839,15 +840,9 @@ pub fn format_trait(context: &RewriteContext, item: &ast::Item, offset: Indent) let body_lo = context.codemap.span_after(item.span, "{"); - let generics_indent = offset + last_line_width(&result); - let shape = generics_shape_from_config(context.config, - Shape::indented(generics_indent, context.config), - 0); - let generics_str = try_opt!(rewrite_generics(context, - generics, - shape, - shape.width, - mk_sp(item.span.lo, body_lo))); + let shape = Shape::indented(offset + last_line_width(&result), context.config); + let generics_str = + try_opt!(rewrite_generics(context, generics, shape, mk_sp(item.span.lo, body_lo))); result.push_str(&generics_str); let trait_bound_str = @@ -1091,16 +1086,9 @@ fn format_tuple_struct(context: &RewriteContext, let where_clause_str = match generics { Some(generics) => { - let generics_indent = offset + last_line_width(&header_str); - let shape = generics_shape_from_config(context.config, - Shape::indented(generics_indent, - context.config), - 0); - let generics_str = try_opt!(rewrite_generics(context, - generics, - shape, - shape.width, - mk_sp(span.lo, body_lo))); + let shape = Shape::indented(offset + last_line_width(&header_str), context.config); + let g_span = mk_sp(span.lo, body_lo); + let generics_str = try_opt!(rewrite_generics(context, generics, shape, g_span)); result.push_str(&generics_str); let where_budget = try_opt!(context @@ -1227,16 +1215,10 @@ pub fn rewrite_type_alias(context: &RewriteContext, result.push_str("type "); result.push_str(&ident.to_string()); - let generics_indent = indent + result.len(); - let generics_span = mk_sp(context.codemap.span_after(span, "type"), ty.span.lo); - let shape = generics_shape_from_config(context.config, - try_opt!(Shape::indented(generics_indent, - context.config) - .sub_width(" =".len())), - 0); - let generics_str = - try_opt!(rewrite_generics(context, generics, shape, shape.width, generics_span)); - + // 2 = `= ` + let shape = try_opt!(Shape::indented(indent + result.len(), context.config).sub_width(2)); + let g_span = mk_sp(context.codemap.span_after(span, "type"), ty.span.lo); + let generics_str = try_opt!(rewrite_generics(context, generics, shape, g_span)); result.push_str(&generics_str); let where_budget = try_opt!(context @@ -1470,23 +1452,14 @@ pub fn rewrite_associated_type(ident: ast::Ident, let prefix = format!("type {}", ident); let type_bounds_str = if let Some(ty_param_bounds) = ty_param_bounds_opt { - let joiner = match context.config.type_punctuation_density() { - TypeDensity::Compressed => "+", - TypeDensity::Wide => " + ", - }; + let shape = Shape::legacy(context.config.max_width(), indent); let bounds: &[_] = ty_param_bounds; - let bound_str = - try_opt!(bounds - .iter() - .map(|ty_bound| { - ty_bound.rewrite(context, - Shape::legacy(context.config.max_width(), - indent)) - }) - .collect::>>()) - .join(joiner); + let bound_str = try_opt!(bounds + .iter() + .map(|ty_bound| ty_bound.rewrite(context, shape)) + .collect::>>()); if bounds.len() > 0 { - format!(": {}", bound_str) + format!(": {}", join_bounds(context, shape, &bound_str)) } else { String::new() } @@ -1711,13 +1684,9 @@ fn rewrite_fn_base(context: &RewriteContext, result.push_str(&ident.to_string()); // Generics. - let generics_indent = indent + last_line_width(&result); - let generics_span = mk_sp(span.lo, span_for_return(&fd.output).lo); - let shape = generics_shape_from_config(context.config, - Shape::indented(generics_indent, context.config), - 0); - let generics_str = - try_opt!(rewrite_generics(context, generics, shape, shape.width, generics_span)); + let shape = Shape::indented(indent + last_line_width(&result), context.config); + let g_span = mk_sp(span.lo, span_for_return(&fd.output).lo); + let generics_str = try_opt!(rewrite_generics(context, generics, shape, g_span)); result.push_str(&generics_str); let snuggle_angle_bracket = generics_str @@ -2182,9 +2151,19 @@ fn newline_for_brace(config: &Config, where_clause: &ast::WhereClause) -> bool { fn rewrite_generics(context: &RewriteContext, generics: &ast::Generics, shape: Shape, - one_line_width: usize, span: Span) -> Option { + let shape = generics_shape_from_config(context.config, shape, 0); + rewrite_generics_inner(context, generics, shape, shape.width, span) + .or_else(|| rewrite_generics_inner(context, generics, shape, 0, span)) +} + +fn rewrite_generics_inner(context: &RewriteContext, + generics: &ast::Generics, + shape: Shape, + one_line_width: usize, + span: Span) + -> Option { // FIXME: convert bounds to where clauses where they get too big or if // there is a where clause at all. let lifetimes: &[_] = &generics.lifetimes; @@ -2286,20 +2265,11 @@ fn rewrite_trait_bounds(context: &RewriteContext, if bounds.is_empty() { return Some(String::new()); } - let joiner = match context.config.type_punctuation_density() { - TypeDensity::Compressed => "+", - TypeDensity::Wide => " + ", - }; let bound_str = try_opt!(bounds .iter() .map(|ty_bound| ty_bound.rewrite(&context, shape)) - .collect::>>()) - .join(joiner); - - let mut result = String::new(); - result.push_str(": "); - result.push_str(&bound_str); - Some(result) + .collect::>>()); + Some(format!(": {}", join_bounds(context, shape, &bound_str))) } fn rewrite_where_clause_rfc_style(context: &RewriteContext, @@ -2463,9 +2433,8 @@ fn format_generics(context: &RewriteContext, offset: Indent, span: Span) -> Option { - let shape = - generics_shape_from_config(context.config, Shape::indented(offset, context.config), 0); - let mut result = try_opt!(rewrite_generics(context, generics, shape, shape.width, span)); + let shape = Shape::indented(offset, context.config); + let mut result = try_opt!(rewrite_generics(context, generics, shape, span)); if !generics.where_clause.predicates.is_empty() || result.contains('\n') { let budget = try_opt!(context diff --git a/src/types.rs b/src/types.rs index 4e74ea8213f1..d2405f390f1d 100644 --- a/src/types.rs +++ b/src/types.rs @@ -22,7 +22,7 @@ use codemap::SpanUtils; use items::{format_generics_item_list, generics_shape_from_config}; use lists::{itemize_list, format_fn_args}; use rewrite::{Rewrite, RewriteContext}; -use utils::{extra_offset, format_mutability, colon_spaces, wrap_str, mk_sp}; +use utils::{extra_offset, format_mutability, colon_spaces, wrap_str, mk_sp, last_line_width}; use expr::{rewrite_unary_prefix, rewrite_pair, rewrite_tuple_type}; use config::TypeDensity; @@ -362,22 +362,15 @@ impl Rewrite for ast::WherePredicate { .collect::>>()) .join(", "); - let joiner = match context.config.type_punctuation_density() { - TypeDensity::Compressed => "+", - TypeDensity::Wide => " + ", - }; // 6 = "for<> ".len() let used_width = lifetime_str.len() + type_str.len() + colon.len() + 6; - let budget = try_opt!(shape.width.checked_sub(used_width)); - let bounds_str: String = try_opt!( - bounds - .iter() - .map(|ty_bound| { - ty_bound.rewrite(context, - Shape::legacy(budget, shape.indent + used_width)) - }) - .collect::>>() - ).join(joiner); + let ty_shape = try_opt!(shape.block_left(used_width)); + let bounds: Vec<_> = + try_opt!(bounds + .iter() + .map(|ty_bound| ty_bound.rewrite(context, ty_shape)) + .collect()); + let bounds_str = join_bounds(context, ty_shape, &bounds); if context.config.spaces_within_angle_brackets() && lifetime_str.len() > 0 { format!("for< {} > {}{}{}", @@ -389,21 +382,14 @@ impl Rewrite for ast::WherePredicate { format!("for<{}> {}{}{}", lifetime_str, type_str, colon, bounds_str) } } else { - let joiner = match context.config.type_punctuation_density() { - TypeDensity::Compressed => "+", - TypeDensity::Wide => " + ", - }; let used_width = type_str.len() + colon.len(); - let budget = try_opt!(shape.width.checked_sub(used_width)); - let bounds_str: String = try_opt!( - bounds - .iter() - .map(|ty_bound| { - ty_bound.rewrite(context, - Shape::legacy(budget, shape.indent + used_width)) - }) - .collect::>>() - ).join(joiner); + let ty_shape = try_opt!(shape.block_left(used_width)); + let bounds: Vec<_> = + try_opt!(bounds + .iter() + .map(|ty_bound| ty_bound.rewrite(context, ty_shape)) + .collect()); + let bounds_str = join_bounds(context, ty_shape, &bounds); format!("{}{}{}", type_str, colon, bounds_str) } @@ -458,11 +444,11 @@ fn rewrite_bounded_lifetime<'b, I>(lt: &ast::Lifetime, .map(|b| b.rewrite(context, shape)) .collect()); let colon = type_bound_colon(context); - let joiner = match context.config.type_punctuation_density() { - TypeDensity::Compressed => "+", - TypeDensity::Wide => " + ", - }; - let result = format!("{}{}{}", result, colon, appendix.join(joiner)); + let overhead = last_line_width(&result) + colon.len(); + let result = format!("{}{}{}", + result, + colon, + join_bounds(context, try_opt!(shape.sub_width(overhead)), &appendix)); wrap_str(result, context.config.max_width(), shape) } } @@ -494,12 +480,8 @@ impl Rewrite for ast::Lifetime { impl Rewrite for ast::TyParamBounds { fn rewrite(&self, context: &RewriteContext, shape: Shape) -> Option { - let joiner = match context.config.type_punctuation_density() { - TypeDensity::Compressed => "+", - TypeDensity::Wide => " + ", - }; let strs: Vec<_> = try_opt!(self.iter().map(|b| b.rewrite(context, shape)).collect()); - wrap_str(strs.join(joiner), context.config.max_width(), shape) + join_bounds(context, shape, &strs).rewrite(context, shape) } } @@ -514,24 +496,12 @@ impl Rewrite for ast::TyParam { result.push_str(&attr_str); result.push_str(&self.ident.to_string()); if !self.bounds.is_empty() { - if context.config.space_before_bound() { - result.push_str(" "); - } - result.push_str(":"); - if context.config.space_after_bound_colon() { - result.push_str(" "); - } - let joiner = match context.config.type_punctuation_density() { - TypeDensity::Compressed => "+", - TypeDensity::Wide => " + ", - }; - let bounds: String = try_opt!(self.bounds - .iter() - .map(|ty_bound| ty_bound.rewrite(context, shape)) - .collect::>>()) - .join(joiner); - - result.push_str(&bounds); + result.push_str(type_bound_colon(context)); + let strs: Vec<_> = try_opt!(self.bounds + .iter() + .map(|ty_bound| ty_bound.rewrite(context, shape)) + .collect()); + result.push_str(&join_bounds(context, shape, &strs)); } if let Some(ref def) = self.default { @@ -732,3 +702,19 @@ fn rewrite_bare_fn(bare_fn: &ast::BareFnTy, Some(result) } + +pub fn join_bounds(context: &RewriteContext, shape: Shape, type_strs: &Vec) -> String { + // Try to join types in a single line + let joiner = match context.config.type_punctuation_density() { + TypeDensity::Compressed => "+", + TypeDensity::Wide => " + ", + }; + let result = type_strs.join(joiner); + if result.contains('\n') || result.len() > shape.width { + let joiner_indent = shape.indent.block_indent(context.config); + let joiner = format!("\n{}+ ", joiner_indent.to_string(context.config)); + type_strs.join(&joiner) + } else { + result + } +} From e94fcfcd39c2658812a59f1adc0f6fca5a36a0cf Mon Sep 17 00:00:00 2001 From: topecongiro Date: Sun, 11 Jun 2017 23:27:02 +0900 Subject: [PATCH 06/12] Update tests --- tests/source/big-impl.rs | 104 +++++++++++++++++++++++++++++++++++ tests/source/impls.rs | 17 ++++++ tests/target/big-impl-rfc.rs | 26 ++++++--- tests/target/big-impl.rs | 62 +++++++++++++++++++++ tests/target/impls.rs | 36 +++++++++++- 5 files changed, 236 insertions(+), 9 deletions(-) create mode 100644 tests/source/big-impl.rs create mode 100644 tests/target/big-impl.rs diff --git a/tests/source/big-impl.rs b/tests/source/big-impl.rs new file mode 100644 index 000000000000..c36b7e6cadb1 --- /dev/null +++ b/tests/source/big-impl.rs @@ -0,0 +1,104 @@ +// #1357 +impl< + 'a, + Select, + From, + Distinct, + Where, + Order, + Limit, + Offset, + Groupby, + DB, +> InternalBoxedDsl<'a, DB> + for SelectStatement< + Select, + From, + Distinct, + Where, + Order, + Limit, + Offset, + GroupBy, + > where + DB: Backend, + Select: QueryFragment + SelectableExpression + 'a, + Distinct: QueryFragment + 'a, + Where: Into + 'a>>>, + Order: QueryFragment + 'a, + Limit: QueryFragment + 'a, + Offset: QueryFragment + 'a, +{ + type Output = BoxedSelectStatement<'a, Select::SqlTypeForSelect, From, DB>; + + fn internal_into_boxed(self) -> Self::Output { + BoxedSelectStatement::new( + Box::new(self.select), + self.from, + Box::new(self.distinct), + self.where_clause.into(), + Box::new(self.order), + Box::new(self.limit), + Box::new(self.offset), + ) + } +} + +// #1369 +impl< + ExcessivelyLongGenericName, + ExcessivelyLongGenericName, + AnotherExcessivelyLongGenericName, +> Foo for Bar { + fn foo() {} +} +impl Foo< + ExcessivelyLongGenericName, + ExcessivelyLongGenericName, + AnotherExcessivelyLongGenericName, +> for Bar { + fn foo() {} +} +impl< + ExcessivelyLongGenericName, + ExcessivelyLongGenericName, + AnotherExcessivelyLongGenericName, +> Foo< + ExcessivelyLongGenericName, + ExcessivelyLongGenericName, + AnotherExcessivelyLongGenericName, +> for Bar { + fn foo() {} +} +impl< + ExcessivelyLongGenericName, + ExcessivelyLongGenericName, + AnotherExcessivelyLongGenericName, +> Foo for Bar< + ExcessivelyLongGenericName, + ExcessivelyLongGenericName, + AnotherExcessivelyLongGenericName, +> { + fn foo() {} +} +impl Foo< + ExcessivelyLongGenericName, + ExcessivelyLongGenericName, + AnotherExcessivelyLongGenericName, +> for Bar< + ExcessivelyLongGenericName, + ExcessivelyLongGenericName, + AnotherExcessivelyLongGenericName, +> { + fn foo() {} +} +impl Foo + for Bar { + fn foo() {} +} diff --git a/tests/source/impls.rs b/tests/source/impls.rs index 1c38a2ff2847..17588fb9d350 100644 --- a/tests/source/impls.rs +++ b/tests/source/impls.rs @@ -122,3 +122,20 @@ impl Issue1249 Drop for RawTable { fn drop() {} } + +// #1168 +pub trait Number: Copy + Eq + Not + Shl + + Shr + + BitAnd + BitOr + BitAndAssign + BitOrAssign + + + +{ + // test + fn zero() -> Self; +} + +// #1642 +pub trait SomeTrait : Clone + Eq + PartialEq + Ord + PartialOrd + Default + Hash + Debug + Display + Write + Read + FromStr { + // comment +} diff --git a/tests/target/big-impl-rfc.rs b/tests/target/big-impl-rfc.rs index 18fa59cb5a0e..108968faaed7 100644 --- a/tests/target/big-impl-rfc.rs +++ b/tests/target/big-impl-rfc.rs @@ -5,7 +5,7 @@ // #1357 impl<'a, Select, From, Distinct, Where, Order, Limit, Offset, Groupby, DB> InternalBoxedDsl<'a, DB> -for SelectStatement + for SelectStatement where DB: Backend, Select: QueryFragment + SelectableExpression + 'a, @@ -32,11 +32,11 @@ where // #1369 impl Foo -for Bar { + for Bar { fn foo() {} } impl Foo -for Bar { + for Bar { fn foo() {} } impl< @@ -44,15 +44,23 @@ impl< ExcessivelyLongGenericName, AnotherExcessivelyLongGenericName, > Foo -for Bar { + for Bar { fn foo() {} } impl Foo -for Bar { + for Bar< + ExcessivelyLongGenericName, + ExcessivelyLongGenericName, + AnotherExcessivelyLongGenericName, + > { fn foo() {} } impl Foo -for Bar { + for Bar< + ExcessivelyLongGenericName, + ExcessivelyLongGenericName, + AnotherExcessivelyLongGenericName, + > { fn foo() {} } impl< @@ -60,6 +68,10 @@ impl< ExcessivelyLongGenericName, AnotherExcessivelyLongGenericName, > Foo -for Bar { + for Bar< + ExcessivelyLongGenericName, + ExcessivelyLongGenericName, + AnotherExcessivelyLongGenericName, + > { fn foo() {} } diff --git a/tests/target/big-impl.rs b/tests/target/big-impl.rs new file mode 100644 index 000000000000..afe2571ec686 --- /dev/null +++ b/tests/target/big-impl.rs @@ -0,0 +1,62 @@ +// #1357 +impl<'a, Select, From, Distinct, Where, Order, Limit, Offset, Groupby, DB> InternalBoxedDsl<'a, DB> + for SelectStatement + where DB: Backend, + Select: QueryFragment + SelectableExpression + 'a, + Distinct: QueryFragment + 'a, + Where: Into + 'a>>>, + Order: QueryFragment + 'a, + Limit: QueryFragment + 'a, + Offset: QueryFragment + 'a +{ + type Output = BoxedSelectStatement<'a, Select::SqlTypeForSelect, From, DB>; + + fn internal_into_boxed(self) -> Self::Output { + BoxedSelectStatement::new(Box::new(self.select), + self.from, + Box::new(self.distinct), + self.where_clause.into(), + Box::new(self.order), + Box::new(self.limit), + Box::new(self.offset)) + } +} + +// #1369 +impl Foo + for Bar { + fn foo() {} +} +impl Foo + for Bar { + fn foo() {} +} +impl Foo for Bar { + fn foo() {} +} +impl Foo + for Bar { + fn foo() {} +} +impl Foo + for Bar { + fn foo() {} +} +impl Foo + for Bar { + fn foo() {} +} diff --git a/tests/target/impls.rs b/tests/target/impls.rs index f8b9f43aeb00..654d4be8967b 100644 --- a/tests/target/impls.rs +++ b/tests/target/impls.rs @@ -126,8 +126,8 @@ mod m { impl PartialEq for S where T: PartialEq {} } -impl Handle, - HandleType> { +impl + Handle, HandleType> { } impl PartialEq @@ -154,3 +154,35 @@ impl impl<#[may_dangle] K, #[may_dangle] V> Drop for RawTable { fn drop() {} } + +// #1168 +pub trait Number + : Copy + + Eq + + Not + + Shl + + Shr + + BitAnd + + BitOr + + BitAndAssign + + BitOrAssign { + // test + fn zero() -> Self; +} + +// #1642 +pub trait SomeTrait + : Clone + + Eq + + PartialEq + + Ord + + PartialOrd + + Default + + Hash + + Debug + + Display + + Write + + Read + + FromStr { + // comment +} From 62e9473d07ec9a35e1c1e63140381055d86bb478 Mon Sep 17 00:00:00 2001 From: topecongiro Date: Mon, 12 Jun 2017 08:53:19 +0900 Subject: [PATCH 07/12] Update rewrite_trait_ref to return Option --- src/items.rs | 74 +++++++++++++++++++++++++--------------------------- 1 file changed, 36 insertions(+), 38 deletions(-) diff --git a/src/items.rs b/src/items.rs index 78226624c4f0..6b9e1e411f1e 100644 --- a/src/items.rs +++ b/src/items.rs @@ -676,25 +676,26 @@ fn format_impl_ref_and_type(context: &RewriteContext, }; if let Some(ref trait_ref) = *trait_ref { - let success = format_trait_ref_then_update_result(context, - &trait_ref, - offset, - &generics_str, - true, - polarity_str, - &mut result); - if !success { + let result_len = result.len(); + if let Some(trait_ref_str) = + rewrite_trait_ref(context, + &trait_ref, + offset, + &generics_str, + true, + polarity_str, + result_len) { + result.push_str(&trait_ref_str); + } else { let generics_str = try_opt!(rewrite_generics_inner(context, generics, shape, 0, mk_sp(lo, hi))); - if !format_trait_ref_then_update_result(context, - &trait_ref, - offset, - &generics_str, - false, - polarity_str, - &mut result) { - return None; - } + result.push_str(&try_opt!(rewrite_trait_ref(context, + &trait_ref, + offset, + &generics_str, + false, + polarity_str, + result_len))); } } else { result.push_str(&generics_str); @@ -752,43 +753,40 @@ fn format_impl_ref_and_type(context: &RewriteContext, } } -// Returns false if failed to update result: then, try using multiline. -fn format_trait_ref_then_update_result(context: &RewriteContext, - trait_ref: &ast::TraitRef, - offset: Indent, - generics_str: &str, - retry: bool, - polarity_str: &str, - result: &mut String) - -> bool { +fn rewrite_trait_ref(context: &RewriteContext, + trait_ref: &ast::TraitRef, + offset: Indent, + generics_str: &str, + retry: bool, + polarity_str: &str, + result_len: usize) + -> Option { // 1 = space between generics and trait_ref let used_space = 1 + polarity_str.len() + if generics_str.contains('\n') { last_line_width(&generics_str) } else { - result.len() + generics_str.len() + result_len + generics_str.len() }; let shape = Shape::indented(offset + used_space, context.config); if let Some(trait_ref_str) = trait_ref.rewrite(context, shape) { if !(retry && trait_ref_str.contains('\n')) { - result.push_str(&format!("{} {}{}", generics_str, polarity_str, &trait_ref_str)); - return true; + return Some(format!("{} {}{}", generics_str, polarity_str, &trait_ref_str)); } } // We could not make enough space for trait_ref, so put it on new line. if !retry { let offset = offset.block_indent(context.config); let shape = Shape::indented(offset, context.config); - if let Some(trait_ref_str) = trait_ref.rewrite(context, shape) { - result.push_str(&format!("{}\n{}{}{}", - generics_str, - &offset.to_string(context.config), - polarity_str, - &trait_ref_str)); - return true; - } + let trait_ref_str = try_opt!(trait_ref.rewrite(context, shape)); + Some(format!("{}\n{}{}{}", + generics_str, + &offset.to_string(context.config), + polarity_str, + &trait_ref_str)) + } else { + None } - false } pub fn format_struct(context: &RewriteContext, From 9ad499786d1eb8008423d9d9810b47c4124e8d47 Mon Sep 17 00:00:00 2001 From: topecongiro Date: Mon, 12 Jun 2017 15:58:27 +0900 Subject: [PATCH 08/12] Use block indent for args if single line args exceeds max width --- src/expr.rs | 18 +++++++++++++++--- tests/source/configs-fn_call_style-block.rs | 6 ++++++ ...nfigs-fn_call_style-block-trailing-comma.rs | 4 +++- tests/target/configs-fn_call_style-block.rs | 7 +++++++ 4 files changed, 31 insertions(+), 4 deletions(-) diff --git a/src/expr.rs b/src/expr.rs index aa5913e5f0fa..b47bf391ac16 100644 --- a/src/expr.rs +++ b/src/expr.rs @@ -1734,9 +1734,12 @@ fn rewrite_call_inner(context: &RewriteContext, force_trailing_comma); } + let args_shape = shape + .sub_width(last_line_width(&callee_str)) + .ok_or(Ordering::Less)?; Ok(format!("{}{}", callee_str, - wrap_args_with_parens(context, &list_str, extendable, shape, nested_shape))) + wrap_args_with_parens(context, &list_str, extendable, args_shape, nested_shape))) } fn need_block_indent(s: &str, shape: Shape) -> bool { @@ -1906,14 +1909,23 @@ fn can_be_overflowed_expr(context: &RewriteContext, expr: &ast::Expr, args_len: } } +fn paren_overhead(context: &RewriteContext) -> usize { + if context.config.spaces_within_parens() { + 4 + } else { + 2 + } +} + fn wrap_args_with_parens(context: &RewriteContext, args_str: &str, is_extendable: bool, shape: Shape, nested_shape: Shape) -> String { - if !context.use_block_indent() || (context.inside_macro && !args_str.contains('\n')) || - is_extendable { + if !context.use_block_indent() || + (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.len() > 0 { format!("( {} )", args_str) } else { diff --git a/tests/source/configs-fn_call_style-block.rs b/tests/source/configs-fn_call_style-block.rs index 2068216d18e7..ee6178c1902b 100644 --- a/tests/source/configs-fn_call_style-block.rs +++ b/tests/source/configs-fn_call_style-block.rs @@ -125,3 +125,9 @@ fn issue1581() { }, ); } + +fn issue1651() { + { + let type_list: Vec<_> = try_opt!(types.iter().map(|ty| ty.rewrite(context, shape)).collect()); + } +} diff --git a/tests/target/configs-fn_call_style-block-trailing-comma.rs b/tests/target/configs-fn_call_style-block-trailing-comma.rs index ebdf41d0e3b3..b6eb94eb6776 100644 --- a/tests/target/configs-fn_call_style-block-trailing-comma.rs +++ b/tests/target/configs-fn_call_style-block-trailing-comma.rs @@ -3,7 +3,9 @@ // rustfmt should not add trailing comma when rewriting macro. See #1528. fn a() { - panic!("this is a long string that goes past the maximum line length causing rustfmt to insert a comma here:"); + panic!( + "this is a long string that goes past the maximum line length causing rustfmt to insert a comma here:" + ); foo( oooptoptoptoptptooptoptoptoptptooptoptoptoptptoptoptoptoptpt(), ); diff --git a/tests/target/configs-fn_call_style-block.rs b/tests/target/configs-fn_call_style-block.rs index ddead8ce5a85..dfc8daef6d90 100644 --- a/tests/target/configs-fn_call_style-block.rs +++ b/tests/target/configs-fn_call_style-block.rs @@ -145,3 +145,10 @@ fn issue1581() { } }); } + +fn issue1651() { + { + let type_list: Vec<_> = + try_opt!(types.iter().map(|ty| ty.rewrite(context, shape)).collect()); + } +} From d269189f19f62de61564d9225cef18d9482bb55c Mon Sep 17 00:00:00 2001 From: topecongiro Date: Mon, 12 Jun 2017 16:23:10 +0900 Subject: [PATCH 09/12] Use correct indent for return type when it goes multi line --- src/items.rs | 2 +- tests/source/configs-fn_args_layout-block.rs | 4 ++++ tests/target/configs-fn_args_layout-block.rs | 11 +++++++++++ 3 files changed, 16 insertions(+), 1 deletion(-) diff --git a/src/items.rs b/src/items.rs index ac2f36ad76a0..43101d9187b2 100644 --- a/src/items.rs +++ b/src/items.rs @@ -1798,7 +1798,7 @@ fn rewrite_fn_base(context: &RewriteContext, indent } else { result.push(' '); - Indent::new(indent.width(), result.len()) + Indent::new(indent.block_indent, last_line_width(&result)) }; if multi_line_ret_str || ret_should_indent { diff --git a/tests/source/configs-fn_args_layout-block.rs b/tests/source/configs-fn_args_layout-block.rs index 55b38101abc7..28d1dffe6b30 100644 --- a/tests/source/configs-fn_args_layout-block.rs +++ b/tests/source/configs-fn_args_layout-block.rs @@ -20,3 +20,7 @@ extern "C" { second_parameter: SecondParameterType, ...); } + +// #1652 +fn deconstruct(foo: Bar) -> (SocketAddr, Header, Method, RequestUri, HttpVersion, AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA) { +} diff --git a/tests/target/configs-fn_args_layout-block.rs b/tests/target/configs-fn_args_layout-block.rs index 04a4d631ca49..f93b84f2d4af 100644 --- a/tests/target/configs-fn_args_layout-block.rs +++ b/tests/target/configs-fn_args_layout-block.rs @@ -32,3 +32,14 @@ extern "C" { ... ); } + +// #1652 +fn deconstruct( + foo: Bar, +) -> (SocketAddr, + Header, + Method, + RequestUri, + HttpVersion, + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA) { +} From 9df1509d1913865303844728de1b24d4495e9a4f Mon Sep 17 00:00:00 2001 From: topecongiro Date: Mon, 12 Jun 2017 17:25:07 +0900 Subject: [PATCH 10/12] Use rewrite instead of visitor for attributes --- src/expr.rs | 15 ++++----------- 1 file changed, 4 insertions(+), 11 deletions(-) diff --git a/src/expr.rs b/src/expr.rs index aa5913e5f0fa..e6889991b07e 100644 --- a/src/expr.rs +++ b/src/expr.rs @@ -1321,20 +1321,13 @@ impl Rewrite for ast::Arm { ref body, } = self; - // FIXME this is all a bit grotty, would be nice to abstract out the - // treatment of attributes. let attr_str = if !attrs.is_empty() { - // We only use this visitor for the attributes, should we use it for - // more? - let mut attr_visitor = FmtVisitor::from_codemap(context.parse_session, context.config); - attr_visitor.block_indent = shape.indent.block_only(); - attr_visitor.last_pos = attrs[0].span.lo; - if attr_visitor.visit_attrs(attrs) { - // Attributes included a skip instruction. + if contains_skip(attrs) { return None; } - attr_visitor.format_missing(pats[0].span.lo); - attr_visitor.buffer.to_string() + format!("{}\n{}", + try_opt!(attrs.rewrite(context, shape)), + shape.indent.to_string(context.config)) } else { String::new() }; From 57fc39305dc765d4454869ab6a6b9667c17b6e57 Mon Sep 17 00:00:00 2001 From: topecongiro Date: Mon, 12 Jun 2017 17:25:38 +0900 Subject: [PATCH 11/12] Put guard on newline if it exceeds max width --- src/expr.rs | 28 +++++++++-------------- tests/target/configs-control_style-rfc.rs | 17 ++++++++++++++ tests/target/match.rs | 4 ++-- 3 files changed, 30 insertions(+), 19 deletions(-) diff --git a/src/expr.rs b/src/expr.rs index e6889991b07e..06993c729b75 100644 --- a/src/expr.rs +++ b/src/expr.rs @@ -1495,28 +1495,22 @@ fn rewrite_guard(context: &RewriteContext, if let Some(ref guard) = *guard { // First try to fit the guard string on the same line as the pattern. // 4 = ` if `, 5 = ` => {` - let overhead = pattern_width + 4 + 5; - if overhead < shape.width { - let cond_shape = shape - .shrink_left(pattern_width + 4) - .unwrap() - .sub_width(5) - .unwrap(); - let cond_str = guard.rewrite(context, cond_shape); - if let Some(cond_str) = cond_str { + if let Some(cond_shape) = shape + .shrink_left(pattern_width + 4) + .and_then(|s| s.sub_width(5)) { + if let Some(cond_str) = guard + .rewrite(context, cond_shape) + .and_then(|s| s.rewrite(context, cond_shape)) { return Some(format!(" if {}", cond_str)); } } // Not enough space to put the guard after the pattern, try a newline. - let overhead = shape.indent.block_indent(context.config).width() + 4 + 5; - if overhead < shape.width { - let cond_str = guard.rewrite(context, - Shape::legacy(shape.width - overhead, - // 3 == `if ` - shape.indent.block_indent(context.config) + - 3)); - if let Some(cond_str) = cond_str { + // 3 == `if ` + if let Some(cond_shape) = Shape::indented(shape.indent.block_indent(context.config) + 3, + context.config) + .sub_width(3) { + if let Some(cond_str) = guard.rewrite(context, cond_shape) { return Some(format!("\n{}if {}", shape .indent diff --git a/tests/target/configs-control_style-rfc.rs b/tests/target/configs-control_style-rfc.rs index a7213c34dfb7..43a10e92339d 100644 --- a/tests/target/configs-control_style-rfc.rs +++ b/tests/target/configs-control_style-rfc.rs @@ -21,3 +21,20 @@ fn main() { } } } + +fn issue1656() { + { + { + match rewrite { + Some(ref body_str) + if (!body_str.contains('\n') && body_str.len() <= arm_shape.width) || + !context.config.wrap_match_arms() || + (extend && first_line_width(body_str) <= arm_shape.width) || + is_block => { + return None; + } + _ => {} + } + } + } +} diff --git a/tests/target/match.rs b/tests/target/match.rs index 6acab043e675..45f62ca68454 100644 --- a/tests/target/match.rs +++ b/tests/target/match.rs @@ -306,8 +306,8 @@ fn guards() { barrrrrrrrrrrr => {} aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa if fooooooooooooooooooooo && - (bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb || - cccccccccccccccccccccccccccccccccccccccc) => {} + (bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb || cccccccccccccccccccccccccccccccccccccccc) => { + } } } From ad628f6accd7024305c8a564fbdf177ba5068ba3 Mon Sep 17 00:00:00 2001 From: topecongiro Date: Mon, 12 Jun 2017 18:34:38 +0900 Subject: [PATCH 12/12] Force multi line if the first attempt of rewriting args failed --- src/expr.rs | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/expr.rs b/src/expr.rs index b47bf391ac16..cbe8671fd922 100644 --- a/src/expr.rs +++ b/src/expr.rs @@ -1721,6 +1721,20 @@ fn rewrite_call_inner(context: &RewriteContext, nested_shape, one_line_width, force_trailing_comma) + .or_else(|| if context.use_block_indent() { + rewrite_call_args(context, + args, + args_span, + Shape::indented(shape + .block() + .indent + .block_indent(context.config), + context.config), + 0, + force_trailing_comma) + } else { + None + }) .ok_or(Ordering::Less)?; if !context.use_block_indent() && need_block_indent(&list_str, nested_shape) && !extendable {