diff --git a/src/expr.rs b/src/expr.rs index aa5913e5f0fa..ef47d0fd6c60 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() }; @@ -1502,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 @@ -1721,6 +1708,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 { @@ -1734,9 +1735,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 +1910,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 { @@ -2063,12 +2076,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 ac2f36ad76a0..18b58e57fe14 100644 --- a/src/items.rs +++ b/src/items.rs @@ -16,12 +16,13 @@ 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; 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}; @@ -527,23 +528,20 @@ 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 = try_opt!(format_impl_ref_and_type(context, item, offset, false)); - - // 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 = 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(), @@ -644,8 +642,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, @@ -665,69 +662,133 @@ 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 = 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(offset + last_line_width(&result), + context.config), + 0); + let generics_str = + try_opt!(rewrite_generics_inner(context, generics, shape, shape.width, mk_sp(lo, hi))); + + let polarity_str = if polarity == ast::ImplPolarity::Negative { + "!" + } else { + "" + }; - if polarity == ast::ImplPolarity::Negative { - result.push_str(" !"); - } if let Some(ref trait_ref) = *trait_ref { - if polarity != ast::ImplPolarity::Negative { - result.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 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 { - result.push_str(" for"); + let generics_str = + try_opt!(rewrite_generics_inner(context, generics, shape, 0, mk_sp(lo, hi))); + 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); } - 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 + result.len() + 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!(); } } +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() + }; + 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')) { + 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); + 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 + } +} + pub fn format_struct(context: &RewriteContext, item_name: &str, ident: ast::Ident, @@ -777,8 +838,7 @@ 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 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); @@ -1024,10 +1084,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 = Shape::indented(generics_indent, context.config); - let generics_str = - try_opt!(rewrite_generics(context, generics, shape, 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 @@ -1154,11 +1213,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 = try_opt!(Shape::indented(generics_indent, context.config).sub_width(" =".len())); - let generics_str = try_opt!(rewrite_generics(context, generics, shape, 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 @@ -1392,23 +1450,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() } @@ -1633,10 +1682,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 = Shape::indented(generics_indent, context.config); - let generics_str = try_opt!(rewrite_generics(context, generics, shape, 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 @@ -1798,7 +1846,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 { @@ -2109,6 +2157,17 @@ fn rewrite_generics(context: &RewriteContext, shape: Shape, 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; @@ -2117,21 +2176,9 @@ 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. - // 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 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| { @@ -2153,21 +2200,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, shape, one_line_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, @@ -2179,20 +2269,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, diff --git a/src/types.rs b/src/types.rs index 7dfc43371789..d2405f390f1d 100644 --- a/src/types.rs +++ b/src/types.rs @@ -19,9 +19,10 @@ 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 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; @@ -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 { @@ -367,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< {} > {}{}{}", @@ -394,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) } @@ -463,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) } } @@ -499,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) } } @@ -519,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 { @@ -737,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 + } +} 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/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/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/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/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 new file mode 100644 index 000000000000..108968faaed7 --- /dev/null +++ b/tests/target/big-impl-rfc.rs @@ -0,0 +1,77 @@ +// 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< + ExcessivelyLongGenericName, + ExcessivelyLongGenericName, + AnotherExcessivelyLongGenericName, + > { + fn foo() {} +} +impl Foo + for Bar< + ExcessivelyLongGenericName, + ExcessivelyLongGenericName, + AnotherExcessivelyLongGenericName, + > { + fn foo() {} +} +impl< + ExcessivelyLongGenericName, + ExcessivelyLongGenericName, + AnotherExcessivelyLongGenericName, +> Foo + 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/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/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) { +} 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()); + } +} 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, } 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 +} 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) => { + } } }