From f56039c7e584bb5b9b5453056a3f4c5197615629 Mon Sep 17 00:00:00 2001 From: Seiichi Uchida Date: Sat, 10 Mar 2018 14:54:13 +0900 Subject: [PATCH] Use rewrite_assign_rhs for rewriting bounds --- src/items.rs | 59 ++++++++---------------- src/types.rs | 126 ++++++++++++++++++++++++++------------------------- 2 files changed, 84 insertions(+), 101 deletions(-) diff --git a/src/items.rs b/src/items.rs index d3286864ce7..2484756fc56 100644 --- a/src/items.rs +++ b/src/items.rs @@ -23,13 +23,14 @@ use codemap::{LineRangeUtils, SpanUtils}; use comment::{combine_strs_with_missing_comments, contains_comment, recover_comment_removed, recover_missing_comment_in_span, rewrite_missing_comment, FindUncommented}; use config::{BraceStyle, Config, Density, IndentStyle}; -use expr::{format_expr, is_empty_block, is_simple_block_stmt, rewrite_assign_rhs, ExprType}; +use expr::{format_expr, is_empty_block, is_simple_block_stmt, rewrite_assign_rhs, + rewrite_assign_rhs_with, ExprType, RhsTactics}; use lists::{definitive_tactic, itemize_list, write_list, ListFormatting, ListItem, Separator}; use rewrite::{Rewrite, RewriteContext}; use overflow; use shape::{Indent, Shape}; use spanned::Spanned; -use types::join_bounds; +use types::TraitTyParamBounds; use utils::{colon_spaces, contains_skip, first_line_width, format_abi, format_constness, format_defaultness, format_mutability, format_unsafety, format_visibility, is_attributes_extendable, last_line_contains_single_line_comment, @@ -919,20 +920,19 @@ pub fn format_trait(context: &RewriteContext, item: &ast::Item, offset: Indent) return None; } } - let trait_bound_str = rewrite_trait_bounds( - context, - type_param_bounds, - Shape::indented(offset, context.config), - )?; - // If the trait, generics, and trait bound cannot fit on the same line, - // put the trait bounds on an indented new line - if offset.width() + last_line_width(&result) + trait_bound_str.len() - > context.config.comment_width() - { - let trait_indent = offset.block_only().block_indent(context.config); - result.push_str(&trait_indent.to_string_with_newline(context.config)); + if !type_param_bounds.is_empty() { + let shape = Shape { + indent: shape.indent.block_unindent(context.config), + ..shape + }; + result = rewrite_assign_rhs_with( + context, + result + ":", + &TraitTyParamBounds::new(type_param_bounds), + shape, + RhsTactics::ForceNextLine, + )?; } - result.push_str(&trait_bound_str); let where_density = if context.config.indent_style() == IndentStyle::Block && result.is_empty() { @@ -1585,16 +1585,12 @@ pub fn rewrite_associated_type( let prefix = format!("type {}", ident); let type_bounds_str = if let Some(bounds) = ty_param_bounds_opt { - // 2 = ": ".len() - let shape = Shape::indented(indent, context.config).offset_left(prefix.len() + 2)?; - let bound_str = bounds - .iter() - .map(|ty_bound| ty_bound.rewrite(context, shape)) - .collect::>>()?; - if !bounds.is_empty() { - format!(": {}", join_bounds(context, shape, &bound_str)) - } else { + if bounds.is_empty() { String::new() + } else { + // 2 = ": ".len() + let shape = Shape::indented(indent, context.config).offset_left(prefix.len() + 2)?; + bounds.rewrite(context, shape).map(|s| format!(": {}", s))? } } else { String::new() @@ -2329,21 +2325,6 @@ pub fn generics_shape_from_config(config: &Config, shape: Shape, offset: usize) } } -fn rewrite_trait_bounds( - context: &RewriteContext, - bounds: &[ast::TyParamBound], - shape: Shape, -) -> Option { - if bounds.is_empty() { - return Some(String::new()); - } - let bound_str = bounds - .iter() - .map(|ty_bound| ty_bound.rewrite(context, shape)) - .collect::>>()?; - Some(format!(": {}", join_bounds(context, shape, &bound_str))) -} - fn rewrite_where_clause_rfc_style( context: &RewriteContext, where_clause: &ast::WhereClause, diff --git a/src/types.rs b/src/types.rs index ac7990b9c0b..80ff8ce498a 100644 --- a/src/types.rs +++ b/src/types.rs @@ -18,7 +18,8 @@ use syntax::symbol::keywords; use codemap::SpanUtils; use config::{IndentStyle, TypeDensity}; -use expr::{rewrite_pair, rewrite_tuple, rewrite_unary_prefix, PairParts, ToExpr}; +use expr::{rewrite_assign_rhs, rewrite_pair, rewrite_tuple, rewrite_unary_prefix, + PairParts, ToExpr}; use lists::{definitive_tactic, itemize_list, write_list, ListFormatting, Separator}; use macros::{rewrite_macro, MacroPosition}; use overflow; @@ -431,64 +432,35 @@ impl Rewrite for ast::WherePredicate { .. }) => { let type_str = bounded_ty.rewrite(context, shape)?; - - let colon = type_bound_colon(context); - - if let Some(lifetime_str) = + let colon = type_bound_colon(context).trim_right(); + let lhs = if let Some(lifetime_str) = rewrite_lifetime_param(context, shape, bound_generic_params) { - // 6 = "for<> ".len() - let used_width = lifetime_str.len() + type_str.len() + colon.len() + 6; - let ty_shape = shape.offset_left(used_width)?; - let bounds = 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_parens_and_brackets() && !lifetime_str.is_empty() { - format!( - "for< {} > {}{}{}", - lifetime_str, type_str, colon, bounds_str - ) + format!("for< {} > {}{}", lifetime_str, type_str, colon) } else { - format!("for<{}> {}{}{}", lifetime_str, type_str, colon, bounds_str) + format!("for<{}> {}{}", lifetime_str, type_str, colon) } } else { - let used_width = type_str.len() + colon.len(); - let ty_shape = match context.config.indent_style() { - IndentStyle::Visual => shape.block_left(used_width)?, - IndentStyle::Block => shape, - }; - let bounds = bounds - .iter() - .map(|ty_bound| ty_bound.rewrite(context, ty_shape)) - .collect::>>()?; - let overhead = type_str.len() + colon.len(); - let bounds_str = join_bounds(context, ty_shape.sub_width(overhead)?, &bounds); + format!("{}{}", type_str, colon) + }; - format!("{}{}{}", type_str, colon, bounds_str) - } + rewrite_assign_rhs(context, lhs, bounds, shape)? } ast::WherePredicate::RegionPredicate(ast::WhereRegionPredicate { ref lifetime, ref bounds, .. - }) => rewrite_bounded_lifetime(lifetime, bounds.iter(), context, shape)?, + }) => rewrite_bounded_lifetime(lifetime, bounds, context, shape)?, ast::WherePredicate::EqPredicate(ast::WhereEqPredicate { ref lhs_ty, ref rhs_ty, .. }) => { - let lhs_ty_str = lhs_ty.rewrite(context, shape)?; - // 3 = " = ".len() - let used_width = 3 + lhs_ty_str.len(); - let budget = shape.width.checked_sub(used_width)?; - let rhs_ty_str = - rhs_ty.rewrite(context, Shape::legacy(budget, shape.indent + used_width))?; - format!("{} = {}", lhs_ty_str, rhs_ty_str) + let lhs_ty_str = lhs_ty.rewrite(context, shape).map(|lhs| lhs + " =")?; + rewrite_assign_rhs(context, lhs_ty_str, &**rhs_ty, shape)? } }; @@ -498,26 +470,23 @@ impl Rewrite for ast::WherePredicate { impl Rewrite for ast::LifetimeDef { fn rewrite(&self, context: &RewriteContext, shape: Shape) -> Option { - rewrite_bounded_lifetime(&self.lifetime, self.bounds.iter(), context, shape) + rewrite_bounded_lifetime(&self.lifetime, &self.bounds, context, shape) } } -fn rewrite_bounded_lifetime<'b, I>( +fn rewrite_bounded_lifetime( lt: &ast::Lifetime, - bounds: I, + bounds: &[ast::Lifetime], context: &RewriteContext, shape: Shape, -) -> Option -where - I: ExactSizeIterator, -{ +) -> Option { let result = lt.rewrite(context, shape)?; if bounds.len() == 0 { Some(result) } else { let appendix = bounds - .into_iter() + .iter() .map(|b| b.rewrite(context, shape)) .collect::>>()?; let colon = type_bound_colon(context); @@ -526,7 +495,7 @@ where "{}{}{}", result, colon, - join_bounds(context, shape.sub_width(overhead)?, &appendix) + join_bounds(context, shape.sub_width(overhead)?, bounds, &appendix, true)? ); Some(result) } @@ -552,12 +521,28 @@ impl Rewrite for ast::Lifetime { } } +/// A simple wrapper over type param bounds in trait. +#[derive(new)] +pub struct TraitTyParamBounds<'a> { + inner: &'a ast::TyParamBounds, +} + +impl<'a> Rewrite for TraitTyParamBounds<'a> { + fn rewrite(&self, context: &RewriteContext, shape: Shape) -> Option { + let strs = self.inner + .iter() + .map(|b| b.rewrite(context, shape)) + .collect::>>()?; + join_bounds(context, shape, self.inner, &strs, false) + } +} + impl Rewrite for ast::TyParamBounds { fn rewrite(&self, context: &RewriteContext, shape: Shape) -> Option { let strs = self.iter() .map(|b| b.rewrite(context, shape)) .collect::>>()?; - Some(join_bounds(context, shape, &strs)) + join_bounds(context, shape, self, &strs, true) } } @@ -572,11 +557,7 @@ impl Rewrite for ast::TyParam { result.push_str(&self.ident.to_string()); if !self.bounds.is_empty() { result.push_str(type_bound_colon(context)); - let strs = self.bounds - .iter() - .map(|ty_bound| ty_bound.rewrite(context, shape)) - .collect::>>()?; - result.push_str(&join_bounds(context, shape, &strs)); + result.push_str(&self.bounds.rewrite(context, shape)?) } if let Some(ref def) = self.default { let eq_str = match context.config.type_punctuation_density() { @@ -794,20 +775,41 @@ fn rewrite_bare_fn( Some(result) } -pub fn join_bounds(context: &RewriteContext, shape: Shape, type_strs: &[String]) -> String { +fn join_bounds( + context: &RewriteContext, + shape: Shape, + items: &[T], + type_strs: &[String], + need_indent: bool, +) -> Option +where + T: Rewrite, +{ // 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!("{}+ ", joiner_indent.to_string_with_newline(context.config)); - type_strs.join(&joiner) - } else { - result + if items.len() == 1 || (!result.contains('\n') && result.len() <= shape.width) { + return Some(result); } + + // We need to use multiple lines. + let (type_strs, offset) = if need_indent { + // Rewrite with additional indentation. + let nested_shape = shape.block_indent(context.config.tab_spaces()); + let type_strs = items + .iter() + .map(|item| item.rewrite(context, nested_shape)) + .collect::>>()?; + (type_strs, nested_shape.indent) + } else { + (type_strs.to_vec(), shape.indent) + }; + + let joiner = format!("{}+ ", offset.to_string_with_newline(context.config)); + Some(type_strs.join(&joiner)) } pub fn can_be_overflowed_type(context: &RewriteContext, ty: &ast::Ty, len: usize) -> bool {