diff --git a/src/expr.rs b/src/expr.rs index 0499e2fcac4..2041722688f 100644 --- a/src/expr.rs +++ b/src/expr.rs @@ -180,6 +180,14 @@ pub(crate) fn format_expr( .unknown_error() .and_then(|control_flow| control_flow.rewrite_result(context, shape)), ast::ExprKind::ConstBlock(ref anon_const) => { + // 6 = "const ". The keyword sits on the first line of the rewrite, so the + // block has that many fewer columns to work with. Gated because widening + // the block by six columns is stable formatting on earlier style editions. + let shape = if context.config.style_edition() >= StyleEdition::Edition2027 { + shape.offset_left_opt(6).unwrap_or(shape) + } else { + shape + }; let rewrite = match anon_const.value.kind { ast::ExprKind::Block(ref block, opt_label) => { // Inner attributes are associated with the `ast::ExprKind::ConstBlock` node, diff --git a/tests/source/issue_7055_narrow_max_width.rs b/tests/source/issue_7055_narrow_max_width.rs new file mode 100644 index 00000000000..8d168a43b20 --- /dev/null +++ b/tests/source/issue_7055_narrow_max_width.rs @@ -0,0 +1,21 @@ +// rustfmt-style_edition: 2027 +// rustfmt-max_width: 30 +// rustfmt-error_on_line_overflow: false + +// Fewer than six columns of +// budget left: still format +// it, do not bail out and +// emit it verbatim. +fn deep() { + if a { + if b { + if c { + if d { + if e { + let q = const { 1 + 2 }; + } + } + } + } + } +} diff --git a/tests/source/issue_7055_style_edition_2021.rs b/tests/source/issue_7055_style_edition_2021.rs new file mode 100644 index 00000000000..60cf284fc33 --- /dev/null +++ b/tests/source/issue_7055_style_edition_2021.rs @@ -0,0 +1,74 @@ +// rustfmt-style_edition: 2021 +// rustfmt-max_width: 100 +// rustfmt-error_on_line_overflow: false + +struct S; + +impl S { + const fn new(_: &str) -> Self { + S + } + + fn go(&self) {} +} + +// The reported symptom. As the receiver of a method call the block was rewritten at +// the full width, the `const ` prefix pushed the result past `max_width`, the chain +// rejected it, and the whole expression was silently left unformatted. +fn receiver_74() { + const { + S::new( + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", + ) + } + .go(); +} + +fn receiver_77() { + const { + S::new( + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", + ) + } + .go(); +} + +fn receiver_80() { + const { + S::new( + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", + ) + } + .go(); +} + +// Not a method receiver, so the over-wide rewrite was accepted and emitted. This is +// the stable formatting the gate protects: on style editions below 2027 these keep +// producing a line past `max_width`. +fn statement_74() { + const { S::new( "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" ) } ; +} + +fn statement_77() { + const { S::new( "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" ) } ; +} + +fn statement_80() { + const { S::new( "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" ) } ; +} + +// The `const ` budget applies to a nested block too. +fn nested() { + let _ = const { + const { S::new( "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" ) } + }; +} + +// Inner attributes belong to the `ConstBlock` node, not the `Block`, so they take the +// `rewrite_block` path directly. Guard that the shape change leaves them alone. +fn inner_attrs() { + let _ = const { + #![allow(unused)] + S::new( "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" ) + }; +} diff --git a/tests/source/issue_7055_style_edition_2024.rs b/tests/source/issue_7055_style_edition_2024.rs new file mode 100644 index 00000000000..876df636155 --- /dev/null +++ b/tests/source/issue_7055_style_edition_2024.rs @@ -0,0 +1,74 @@ +// rustfmt-style_edition: 2024 +// rustfmt-max_width: 100 +// rustfmt-error_on_line_overflow: false + +struct S; + +impl S { + const fn new(_: &str) -> Self { + S + } + + fn go(&self) {} +} + +// The reported symptom. As the receiver of a method call the block was rewritten at +// the full width, the `const ` prefix pushed the result past `max_width`, the chain +// rejected it, and the whole expression was silently left unformatted. +fn receiver_74() { + const { + S::new( + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", + ) + } + .go(); +} + +fn receiver_77() { + const { + S::new( + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", + ) + } + .go(); +} + +fn receiver_80() { + const { + S::new( + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", + ) + } + .go(); +} + +// Not a method receiver, so the over-wide rewrite was accepted and emitted. This is +// the stable formatting the gate protects: on style editions below 2027 these keep +// producing a line past `max_width`. +fn statement_74() { + const { S::new( "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" ) } ; +} + +fn statement_77() { + const { S::new( "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" ) } ; +} + +fn statement_80() { + const { S::new( "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" ) } ; +} + +// The `const ` budget applies to a nested block too. +fn nested() { + let _ = const { + const { S::new( "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" ) } + }; +} + +// Inner attributes belong to the `ConstBlock` node, not the `Block`, so they take the +// `rewrite_block` path directly. Guard that the shape change leaves them alone. +fn inner_attrs() { + let _ = const { + #![allow(unused)] + S::new( "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" ) + }; +} diff --git a/tests/source/issue_7055_style_edition_2027.rs b/tests/source/issue_7055_style_edition_2027.rs new file mode 100644 index 00000000000..969daa60846 --- /dev/null +++ b/tests/source/issue_7055_style_edition_2027.rs @@ -0,0 +1,74 @@ +// rustfmt-style_edition: 2027 +// rustfmt-max_width: 100 +// rustfmt-error_on_line_overflow: false + +struct S; + +impl S { + const fn new(_: &str) -> Self { + S + } + + fn go(&self) {} +} + +// The reported symptom. As the receiver of a method call the block was rewritten at +// the full width, the `const ` prefix pushed the result past `max_width`, the chain +// rejected it, and the whole expression was silently left unformatted. +fn receiver_74() { + const { + S::new( + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", + ) + } + .go(); +} + +fn receiver_77() { + const { + S::new( + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", + ) + } + .go(); +} + +fn receiver_80() { + const { + S::new( + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", + ) + } + .go(); +} + +// Not a method receiver, so the over-wide rewrite was accepted and emitted. This is +// the stable formatting the gate protects: on style editions below 2027 these keep +// producing a line past `max_width`. +fn statement_74() { + const { S::new( "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" ) } ; +} + +fn statement_77() { + const { S::new( "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" ) } ; +} + +fn statement_80() { + const { S::new( "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" ) } ; +} + +// The `const ` budget applies to a nested block too. +fn nested() { + let _ = const { + const { S::new( "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" ) } + }; +} + +// Inner attributes belong to the `ConstBlock` node, not the `Block`, so they take the +// `rewrite_block` path directly. Guard that the shape change leaves them alone. +fn inner_attrs() { + let _ = const { + #![allow(unused)] + S::new( "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" ) + }; +} diff --git a/tests/target/issue_7055_narrow_max_width.rs b/tests/target/issue_7055_narrow_max_width.rs new file mode 100644 index 00000000000..2e0cf163a5a --- /dev/null +++ b/tests/target/issue_7055_narrow_max_width.rs @@ -0,0 +1,23 @@ +// rustfmt-style_edition: 2027 +// rustfmt-max_width: 30 +// rustfmt-error_on_line_overflow: false + +// Fewer than six columns of +// budget left: still format +// it, do not bail out and +// emit it verbatim. +fn deep() { + if a { + if b { + if c { + if d { + if e { + let q = const { + 1 + 2 + }; + } + } + } + } + } +} diff --git a/tests/target/issue_7055_style_edition_2021.rs b/tests/target/issue_7055_style_edition_2021.rs new file mode 100644 index 00000000000..c5bfe097ae8 --- /dev/null +++ b/tests/target/issue_7055_style_edition_2021.rs @@ -0,0 +1,70 @@ +// rustfmt-style_edition: 2021 +// rustfmt-max_width: 100 +// rustfmt-error_on_line_overflow: false + +struct S; + +impl S { + const fn new(_: &str) -> Self { + S + } + + fn go(&self) {} +} + +// The reported symptom. As the receiver of a method call the block was rewritten at +// the full width, the `const ` prefix pushed the result past `max_width`, the chain +// rejected it, and the whole expression was silently left unformatted. +fn receiver_74() { + const { S::new("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa") } + .go(); +} + +fn receiver_77() { + const { + S::new( + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", + ) + } + .go(); +} + +fn receiver_80() { + const { + S::new( + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", + ) + } + .go(); +} + +// Not a method receiver, so the over-wide rewrite was accepted and emitted. This is +// the stable formatting the gate protects: on style editions below 2027 these keep +// producing a line past `max_width`. +fn statement_74() { + const { S::new("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa") }; +} + +fn statement_77() { + const { S::new("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa") }; +} + +fn statement_80() { + const { S::new("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa") }; +} + +// The `const ` budget applies to a nested block too. +fn nested() { + let _ = const { + const { S::new("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa") } + }; +} + +// Inner attributes belong to the `ConstBlock` node, not the `Block`, so they take the +// `rewrite_block` path directly. Guard that the shape change leaves them alone. +fn inner_attrs() { + let _ = const { + #![allow(unused)] + S::new("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa") + }; +} diff --git a/tests/target/issue_7055_style_edition_2024.rs b/tests/target/issue_7055_style_edition_2024.rs new file mode 100644 index 00000000000..92e52604371 --- /dev/null +++ b/tests/target/issue_7055_style_edition_2024.rs @@ -0,0 +1,70 @@ +// rustfmt-style_edition: 2024 +// rustfmt-max_width: 100 +// rustfmt-error_on_line_overflow: false + +struct S; + +impl S { + const fn new(_: &str) -> Self { + S + } + + fn go(&self) {} +} + +// The reported symptom. As the receiver of a method call the block was rewritten at +// the full width, the `const ` prefix pushed the result past `max_width`, the chain +// rejected it, and the whole expression was silently left unformatted. +fn receiver_74() { + const { S::new("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa") } + .go(); +} + +fn receiver_77() { + const { + S::new( + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", + ) + } + .go(); +} + +fn receiver_80() { + const { + S::new( + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", + ) + } + .go(); +} + +// Not a method receiver, so the over-wide rewrite was accepted and emitted. This is +// the stable formatting the gate protects: on style editions below 2027 these keep +// producing a line past `max_width`. +fn statement_74() { + const { S::new("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa") }; +} + +fn statement_77() { + const { S::new("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa") }; +} + +fn statement_80() { + const { S::new("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa") }; +} + +// The `const ` budget applies to a nested block too. +fn nested() { + let _ = const { + const { S::new("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa") } + }; +} + +// Inner attributes belong to the `ConstBlock` node, not the `Block`, so they take the +// `rewrite_block` path directly. Guard that the shape change leaves them alone. +fn inner_attrs() { + let _ = const { + #![allow(unused)] + S::new("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa") + }; +} diff --git a/tests/target/issue_7055_style_edition_2027.rs b/tests/target/issue_7055_style_edition_2027.rs new file mode 100644 index 00000000000..0142dd50e56 --- /dev/null +++ b/tests/target/issue_7055_style_edition_2027.rs @@ -0,0 +1,70 @@ +// rustfmt-style_edition: 2027 +// rustfmt-max_width: 100 +// rustfmt-error_on_line_overflow: false + +struct S; + +impl S { + const fn new(_: &str) -> Self { + S + } + + fn go(&self) {} +} + +// The reported symptom. As the receiver of a method call the block was rewritten at +// the full width, the `const ` prefix pushed the result past `max_width`, the chain +// rejected it, and the whole expression was silently left unformatted. +fn receiver_74() { + const { S::new("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa") } + .go(); +} + +fn receiver_77() { + const { + S::new("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa") + } + .go(); +} + +fn receiver_80() { + const { + S::new("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa") + } + .go(); +} + +// Not a method receiver, so the over-wide rewrite was accepted and emitted. This is +// the stable formatting the gate protects: on style editions below 2027 these keep +// producing a line past `max_width`. +fn statement_74() { + const { S::new("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa") }; +} + +fn statement_77() { + const { + S::new("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa") + }; +} + +fn statement_80() { + const { + S::new("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa") + }; +} + +// The `const ` budget applies to a nested block too. +fn nested() { + let _ = const { + const { S::new("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa") } + }; +} + +// Inner attributes belong to the `ConstBlock` node, not the `Block`, so they take the +// `rewrite_block` path directly. Guard that the shape change leaves them alone. +fn inner_attrs() { + let _ = const { + #![allow(unused)] + S::new("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa") + }; +}