diff --git a/Configurations.md b/Configurations.md index 3eb8cbd780f2..4d41fe52e3d3 100644 --- a/Configurations.md +++ b/Configurations.md @@ -2089,6 +2089,88 @@ fn main() { See also: [`match_block_trailing_comma`](#match_block_trailing_comma). +## `overflow_delimited_expr` + +When structs, slices, arrays, and block/array-like macros are used as the last +argument in an expression list, allow them to overflow (like blocks/closures) +instead of being indented on a new line. + +- **Default value**: `false` +- **Possible values**: `true`, `false` +- **Stable**: No + +#### `false` (default): + +```rust +fn example() { + foo(ctx, |param| { + action(); + foo(param) + }); + + foo( + ctx, + Bar { + x: value, + y: value2, + }, + ); + + foo( + ctx, + &[ + MAROON_TOMATOES, + PURPLE_POTATOES, + ORGANE_ORANGES, + GREEN_PEARS, + RED_APPLES, + ], + ); + + foo( + ctx, + vec![ + MAROON_TOMATOES, + PURPLE_POTATOES, + ORGANE_ORANGES, + GREEN_PEARS, + RED_APPLES, + ], + ); +} +``` + +#### `true`: + +```rust +fn example() { + foo(ctx, |param| { + action(); + foo(param) + }); + + foo(ctx, Bar { + x: value, + y: value2, + }); + + foo(ctx, &[ + MAROON_TOMATOES, + PURPLE_POTATOES, + ORGANE_ORANGES, + GREEN_PEARS, + RED_APPLES, + ]); + + foo(ctx, vec![ + MAROON_TOMATOES, + PURPLE_POTATOES, + ORGANE_ORANGES, + GREEN_PEARS, + RED_APPLES, + ]); +} +``` ## `blank_lines_upper_bound` diff --git a/src/config/mod.rs b/src/config/mod.rs index c3b998d0211e..84d94fada776 100644 --- a/src/config/mod.rs +++ b/src/config/mod.rs @@ -88,8 +88,10 @@ create_config! { // Misc. remove_nested_parens: bool, true, true, "Remove nested parens"; combine_control_expr: bool, true, false, "Combine control expressions with function calls"; - struct_field_align_threshold: usize, 0, false, "Align struct fields if their diffs fits within \ - threshold"; + overflow_delimited_expr: bool, false, false, + "Allow trailing bracket/brace delimited expressions to overflow"; + struct_field_align_threshold: usize, 0, false, + "Align struct fields if their diffs fits within threshold"; enum_discrim_align_threshold: usize, 0, false, "Align enum variants discrims, if their diffs fit within threshold"; match_arm_blocks: bool, true, false, "Wrap the body of arms in blocks when it does not fit on \ diff --git a/src/expr.rs b/src/expr.rs index 08b9ad3079c7..aea5fa5f96fe 100644 --- a/src/expr.rs +++ b/src/expr.rs @@ -1340,15 +1340,28 @@ pub fn can_be_overflowed_expr(context: &RewriteContext, expr: &ast::Expr, args_l | ast::ExprKind::WhileLet(..) => { context.config.combine_control_expr() && context.use_block_indent() && args_len == 1 } - ast::ExprKind::Block(..) | ast::ExprKind::Closure(..) => { - context.use_block_indent() || context.config.indent_style() == IndentStyle::Visual + + // Handle always block-like expressions + ast::ExprKind::Block(..) | ast::ExprKind::Closure(..) => true, + + // Handle `[]` and `{}`-like expressions + ast::ExprKind::Array(..) | ast::ExprKind::Struct(..) => { + context.config.overflow_delimited_expr() + || (context.use_block_indent() && args_len == 1) } - ast::ExprKind::Array(..) - | ast::ExprKind::Call(..) - | ast::ExprKind::Mac(..) - | ast::ExprKind::MethodCall(..) - | ast::ExprKind::Struct(..) - | ast::ExprKind::Tup(..) => context.use_block_indent() && args_len == 1, + ast::ExprKind::Mac(ref macro_) => { + match (macro_.node.delim, context.config.overflow_delimited_expr()) { + (ast::MacDelimiter::Bracket, true) | (ast::MacDelimiter::Brace, true) => true, + _ => context.use_block_indent() && args_len == 1, + } + } + + // Handle parenthetical expressions + ast::ExprKind::Call(..) | ast::ExprKind::MethodCall(..) | ast::ExprKind::Tup(..) => { + context.use_block_indent() && args_len == 1 + } + + // Handle unary-like expressions ast::ExprKind::AddrOf(_, ref expr) | ast::ExprKind::Box(ref expr) | ast::ExprKind::Try(ref expr) diff --git a/src/overflow.rs b/src/overflow.rs index 31cd1b054662..4a583fc1de83 100644 --- a/src/overflow.rs +++ b/src/overflow.rs @@ -404,6 +404,7 @@ impl<'a> Context<'a> { closures::rewrite_last_closure(self.context, expr, shape) } } + // When overflowing the expressions which consists of a control flow // expression, avoid condition to use multi line. ast::ExprKind::If(..) @@ -422,6 +423,7 @@ impl<'a> Context<'a> { expr.rewrite(self.context, shape) } } + _ => expr.rewrite(self.context, shape), } } diff --git a/tests/source/expr-overflow-delimited.rs b/tests/source/expr-overflow-delimited.rs new file mode 100644 index 000000000000..cd80ca6fcebc --- /dev/null +++ b/tests/source/expr-overflow-delimited.rs @@ -0,0 +1,155 @@ +// rustfmt-overflow_delimited_expr: true + +fn combine_blocklike() { + do_thing( + |param| { + action(); + foo(param) + }, + ); + + do_thing( + x, + |param| { + action(); + foo(param) + }, + ); + + do_thing( + x, + + // I'll be discussing the `action` with your para(m)legal counsel + |param| { + action(); + foo(param) + }, + ); + + do_thing( + Bar { + x: value, + y: value2, + }, + ); + + do_thing( + x, + Bar { + x: value, + y: value2, + }, + ); + + do_thing( + x, + + // Let me tell you about that one time at the `Bar` + Bar { + x: value, + y: value2, + }, + ); + + do_thing( + &[ + value_with_longer_name, + value2_with_longer_name, + value3_with_longer_name, + value4_with_longer_name, + ], + ); + + do_thing( + x, + &[ + value_with_longer_name, + value2_with_longer_name, + value3_with_longer_name, + value4_with_longer_name, + ], + ); + + do_thing( + x, + + // Just admit it; my list is longer than can be folded on to one line + &[ + value_with_longer_name, + value2_with_longer_name, + value3_with_longer_name, + value4_with_longer_name, + ], + ); + + do_thing( + vec![ + value_with_longer_name, + value2_with_longer_name, + value3_with_longer_name, + value4_with_longer_name, + ], + ); + + do_thing( + x, + vec![ + value_with_longer_name, + value2_with_longer_name, + value3_with_longer_name, + value4_with_longer_name, + ], + ); + + do_thing( + x, + + // Just admit it; my list is longer than can be folded on to one line + vec![ + value_with_longer_name, + value2_with_longer_name, + value3_with_longer_name, + value4_with_longer_name, + ], + ); + + do_thing( + x, + ( + 1, + 2, + 3, + |param| { + action(); + foo(param) + }, + ), + ); +} + +fn combine_struct_sample() { + let identity = verify( + &ctx, + VerifyLogin { + type_: LoginType::Username, + username: args.username.clone(), + password: Some(args.password.clone()), + domain: None, + }, + )?; +} + +fn combine_macro_sample() { + rocket::ignite() + .mount( + "/", + routes![ + http::auth::login, + http::auth::logout, + http::cors::options, + http::action::dance, + http::action::sleep, + ], + ) + .launch(); +} diff --git a/tests/target/expr-overflow-delimited.rs b/tests/target/expr-overflow-delimited.rs new file mode 100644 index 000000000000..b00e81fcd5a5 --- /dev/null +++ b/tests/target/expr-overflow-delimited.rs @@ -0,0 +1,120 @@ +// rustfmt-overflow_delimited_expr: true + +fn combine_blocklike() { + do_thing(|param| { + action(); + foo(param) + }); + + do_thing(x, |param| { + action(); + foo(param) + }); + + do_thing( + x, + // I'll be discussing the `action` with your para(m)legal counsel + |param| { + action(); + foo(param) + }, + ); + + do_thing(Bar { + x: value, + y: value2, + }); + + do_thing(x, Bar { + x: value, + y: value2, + }); + + do_thing( + x, + // Let me tell you about that one time at the `Bar` + Bar { + x: value, + y: value2, + }, + ); + + do_thing(&[ + value_with_longer_name, + value2_with_longer_name, + value3_with_longer_name, + value4_with_longer_name, + ]); + + do_thing(x, &[ + value_with_longer_name, + value2_with_longer_name, + value3_with_longer_name, + value4_with_longer_name, + ]); + + do_thing( + x, + // Just admit it; my list is longer than can be folded on to one line + &[ + value_with_longer_name, + value2_with_longer_name, + value3_with_longer_name, + value4_with_longer_name, + ], + ); + + do_thing(vec![ + value_with_longer_name, + value2_with_longer_name, + value3_with_longer_name, + value4_with_longer_name, + ]); + + do_thing(x, vec![ + value_with_longer_name, + value2_with_longer_name, + value3_with_longer_name, + value4_with_longer_name, + ]); + + do_thing( + x, + // Just admit it; my list is longer than can be folded on to one line + vec![ + value_with_longer_name, + value2_with_longer_name, + value3_with_longer_name, + value4_with_longer_name, + ], + ); + + do_thing( + x, + (1, 2, 3, |param| { + action(); + foo(param) + }), + ); +} + +fn combine_struct_sample() { + let identity = verify(&ctx, VerifyLogin { + type_: LoginType::Username, + username: args.username.clone(), + password: Some(args.password.clone()), + domain: None, + })?; +} + +fn combine_macro_sample() { + rocket::ignite() + .mount("/", routes![ + http::auth::login, + http::auth::logout, + http::cors::options, + http::action::dance, + http::action::sleep, + ]) + .launch(); +}