Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions check_diff/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ pub enum Edition {
Edition2021,
/// rust edition 2024
Edition2024,
/// rust edition 2027
Edition2027,
}

impl Edition {
Expand All @@ -30,6 +32,7 @@ impl Edition {
Edition::Edition2018 => "2018",
Edition::Edition2021 => "2021",
Edition::Edition2024 => "2024",
Edition::Edition2027 => "2027",
}
}
}
Expand All @@ -43,6 +46,7 @@ impl FromStr for Edition {
"2018" => Ok(Edition::Edition2018),
"2021" => Ok(Edition::Edition2021),
"2024" => Ok(Edition::Edition2024),
"2027" => Ok(Edition::Edition2027),
_ => Err(format!("Invalid rust language edition {s}")),
}
}
Expand All @@ -54,13 +58,16 @@ pub enum StyleEdition {
Edition2021,
// rustfmt style_edition 2024
Edition2024,
// rustfmt style_edition 2027
Edition2027,
}

impl StyleEdition {
fn as_str(&self) -> &str {
match self {
StyleEdition::Edition2021 => "2021",
StyleEdition::Edition2024 => "2024",
StyleEdition::Edition2027 => "2027",
}
}
}
Expand All @@ -74,6 +81,7 @@ impl FromStr for StyleEdition {
"2018" => Ok(StyleEdition::Edition2021),
"2021" => Ok(StyleEdition::Edition2021),
"2024" => Ok(StyleEdition::Edition2024),
"2027" => Ok(StyleEdition::Edition2027),
_ => Err(format!("Invalid rustfmt style edition {s}")),
}
}
Expand Down
2 changes: 1 addition & 1 deletion src/bin/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,7 @@ fn make_opts() -> Options {
"",
"style-edition",
"The edition of the Style Guide (unstable).",
"[2015|2018|2021|2024]",
"[2015|2018|2021|2024|2027]",
);
opts.optopt(
"",
Expand Down
7 changes: 7 additions & 0 deletions src/config/options.rs
Original file line number Diff line number Diff line change
Expand Up @@ -458,6 +458,10 @@ pub enum Edition {
#[doc_hint = "2024"]
/// Edition 2024.
Edition2024,
#[value = "2027"]
#[doc_hint = "2027"]
/// Edition 2027.
Edition2027,
}

impl Default for Edition {
Expand All @@ -473,6 +477,8 @@ impl From<Edition> for rustc_span::edition::Edition {
Edition::Edition2018 => Self::Edition2018,
Edition::Edition2021 => Self::Edition2021,
Edition::Edition2024 => Self::Edition2024,
// FIXME: rustc doesn't have an edition 2027 yet.
Edition::Edition2027 => Self::Edition2024,
}
}
}
Expand All @@ -484,6 +490,7 @@ impl From<Edition> for StyleEdition {
Edition::Edition2018 => StyleEdition::Edition2018,
Edition::Edition2021 => StyleEdition::Edition2021,
Edition::Edition2024 => StyleEdition::Edition2024,
Edition::Edition2027 => StyleEdition::Edition2027,
}
}
}
Expand Down
15 changes: 13 additions & 2 deletions src/lists.rs
Original file line number Diff line number Diff line change
Expand Up @@ -198,7 +198,7 @@ impl ListItem {
}

fn empty_result(s: &RewriteResult) -> bool {
!matches!(*s, Ok(ref s) if !s.is_empty())
!matches!(*s, Ok(ref s) | Err(RewriteError::InlineComment(ref s)) if !s.is_empty())
}

!(empty(&self.pre_comment) && empty_result(&self.item) && empty(&self.post_comment))
Expand Down Expand Up @@ -285,7 +285,18 @@ where
let indent_str = &formatting.shape.indent.to_string(formatting.config);
while let Some((i, item)) = iter.next() {
let item = item.as_ref();
let inner_item = item.item.as_ref().or_else(|err| Err(err.clone()))?;
let inner_item = match item.item.as_ref() {
Ok(item) => item,
Err(RewriteError::InlineComment(item)) => {
// Keep the original contents and recover, allowing the subsequent items to be
// formatted while keeping the original formatting of this item.
// This is currently only relevant to or-patterns with comments in between patterns.
// We gate this under future edition 2027 because the amount of code that needs to
// be reformatted in the wild is quite high.
item
}
Err(err) => return Err(err.clone()),
};
let first = i == 0;
let last = iter.peek().is_none();
let mut separate = match sep_place {
Expand Down
20 changes: 16 additions & 4 deletions src/matches.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,9 @@ use rustc_ast::{MatchKind, ast};
use rustc_span::{BytePos, Span};
use tracing::debug;

use crate::comment::{FindUncommented, combine_strs_with_missing_comments, rewrite_comment};
use crate::comment::{
FindUncommented, combine_strs_with_missing_comments, recover_comment_removed, rewrite_comment,
};
use crate::config::lists::*;
use crate::config::{Config, ControlBraceStyle, IndentStyle, MatchArmLeadingPipe, StyleEdition};
use crate::expr::{
Expand Down Expand Up @@ -293,7 +295,13 @@ fn rewrite_match_arm(
.offset_left(pipe_offset, arm.span)?
}
};
let pats_str = arm.pat.rewrite_result(context, pat_shape)?;
let pats_str_rewritten = arm.pat.rewrite_result(context, pat_shape)?;
// FIXME: if the original pattern span is multiline, then we should at least try to reindent
// it, but for now we leave it as it was before.
let pats_str = recover_comment_removed(pats_str_rewritten.clone(), arm.pat.span, context);
// We will continue formatting all other elements of of the `match`, but will still signal the
// error.
let inline_comment = pats_str != pats_str_rewritten;

// Guard
let block_like_pat = trimmed_last_line_width(&pats_str) <= context.config.tab_spaces();
Expand All @@ -319,15 +327,19 @@ fn rewrite_match_arm(
arm.pat.span.hi(),
arm.body.as_ref().unknown_error()?.span().lo(),
);
rewrite_match_body(
let body = rewrite_match_body(
context,
arm.body.as_ref().unknown_error()?,
&lhs_str,
shape,
guard_str.contains('\n'),
arrow_span,
is_last,
)
)?;
if inline_comment && context.config.style_edition() >= StyleEdition::Edition2027 {
return Err(RewriteError::InlineComment(body));
}
Ok(body)
}

fn stmt_is_expr_mac(stmt: &ast::Stmt) -> bool {
Expand Down
7 changes: 7 additions & 0 deletions src/rewrite.rs
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,13 @@ pub(crate) enum RewriteError {
#[error("Failed to format given macro{} at: {span:?}", kind)]
MacroFailure { kind: MacroErrorKind, span: Span },

/// This failure will normally happen when an or-pattern has comments in between its elements.
///
/// We will keep the original code, report an error, but recover and format code that comes
/// later properly.
#[error("Formatting was skipped due to a comment that would have been removed.")]
InlineComment(String),

/// Format failure that does not fit to above categories.
#[error("An unknown error occurred during formatting.")]
Unknown,
Expand Down
14 changes: 14 additions & 0 deletions tests/source/match.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
// rustfmt-edition: 2027
// rustfmt-normalize_comments: true
// Match expressions.

Expand Down Expand Up @@ -590,3 +591,16 @@ unsafe {}
}
}
}

fn issue_4119() {
match () {
()=> {}
() // Comment
| () => {
{
println!("Foo");
}
}
()=> {}
}
}
12 changes: 12 additions & 0 deletions tests/target/match.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
// rustfmt-edition: 2027
// rustfmt-normalize_comments: true
// Match expressions.

Expand Down Expand Up @@ -635,3 +636,14 @@ fn issue_4109() {
}
}
}

fn issue_4119() {
match () {
() => {}
() // Comment
| () => {
println!("Foo");
Copy link
Copy Markdown
Contributor Author

@estebank estebank May 12, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This highlights the outstanding problem with this approach: the pattern is kept with bad formatting, where this should instead have been indented to the proper level.

View changes since the review

}
() => {}
}
}
Loading