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:

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:

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:

pub fn main() {
    /*   let s = String::from(
        "
hello
world
",
    ); */
}

Style edition 2021:

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:

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:

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:

impl<
        Target: FromEvent<A> + FromEvent<B>,
        A: Widget2<Ctx = C>,
        B: Widget2<Ctx = C>,
        C: for<'a> CtxFamily<'a>,
    > Widget2 for WidgetEventLifter<Target, A, B>
{
    type Ctx = C;
    type Event = Vec<Target>;
}

Style edition 2024:

impl<
    Target: FromEvent<A> + FromEvent<B>,
    A: Widget2<Ctx = C>,
    B: Widget2<Ctx = C>,
    C: for<'a> CtxFamily<'a>,
> Widget2 for WidgetEventLifter<Target, A, B>
{
    type Ctx = C;
    type Event = Vec<Target>;
}

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:

fn build_sorted_static_get_entry_names(
    mut entries: Vec<(u8, &'static str)>,
) -> (impl Fn(
    AlphabeticalTraversal,
    Box<dyn dirents_sink::Sink<AlphabeticalTraversal>>,
) -> BoxFuture<'static, Result<Box<dyn dirents_sink::Sealed>, Status>>
        + Send
        + Sync
        + 'static) {
}

Style edition 2024:

fn build_sorted_static_get_entry_names(
    mut entries: Vec<(u8, &'static str)>,
) -> (
    impl Fn(
        AlphabeticalTraversal,
        Box<dyn dirents_sink::Sink<AlphabeticalTraversal>>,
    ) -> BoxFuture<'static, Result<Box<dyn dirents_sink::Sealed>, 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:

fn main() {
    let _ = ((1,),).0 .0;
}

Style edition 2024:

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:

fn foo() {
    match 0 {
        0 => {
            return AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
        }
        _ => "",
    };
}

Style edition 2024:

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:

fn main() {
    let [aaaaaaaaaaaaaaaaaaaaaaaaaa, bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb, cccccccccccccccccccccccccc, ddddddddddddddddddddddddd] =
        panic!();
}

Style edition 2024:

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:

fn main() {
    let toto = || {
        if true {
            42
        } else {
            24
        }
    };

    {
        T
    }
}

Style edition 2024:

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:

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:

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:

fn main() {
    thread::spawn(|| loop {
        println!("iteration");
    });
}

Style edition 2024:

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:

fn foo<T>(_: T)
where
    T: std::fmt::Debug,

    T: std::fmt::Display,
{
}

Style edition 2024:

fn foo<T>(_: 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:

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:

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:

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:

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:

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:

macro_rules! test {
    ($aasdfghj:expr, $qwertyuiop:expr, $zxcvbnmasdfghjkl:expr, $aeiouaeiouaeio:expr, $add:expr) => {{
        return;
    }};
}

Style edition 2024:

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:

fn main() {
    match a {
        _ =>
        // comment with =>
                {
            println!("A")
        }
    }
}

Style edition 2024:

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:

pub fn main() {
    match a {
        #![attr1]
    #![attr2]
        _ => None,
    }
}

Style edition 2024:

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.