diff --git a/src/SUMMARY.md b/src/SUMMARY.md index 3b572ad5..51c916fa 100644 --- a/src/SUMMARY.md +++ b/src/SUMMARY.md @@ -66,6 +66,7 @@ - [Rustdoc nested `include!` change](rust-2024/rustdoc-nested-includes.md) - [Rustfmt](rust-2024/rustfmt.md) - [Rustfmt: Style edition](rust-2024/rustfmt-style-edition.md) + - [Rustfmt: Formatting fixes](rust-2024/rustfmt-formatting-fixes.md) - [Rustfmt: Combine all delimited exprs as last argument](rust-2024/rustfmt-overflow-delimited-expr.md) - [Rustfmt: Raw identifier sorting](rust-2024/rustfmt-raw-identifier-sorting.md) - [Rustfmt: Version sorting](rust-2024/rustfmt-version-sorting.md) diff --git a/src/rust-2024/rustfmt-formatting-fixes.md b/src/rust-2024/rustfmt-formatting-fixes.md new file mode 100644 index 00000000..6b6d4c8b --- /dev/null +++ b/src/rust-2024/rustfmt-formatting-fixes.md @@ -0,0 +1,644 @@ +# Rustfmt: Formatting fixes + +## Summary + +- Fixes to various formatting scenarios. + +## Details + +The 2024 style edition introduces several fixes to various formatting scenarios. + +### Don't align unrelated trailing comments after items or at the end of blocks + + + +Previously rustfmt would assume that a comment on a line following an item with a trailing comment should be indented to match the trailing comment. This has been changed so that those comments are not indented. + +**Style edition 2021:** + +```rust,ignore +pub const IFF_MULTICAST: ::c_int = 0x0000000800; // Supports multicast + // Multicast using broadcst. add. + +pub const SQ_CRETAB: u16 = 0x000e; // CREATE TABLE +pub const SQ_DRPTAB: u16 = 0x000f; // DROP TABLE +pub const SQ_CREIDX: u16 = 0x0010; // CREATE INDEX + //const SQ_DRPIDX: u16 = 0x0011; // DROP INDEX + //const SQ_GRANT: u16 = 0x0012; // GRANT + //const SQ_REVOKE: u16 = 0x0013; // REVOKE + +fn foo() { + let f = bar(); // Donec consequat mi. Quisque vitae dolor. Integer lobortis. Maecenas id nulla. Lorem. + // Id turpis. Nam posuere lectus vitae nibh. Etiam tortor orci, sagittis + // malesuada, rhoncus quis, hendrerit eget, libero. Quisque commodo nulla at + let b = baz(); + + let normalized = self.ctfont.all_traits().normalized_weight(); // [-1.0, 1.0] + // TODO(emilio): It may make sense to make this range [.01, 10.0], to align + // with css-fonts-4's range of [1, 1000]. +} +``` + +**Style edition 2024:** + +```rust,ignore +pub const IFF_MULTICAST: ::c_int = 0x0000000800; // Supports multicast +// Multicast using broadcst. add. + +pub const SQ_CRETAB: u16 = 0x000e; // CREATE TABLE +pub const SQ_DRPTAB: u16 = 0x000f; // DROP TABLE +pub const SQ_CREIDX: u16 = 0x0010; // CREATE INDEX +//const SQ_DRPIDX: u16 = 0x0011; // DROP INDEX +//const SQ_GRANT: u16 = 0x0012; // GRANT +//const SQ_REVOKE: u16 = 0x0013; // REVOKE + +fn foo() { + let f = bar(); // Donec consequat mi. Quisque vitae dolor. Integer lobortis. Maecenas id nulla. Lorem. + // Id turpis. Nam posuere lectus vitae nibh. Etiam tortor orci, sagittis + // malesuada, rhoncus quis, hendrerit eget, libero. Quisque commodo nulla at + let b = baz(); + + let normalized = self.ctfont.all_traits().normalized_weight(); // [-1.0, 1.0] + // TODO(emilio): It may make sense to make this range [.01, 10.0], to align + // with css-fonts-4's range of [1, 1000]. +} +``` + +### Don't indent strings in comments + + + +Previously rustfmt would incorrectly attempt to format strings in comments. + +**Original:** + +```rust,ignore +pub fn main() { + /* let s = String::from( + " +hello +world +", + ); */ +} +``` + +**Style edition 2021:** + +```rust,ignore +pub fn main() { + /* let s = String::from( + " + hello + world + ", + ); */ +} +``` + +**Style edition 2024:** + +No change from original. + +### Long strings don't prevent formatting expressions + + + +In some situations, long strings would previously prevent the expression from being formatted. + +**Style edition 2021:** + +```rust,ignore +fn main() { + let value = if x == "Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum." { 0 } else {10}; + + let x = Testing { + foo: "long_long_long_long_long_long_long_lo_long_long_long_long_long_long__long_long_long_long_long_long_", +bar: "long_long_long_long_long_long_long_long_long_long_lo_long_long_lolong_long_long_lo_long_long_lolong_long_long_lo_long_long_lo", +}; +} +``` + +**Style edition 2024:** + +```rust,ignore +fn main() { + let value = if x + == "Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum." + { + 0 + } else { + 10 + }; + + let x = Testing { + foo: "long_long_long_long_long_long_long_lo_long_long_long_long_long_long__long_long_long_long_long_long_", + bar: "long_long_long_long_long_long_long_long_long_long_lo_long_long_lolong_long_long_lo_long_long_lolong_long_long_lo_long_long_lo", + }; +} +``` + +### Fixed indentation of generics in impl blocks + + + +Generics in `impl` items had excessive indentation. + +**Style edition 2021:** + +```rust,ignore +impl< + Target: FromEvent + FromEvent, + A: Widget2, + B: Widget2, + C: for<'a> CtxFamily<'a>, + > Widget2 for WidgetEventLifter +{ + type Ctx = C; + type Event = Vec; +} +``` + +**Style edition 2024:** + +```rust,ignore +impl< + Target: FromEvent + FromEvent, + A: Widget2, + B: Widget2, + C: for<'a> CtxFamily<'a>, +> Widget2 for WidgetEventLifter +{ + type Ctx = C; + type Event = Vec; +} +``` + +### Use correct indentation when formatting a complex `fn` + + + +In some cases, a complex `fn` signature could end up with an unusual indentation that is now fixed. + +**Style edition 2021:** + +```rust,ignore +fn build_sorted_static_get_entry_names( + mut entries: Vec<(u8, &'static str)>, +) -> (impl Fn( + AlphabeticalTraversal, + Box>, +) -> BoxFuture<'static, Result, Status>> + + Send + + Sync + + 'static) { +} +``` + +**Style edition 2024:** + +```rust,ignore +fn build_sorted_static_get_entry_names( + mut entries: Vec<(u8, &'static str)>, +) -> ( + impl Fn( + AlphabeticalTraversal, + Box>, + ) -> BoxFuture<'static, Result, Status>> + + Send + + Sync + + 'static +) { +} +``` + +### Avoid extra space in nested tuple indexing expression + + + +Nested tuple indexing expressions would incorrectly include an extra space. + +**Style edition 2021:** + +```rust,ignore +fn main() { + let _ = ((1,),).0 .0; +} +``` + +**Style edition 2024:** + +```rust,ignore +fn main() { + let _ = ((1,),).0.0; +} +``` + +### End return/break/continue inside a block in a match with a semicolon + + + +A `return`, `break`, or `continue` inside a block in a match arm was incorrectly missing a semicolon. + +**Style edition 2021:** + +```rust,ignore +fn foo() { + match 0 { + 0 => { + return AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + } + _ => "", + }; +} +``` + +**Style edition 2024:** + +```rust,ignore +fn foo() { + match 0 { + 0 => { + return AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA; + } + _ => "", + }; +} +``` + +### Long array and slice patterns are now wrapped + + + +Long array and slice patterns were not getting wrapped properly. + +**Style edition 2021:** + +```rust,ignore +fn main() { + let [aaaaaaaaaaaaaaaaaaaaaaaaaa, bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb, cccccccccccccccccccccccccc, ddddddddddddddddddddddddd] = + panic!(); +} +``` + +**Style edition 2024:** + +```rust,ignore +fn main() { + let [ + aaaaaaaaaaaaaaaaaaaaaaaaaa, + bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb, + cccccccccccccccccccccccccc, + ddddddddddddddddddddddddd, + ] = panic!(); +} +``` + +### Format the last expression-statement as an expression + + + +The last statement in a block which is an expression is now formatted as an expression. + +**Style edition 2021:** + +```rust,ignore +fn main() { + let toto = || { + if true { + 42 + } else { + 24 + } + }; + + { + T + } +} +``` + +**Style edition 2024:** + +```rust,ignore +fn main() { + let toto = || { + if true { 42 } else { 24 } + }; + + { T } +} +``` + +### Same formatting between function and macro calls + + + +Some formatting is now the same in a macro invocation as it is in a function call. + +**Style edition 2021:** + +```rust,ignore +fn main() { + macro_call!(HAYSTACK + .par_iter() + .find_any(|&&x| x[0] % 1000 == 999) + .is_some()); + + fn_call( + HAYSTACK + .par_iter() + .find_any(|&&x| x[0] % 1000 == 999) + .is_some(), + ); +} +``` + +**Style edition 2024:** + +```rust,ignore +fn main() { + macro_call!( + HAYSTACK + .par_iter() + .find_any(|&&x| x[0] % 1000 == 999) + .is_some() + ); + + fn_call( + HAYSTACK + .par_iter() + .find_any(|&&x| x[0] % 1000 == 999) + .is_some(), + ); +} +``` + +### Force block closures for closures with a single loop body + + + +Closures with a single loop are now formatted as a block expression. + +**Style edition 2021:** + +```rust,ignore +fn main() { + thread::spawn(|| loop { + println!("iteration"); + }); +} +``` + +**Style edition 2024:** + +```rust,ignore +fn main() { + thread::spawn(|| { + loop { + println!("iteration"); + } + }); +} +``` + +### Empty lines in where clauses are now removed + + + +Empty lines in a `where` clause are now removed. + +**Style edition 2021:** + +```rust,ignore +fn foo(_: T) +where + T: std::fmt::Debug, + + T: std::fmt::Display, +{ +} +``` + +**Style edition 2024:** + +```rust,ignore +fn foo(_: T) +where + T: std::fmt::Debug, + T: std::fmt::Display, +{ +} +``` + +### Fixed formatting of a let-else statement with an attribute + + + +If a let-else statement had an attribute, then it would cause the `else` clause to incorrectly wrap the `else` part separately. + +**Style edition 2021:** + +```rust,ignore +fn main() { + #[cfg(target_os = "linux")] + let x = 42 + else { + todo!() + }; + + // This is the same without an attribute. + let x = 42 else { todo!() }; +} +``` + +**Style edition 2024:** + +```rust,ignore +fn main() { + #[cfg(target_os = "linux")] + let x = 42 else { todo!() }; + + // This is the same without an attribute. + let x = 42 else { todo!() }; +} +``` + +### Off-by-one error for wrapping enum variant doc comments + + + +When using the `wrap_comments` feature, the comments were being wrapped at a column width off-by-one. + +**Original:** + +```rust,ignore +pub enum Severity { + /// But here, this comment is 120 columns wide and the formatter wants to split it up onto two separate lines still. + Error, + /// This comment is 119 columns wide and works perfectly. Lorem ipsum. lorem ipsum. lorem ipsum. lorem ipsum lorem. + Warning, +} +``` + +**Style edition 2021:** + +```rust,ignore +pub enum Severity { + /// But here, this comment is 120 columns wide and the formatter wants to split it up onto two separate lines + /// still. + Error, + /// This comment is 119 columns wide and works perfectly. Lorem ipsum. lorem ipsum. lorem ipsum. lorem ipsum lorem. + Warning, +} +``` + +**Style edition 2024:** + +```rust,ignore +pub enum Severity { + /// But here, this comment is 120 columns wide and the formatter wants to split it up onto two separate lines still. + Error, + /// This comment is 119 columns wide and works perfectly. Lorem ipsum. lorem ipsum. lorem ipsum. lorem ipsum lorem. + Warning, +} +``` + +### Off-by-one error for `format_macro_matchers` + + + +When using the `format_macro_matchers` feature, the matcher was being wrapped at a column width off-by-one. + +**Style edition 2021:** + +```rust,ignore +macro_rules! test { + ($aasdfghj:expr, $qwertyuiop:expr, $zxcvbnmasdfghjkl:expr, $aeiouaeiouaeio:expr, $add:expr) => {{ + return; + }}; +} +``` + +**Style edition 2024:** + +```rust,ignore +macro_rules! test { + ( + $aasdfghj:expr, $qwertyuiop:expr, $zxcvbnmasdfghjkl:expr, $aeiouaeiouaeio:expr, $add:expr + ) => {{ + return; + }}; +} +``` + +### Fixed failure with `=>` in comment after match `=>` + + + +In certain circumstances if a comment contained a `=>` after the `=>` in a match expression, this would cause a failure to format correctly. + +**Style edition 2021:** + +```rust,ignore +fn main() { + match a { + _ => + // comment with => + { + println!("A") + } + } +} +``` + +**Style edition 2024:** + +```rust,ignore +fn main() { + match a { + _ => + // comment with => + { + println!("A") + } + } +} +``` + +### Multiple inner attributes in a match expression indented incorrectly + + + +Multiple inner attributes in a match expression were being indented incorrectly. + +**Style edition 2021:** + +```rust,ignore +pub fn main() { + match a { + #![attr1] + #![attr2] + _ => None, + } +} +``` + +**Style edition 2024:** + +```rust,ignore +pub fn main() { + match a { + #![attr1] + #![attr2] + _ => None, + } +} +``` + +## Migration + +The change can be applied automatically by running `cargo fmt` or `rustfmt` with the 2024 Edition. See the [Style edition] chapter for more information on migrating and how style editions work. + +[Style edition]: rustfmt-style-edition.md