From b276cb7eacf6acb66845062510b185d46d618d8b Mon Sep 17 00:00:00 2001 From: Cameron Steffen Date: Sat, 29 Jan 2022 22:15:30 -0600 Subject: [PATCH] Add support for ExprKind::Let --- src/expr.rs | 26 +++++++++++++++++++++++++- src/pairs.rs | 22 +++++++++++++++++----- tests/cargo-fmt/main.rs | 2 +- tests/source/let_chains.rs | 11 +++++++++++ tests/source/match.rs | 1 + tests/target/let_chains.rs | 23 +++++++++++++++++++++++ tests/target/match.rs | 2 ++ 7 files changed, 80 insertions(+), 7 deletions(-) create mode 100644 tests/source/let_chains.rs create mode 100644 tests/target/let_chains.rs diff --git a/src/expr.rs b/src/expr.rs index e1865c8afc2..7eaa1818856 100644 --- a/src/expr.rs +++ b/src/expr.rs @@ -127,7 +127,7 @@ pub(crate) fn format_expr( ast::ExprKind::Tup(ref items) => { rewrite_tuple(context, items.iter(), expr.span, shape, items.len() == 1) } - ast::ExprKind::Let(..) => None, + ast::ExprKind::Let(ref pat, ref expr, _span) => rewrite_let(context, shape, pat, expr), ast::ExprKind::If(..) | ast::ExprKind::ForLoop(..) | ast::ExprKind::Loop(..) @@ -1779,6 +1779,30 @@ fn rewrite_tuple_in_visual_indent_style<'a, T: 'a + IntoOverflowableItem<'a>>( Some(format!("({})", list_str)) } +fn rewrite_let( + context: &RewriteContext<'_>, + shape: Shape, + pat: &ast::Pat, + expr: &ast::Expr, +) -> Option { + let mut result = "let ".to_owned(); + + // 4 = "let ".len() + let pat_shape = shape.offset_left(4)?; + let pat_str = pat.rewrite(context, pat_shape)?; + result.push_str(&pat_str); + + result.push_str(" ="); + + rewrite_assign_rhs( + context, + result, + expr, + &RhsAssignKind::Expr(&expr.kind, expr.span), + shape, + ) +} + pub(crate) fn rewrite_tuple<'a, T: 'a + IntoOverflowableItem<'a>>( context: &'a RewriteContext<'_>, items: impl Iterator, diff --git a/src/pairs.rs b/src/pairs.rs index d1c75126ea4..d366f5a0476 100644 --- a/src/pairs.rs +++ b/src/pairs.rs @@ -34,11 +34,14 @@ pub(crate) fn rewrite_all_pairs( shape: Shape, context: &RewriteContext<'_>, ) -> Option { - expr.flatten(context, shape).and_then(|list| { + let list = expr.flatten(context, shape)?; + if !list.force_multi_line { // First we try formatting on one line. - rewrite_pairs_one_line(&list, shape, context) - .or_else(|| rewrite_pairs_multiline(&list, shape, context)) - }) + if let Some(out) = rewrite_pairs_one_line(&list, shape, context) { + return Some(out); + } + } + rewrite_pairs_multiline(&list, shape, context) } // This may return a multi-line result since we allow the last expression to go @@ -246,6 +249,7 @@ trait FlattenPair: Rewrite + Sized { struct PairList<'a, 'b, T: Rewrite> { list: Vec<(&'b T, Option)>, separators: Vec<&'a str>, + force_multi_line: bool, } impl FlattenPair for ast::Expr { @@ -283,6 +287,7 @@ impl FlattenPair for ast::Expr { let mut stack = vec![]; let mut list = vec![]; let mut separators = vec![]; + let mut force_multi_line = false; let mut node = self; loop { match node.kind { @@ -293,6 +298,9 @@ impl FlattenPair for ast::Expr { _ => { let op_len = separators.last().map_or(0, |s: &&str| s.len()); let rw = default_rewrite(node, op_len, list.is_empty()); + // a `let` expression forces multi-line, unless it is the first expression + force_multi_line |= + !list.is_empty() && matches!(node.kind, ast::ExprKind::Let(..)); list.push((node, rw)); if let Some(pop) = stack.pop() { match pop.kind { @@ -310,7 +318,11 @@ impl FlattenPair for ast::Expr { } assert_eq!(list.len() - 1, separators.len()); - Some(PairList { list, separators }) + Some(PairList { + list, + separators, + force_multi_line, + }) } } diff --git a/tests/cargo-fmt/main.rs b/tests/cargo-fmt/main.rs index bf81f253f69..3713552c66a 100644 --- a/tests/cargo-fmt/main.rs +++ b/tests/cargo-fmt/main.rs @@ -1,8 +1,8 @@ // Integration tests for cargo-fmt. use std::env; -use std::process::Command; use std::path::Path; +use std::process::Command; /// Run the cargo-fmt executable and return its output. fn cargo_fmt(args: &[&str]) -> (String, String) { diff --git a/tests/source/let_chains.rs b/tests/source/let_chains.rs new file mode 100644 index 00000000000..bae32044777 --- /dev/null +++ b/tests/source/let_chains.rs @@ -0,0 +1,11 @@ +fn main() { + // can be one line + if let x = x && x {} + // must wrap + if xxx && let x = x {} + + if aaaaaaaaaaaaaaaaaaaaa && aaaaaaaaaaaaaaa && aaaaaaaaa && let Some(x) = xxxxxxxxxxxx && aaaaaaa && let None = aaaaaaaaaa {} + + if aaaaaaaaaaaaaaaaaaaaa && aaaaaaaaaaaaaaa || aaaaaaaaa && let Some(x) = xxxxxxxxxxxx && aaaaaaa && let None = aaaaaaaaaa {} + +} \ No newline at end of file diff --git a/tests/source/match.rs b/tests/source/match.rs index b5dc9957a2c..4a7242a3a80 100644 --- a/tests/source/match.rs +++ b/tests/source/match.rs @@ -292,6 +292,7 @@ fn guards() { aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa if fooooooooooooooooooooo && (bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb || cccccccccccccccccccccccccccccccccccccccc) => {} + aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa if let Some(foooooooooooooo) = hiiiiiiiiiiiiiii => {} } } diff --git a/tests/target/let_chains.rs b/tests/target/let_chains.rs new file mode 100644 index 00000000000..4d4383a5ab5 --- /dev/null +++ b/tests/target/let_chains.rs @@ -0,0 +1,23 @@ +fn main() { + // can be one line + if let x = x && x {} + // must wrap + if xxx + && let x = x + {} + + if aaaaaaaaaaaaaaaaaaaaa + && aaaaaaaaaaaaaaa + && aaaaaaaaa + && let Some(x) = xxxxxxxxxxxx + && aaaaaaa + && let None = aaaaaaaaaa + {} + + if aaaaaaaaaaaaaaaaaaaaa && aaaaaaaaaaaaaaa + || aaaaaaaaa + && let Some(x) = xxxxxxxxxxxx + && aaaaaaa + && let None = aaaaaaaaaa + {} +} diff --git a/tests/target/match.rs b/tests/target/match.rs index 1bf3fb758ee..1ec283d543a 100644 --- a/tests/target/match.rs +++ b/tests/target/match.rs @@ -317,6 +317,8 @@ fn guards() { if fooooooooooooooooooooo && (bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb || cccccccccccccccccccccccccccccccccccccccc) => {} + aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + if let Some(foooooooooooooo) = hiiiiiiiiiiiiiii => {} } }