diff --git a/Configurations.md b/Configurations.md index 08e60b1c837..c64383f6b37 100644 --- a/Configurations.md +++ b/Configurations.md @@ -1836,6 +1836,33 @@ fn say_hi() { } ``` +## `preserve_closure_block_wrapping` + +Preserves block wraping arround closures. For example, useful when the closure `||` can be +confused with OR. + +- **Default value**: `false` +- **Possible values**: `true`, `false` +- **Stable**: No + +#### `true`: +Original block wrapping is preserved: +```rust +fn main() { + let explicit_conversion_preserves_semantics = + || { !is_mod || (is_mod && attrs.map_or(true, |a| a.is_empty())) }; +} +``` + +#### `false` (default): +Block is not preserved: +```rust +fn main() { + let explicit_conversion_preserves_semantics = + || !is_mod || (is_mod && attrs.map_or(true, |a| a.is_empty())); +} +``` + ## `overflow_delimited_expr` When structs, slices, arrays, and block/array-like macros are used as the last diff --git a/src/config.rs b/src/config.rs index 737194c8e9b..1c2689d0f4f 100644 --- a/src/config.rs +++ b/src/config.rs @@ -134,6 +134,7 @@ create_config! { format_generated_files: bool, false, false, "Format generated files"; preserve_block_start_blank_lines: bool, false, false, "Preserve blank lines at the start of \ blocks."; + preserve_closure_block_wrapping: bool, false , false, "Preserve block wrapping around closures"; // Options that can change the source code beyond whitespace/blocks (somewhat linty things) merge_derives: bool, true, true, "Merge multiple `#[derive(...)]` into a single one"; @@ -623,6 +624,7 @@ edition = "2018" inline_attribute_width = 0 format_generated_files = false preserve_block_start_blank_lines = false +preserve_closure_block_wrapping = false merge_derives = true use_try_shorthand = false use_field_init_shorthand = false diff --git a/src/formatting/closures.rs b/src/formatting/closures.rs index fabbf3904eb..a47ace7107d 100644 --- a/src/formatting/closures.rs +++ b/src/formatting/closures.rs @@ -55,8 +55,19 @@ pub(crate) fn rewrite_closure( .map(|s| format!("{} {}", prefix, s)); } + // Whether a closure block wrapping may not be preserved (#4394). + let can_try_rewrite_without_block = if context.inside_macro() { + false + } else if context.config.preserve_closure_block_wrapping() + && context.snippet(body.span).trim_start().starts_with('{') + { + false + } else { + true + }; + let result = match fn_decl.output { - ast::FnRetTy::Default(_) if !context.inside_macro() => { + ast::FnRetTy::Default(_) if can_try_rewrite_without_block => { try_rewrite_without_block(body, &prefix, capture, context, shape, body_shape) } _ => None, diff --git a/tests/source/preserve_closure_block_wrapping.rs b/tests/source/preserve_closure_block_wrapping.rs new file mode 100755 index 00000000000..b53367a1da0 --- /dev/null +++ b/tests/source/preserve_closure_block_wrapping.rs @@ -0,0 +1,32 @@ +// rustfmt-preserve_closure_block_wrapping: true + +fn main() { +let explicit_conversion_preserves_semantics = + || { !is_mod || (is_mod && attrs.map_or(true, |a| a.is_empty())) }; +} + +fn main() { +|| {{}}; +} + +fn issue1524() { +let f = |x| {{{{x}}}}; +let f = |x| {{{x}}}; +let f = |x| {{x}}; +let f = |x| {x}; +let f = |x| x; +} + +fn main() { +let arg_test2 = |big_argument_name, test123| {looooooooooooooooooong_function_naaaaaaaaaaaaaaaaame()}; +} + +impl Foo { +pub fn bar(&self) { + Some(SomeType { + push_closure_out_to_100_chars: iter(otherwise_it_works_ok.into_iter().map(|f| { + Ok(f) + })), + }) +} +} diff --git a/tests/target/preserve_closure_block_wrapping.rs b/tests/target/preserve_closure_block_wrapping.rs new file mode 100755 index 00000000000..a25ccdfec8f --- /dev/null +++ b/tests/target/preserve_closure_block_wrapping.rs @@ -0,0 +1,45 @@ +// rustfmt-preserve_closure_block_wrapping: true + +fn main() { + let explicit_conversion_preserves_semantics = + || { !is_mod || (is_mod && attrs.map_or(true, |a| a.is_empty())) }; +} + +fn main() { + || { {} }; +} + +fn issue1524() { + let f = |x| { + { + { + { x } + } + } + }; + let f = |x| { + { + { x } + } + }; + let f = |x| { + { x } + }; + let f = |x| { x }; + let f = |x| x; +} + +fn main() { + let arg_test2 = + |big_argument_name, test123| { looooooooooooooooooong_function_naaaaaaaaaaaaaaaaame() }; +} + +impl Foo { + pub fn bar(&self) { + Some(SomeType { + push_closure_out_to_100_chars: iter( + otherwise_it_works_ok.into_iter().map(|f| { Ok(f) }), + ), + }) + } +}