diff --git a/src/bin/main.rs b/src/bin/main.rs index 5b6398f028ef..7767ea847646 100644 --- a/src/bin/main.rs +++ b/src/bin/main.rs @@ -422,8 +422,7 @@ fn determine_operation(matches: &Matches) -> Result { // we will do comparison later, so here tries to canonicalize first // to get the expected behavior. p.canonicalize().unwrap_or(p) - }) - .collect(); + }).collect(); Ok(Operation::Format { files, diff --git a/src/cargo-fmt/main.rs b/src/cargo-fmt/main.rs index 3246908e20c1..2d8234ef41e3 100644 --- a/src/cargo-fmt/main.rs +++ b/src/cargo-fmt/main.rs @@ -163,8 +163,7 @@ fn format_crate( if verbosity == Verbosity::Verbose { println!("[{}] {:?}", t.kind, t.path) } - }) - .map(|t| t.path) + }).map(|t| t.path) .collect(); run_rustfmt(&files, &rustfmt_args, verbosity) diff --git a/src/chains.rs b/src/chains.rs index 52999635cf12..7acb9b9126f4 100644 --- a/src/chains.rs +++ b/src/chains.rs @@ -84,107 +84,277 @@ use syntax::codemap::Span; use syntax::{ast, ptr}; pub fn rewrite_chain(expr: &ast::Expr, context: &RewriteContext, shape: Shape) -> Option { - debug!("rewrite_chain {:?}", shape); - let total_span = expr.span; - let (parent, subexpr_list) = make_subexpr_list(expr, context); + let chain = Chain::from_ast(expr, context); + debug!("rewrite_chain {:?} {:?}", chain, shape); - // Bail out if the chain is just try sugar, i.e., an expression followed by - // any number of `?`s. - if chain_only_try(&subexpr_list) { - return rewrite_try(&parent, subexpr_list.len(), context, shape); + // If this is just an expression with some `?`s, then format it trivially and + // return early. + if chain.children.is_empty() { + return chain.parent.rewrite(context, shape); } - let suffix_try_num = subexpr_list.iter().take_while(|e| is_try(e)).count(); - let prefix_try_num = subexpr_list.iter().rev().take_while(|e| is_try(e)).count(); + chain.rewrite(context, shape) +} + +// An expression plus trailing `?`s to be formatted together. +#[derive(Debug)] +struct ChainItem { + // FIXME: we can't use a reference here because to convert `try!` to `?` we + // synthesise the AST node. However, I think we could use `Cow` and that + // would remove a lot of cloning. + expr: ast::Expr, + tries: usize, +} + +impl Rewrite for ChainItem { + fn rewrite(&self, context: &RewriteContext, shape: Shape) -> Option { + let rewrite = self.expr.rewrite(context, shape.sub_width(self.tries)?)?; + Some(format!("{}{}", rewrite, "?".repeat(self.tries))) + } +} + +impl ChainItem { + // Rewrite the last element in the chain `expr`. E.g., given `a.b.c` we rewrite + // `.c` and any trailing `?`s. + fn rewrite_postfix(&self, context: &RewriteContext, shape: Shape) -> Option { + let shape = shape.sub_width(self.tries)?; + let mut rewrite = match self.expr.node { + ast::ExprKind::MethodCall(ref segment, ref expressions) => { + let types = match segment.args { + Some(ref params) => match **params { + ast::GenericArgs::AngleBracketed(ref data) => &data.args[..], + _ => &[], + }, + _ => &[], + }; + Self::rewrite_method_call( + segment.ident, + types, + expressions, + self.expr.span, + context, + shape, + )? + } + ast::ExprKind::Field(ref nested, ref field) => { + let space = + if Self::is_tup_field_access(&self.expr) && Self::is_tup_field_access(nested) { + " " + } else { + "" + }; + let result = format!("{}.{}", space, field.name); + if result.len() <= shape.width { + result + } else { + return None; + } + } + _ => unreachable!(), + }; + rewrite.push_str(&"?".repeat(self.tries)); + Some(rewrite) + } + + fn is_tup_field_access(expr: &ast::Expr) -> bool { + match expr.node { + ast::ExprKind::Field(_, ref field) => { + field.name.to_string().chars().all(|c| c.is_digit(10)) + } + _ => false, + } + } + + fn rewrite_method_call( + method_name: ast::Ident, + types: &[ast::GenericArg], + args: &[ptr::P], + span: Span, + context: &RewriteContext, + shape: Shape, + ) -> Option { + let (lo, type_str) = if types.is_empty() { + (args[0].span.hi(), String::new()) + } else { + let type_list = types + .iter() + .map(|ty| ty.rewrite(context, shape)) + .collect::>>()?; + + let type_str = format!("::<{}>", type_list.join(", ")); + + (types.last().unwrap().span().hi(), type_str) + }; + + let callee_str = format!(".{}{}", method_name, type_str); + let span = mk_sp(lo, span.hi()); + + rewrite_call(context, &callee_str, &args[1..], span, shape) + } +} + +#[derive(Debug)] +struct Chain { + parent: ChainItem, + children: Vec, +} + +impl Chain { + fn from_ast(expr: &ast::Expr, context: &RewriteContext) -> Chain { + let subexpr_list = Self::make_subexpr_list(expr, context); + + // Un-parse the expression tree into ChainItems + let mut children = vec![]; + let mut sub_tries = 0; + for subexpr in subexpr_list { + match subexpr.node { + ast::ExprKind::Try(_) => sub_tries += 1, + _ => { + children.push(ChainItem { + expr: subexpr, + tries: sub_tries, + }); + sub_tries = 0; + } + } + } + + Chain { + parent: children.pop().unwrap(), + children, + } + } + + // Returns a Vec of the prefixes of the chain. + // E.g., for input `a.b.c` we return [`a.b.c`, `a.b`, 'a'] + fn make_subexpr_list(expr: &ast::Expr, context: &RewriteContext) -> Vec { + let mut subexpr_list = vec![expr.clone()]; + + while let Some(subexpr) = Self::pop_expr_chain(subexpr_list.last().unwrap(), context) { + subexpr_list.push(subexpr.clone()); + } + + subexpr_list + } + + // Returns the expression's subexpression, if it exists. When the subexpr + // is a try! macro, we'll convert it to shorthand when the option is set. + fn pop_expr_chain(expr: &ast::Expr, context: &RewriteContext) -> Option { + match expr.node { + ast::ExprKind::MethodCall(_, ref expressions) => { + Some(Self::convert_try(&expressions[0], context)) + } + ast::ExprKind::Field(ref subexpr, _) | ast::ExprKind::Try(ref subexpr) => { + Some(Self::convert_try(subexpr, context)) + } + _ => None, + } + } + + fn convert_try(expr: &ast::Expr, context: &RewriteContext) -> ast::Expr { + match expr.node { + ast::ExprKind::Mac(ref mac) if context.config.use_try_shorthand() => { + if let Some(subexpr) = convert_try_mac(mac, context) { + subexpr + } else { + expr.clone() + } + } + _ => expr.clone(), + } + } +} + +impl Rewrite for Chain { + fn rewrite(&self, context: &RewriteContext, shape: Shape) -> Option { + debug!("rewrite chain {:?} {:?}", self, shape); + + let mut formatter = match context.config.indent_style() { + IndentStyle::Block => Box::new(ChainFormatterBlock::new(self)) as Box, + IndentStyle::Visual => Box::new(ChainFormatterVisual::new(self)) as Box, + }; + + formatter.format_root(&self.parent, context, shape)?; + if let Some(result) = formatter.pure_root() { + return wrap_str(result, context.config.max_width(), shape); + } + + // Decide how to layout the rest of the chain. + let child_shape = formatter.child_shape(context, shape)?; + + formatter.format_children(context, child_shape)?; + formatter.format_last_child(context, shape, child_shape)?; + + let result = formatter.join_rewrites(context, child_shape)?; + wrap_str(result, context.config.max_width(), shape) + } +} + +// There are a few types for formatting chains. This is because there is a lot +// in common between formatting with block vs visual indent, but they are +// different enough that branching on the indent all over the place gets ugly. +// Anything that can format a chain is a ChainFormatter. +trait ChainFormatter { // Parent is the first item in the chain, e.g., `foo` in `foo.bar.baz()`. - let parent_shape = if is_block_expr(context, &parent, "\n") { - match context.config.indent_style() { - IndentStyle::Visual => shape.visual_indent(0), - IndentStyle::Block => shape, + // Root is the parent plus any other chain items placed on the first line to + // avoid an orphan. E.g., + // ``` + // foo.bar + // .baz() + // ``` + // If `bar` were not part of the root, then foo would be orphaned and 'float'. + fn format_root( + &mut self, + parent: &ChainItem, + context: &RewriteContext, + shape: Shape, + ) -> Option<()>; + fn child_shape(&self, context: &RewriteContext, shape: Shape) -> Option; + fn format_children(&mut self, context: &RewriteContext, child_shape: Shape) -> Option<()>; + fn format_last_child( + &mut self, + context: &RewriteContext, + shape: Shape, + child_shape: Shape, + ) -> Option<()>; + fn join_rewrites(&self, context: &RewriteContext, child_shape: Shape) -> Option; + // Returns `Some` if the chain is only a root, None otherwise. + fn pure_root(&mut self) -> Option; +} + +// Data and behaviour that is shared by both chain formatters. The concrete +// formatters can delegate much behaviour to `ChainFormatterShared`. +struct ChainFormatterShared<'a> { + // The current working set of child items. + children: &'a [ChainItem], + // The current rewrites of items (includes trailing `?`s, but not any way to + // connect the rewrites together). + rewrites: Vec, + // Whether the chain can fit on one line. + fits_single_line: bool, + // The number of children in the chain. This is not equal to `self.children.len()` + // because `self.children` will change size as we process the chain. + child_count: usize, +} + +impl<'a> ChainFormatterShared<'a> { + fn new(chain: &'a Chain) -> ChainFormatterShared<'a> { + ChainFormatterShared { + children: &chain.children, + rewrites: Vec::with_capacity(chain.children.len() + 1), + fits_single_line: false, + child_count: chain.children.len(), } - } else { - shape - }; - let parent_rewrite = parent - .rewrite(context, parent_shape) - .map(|parent_rw| parent_rw + &"?".repeat(prefix_try_num))?; - let parent_rewrite_contains_newline = parent_rewrite.contains('\n'); - let is_small_parent = shape.offset + parent_rewrite.len() <= context.config.tab_spaces(); + } - // Decide how to layout the rest of the chain. `extend` is true if we can - // put the first non-parent item on the same line as the parent. - let (nested_shape, extend) = if !parent_rewrite_contains_newline && is_continuable(&parent) { - ( - chain_indent(context, shape.add_offset(parent_rewrite.len())), - context.config.indent_style() == IndentStyle::Visual || is_small_parent, - ) - } else if is_block_expr(context, &parent, &parent_rewrite) { - match context.config.indent_style() { - // Try to put the first child on the same line with parent's last line - IndentStyle::Block => (parent_shape.block_indent(context.config.tab_spaces()), true), - // The parent is a block, so align the rest of the chain with the closing - // brace. - IndentStyle::Visual => (parent_shape, false), + fn pure_root(&mut self) -> Option { + if self.children.is_empty() { + assert_eq!(self.rewrites.len(), 1); + Some(self.rewrites.pop().unwrap()) + } else { + None } - } else { - ( - chain_indent(context, shape.add_offset(parent_rewrite.len())), - false, - ) - }; - - let other_child_shape = nested_shape.with_max_width(context.config); - - let first_child_shape = if extend { - let overhead = last_line_width(&parent_rewrite); - let offset = trimmed_last_line_width(&parent_rewrite) + prefix_try_num; - match context.config.indent_style() { - IndentStyle::Visual => parent_shape.offset_left(overhead)?, - IndentStyle::Block => parent_shape.offset_left(offset)?, - } - } else { - other_child_shape - }; - debug!( - "child_shapes {:?} {:?}", - first_child_shape, other_child_shape - ); - - let child_shape_iter = Some(first_child_shape) - .into_iter() - .chain(iter::repeat(other_child_shape)); - let subexpr_num = subexpr_list.len(); - let last_subexpr = &subexpr_list[suffix_try_num]; - let subexpr_list = &subexpr_list[suffix_try_num..subexpr_num - prefix_try_num]; - let iter = subexpr_list.iter().skip(1).rev().zip(child_shape_iter); - let mut rewrites = iter - .map(|(e, shape)| rewrite_chain_subexpr(e, total_span, context, shape)) - .collect::>>()?; - - // Total of all items excluding the last. - let extend_last_subexpr = if is_small_parent { - rewrites.len() == 1 && last_line_extendable(&rewrites[0]) - } else { - rewrites.is_empty() && last_line_extendable(&parent_rewrite) - }; - let almost_total = if extend_last_subexpr { - last_line_width(&parent_rewrite) - } else { - rewrites.iter().fold(0, |a, b| a + b.len()) + parent_rewrite.len() - } + suffix_try_num; - let one_line_budget = if rewrites.is_empty() { - shape.width - } else { - min(shape.width, context.config.width_heuristics().chain_width) - }; - let all_in_one_line = !parent_rewrite_contains_newline - && rewrites.iter().all(|s| !s.contains('\n')) - && almost_total < one_line_budget; - let last_shape = if rewrites.is_empty() { - first_child_shape - } else { - other_child_shape - }.sub_width(shape.rhs_overhead(context.config) + suffix_try_num)?; + } // Rewrite the last child. The last child of a chain requires special treatment. We need to // know whether 'overflowing' the last child make a better formatting: @@ -218,142 +388,305 @@ pub fn rewrite_chain(expr: &ast::Expr, context: &RewriteContext, shape: Shape) - // result // }) // ``` + fn format_last_child( + &mut self, + may_extend: bool, + context: &RewriteContext, + shape: Shape, + child_shape: Shape, + ) -> Option<()> { + let last = &self.children[0]; + let extendable = + may_extend && last_line_extendable(&self.rewrites[self.rewrites.len() - 1]); + let prev_last_line_width = last_line_width(&self.rewrites[self.rewrites.len() - 1]); - // `rewrite_last` rewrites the last child on its own line. We use a closure here instead of - // directly calling `rewrite_chain_subexpr()` to avoid exponential blowup. - let rewrite_last = || rewrite_chain_subexpr(last_subexpr, total_span, context, last_shape); - let (last_subexpr_str, fits_single_line) = if all_in_one_line || extend_last_subexpr { - // First we try to 'overflow' the last child and see if it looks better than using - // vertical layout. - parent_shape.offset_left(almost_total).map(|shape| { - if let Some(rw) = rewrite_chain_subexpr(last_subexpr, total_span, context, shape) { - // We allow overflowing here only if both of the following conditions match: - // 1. The entire chain fits in a single line expect the last child. - // 2. `last_child_str.lines().count() >= 5`. - let line_count = rw.lines().count(); - let fits_single_line = almost_total + first_line_width(&rw) <= one_line_budget; - if fits_single_line && line_count >= 5 { - (Some(rw), true) - } else { - // We could not know whether overflowing is better than using vertical layout, - // just by looking at the overflowed rewrite. Now we rewrite the last child - // on its own line, and compare two rewrites to choose which is better. - match rewrite_last() { - Some(ref new_rw) if !fits_single_line => (Some(new_rw.clone()), false), - Some(ref new_rw) if new_rw.lines().count() >= line_count => { - (Some(rw), fits_single_line) + // Total of all items excluding the last. + let almost_total = if extendable { + prev_last_line_width + } else { + self.rewrites.iter().fold(0, |a, b| a + b.len()) + } + last.tries; + let one_line_budget = if self.child_count == 1 { + shape.width + } else { + min(shape.width, context.config.width_heuristics().chain_width) + }.saturating_sub(almost_total); + + let all_in_one_line = + self.rewrites.iter().all(|s| !s.contains('\n')) && one_line_budget > 0; + let last_shape = if all_in_one_line { + shape.sub_width(last.tries)? + } else if extendable { + child_shape.sub_width(last.tries)? + } else { + child_shape.sub_width(shape.rhs_overhead(context.config) + last.tries)? + }; + + let mut last_subexpr_str = None; + if all_in_one_line || extendable { + // First we try to 'overflow' the last child and see if it looks better than using + // vertical layout. + if let Some(one_line_shape) = last_shape.offset_left(almost_total) { + if let Some(rw) = last.rewrite_postfix(context, one_line_shape) { + // We allow overflowing here only if both of the following conditions match: + // 1. The entire chain fits in a single line except the last child. + // 2. `last_child_str.lines().count() >= 5`. + let line_count = rw.lines().count(); + let could_fit_single_line = first_line_width(&rw) <= one_line_budget; + if could_fit_single_line && line_count >= 5 { + last_subexpr_str = Some(rw); + self.fits_single_line = all_in_one_line; + } else { + // We could not know whether overflowing is better than using vertical + // layout, just by looking at the overflowed rewrite. Now we rewrite the + // last child on its own line, and compare two rewrites to choose which is + // better. + let last_shape = child_shape + .sub_width(shape.rhs_overhead(context.config) + last.tries)?; + match last.rewrite_postfix(context, last_shape) { + Some(ref new_rw) if !could_fit_single_line => { + last_subexpr_str = Some(new_rw.clone()); + } + Some(ref new_rw) if new_rw.lines().count() >= line_count => { + last_subexpr_str = Some(rw); + self.fits_single_line = could_fit_single_line && all_in_one_line; + } + new_rw @ Some(..) => { + last_subexpr_str = new_rw; + } + _ => { + last_subexpr_str = Some(rw); + self.fits_single_line = could_fit_single_line && all_in_one_line; + } } - new_rw @ Some(..) => (new_rw, false), - _ => (Some(rw), fits_single_line), } } - } else { - (rewrite_last(), false) } - })? - } else { - (rewrite_last(), false) - }; - rewrites.push(last_subexpr_str?); - - let connector = if fits_single_line && !parent_rewrite_contains_newline { - // Yay, we can put everything on one line. - Cow::from("") - } else { - // Use new lines. - if *context.force_one_line_chain.borrow() { - return None; } - nested_shape.indent.to_string_with_newline(context.config) - }; - let first_connector = if is_small_parent - || fits_single_line - || last_line_extendable(&parent_rewrite) - || context.config.indent_style() == IndentStyle::Visual - { - "" - } else { - &connector - }; + last_subexpr_str = last_subexpr_str.or_else(|| last.rewrite_postfix(context, last_shape)); + self.rewrites.push(last_subexpr_str?); + Some(()) + } - let result = if is_small_parent && rewrites.len() > 1 { - let second_connector = if fits_single_line - || rewrites[1] == "?" - || last_line_extendable(&rewrites[0]) - || context.config.indent_style() == IndentStyle::Visual - { - "" + fn join_rewrites( + &self, + context: &RewriteContext, + child_shape: Shape, + block_like_iter: impl Iterator, + ) -> Option { + let connector = if self.fits_single_line { + // Yay, we can put everything on one line. + Cow::from("") } else { - &connector + // Use new lines. + if *context.force_one_line_chain.borrow() { + return None; + } + child_shape.to_string_with_newline(context.config) }; - format!( - "{}{}{}{}{}", - parent_rewrite, - first_connector, - rewrites[0], - second_connector, - join_rewrites(&rewrites[1..], &connector) - ) - } else { - format!( - "{}{}{}", - parent_rewrite, - first_connector, - join_rewrites(&rewrites, &connector) - ) - }; - let result = format!("{}{}", result, "?".repeat(suffix_try_num)); - if context.config.indent_style() == IndentStyle::Visual { - wrap_str(result, context.config.max_width(), shape) - } else { + + let mut rewrite_iter = self.rewrites.iter(); + let mut result = rewrite_iter.next().unwrap().clone(); + + for (rewrite, prev_is_block_like) in rewrite_iter.zip(block_like_iter) { + if !prev_is_block_like { + result.push_str(&connector); + } + result.push_str(&rewrite); + } + Some(result) } } -// True if the chain is only `?`s. -fn chain_only_try(exprs: &[ast::Expr]) -> bool { - exprs.iter().all(|e| { - if let ast::ExprKind::Try(_) = e.node { - true - } else { - false - } - }) +// Formats a chain using block indent. +struct ChainFormatterBlock<'a> { + shared: ChainFormatterShared<'a>, + // For each rewrite, whether the corresponding item is block-like. + is_block_like: Vec, } -fn rewrite_try( - expr: &ast::Expr, - try_count: usize, - context: &RewriteContext, - shape: Shape, -) -> Option { - let sub_expr = expr.rewrite(context, shape.sub_width(try_count)?)?; - Some(format!("{}{}", sub_expr, "?".repeat(try_count))) +impl<'a> ChainFormatterBlock<'a> { + fn new(chain: &'a Chain) -> ChainFormatterBlock<'a> { + ChainFormatterBlock { + shared: ChainFormatterShared::new(chain), + is_block_like: Vec::with_capacity(chain.children.len() + 1), + } + } } -fn join_rewrites(rewrites: &[String], connector: &str) -> String { - let mut rewrite_iter = rewrites.iter(); - let mut result = rewrite_iter.next().unwrap().clone(); +impl<'a> ChainFormatter for ChainFormatterBlock<'a> { + fn format_root( + &mut self, + parent: &ChainItem, + context: &RewriteContext, + shape: Shape, + ) -> Option<()> { + let mut root_rewrite: String = parent.rewrite(context, shape)?; - for rewrite in rewrite_iter { - if rewrite != "?" { - result.push_str(connector); + let mut root_ends_with_block = is_block_expr(context, &parent.expr, &root_rewrite); + let tab_width = context.config.tab_spaces().saturating_sub(shape.offset); + + while root_rewrite.len() <= tab_width && !root_rewrite.contains('\n') { + let item = &self.shared.children[self.shared.children.len() - 1]; + let shape = shape.offset_left(root_rewrite.len())?; + match &item.rewrite_postfix(context, shape) { + Some(rewrite) => root_rewrite.push_str(rewrite), + None => break, + } + + root_ends_with_block = is_block_expr(context, &item.expr, &root_rewrite); + + self.shared.children = &self.shared.children[..self.shared.children.len() - 1]; + if self.shared.children.is_empty() { + break; + } } - result.push_str(&rewrite); + self.is_block_like.push(root_ends_with_block); + self.shared.rewrites.push(root_rewrite); + Some(()) } - result + fn child_shape(&self, context: &RewriteContext, shape: Shape) -> Option { + Some( + if self.is_block_like[0] { + shape.block_indent(0) + } else { + shape.block_indent(context.config.tab_spaces()) + }.with_max_width(context.config), + ) + } + + fn format_children(&mut self, context: &RewriteContext, child_shape: Shape) -> Option<()> { + for item in self.shared.children[1..].iter().rev() { + let rewrite = item.rewrite_postfix(context, child_shape)?; + self.is_block_like + .push(is_block_expr(context, &item.expr, &rewrite)); + self.shared.rewrites.push(rewrite); + } + Some(()) + } + + fn format_last_child( + &mut self, + context: &RewriteContext, + shape: Shape, + child_shape: Shape, + ) -> Option<()> { + self.shared + .format_last_child(true, context, shape, child_shape) + } + + fn join_rewrites(&self, context: &RewriteContext, child_shape: Shape) -> Option { + self.shared + .join_rewrites(context, child_shape, self.is_block_like.iter().cloned()) + } + + fn pure_root(&mut self) -> Option { + self.shared.pure_root() + } +} + +// Format a chain using visual indent. +struct ChainFormatterVisual<'a> { + shared: ChainFormatterShared<'a>, + // The extra offset from the chain's shape to the position of the `.` + offset: usize, +} + +impl<'a> ChainFormatterVisual<'a> { + fn new(chain: &'a Chain) -> ChainFormatterVisual<'a> { + ChainFormatterVisual { + shared: ChainFormatterShared::new(chain), + offset: 0, + } + } +} + +impl<'a> ChainFormatter for ChainFormatterVisual<'a> { + fn format_root( + &mut self, + parent: &ChainItem, + context: &RewriteContext, + shape: Shape, + ) -> Option<()> { + let parent_shape = shape.visual_indent(0); + let mut root_rewrite = parent.rewrite(context, parent_shape)?; + let multiline = root_rewrite.contains('\n'); + self.offset = if multiline { + last_line_width(&root_rewrite).saturating_sub(shape.used_width()) + } else { + trimmed_last_line_width(&root_rewrite) + }; + + if !multiline || is_block_expr(context, &parent.expr, &root_rewrite) { + let item = &self.shared.children[self.shared.children.len() - 1]; + let child_shape = parent_shape + .visual_indent(self.offset) + .sub_width(self.offset)?; + let rewrite = item.rewrite_postfix(context, child_shape)?; + match wrap_str(rewrite, context.config.max_width(), shape) { + Some(rewrite) => root_rewrite.push_str(&rewrite), + None => { + // We couldn't fit in at the visual indent, try the last + // indent. + let rewrite = item.rewrite_postfix(context, parent_shape)?; + root_rewrite.push_str(&rewrite); + self.offset = 0; + } + } + + self.shared.children = &self.shared.children[..self.shared.children.len() - 1]; + } + + self.shared.rewrites.push(root_rewrite); + Some(()) + } + + fn child_shape(&self, context: &RewriteContext, shape: Shape) -> Option { + shape + .with_max_width(context.config) + .offset_left(self.offset) + .map(|s| s.visual_indent(0)) + } + + fn format_children(&mut self, context: &RewriteContext, child_shape: Shape) -> Option<()> { + for item in self.shared.children[1..].iter().rev() { + let rewrite = item.rewrite_postfix(context, child_shape)?; + self.shared.rewrites.push(rewrite); + } + Some(()) + } + + fn format_last_child( + &mut self, + context: &RewriteContext, + shape: Shape, + child_shape: Shape, + ) -> Option<()> { + self.shared + .format_last_child(false, context, shape, child_shape) + } + + fn join_rewrites(&self, context: &RewriteContext, child_shape: Shape) -> Option { + self.shared + .join_rewrites(context, child_shape, iter::repeat(false)) + } + + fn pure_root(&mut self) -> Option { + self.shared.pure_root() + } } // States whether an expression's last line exclusively consists of closing // parens, braces, and brackets in its idiomatic formatting. fn is_block_expr(context: &RewriteContext, expr: &ast::Expr, repr: &str) -> bool { match expr.node { - ast::ExprKind::Mac(..) | ast::ExprKind::Call(..) => { - context.use_block_indent() && repr.contains('\n') - } - ast::ExprKind::Struct(..) + ast::ExprKind::Mac(..) + | ast::ExprKind::Call(..) + | ast::ExprKind::MethodCall(..) + | ast::ExprKind::Struct(..) | ast::ExprKind::While(..) | ast::ExprKind::WhileLet(..) | ast::ExprKind::If(..) @@ -365,147 +698,14 @@ fn is_block_expr(context: &RewriteContext, expr: &ast::Expr, repr: &str) -> bool ast::ExprKind::Paren(ref expr) | ast::ExprKind::Binary(_, _, ref expr) | ast::ExprKind::Index(_, ref expr) - | ast::ExprKind::Unary(_, ref expr) => is_block_expr(context, expr, repr), - _ => false, - } -} - -// Returns the root of the chain and a Vec of the prefixes of the rest of the chain. -// E.g., for input `a.b.c` we return (`a`, [`a.b.c`, `a.b`]) -fn make_subexpr_list(expr: &ast::Expr, context: &RewriteContext) -> (ast::Expr, Vec) { - let mut subexpr_list = vec![expr.clone()]; - - while let Some(subexpr) = pop_expr_chain(subexpr_list.last().unwrap(), context) { - subexpr_list.push(subexpr.clone()); - } - - let parent = subexpr_list.pop().unwrap(); - (parent, subexpr_list) -} - -fn chain_indent(context: &RewriteContext, shape: Shape) -> Shape { - match context.config.indent_style() { - IndentStyle::Visual => shape.visual_indent(0), - IndentStyle::Block => shape - .block_indent(context.config.tab_spaces()) - .with_max_width(context.config), - } -} - -// Returns the expression's subexpression, if it exists. When the subexpr -// is a try! macro, we'll convert it to shorthand when the option is set. -fn pop_expr_chain(expr: &ast::Expr, context: &RewriteContext) -> Option { - match expr.node { - ast::ExprKind::MethodCall(_, ref expressions) => { - Some(convert_try(&expressions[0], context)) - } - ast::ExprKind::Field(ref subexpr, _) | ast::ExprKind::Try(ref subexpr) => { - Some(convert_try(subexpr, context)) - } - _ => None, - } -} - -fn convert_try(expr: &ast::Expr, context: &RewriteContext) -> ast::Expr { - match expr.node { - ast::ExprKind::Mac(ref mac) if context.config.use_try_shorthand() => { - if let Some(subexpr) = convert_try_mac(mac, context) { - subexpr - } else { - expr.clone() - } - } - _ => expr.clone(), - } -} - -// Rewrite the last element in the chain `expr`. E.g., given `a.b.c` we rewrite -// `.c`. -fn rewrite_chain_subexpr( - expr: &ast::Expr, - span: Span, - context: &RewriteContext, - shape: Shape, -) -> Option { - let rewrite_element = |expr_str: String| { - if expr_str.len() <= shape.width { - Some(expr_str) - } else { - None - } - }; - - match expr.node { - ast::ExprKind::MethodCall(ref segment, ref expressions) => { - let types = match segment.args { - Some(ref params) => match **params { - ast::GenericArgs::AngleBracketed(ref data) => &data.args[..], - _ => &[], - }, - _ => &[], - }; - rewrite_method_call(segment.ident, types, expressions, span, context, shape) - } - ast::ExprKind::Field(ref nested, ref field) => { - let space = if is_tup_field_access(expr) && is_tup_field_access(nested) { - " " - } else { - "" - }; - rewrite_element(format!("{}.{}", space, field.name)) - } - ast::ExprKind::Try(_) => rewrite_element(String::from("?")), - _ => unreachable!(), - } -} - -fn is_tup_field_access(expr: &ast::Expr) -> bool { - match expr.node { - ast::ExprKind::Field(_, ref field) => { - field.name.to_string().chars().all(|c| c.is_digit(10)) + | ast::ExprKind::Unary(_, ref expr) + | ast::ExprKind::Closure(_, _, _, _, ref expr, _) + | ast::ExprKind::Try(ref expr) + | ast::ExprKind::Yield(Some(ref expr)) => is_block_expr(context, expr, repr), + // This can only be a string lit + ast::ExprKind::Lit(_) => { + repr.contains('\n') && trimmed_last_line_width(repr) <= context.config.tab_spaces() } _ => false, } } - -// Determines if we can continue formatting a given expression on the same line. -fn is_continuable(expr: &ast::Expr) -> bool { - match expr.node { - ast::ExprKind::Path(..) => true, - _ => false, - } -} - -fn is_try(expr: &ast::Expr) -> bool { - match expr.node { - ast::ExprKind::Try(..) => true, - _ => false, - } -} - -fn rewrite_method_call( - method_name: ast::Ident, - types: &[ast::GenericArg], - args: &[ptr::P], - span: Span, - context: &RewriteContext, - shape: Shape, -) -> Option { - let (lo, type_str) = if types.is_empty() { - (args[0].span.hi(), String::new()) - } else { - let type_list = types - .iter() - .map(|ty| ty.rewrite(context, shape)) - .collect::>>()?; - - let type_str = format!("::<{}>", type_list.join(", ")); - - (types.last().unwrap().span().hi(), type_str) - }; - - let callee_str = format!(".{}{}", method_name, type_str); - let span = mk_sp(lo, span.hi()); - - rewrite_call(context, &callee_str, &args[1..], span, shape) -} diff --git a/src/closures.rs b/src/closures.rs index 783ca1c029b1..c03c8e6b6065 100644 --- a/src/closures.rs +++ b/src/closures.rs @@ -198,8 +198,7 @@ fn rewrite_closure_expr( } else { Some(rw) } - }) - .map(|rw| format!("{} {}", prefix, rw)) + }).map(|rw| format!("{} {}", prefix, rw)) } // Rewrite closure whose body is block. @@ -376,10 +375,8 @@ where .map(|e| match e.node { ast::ExprKind::Closure(..) => true, _ => false, - }) - .unwrap_or(false) - }) - .count() + }).unwrap_or(false) + }).count() > 1 } diff --git a/src/comment.rs b/src/comment.rs index 3d55f6560e3e..ed83a3925b00 100644 --- a/src/comment.rs +++ b/src/comment.rs @@ -348,8 +348,7 @@ fn rewrite_comment_inner( } line - }) - .map(|s| left_trim_comment_line(s, &style)) + }).map(|s| left_trim_comment_line(s, &style)) .map(|(line, has_leading_whitespace)| { if orig.starts_with("/*") && line_breaks == 0 { ( @@ -517,8 +516,7 @@ fn trim_custom_comment_prefix(s: &str) -> String { } else { line } - }) - .collect::>() + }).collect::>() .join("\n") } @@ -606,8 +604,7 @@ fn light_rewrite_comment( }; // Preserve markdown's double-space line break syntax in doc comment. trim_right_unless_two_whitespaces(left_trimmed, is_doc_comment) - }) - .collect(); + }).collect(); Some(lines.join(&format!("\n{}", offset.to_string(config)))) } @@ -1341,8 +1338,7 @@ mod test { .filter_map(|(s, c)| match s { FullCodeCharKind::Normal | FullCodeCharKind::InString => Some(c), _ => None, - }) - .collect() + }).collect() } #[test] diff --git a/src/config/options.rs b/src/config/options.rs index a581cdef43df..c48f9a4d7272 100644 --- a/src/config/options.rs +++ b/src/config/options.rs @@ -322,8 +322,7 @@ impl IgnoreList { path.push(s); path } - }) - .collect(); + }).collect(); } fn skip_file_inner(&self, file: &Path) -> bool { diff --git a/src/expr.rs b/src/expr.rs index 6e1af266e9bf..6814b91e0532 100644 --- a/src/expr.rs +++ b/src/expr.rs @@ -39,9 +39,9 @@ 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, ptr_vec_to_ref_vec, - semicolon_for_stmt, wrap_str, + 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; @@ -1212,8 +1212,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(), ); @@ -1953,6 +1952,9 @@ pub fn prefer_next_line(orig_rhs: &str, next_line_rhs: &str, rhs_tactics: RhsTac 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( diff --git a/src/formatting.rs b/src/formatting.rs index ee2539a2fa50..42ab4e89c3bc 100644 --- a/src/formatting.rs +++ b/src/formatting.rs @@ -246,8 +246,7 @@ impl FormattingError { fl.file .get_line(fl.lines[0].line_index) .map(|l| l.into_owned()) - }) - .unwrap_or_else(|| String::new()), + }).unwrap_or_else(|| String::new()), } } diff --git a/src/git-rustfmt/main.rs b/src/git-rustfmt/main.rs index d6ab36614824..d47827ab55e1 100644 --- a/src/git-rustfmt/main.rs +++ b/src/git-rustfmt/main.rs @@ -46,8 +46,7 @@ fn prune_files(files: Vec<&str>) -> Vec<&str> { return true; } pruned_prefixes.iter().all(|pp| !f.starts_with(pp)) - }) - .collect() + }).collect() } fn git_diff(commits: &str) -> String { diff --git a/src/imports.rs b/src/imports.rs index f087ea5e52a8..93f2ac8867a0 100644 --- a/src/imports.rs +++ b/src/imports.rs @@ -344,8 +344,7 @@ impl UseTree { .zip(items.into_iter()) .map(|(t, list_item)| { Self::from_ast(context, &t.0, Some(list_item), None, None, None) - }) - .collect(), + }).collect(), )); } UseTreeKind::Simple(ref rename, ..) => { diff --git a/src/items.rs b/src/items.rs index 721f02b01878..23338435d9ac 100644 --- a/src/items.rs +++ b/src/items.rs @@ -1669,7 +1669,7 @@ fn rewrite_static( &**expr, Shape::legacy(remaining_width, offset.block_only()), ).and_then(|res| recover_comment_removed(res, static_parts.span, context)) - .map(|s| if s.ends_with(';') { s } else { s + ";" }) + .map(|s| if s.ends_with(';') { s } else { s + ";" }) } else { Some(format!("{}{};", prefix, ty_str)) } @@ -2783,17 +2783,15 @@ impl Rewrite for ast::ForeignItem { let span = mk_sp(self.span.lo(), self.span.hi() - BytePos(1)); let item_str = match self.node { - ast::ForeignItemKind::Fn(ref fn_decl, ref generics) => { - rewrite_fn_base( - context, - shape.indent, - self.ident, - &FnSig::new(fn_decl, generics, self.vis.clone()), - span, - false, - false, - ).map(|(s, _)| format!("{};", s)) - } + ast::ForeignItemKind::Fn(ref fn_decl, ref generics) => rewrite_fn_base( + context, + shape.indent, + self.ident, + &FnSig::new(fn_decl, generics, self.vis.clone()), + span, + false, + false, + ).map(|(s, _)| format!("{};", s)), ast::ForeignItemKind::Static(ref ty, is_mutable) => { // FIXME(#21): we're dropping potential comments in between the // function keywords here. diff --git a/src/macros.rs b/src/macros.rs index 4f3891fbf495..b55375b949c1 100644 --- a/src/macros.rs +++ b/src/macros.rs @@ -1115,8 +1115,7 @@ fn indent_macro_snippet( }; trimmed_lines.push((trimmed, line, prefix_space_width)); prefix_space_width - }) - .min()?; + }).min()?; Some( first_line + "\n" + &trimmed_lines @@ -1132,8 +1131,7 @@ fn indent_macro_snippet( } None => String::new(), }, - ) - .collect::>() + ).collect::>() .join("\n"), ) } @@ -1296,8 +1294,7 @@ impl MacroBranch { } (s + l + "\n", !kind.is_string() || l.ends_with('\\')) }, - ) - .0; + ).0; // Undo our replacement of macro variables. // FIXME: this could be *much* more efficient. diff --git a/src/pairs.rs b/src/pairs.rs index 2c4358f7278a..17b869750226 100644 --- a/src/pairs.rs +++ b/src/pairs.rs @@ -125,7 +125,7 @@ fn rewrite_pairs_multiline( IndentStyle::Visual => shape.visual_indent(0), IndentStyle::Block => shape.block_indent(context.config.tab_spaces()), }).with_max_width(&context.config) - .sub_width(rhs_offset)?; + .sub_width(rhs_offset)?; let indent_str = nested_shape.indent.to_string_with_newline(context.config); let mut result = String::new(); diff --git a/src/reorder.rs b/src/reorder.rs index 5947b4ae87ff..48ddd1163379 100644 --- a/src/reorder.rs +++ b/src/reorder.rs @@ -151,8 +151,7 @@ fn rewrite_reorderable_items( .map(|use_tree| ListItem { item: use_tree.rewrite_top_level(context, nested_shape), ..use_tree.list_item.unwrap_or_else(ListItem::empty) - }) - .collect(); + }).collect(); wrap_reorderable_items(context, &item_vec, nested_shape) } @@ -249,8 +248,7 @@ impl<'b, 'a: 'b> FmtVisitor<'a> { last = current; in_same_group }) - }) - .count(); + }).count(); let items = &items[..item_length]; let at_least_one_in_file_lines = items diff --git a/src/rustfmt_diff.rs b/src/rustfmt_diff.rs index de52b28c08bb..2a331eec19ae 100644 --- a/src/rustfmt_diff.rs +++ b/src/rustfmt_diff.rs @@ -193,13 +193,15 @@ where W: Write, { for mismatch in diff { - let (num_removed, num_added) = mismatch.lines.iter().fold((0, 0), |(rem, add), line| { - match *line { - DiffLine::Context(_) => panic!("No Context expected"), - DiffLine::Expected(_) => (rem, add + 1), - DiffLine::Resulting(_) => (rem + 1, add), - } - }); + let (num_removed, num_added) = + mismatch + .lines + .iter() + .fold((0, 0), |(rem, add), line| match *line { + DiffLine::Context(_) => panic!("No Context expected"), + DiffLine::Expected(_) => (rem, add + 1), + DiffLine::Resulting(_) => (rem + 1, add), + }); // Write a header with enough information to separate the modified lines. writeln!( out, diff --git a/src/shape.rs b/src/shape.rs index ab33826c028f..12a911a19315 100644 --- a/src/shape.rs +++ b/src/shape.rs @@ -274,6 +274,12 @@ impl Shape { ); Shape { width, ..*self } } + + pub fn to_string_with_newline(&self, config: &Config) -> Cow<'static, str> { + let mut offset_indent = self.indent; + offset_indent.alignment = self.offset; + offset_indent.to_string_inner(config, 0) + } } #[cfg(test)] diff --git a/src/test/mod.rs b/src/test/mod.rs index 63b5f244b906..ba4607be37ce 100644 --- a/src/test/mod.rs +++ b/src/test/mod.rs @@ -514,8 +514,7 @@ fn read_significant_comments(file_name: &Path) -> HashMap { .to_owned(), ) }) - }) - .collect() + }).collect() } // Compare output to input. @@ -884,8 +883,8 @@ fn configuration_snippet_tests() { fs::File::open(Path::new(CONFIGURATIONS_FILE_NAME)) .expect(&format!("Couldn't read file {}", CONFIGURATIONS_FILE_NAME)), ).lines() - .map(|l| l.unwrap()) - .enumerate(); + .map(|l| l.unwrap()) + .enumerate(); let mut code_blocks: Vec = Vec::new(); let mut hash_set = Config::hash_set(); @@ -961,5 +960,5 @@ fn verify_check_works() { "--check", temp_file.path.to_str().unwrap(), ]).succeeds() - .unwrap(); + .unwrap(); } diff --git a/src/types.rs b/src/types.rs index 0c978ea28a67..d6e4001eacfc 100644 --- a/src/types.rs +++ b/src/types.rs @@ -548,7 +548,8 @@ impl Rewrite for ast::GenericParam { }; result.push_str(eq_str); let budget = shape.width.checked_sub(result.len())?; - let rewrite = def.rewrite(context, Shape::legacy(budget, shape.indent + result.len()))?; + let rewrite = + def.rewrite(context, Shape::legacy(budget, shape.indent + result.len()))?; result.push_str(&rewrite); } @@ -793,8 +794,7 @@ fn rewrite_lifetime_param( .filter(|p| match p.kind { ast::GenericParamKind::Lifetime => true, _ => false, - }) - .map(|lt| lt.rewrite(context, shape)) + }).map(|lt| lt.rewrite(context, shape)) .collect::>>()? .join(", "); if result.is_empty() { diff --git a/src/utils.rs b/src/utils.rs index f1b0582b1200..b8474792cd30 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -382,6 +382,7 @@ pub fn colon_spaces(before: bool, after: bool) -> &'static str { } } +#[inline] pub fn left_most_sub_expr(e: &ast::Expr) -> &ast::Expr { match e.node { ast::ExprKind::Call(ref e, _) @@ -398,6 +399,12 @@ pub fn left_most_sub_expr(e: &ast::Expr) -> &ast::Expr { } } +#[inline] pub fn starts_with_newline(s: &str) -> bool { s.starts_with('\n') || s.starts_with("\r\n") } + +#[inline] +pub fn first_line_ends_with(s: &str, c: char) -> bool { + s.lines().next().map_or(false, |l| l.ends_with(c)) +} diff --git a/src/vertical.rs b/src/vertical.rs index 1b7fdb9be1d1..ead5719f61f8 100644 --- a/src/vertical.rs +++ b/src/vertical.rs @@ -200,14 +200,12 @@ fn struct_field_prefix_max_min_width( Some(field_str.len()) } }) - }) - .fold(Some((0, ::std::usize::MAX)), |acc, len| match (acc, len) { + }).fold(Some((0, ::std::usize::MAX)), |acc, len| match (acc, len) { (Some((max_len, min_len)), Some(len)) => { Some((cmp::max(max_len, len), cmp::min(min_len, len))) } _ => None, - }) - .unwrap_or((0, 0)) + }).unwrap_or((0, 0)) } fn rewrite_aligned_items_inner( diff --git a/tests/source/chains.rs b/tests/source/chains.rs index 749d18c57d79..52a077e435f5 100644 --- a/tests/source/chains.rs +++ b/tests/source/chains.rs @@ -228,3 +228,34 @@ fn issue2415() { })() .unwrap_or_else(|_: Box<::std::error::Error>| String::from("")); } + +impl issue_2786 { + fn thing(&self) { + foo(|a| { + println!("a"); + println!("b"); + }).bar(|c| { + println!("a"); + println!("b"); + }) + .baz(|c| { + println!("a"); + println!("b"); + }) + } +} + +fn issue_2773() { + let bar = Some(0); + bar.or_else(|| { + // do stuff + None + }).or_else(|| { + // do other stuff + None + }) + .and_then(|val| { + // do this stuff + None + }); +} diff --git a/tests/target/chains-visual.rs b/tests/target/chains-visual.rs index 3db40053e6b1..ab49096e55ab 100644 --- a/tests/target/chains-visual.rs +++ b/tests/target/chains-visual.rs @@ -15,16 +15,16 @@ fn main() { // Test case where first chain element isn't a path, but is shorter than // the size of a tab. x().y(|| match cond() { - true => (), - false => (), - }); + true => (), + false => (), + }); loong_func().quux(move || if true { 1 } else { 2 }); some_fuuuuuuuuunction().method_call_a(aaaaa, bbbbb, |c| { - let x = c; - x - }); + let x = c; + x + }); some_fuuuuuuuuunction().method_call_a(aaaaa, bbbbb, |c| { let x = c; @@ -59,7 +59,7 @@ fn floaters() { let x = Foo { field1: val1, field2: val2, }.method_call() - .method_call(); + .method_call(); let y = if cond { val1 } else { val2 }.method_call(); @@ -80,7 +80,7 @@ fn floaters() { } else { none(); }.bar() - .baz(); + .baz(); Foo { x: val }.baz(|| { force(); @@ -90,10 +90,10 @@ fn floaters() { Foo { y: i_am_multi_line, z: ok, }.baz(|| { - force(); - multiline(); - }) - .quux(); + force(); + multiline(); + }) + .quux(); a + match x { true => "yay!", @@ -137,9 +137,9 @@ fn issue1434() { for _ in 0..100 { let prototype_id = PrototypeIdData::from_reader::<_, B>(&mut self.file_cursor).chain_err(|| { - format!("could not read prototype ID at offset {:#010x}", - current_offset) - })?; + format!("could not read prototype ID at offset {:#010x}", + current_offset) + })?; } } diff --git a/tests/target/chains.rs b/tests/target/chains.rs index 69c7671503d9..2d945e3c390d 100644 --- a/tests/target/chains.rs +++ b/tests/target/chains.rs @@ -38,8 +38,7 @@ fn main() { .method_call_a(aaaaa, bbbbb, |c| { let x = c; x - }) - .method_call_b(aaaaa, bbbbb, |c| { + }).method_call_b(aaaaa, bbbbb, |c| { let x = c; x }); @@ -65,8 +64,7 @@ fn main() { .map(|x| { x += 1; x - }) - .filter(some_mod::some_filter) + }).filter(some_mod::some_filter) } fn floaters() { @@ -79,7 +77,7 @@ fn floaters() { field1: val1, field2: val2, }.method_call() - .method_call(); + .method_call(); let y = if cond { val1 @@ -106,15 +104,14 @@ fn floaters() { } else { none(); }.bar() - .baz(); + .baz(); Foo { x: val, }.baz(|| { force(); multiline(); - }) - .quux(); + }).quux(); Foo { y: i_am_multi_line, @@ -122,8 +119,7 @@ fn floaters() { }.baz(|| { force(); multiline(); - }) - .quux(); + }).quux(); a + match x { true => "yay!", @@ -238,8 +234,7 @@ impl Foo { } } }) - }) - .collect(); + }).collect(); } } @@ -255,3 +250,32 @@ fn issue2415() { })().ok_or("")?) })().unwrap_or_else(|_: Box<::std::error::Error>| String::from("")); } + +impl issue_2786 { + fn thing(&self) { + foo(|a| { + println!("a"); + println!("b"); + }).bar(|c| { + println!("a"); + println!("b"); + }).baz(|c| { + println!("a"); + println!("b"); + }) + } +} + +fn issue_2773() { + let bar = Some(0); + bar.or_else(|| { + // do stuff + None + }).or_else(|| { + // do other stuff + None + }).and_then(|val| { + // do this stuff + None + }); +} diff --git a/tests/target/closure.rs b/tests/target/closure.rs index 5bc89d582229..2360ccfbd2fd 100644 --- a/tests/target/closure.rs +++ b/tests/target/closure.rs @@ -138,18 +138,20 @@ fn issue470() { { { { - let explicit_arg_decls = explicit_arguments.into_iter().enumerate().map( - |(index, (ty, pattern))| { - let lvalue = Lvalue::Arg(index as u32); - block = this.pattern( - block, - argument_extent, - hair::PatternRef::Hair(pattern), - &lvalue, - ); - ArgDecl { ty: ty } - }, - ); + let explicit_arg_decls = + explicit_arguments + .into_iter() + .enumerate() + .map(|(index, (ty, pattern))| { + let lvalue = Lvalue::Arg(index as u32); + block = this.pattern( + block, + argument_extent, + hair::PatternRef::Hair(pattern), + &lvalue, + ); + ArgDecl { ty: ty } + }); } } } @@ -169,8 +171,7 @@ fn issue1329() { .map(|x| { x += 1; x - }) - .filter + }).filter } fn issue325() { diff --git a/tests/target/configs/indent_style/block_call.rs b/tests/target/configs/indent_style/block_call.rs index 77f3c551f0a5..19a45cb9f74e 100644 --- a/tests/target/configs/indent_style/block_call.rs +++ b/tests/target/configs/indent_style/block_call.rs @@ -117,8 +117,7 @@ impl Cursor { debug_assert_eq!(n, -1); None } - }) - .or_else(|| { + }).or_else(|| { let canonical = self.canonical(); if canonical != *self { canonical.num_template_args() diff --git a/tests/target/expr-block.rs b/tests/target/expr-block.rs index 3e23d5ee20d7..501ee3eaea04 100644 --- a/tests/target/expr-block.rs +++ b/tests/target/expr-block.rs @@ -141,8 +141,7 @@ fn issue_1450() { Relaxed, Release, Relaxed, - ) - .is_ok() + ).is_ok() { return; } diff --git a/tests/target/file-lines-1.rs b/tests/target/file-lines-1.rs index 2601ca9fc94a..1c63b105b988 100644 --- a/tests/target/file-lines-1.rs +++ b/tests/target/file-lines-1.rs @@ -5,7 +5,7 @@ fn floaters() { field1: val1, field2: val2, }.method_call() - .method_call(); + .method_call(); let y = if cond { val1 diff --git a/tests/target/file-lines-3.rs b/tests/target/file-lines-3.rs index 4831e5164a80..9aba967e29dd 100644 --- a/tests/target/file-lines-3.rs +++ b/tests/target/file-lines-3.rs @@ -5,7 +5,7 @@ fn floaters() { field1: val1, field2: val2, }.method_call() - .method_call(); + .method_call(); let y = if cond { val1 } else { val2 }.method_call(); diff --git a/tests/target/issue-2759.rs b/tests/target/issue-2759.rs index 3685afbdc0e7..4441b140386e 100644 --- a/tests/target/issue-2759.rs +++ b/tests/target/issue-2759.rs @@ -56,8 +56,8 @@ fn bar() {} /// .boxed(), /// ] /// }).bind("127.0.0.1:8080") -/// .unwrap() -/// .run() +/// .unwrap() +/// .run() /// # }); /// } /// ``` diff --git a/tests/target/macros.rs b/tests/target/macros.rs index 00b91ca81a29..ac076615f99a 100644 --- a/tests/target/macros.rs +++ b/tests/target/macros.rs @@ -183,8 +183,7 @@ fn issue_1885() { chan_select! { rx.recv() => {} } - }) - .collect::>(); + }).collect::>(); } fn issue_1917() { diff --git a/tests/target/match.rs b/tests/target/match.rs index cda0ed2abe57..e0774ef011ca 100644 --- a/tests/target/match.rs +++ b/tests/target/match.rs @@ -381,8 +381,7 @@ fn issue1456() { .iter() .map(|node| { XPathNodeReader::new(node, &context).and_then(|r| ArtistRef::from_xml(&r)) - }) - .collect(); + }).collect(); res? } _ => Vec::new(),