X-Git-Url: https://git.lizzy.rs/?a=blobdiff_plain;f=src%2Fexpr.rs;h=72cf618dca546fc7c0213013d2340ec4dd989161;hb=caefd218c9f6c43493c28c5cc4ea8828c494830e;hp=c719f9938ee995c8bb43992f30692deea44b9681;hpb=98c6f7b7313c0053f822a10ab473f31bf1f480ef;p=rust.git diff --git a/src/expr.rs b/src/expr.rs index c719f9938ee..72cf618dca5 100644 --- a/src/expr.rs +++ b/src/expr.rs @@ -19,23 +19,30 @@ use chains::rewrite_chain; use closures; use codemap::{LineRangeUtils, SpanUtils}; -use comment::{combine_strs_with_missing_comments, contains_comment, recover_comment_removed, - rewrite_comment, rewrite_missing_comment, CharClasses, FindUncommented}; +use comment::{ + combine_strs_with_missing_comments, contains_comment, recover_comment_removed, rewrite_comment, + rewrite_missing_comment, CharClasses, FindUncommented, +}; use config::{Config, ControlBraceStyle, IndentStyle}; -use lists::{definitive_tactic, itemize_list, shape_for_tactic, struct_lit_formatting, - struct_lit_shape, struct_lit_tactic, write_list, ListFormatting, ListItem, Separator}; +use lists::{ + definitive_tactic, itemize_list, shape_for_tactic, struct_lit_formatting, struct_lit_shape, + struct_lit_tactic, write_list, ListFormatting, ListItem, Separator, +}; use macros::{rewrite_macro, MacroArg, MacroPosition}; use matches::rewrite_match; use overflow; +use pairs::{rewrite_all_pairs, rewrite_pair, PairParts}; use patterns::{can_be_overflowed_pat, is_short_pattern, TuplePatField}; use rewrite::{Rewrite, RewriteContext}; use shape::{Indent, Shape}; use spanned::Spanned; use string::{rewrite_string, StringFormat}; use types::{can_be_overflowed_type, rewrite_path, PathContext}; -use utils::{colon_spaces, contains_skip, count_newlines, first_line_width, inner_attributes, - last_line_extendable, last_line_width, mk_sp, outer_attributes, paren_overhead, - ptr_vec_to_ref_vec, semicolon_for_stmt, wrap_str}; +use utils::{ + colon_spaces, contains_skip, count_newlines, first_line_ends_with, first_line_width, + inner_attributes, last_line_extendable, last_line_width, mk_sp, outer_attributes, + ptr_vec_to_ref_vec, semicolon_for_stmt, wrap_str, +}; use vertical::rewrite_with_alignment; use visitor::FmtVisitor; @@ -70,7 +77,7 @@ pub fn format_expr( expr.span, context, shape, - None, + choose_separator_tactic(context, expr.span), None, ), ast::ExprKind::Lit(ref l) => rewrite_literal(context, l, shape), @@ -80,16 +87,18 @@ pub fn format_expr( rewrite_call(context, &callee_str, args, inner_span, shape) } ast::ExprKind::Paren(ref subexpr) => rewrite_paren(context, subexpr, shape, expr.span), - ast::ExprKind::Binary(ref op, ref lhs, ref rhs) => { + ast::ExprKind::Binary(op, ref lhs, ref rhs) => { // FIXME: format comments between operands and operator - rewrite_pair( - &**lhs, - &**rhs, - PairParts::new("", &format!(" {} ", context.snippet(op.span)), ""), - context, - shape, - context.config.binop_separator(), - ) + rewrite_all_pairs(expr, shape, context).or_else(|| { + rewrite_pair( + &**lhs, + &**rhs, + PairParts::infix(&format!(" {} ", context.snippet(op.span))), + context, + shape, + context.config.binop_separator(), + ) + }) } ast::ExprKind::Unary(ref op, ref subexpr) => rewrite_unary_op(context, op, subexpr, shape), ast::ExprKind::Struct(ref path, ref fields, ref base) => rewrite_struct_lit( @@ -110,29 +119,33 @@ pub fn format_expr( | ast::ExprKind::While(..) | ast::ExprKind::WhileLet(..) => to_control_flow(expr, expr_type) .and_then(|control_flow| control_flow.rewrite(context, shape)), - ast::ExprKind::Block(ref block) => { + ast::ExprKind::Block(ref block, opt_label) => { match expr_type { ExprType::Statement => { if is_unsafe_block(block) { - rewrite_block(block, Some(&expr.attrs), context, shape) + rewrite_block(block, Some(&expr.attrs), opt_label, context, shape) } else if let rw @ Some(_) = - rewrite_empty_block(context, block, Some(&expr.attrs), "", shape) + rewrite_empty_block(context, block, Some(&expr.attrs), opt_label, "", shape) { // Rewrite block without trying to put it in a single line. rw } else { let prefix = block_prefix(context, block, shape)?; + rewrite_block_with_visitor( context, &prefix, block, Some(&expr.attrs), + opt_label, shape, true, ) } } - ExprType::SubExpression => rewrite_block(block, Some(&expr.attrs), context, shape), + ExprType::SubExpression => { + rewrite_block(block, Some(&expr.attrs), opt_label, context, shape) + } } } ast::ExprKind::Match(ref cond, ref arms) => { @@ -171,21 +184,14 @@ pub fn format_expr( } else { Some("yield".to_string()) }, - ast::ExprKind::Closure(capture, movability, ref fn_decl, ref body, _) => { + ast::ExprKind::Closure(capture, asyncness, movability, ref fn_decl, ref body, _) => { closures::rewrite_closure( - capture, - movability, - fn_decl, - body, - expr.span, - context, - shape, + capture, asyncness, movability, fn_decl, body, expr.span, context, shape, ) } - ast::ExprKind::Try(..) - | ast::ExprKind::Field(..) - | ast::ExprKind::TupField(..) - | ast::ExprKind::MethodCall(..) => rewrite_chain(expr, context, shape), + ast::ExprKind::Try(..) | ast::ExprKind::Field(..) | ast::ExprKind::MethodCall(..) => { + rewrite_chain(expr, context, shape) + } ast::ExprKind::Mac(ref mac) => { rewrite_macro(mac, None, context, shape, MacroPosition::Expression).or_else(|| { wrap_str( @@ -206,7 +212,7 @@ pub fn format_expr( ast::ExprKind::Cast(ref expr, ref ty) => rewrite_pair( &**expr, &**ty, - PairParts::new("", " as ", ""), + PairParts::infix(" as "), context, shape, SeparatorPlace::Front, @@ -214,7 +220,7 @@ pub fn format_expr( ast::ExprKind::Type(ref expr, ref ty) => rewrite_pair( &**expr, &**ty, - PairParts::new("", ": ", ""), + PairParts::infix(": "), context, shape, SeparatorPlace::Back, @@ -222,21 +228,14 @@ pub fn format_expr( ast::ExprKind::Index(ref expr, ref index) => { rewrite_index(&**expr, &**index, context, shape) } - ast::ExprKind::Repeat(ref expr, ref repeats) => { - let (lbr, rbr) = if context.config.spaces_within_parens_and_brackets() { - ("[ ", " ]") - } else { - ("[", "]") - }; - rewrite_pair( - &**expr, - &**repeats, - PairParts::new(lbr, "; ", rbr), - context, - shape, - SeparatorPlace::Back, - ) - } + ast::ExprKind::Repeat(ref expr, ref repeats) => rewrite_pair( + &**expr, + &*repeats.value, + PairParts::new("[", "; ", "]"), + context, + shape, + SeparatorPlace::Back, + ), ast::ExprKind::Range(ref lhs, ref rhs, limits) => { let delim = match limits { ast::RangeLimits::HalfOpen => "..", @@ -255,19 +254,42 @@ fn needs_space_before_range(context: &RewriteContext, lhs: &ast::Expr) -> bool { } } + fn needs_space_after_range(rhs: &ast::Expr) -> bool { + match rhs.node { + // Don't format `.. ..` into `....`, which is invalid. + // + // This check is unnecessary for `lhs`, because a range + // starting from another range needs parentheses as `(x ..) ..` + // (`x .. ..` is a range from `x` to `..`). + ast::ExprKind::Range(None, _, _) => true, + _ => false, + } + } + + let default_sp_delim = |lhs: Option<&ast::Expr>, rhs: Option<&ast::Expr>| { + let space_if = |b: bool| if b { " " } else { "" }; + + format!( + "{}{}{}", + lhs.map(|lhs| space_if(needs_space_before_range(context, lhs))) + .unwrap_or(""), + delim, + rhs.map(|rhs| space_if(needs_space_after_range(rhs))) + .unwrap_or(""), + ) + }; + match (lhs.as_ref().map(|x| &**x), rhs.as_ref().map(|x| &**x)) { (Some(lhs), Some(rhs)) => { let sp_delim = if context.config.spaces_around_ranges() { format!(" {} ", delim) - } else if needs_space_before_range(context, lhs) { - format!(" {}", delim) } else { - delim.to_owned() + default_sp_delim(Some(lhs), Some(rhs)) }; rewrite_pair( &*lhs, &*rhs, - PairParts::new("", &sp_delim, ""), + PairParts::infix(&sp_delim), context, shape, context.config.binop_separator(), @@ -277,7 +299,7 @@ fn needs_space_before_range(context: &RewriteContext, lhs: &ast::Expr) -> bool { let sp_delim = if context.config.spaces_around_ranges() { format!("{} ", delim) } else { - delim.to_owned() + default_sp_delim(None, Some(rhs)) }; rewrite_unary_prefix(context, &sp_delim, &*rhs, shape) } @@ -285,7 +307,7 @@ fn needs_space_before_range(context: &RewriteContext, lhs: &ast::Expr) -> bool { let sp_delim = if context.config.spaces_around_ranges() { format!(" {}", delim) } else { - delim.to_owned() + default_sp_delim(Some(lhs), None) }; rewrite_unary_suffix(context, &sp_delim, &*lhs, shape) } @@ -294,23 +316,61 @@ fn needs_space_before_range(context: &RewriteContext, lhs: &ast::Expr) -> bool { } // We do not format these expressions yet, but they should still // satisfy our width restrictions. - ast::ExprKind::InPlace(..) | ast::ExprKind::InlineAsm(..) => { - Some(context.snippet(expr.span).to_owned()) - } + ast::ExprKind::InlineAsm(..) => Some(context.snippet(expr.span).to_owned()), ast::ExprKind::Catch(ref block) => { - if let rw @ Some(_) = - rewrite_single_line_block(context, "do catch ", block, Some(&expr.attrs), shape) - { + if let rw @ Some(_) = rewrite_single_line_block( + context, + "do catch ", + block, + Some(&expr.attrs), + None, + shape, + ) { rw } else { // 9 = `do catch ` - let budget = shape.width.checked_sub(9).unwrap_or(0); + let budget = shape.width.saturating_sub(9); Some(format!( "{}{}", "do catch ", rewrite_block( block, Some(&expr.attrs), + None, + context, + Shape::legacy(budget, shape.indent) + )? + )) + } + } + // FIXME(#2743) + ast::ExprKind::ObsoleteInPlace(..) => unimplemented!(), + ast::ExprKind::Async(capture_by, _node_id, ref block) => { + let mover = if capture_by == ast::CaptureBy::Value { + "move " + } else { + "" + }; + if let rw @ Some(_) = rewrite_single_line_block( + context, + format!("{}{}", "async ", mover).as_str(), + block, + Some(&expr.attrs), + None, + shape, + ) { + rw + } else { + // 6 = `async ` + let budget = shape.width.saturating_sub(6); + Some(format!( + "{}{}{}", + "async ", + mover, + rewrite_block( + block, + Some(&expr.attrs), + None, context, Shape::legacy(budget, shape.indent) )? @@ -332,95 +392,6 @@ fn needs_space_before_range(context: &RewriteContext, lhs: &ast::Expr) -> bool { }) } -#[derive(new, Clone, Copy)] -pub struct PairParts<'a> { - prefix: &'a str, - infix: &'a str, - suffix: &'a str, -} - -pub fn rewrite_pair( - lhs: &LHS, - rhs: &RHS, - pp: PairParts, - context: &RewriteContext, - shape: Shape, - separator_place: SeparatorPlace, -) -> Option -where - LHS: Rewrite, - RHS: Rewrite, -{ - let lhs_overhead = match separator_place { - SeparatorPlace::Back => shape.used_width() + pp.prefix.len() + pp.infix.trim_right().len(), - SeparatorPlace::Front => shape.used_width(), - }; - let lhs_shape = Shape { - width: context.budget(lhs_overhead), - ..shape - }; - let lhs_result = lhs.rewrite(context, lhs_shape) - .map(|lhs_str| format!("{}{}", pp.prefix, lhs_str))?; - - // Try to put both lhs and rhs on the same line. - let rhs_orig_result = shape - .offset_left(last_line_width(&lhs_result) + pp.infix.len()) - .and_then(|s| s.sub_width(pp.suffix.len())) - .and_then(|rhs_shape| rhs.rewrite(context, rhs_shape)); - if let Some(ref rhs_result) = rhs_orig_result { - // If the length of the lhs is equal to or shorter than the tab width or - // the rhs looks like block expression, we put the rhs on the same - // line with the lhs even if the rhs is multi-lined. - let allow_same_line = lhs_result.len() <= context.config.tab_spaces() - || rhs_result - .lines() - .next() - .map(|first_line| first_line.ends_with('{')) - .unwrap_or(false); - if !rhs_result.contains('\n') || allow_same_line { - let one_line_width = last_line_width(&lhs_result) + pp.infix.len() - + first_line_width(rhs_result) + pp.suffix.len(); - if one_line_width <= shape.width { - return Some(format!( - "{}{}{}{}", - lhs_result, pp.infix, rhs_result, pp.suffix - )); - } - } - } - - // We have to use multiple lines. - // Re-evaluate the rhs because we have more space now: - let mut rhs_shape = match context.config.indent_style() { - IndentStyle::Visual => shape - .sub_width(pp.suffix.len() + pp.prefix.len())? - .visual_indent(pp.prefix.len()), - IndentStyle::Block => { - // Try to calculate the initial constraint on the right hand side. - let rhs_overhead = shape.rhs_overhead(context.config); - Shape::indented(shape.indent.block_indent(context.config), context.config) - .sub_width(rhs_overhead)? - } - }; - let infix = match separator_place { - SeparatorPlace::Back => pp.infix.trim_right(), - SeparatorPlace::Front => pp.infix.trim_left(), - }; - if separator_place == SeparatorPlace::Front { - rhs_shape = rhs_shape.offset_left(infix.len())?; - } - let rhs_result = rhs.rewrite(context, rhs_shape)?; - let indent_str = rhs_shape.indent.to_string_with_newline(context.config); - let infix_with_sep = match separator_place { - SeparatorPlace::Back => format!("{}{}", infix, indent_str), - SeparatorPlace::Front => format!("{}{}", indent_str, infix), - }; - Some(format!( - "{}{}{}{}", - lhs_result, infix_with_sep, rhs_result, pp.suffix - )) -} - pub fn rewrite_array( name: &str, exprs: &[&T], @@ -445,16 +416,18 @@ fn rewrite_empty_block( context: &RewriteContext, block: &ast::Block, attrs: Option<&[ast::Attribute]>, + label: Option, prefix: &str, shape: Shape, ) -> Option { + let label_str = rewrite_label(label); if attrs.map_or(false, |a| !inner_attributes(a).is_empty()) { return None; } if block.stmts.is_empty() && !block_contains_comment(block, context.codemap) && shape.width >= 2 { - return Some(format!("{}{{}}", prefix)); + return Some(format!("{}{}{{}}", prefix, label_str)); } // If a block contains only a single-line comment, then leave it on one line. @@ -462,10 +435,12 @@ fn rewrite_empty_block( let user_str = user_str.trim(); if user_str.starts_with('{') && user_str.ends_with('}') { let comment_str = user_str[1..user_str.len() - 1].trim(); - if block.stmts.is_empty() && !comment_str.contains('\n') && !comment_str.starts_with("//") + if block.stmts.is_empty() + && !comment_str.contains('\n') + && !comment_str.starts_with("//") && comment_str.len() + 4 <= shape.width { - return Some(format!("{}{{ {} }}", prefix, comment_str)); + return Some(format!("{}{}{{ {} }}", prefix, label_str, comment_str)); } } @@ -505,12 +480,14 @@ fn rewrite_single_line_block( prefix: &str, block: &ast::Block, attrs: Option<&[ast::Attribute]>, + label: Option, shape: Shape, ) -> Option { if is_simple_block(block, attrs, context.codemap) { let expr_shape = shape.offset_left(last_line_width(prefix))?; let expr_str = block.stmts[0].rewrite(context, expr_shape)?; - let result = format!("{}{{ {} }}", prefix, expr_str); + let label_str = rewrite_label(label); + let result = format!("{}{}{{ {} }}", prefix, label_str, expr_str); if result.len() <= shape.width && !result.contains('\n') { return Some(result); } @@ -523,10 +500,11 @@ pub fn rewrite_block_with_visitor( prefix: &str, block: &ast::Block, attrs: Option<&[ast::Attribute]>, + label: Option, shape: Shape, has_braces: bool, ) -> Option { - if let rw @ Some(_) = rewrite_empty_block(context, block, attrs, prefix, shape) { + if let rw @ Some(_) = rewrite_empty_block(context, block, attrs, label, prefix, shape) { return rw; } @@ -543,19 +521,21 @@ pub fn rewrite_block_with_visitor( } let inner_attrs = attrs.map(inner_attributes); + let label_str = rewrite_label(label); visitor.visit_block(block, inner_attrs.as_ref().map(|a| &**a), has_braces); - Some(format!("{}{}", prefix, visitor.buffer)) + Some(format!("{}{}{}", prefix, label_str, visitor.buffer)) } impl Rewrite for ast::Block { fn rewrite(&self, context: &RewriteContext, shape: Shape) -> Option { - rewrite_block(self, None, context, shape) + rewrite_block(self, None, None, context, shape) } } fn rewrite_block( block: &ast::Block, attrs: Option<&[ast::Attribute]>, + label: Option, context: &RewriteContext, shape: Shape, ) -> Option { @@ -563,14 +543,16 @@ fn rewrite_block( // shape.width is used only for the single line case: either the empty block `{}`, // or an unsafe expression `unsafe { e }`. - if let rw @ Some(_) = rewrite_empty_block(context, block, attrs, &prefix, shape) { + if let rw @ Some(_) = rewrite_empty_block(context, block, attrs, label, &prefix, shape) { return rw; } - let result = rewrite_block_with_visitor(context, &prefix, block, attrs, shape, true); + let result = rewrite_block_with_visitor(context, &prefix, block, attrs, label, shape, true); if let Some(ref result_str) = result { if result_str.lines().count() <= 3 { - if let rw @ Some(_) = rewrite_single_line_block(context, &prefix, block, attrs, shape) { + if let rw @ Some(_) = + rewrite_single_line_block(context, &prefix, block, attrs, label, shape) + { return rw; } } @@ -786,7 +768,7 @@ fn rewrite_single_line( let else_block = self.else_block?; let fixed_cost = self.keyword.len() + " { } else { }".len(); - if let ast::ExprKind::Block(ref else_node) = else_block.node { + if let ast::ExprKind::Block(ref else_node, _) = else_block.node { if !is_simple_block(self.block, None, context.codemap) || !is_simple_block(else_node, None, context.codemap) || pat_expr_str.contains('\n') @@ -901,8 +883,7 @@ fn rewrite_cond( let one_line_budget = context .config .max_width() - .checked_sub(constr_shape.used_width() + offset + brace_overhead) - .unwrap_or(0); + .saturating_sub(constr_shape.used_width() + offset + brace_overhead); let force_newline_brace = (pat_expr_string.contains('\n') || pat_expr_string.len() > one_line_budget) && !last_line_extendable(&pat_expr_string); @@ -912,16 +893,16 @@ fn rewrite_cond( && context .config .width_heuristics() - .single_line_if_else_max_width > 0 + .single_line_if_else_max_width + > 0 { let trial = self.rewrite_single_line(&pat_expr_string, context, shape.width); if let Some(cond_str) = trial { - if cond_str.len() - <= context - .config - .width_heuristics() - .single_line_if_else_max_width + if cond_str.len() <= context + .config + .width_heuristics() + .single_line_if_else_max_width { return Some((cond_str, 0)); } @@ -936,7 +917,9 @@ fn rewrite_cond( // `for event in event` // Do not include label in the span. - let lo = self.label.map_or(self.span.lo(), |label| label.span.hi()); + let lo = self + .label + .map_or(self.span.lo(), |label| label.ident.span.hi()); let between_kwd_cond = mk_sp( context .snippet_provider @@ -1006,7 +989,7 @@ fn rewrite(&self, context: &RewriteContext, shape: Shape) -> Option { return Some(cond_str); } - let block_width = shape.width.checked_sub(used_width).unwrap_or(0); + let block_width = shape.width.saturating_sub(used_width); // This is used only for the empty block case: `{}`. So, we use 1 if we know // we should avoid the single line case. let block_width = if self.else_block.is_some() || self.nested_if { @@ -1021,7 +1004,7 @@ fn rewrite(&self, context: &RewriteContext, shape: Shape) -> Option { let block_str = { let old_val = context.is_if_else_block.replace(self.else_block.is_some()); let result = - rewrite_block_with_visitor(context, "", self.block, None, block_shape, true); + rewrite_block_with_visitor(context, "", self.block, None, None, block_shape, true); context.is_if_else_block.replace(old_val); result? }; @@ -1144,8 +1127,10 @@ pub fn is_simple_block( attrs: Option<&[ast::Attribute]>, codemap: &CodeMap, ) -> bool { - (block.stmts.len() == 1 && stmt_is_expr(&block.stmts[0]) - && !block_contains_comment(block, codemap) && attrs.map_or(true, |a| a.is_empty())) + (block.stmts.len() == 1 + && stmt_is_expr(&block.stmts[0]) + && !block_contains_comment(block, codemap) + && attrs.map_or(true, |a| a.is_empty())) } /// Checks whether a block contains at most one statement or expression, and no @@ -1155,7 +1140,8 @@ pub fn is_simple_block_stmt( attrs: Option<&[ast::Attribute]>, codemap: &CodeMap, ) -> bool { - block.stmts.len() <= 1 && !block_contains_comment(block, codemap) + block.stmts.len() <= 1 + && !block_contains_comment(block, codemap) && attrs.map_or(true, |a| a.is_empty()) } @@ -1166,7 +1152,8 @@ pub fn is_empty_block( attrs: Option<&[ast::Attribute]>, codemap: &CodeMap, ) -> bool { - block.stmts.is_empty() && !block_contains_comment(block, codemap) + block.stmts.is_empty() + && !block_contains_comment(block, codemap) && attrs.map_or(true, |a| inner_attributes(a).is_empty()) } @@ -1190,11 +1177,13 @@ pub fn rewrite_multiple_patterns( pats: &[&ast::Pat], shape: Shape, ) -> Option { - let pat_strs = pats.iter() + let pat_strs = pats + .iter() .map(|p| p.rewrite(context, shape)) .collect::>>()?; - let use_mixed_layout = pats.iter() + let use_mixed_layout = pats + .iter() .zip(pat_strs.iter()) .all(|(pat, pat_str)| is_short_pattern(pat, pat_str)); let items: Vec<_> = pat_strs.into_iter().map(ListItem::from_str).collect(); @@ -1216,6 +1205,7 @@ pub fn rewrite_multiple_patterns( shape, ends_with_newline: false, preserve_newline: false, + nested: false, config: context.config, }; write_list(&items, &fmt) @@ -1252,8 +1242,7 @@ fn rewrite_string_lit(context: &RewriteContext, span: Span, shape: Shape) -> Opt new_indent.to_string(context.config), line.trim_left() ) - }) - .collect::>() + }).collect::>() .join("\n") .trim_left(), ); @@ -1269,7 +1258,6 @@ fn rewrite_string_lit(context: &RewriteContext, span: Span, shape: Shape) -> Opt rewrite_string( str_lit, &StringFormat::new(shape.visual_indent(0), context.config), - None, ) } @@ -1321,6 +1309,18 @@ pub fn maybe_get_args_offset(callee_str: &str, args: &[&T]) -> Option ("debug_assert_ne!", 2), ]; +fn choose_separator_tactic(context: &RewriteContext, span: Span) -> Option { + if context.inside_macro() { + if span_ends_with_comma(context, span) { + Some(SeparatorTactic::Always) + } else { + Some(SeparatorTactic::Never) + } + } else { + None + } +} + pub fn rewrite_call( context: &RewriteContext, callee: &str, @@ -1335,15 +1335,7 @@ pub fn rewrite_call( shape, span, context.config.width_heuristics().fn_call_width, - if context.inside_macro() { - if span_ends_with_comma(context, span) { - Some(SeparatorTactic::Always) - } else { - Some(SeparatorTactic::Never) - } - } else { - None - }, + choose_separator_tactic(context, span), ) } @@ -1356,10 +1348,10 @@ fn is_simple_expr(expr: &ast::Expr) -> bool { | ast::ExprKind::Cast(ref expr, _) | ast::ExprKind::Field(ref expr, _) | ast::ExprKind::Try(ref expr) - | ast::ExprKind::TupField(ref expr, _) | ast::ExprKind::Unary(_, ref expr) => is_simple_expr(expr), - ast::ExprKind::Index(ref lhs, ref rhs) | ast::ExprKind::Repeat(ref lhs, ref rhs) => { - is_simple_expr(lhs) && is_simple_expr(rhs) + ast::ExprKind::Index(ref lhs, ref rhs) => is_simple_expr(lhs) && is_simple_expr(rhs), + ast::ExprKind::Repeat(ref lhs, ref rhs) => { + is_simple_expr(lhs) && is_simple_expr(&*rhs.value) } _ => false, } @@ -1422,11 +1414,14 @@ pub fn is_nested_call(expr: &ast::Expr) -> bool { pub fn span_ends_with_comma(context: &RewriteContext, span: Span) -> bool { let mut result: bool = Default::default(); let mut prev_char: char = Default::default(); + let closing_delimiters = &[')', '}', ']']; for (kind, c) in CharClasses::new(context.snippet(span).chars()) { match c { _ if kind.is_comment() || c.is_whitespace() => continue, - ')' | '}' => result = result && prev_char != ')' && prev_char != '}', + c if closing_delimiters.contains(&c) => { + result &= !closing_delimiters.contains(&prev_char); + } ',' => result = true, _ => result = false, } @@ -1447,6 +1442,7 @@ fn rewrite_paren( // Extract comments within parens. let mut pre_comment; let mut post_comment; + let remove_nested_parens = context.config.remove_nested_parens(); loop { // 1 = "(" or ")" let pre_span = mk_sp(span.lo() + BytePos(1), subexpr.span.lo()); @@ -1456,7 +1452,7 @@ fn rewrite_paren( // Remove nested parens if there are no comments. if let ast::ExprKind::Paren(ref subsubexpr) = subexpr.node { - if pre_comment.is_empty() && post_comment.is_empty() { + if remove_nested_parens && pre_comment.is_empty() && post_comment.is_empty() { span = subexpr.span; subexpr = subsubexpr; continue; @@ -1466,27 +1462,15 @@ fn rewrite_paren( break; } - let total_paren_overhead = paren_overhead(context); - let paren_overhead = total_paren_overhead / 2; - let sub_shape = shape - .offset_left(paren_overhead) - .and_then(|s| s.sub_width(paren_overhead))?; - - let paren_wrapper = |s: &str| { - if context.config.spaces_within_parens_and_brackets() && !s.is_empty() { - format!("( {}{}{} )", pre_comment, s, post_comment) - } else { - format!("({}{}{})", pre_comment, s, post_comment) - } - }; + // 1 `(` + let sub_shape = shape.offset_left(1).and_then(|s| s.sub_width(1))?; let subexpr_str = subexpr.rewrite(context, sub_shape)?; debug!("rewrite_paren, subexpr_str: `{:?}`", subexpr_str); - if subexpr_str.contains('\n') - || first_line_width(&subexpr_str) + total_paren_overhead <= shape.width - { - Some(paren_wrapper(&subexpr_str)) + // 2 = `()` + if subexpr_str.contains('\n') || first_line_width(&subexpr_str) + 2 <= shape.width { + Some(format!("({}{}{})", pre_comment, &subexpr_str, post_comment)) } else { None } @@ -1500,54 +1484,44 @@ fn rewrite_index( ) -> Option { let expr_str = expr.rewrite(context, shape)?; - let (lbr, rbr) = if context.config.spaces_within_parens_and_brackets() { - ("[ ", " ]") - } else { - ("[", "]") - }; - - let offset = last_line_width(&expr_str) + lbr.len(); + let offset = last_line_width(&expr_str) + 1; let rhs_overhead = shape.rhs_overhead(context.config); let index_shape = if expr_str.contains('\n') { Shape::legacy(context.config.max_width(), shape.indent) .offset_left(offset) - .and_then(|shape| shape.sub_width(rbr.len() + rhs_overhead)) + .and_then(|shape| shape.sub_width(1 + rhs_overhead)) } else { - shape.visual_indent(offset).sub_width(offset + rbr.len()) + shape.visual_indent(offset).sub_width(offset + 1) }; let orig_index_rw = index_shape.and_then(|s| index.rewrite(context, s)); // Return if index fits in a single line. match orig_index_rw { Some(ref index_str) if !index_str.contains('\n') => { - return Some(format!("{}{}{}{}", expr_str, lbr, index_str, rbr)); + return Some(format!("{}[{}]", expr_str, index_str)); } _ => (), } // Try putting index on the next line and see if it fits in a single line. let indent = shape.indent.block_indent(context.config); - let index_shape = Shape::indented(indent, context.config).offset_left(lbr.len())?; - let index_shape = index_shape.sub_width(rbr.len() + rhs_overhead)?; + let index_shape = Shape::indented(indent, context.config).offset_left(1)?; + let index_shape = index_shape.sub_width(1 + rhs_overhead)?; let new_index_rw = index.rewrite(context, index_shape); match (orig_index_rw, new_index_rw) { (_, Some(ref new_index_str)) if !new_index_str.contains('\n') => Some(format!( - "{}{}{}{}{}", + "{}{}[{}]", expr_str, indent.to_string_with_newline(context.config), - lbr, new_index_str, - rbr )), (None, Some(ref new_index_str)) => Some(format!( - "{}{}{}{}{}", + "{}{}[{}]", expr_str, indent.to_string_with_newline(context.config), - lbr, new_index_str, - rbr )), - (Some(ref index_str), _) => Some(format!("{}{}{}{}", expr_str, lbr, index_str, rbr)), + (Some(ref index_str), _) => Some(format!("{}[{}]", expr_str, index_str)), _ => None, } } @@ -1647,11 +1621,7 @@ enum StructLitField<'a> { let nested_shape = shape_for_tactic(tactic, h_shape, v_shape); let ends_with_comma = span_ends_with_comma(context, span); - let force_no_trailing_comma = if context.inside_macro() && !ends_with_comma { - true - } else { - false - }; + let force_no_trailing_comma = context.inside_macro() && !ends_with_comma; let fmt = struct_lit_formatting( nested_shape, @@ -1678,7 +1648,8 @@ pub fn wrap_struct_field( one_line_width: usize, ) -> String { if context.config.indent_style() == IndentStyle::Block - && (fields_str.contains('\n') || !context.config.struct_lit_single_line() + && (fields_str.contains('\n') + || !context.config.struct_lit_single_line() || fields_str.len() > one_line_width) { format!( @@ -1710,12 +1681,12 @@ pub fn rewrite_field( if !attrs_str.is_empty() { attrs_str.push_str(&shape.indent.to_string_with_newline(context.config)); }; - let name = field.ident.node.to_string(); + let name = context.snippet(field.ident.span); if field.is_shorthand { Some(attrs_str + &name) } else { let mut separator = String::from(struct_lit_field_separator(context.config)); - for _ in 0..prefix_max_width.checked_sub(name.len()).unwrap_or(0) { + for _ in 0..prefix_max_width.saturating_sub(name.len()) { separator.push(' '); } let overhead = name.len() + separator.len(); @@ -1765,13 +1736,7 @@ fn rewrite_tuple_in_visual_indent_style<'a, T>( .next() .unwrap() .rewrite(context, nested_shape) - .map(|s| { - if context.config.spaces_within_parens_and_brackets() { - format!("( {}, )", s) - } else { - format!("({},)", s) - } - }); + .map(|s| format!("({},)", s)); } let list_lo = context.snippet_provider.span_after(span, "("); @@ -1803,15 +1768,12 @@ fn rewrite_tuple_in_visual_indent_style<'a, T>( shape, ends_with_newline: false, preserve_newline: false, + nested: false, config: context.config, }; let list_str = write_list(&item_vec, &fmt)?; - if context.config.spaces_within_parens_and_brackets() && !list_str.is_empty() { - Some(format!("( {} )", list_str)) - } else { - Some(format!("({})", list_str)) - } + Some(format!("({})", list_str)) } pub fn rewrite_tuple<'a, T>( @@ -1832,12 +1794,10 @@ pub fn rewrite_tuple<'a, T>( } else { Some(SeparatorTactic::Never) } + } else if items.len() == 1 { + Some(SeparatorTactic::Always) } else { - if items.len() == 1 { - Some(SeparatorTactic::Always) - } else { - None - } + None }; overflow::rewrite_with_parens( context, @@ -1919,8 +1879,8 @@ fn rewrite_assignment( pub enum RhsTactics { /// Use heuristics. Default, - /// Put the rhs on the next line if it uses multiple line. - ForceNextLine, + /// Put the rhs on the next line if it uses multiple line, without extra indentation. + ForceNextLineWithoutIndent, } // The left hand side must contain everything up to, and including, the @@ -1942,13 +1902,11 @@ pub fn rewrite_assign_rhs_with, R: Rewrite>( rhs_tactics: RhsTactics, ) -> Option { let lhs = lhs.into(); - let last_line_width = last_line_width(&lhs) - .checked_sub(if lhs.contains('\n') { - shape.indent.width() - } else { - 0 - }) - .unwrap_or(0); + let last_line_width = last_line_width(&lhs).saturating_sub(if lhs.contains('\n') { + shape.indent.width() + } else { + 0 + }); // 1 = space between operator and rhs. let orig_shape = shape.offset_left(last_line_width + 1).unwrap_or(Shape { width: 0, @@ -1979,11 +1937,12 @@ fn choose_rhs( _ => { // Expression did not fit on the same line as the identifier. // Try splitting the line and see if that works better. - let new_shape = - Shape::indented(shape.indent.block_indent(context.config), context.config) - .sub_width(shape.rhs_overhead(context.config))?; + let new_shape = shape_from_rhs_tactic(context, shape, rhs_tactics)?; let new_rhs = expr.rewrite(context, new_shape); - let new_indent_str = &new_shape.indent.to_string_with_newline(context.config); + let new_indent_str = &shape + .indent + .block_indent(context.config) + .to_string_with_newline(context.config); match (orig_rhs, new_rhs) { (Some(ref orig_rhs), Some(ref new_rhs)) @@ -1999,15 +1958,33 @@ fn choose_rhs( } (None, Some(ref new_rhs)) => Some(format!("{}{}", new_indent_str, new_rhs)), (None, None) => None, - (Some(ref orig_rhs), _) => Some(format!(" {}", orig_rhs)), + (Some(orig_rhs), _) => Some(format!(" {}", orig_rhs)), } } } } +fn shape_from_rhs_tactic( + context: &RewriteContext, + shape: Shape, + rhs_tactic: RhsTactics, +) -> Option { + match rhs_tactic { + RhsTactics::ForceNextLineWithoutIndent => Some(shape.with_max_width(context.config)), + RhsTactics::Default => { + Shape::indented(shape.indent.block_indent(context.config), context.config) + .sub_width(shape.rhs_overhead(context.config)) + } + } +} + pub fn prefer_next_line(orig_rhs: &str, next_line_rhs: &str, rhs_tactics: RhsTactics) -> bool { - rhs_tactics == RhsTactics::ForceNextLine || !next_line_rhs.contains('\n') + rhs_tactics == RhsTactics::ForceNextLineWithoutIndent + || !next_line_rhs.contains('\n') || count_newlines(orig_rhs) > count_newlines(next_line_rhs) + 1 + || first_line_ends_with(orig_rhs, '(') && !first_line_ends_with(next_line_rhs, '(') + || first_line_ends_with(orig_rhs, '{') && !first_line_ends_with(next_line_rhs, '{') + || first_line_ends_with(orig_rhs, '[') && !first_line_ends_with(next_line_rhs, '[') } fn rewrite_expr_addrof( @@ -2095,3 +2072,15 @@ fn can_be_overflowed(&self, _: &RewriteContext, _: usize) -> bool { false } } + +pub fn is_method_call(expr: &ast::Expr) -> bool { + match expr.node { + ast::ExprKind::MethodCall(..) => true, + ast::ExprKind::AddrOf(_, ref expr) + | ast::ExprKind::Box(ref expr) + | ast::ExprKind::Cast(ref expr, _) + | ast::ExprKind::Try(ref expr) + | ast::ExprKind::Unary(_, ref expr) => is_method_call(expr), + _ => false, + } +}