-
Notifications
You must be signed in to change notification settings - Fork 933
Implement trailing_semicolon = "Preserve"
#6149
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from 3 commits
fc7f6e1
10e6db2
8f944d0
3126770
922e8ba
1973b90
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -32,7 +32,7 @@ use crate::types::{rewrite_path, PathContext}; | |
use crate::utils::{ | ||
colon_spaces, contains_skip, count_newlines, filtered_str_fits, first_line_ends_with, | ||
inner_attributes, last_line_extendable, last_line_width, mk_sp, outer_attributes, | ||
semicolon_for_expr, unicode_str_width, wrap_str, | ||
semicolon_for_expr_extra_hacky_double_counted_spacing, unicode_str_width, wrap_str, | ||
}; | ||
use crate::vertical::rewrite_with_alignment; | ||
use crate::visitor::FmtVisitor; | ||
|
@@ -64,7 +64,9 @@ pub(crate) fn format_expr( | |
if contains_skip(&*expr.attrs) { | ||
return Some(context.snippet(expr.span()).to_owned()); | ||
} | ||
let shape = if expr_type == ExprType::Statement && semicolon_for_expr(context, expr) { | ||
let shape = if expr_type == ExprType::Statement | ||
&& semicolon_for_expr_extra_hacky_double_counted_spacing(context, expr) | ||
{ | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I cannot remember what the bug policy here is, but ideally we'd just remove this adjustment to There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You can fix the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I fixed it in Version=Two, added a test for one&two, and fixed the cases that changed rustfmt's own formatting (since rustfmt apparently uses Two! 😆) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. responded to this in #6149 (comment) |
||
shape.sub_width(1)? | ||
} else { | ||
shape | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -8,7 +8,7 @@ use crate::rewrite::{Rewrite, RewriteContext}; | |
use crate::shape::Shape; | ||
use crate::source_map::LineRangeUtils; | ||
use crate::spanned::Spanned; | ||
use crate::utils::semicolon_for_stmt; | ||
use crate::utils::{semicolon_for_expr, semicolon_for_stmt}; | ||
|
||
pub(crate) struct Stmt<'a> { | ||
inner: &'a ast::Stmt, | ||
|
@@ -116,7 +116,7 @@ fn format_stmt( | |
|
||
let result = match stmt.kind { | ||
ast::StmtKind::Local(ref local) => local.rewrite(context, shape), | ||
ast::StmtKind::Expr(ref ex) | ast::StmtKind::Semi(ref ex) => { | ||
ast::StmtKind::Semi(ref ex) => { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. was this the cause of the double semicolon counting? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. See the comment below; I pointed out the reason for the the double semicolon counting in more detail. I split these two branches because we need to preserve semicolons only if we have a |
||
let suffix = if semicolon_for_stmt(context, stmt, is_last_expr) { | ||
";" | ||
} else { | ||
|
@@ -126,6 +126,16 @@ fn format_stmt( | |
let shape = shape.sub_width(suffix.len())?; | ||
format_expr(ex, expr_type, context, shape).map(|s| s + suffix) | ||
} | ||
ast::StmtKind::Expr(ref ex) => { | ||
let suffix = if semicolon_for_expr(context, ex) { | ||
";" | ||
} else { | ||
"" | ||
}; | ||
|
||
let shape = shape.sub_width(suffix.len())?; | ||
format_expr(ex, expr_type, context, shape).map(|s| s + suffix) | ||
} | ||
ast::StmtKind::MacCall(..) | ast::StmtKind::Item(..) | ast::StmtKind::Empty => None, | ||
}; | ||
result.and_then(|res| recover_comment_removed(res, stmt.span(), context)) | ||
|
Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
@@ -10,7 +10,7 @@ use rustc_span::{sym, symbol, BytePos, LocalExpnId, Span, Symbol, SyntaxContext} | |||||||||||||||||||||||||||||||
use unicode_width::UnicodeWidthStr; | ||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||
use crate::comment::{filter_normal_code, CharClasses, FullCodeCharKind, LineClasses}; | ||||||||||||||||||||||||||||||||
use crate::config::{Config, Version}; | ||||||||||||||||||||||||||||||||
use crate::config::{Config, TrailingSemicolon, Version}; | ||||||||||||||||||||||||||||||||
use crate::rewrite::RewriteContext; | ||||||||||||||||||||||||||||||||
use crate::shape::{Indent, Shape}; | ||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||
|
@@ -273,15 +273,43 @@ pub(crate) fn contains_skip(attrs: &[Attribute]) -> bool { | |||||||||||||||||||||||||||||||
#[inline] | ||||||||||||||||||||||||||||||||
pub(crate) fn semicolon_for_expr(context: &RewriteContext<'_>, expr: &ast::Expr) -> bool { | ||||||||||||||||||||||||||||||||
// Never try to insert semicolons on expressions when we're inside | ||||||||||||||||||||||||||||||||
// a macro definition - this can prevent the macro from compiling | ||||||||||||||||||||||||||||||||
// a macro definition - this can prevent the macro from compiling | ||||||||||||||||||||||||||||||||
// when used in expression position | ||||||||||||||||||||||||||||||||
if context.is_macro_def { | ||||||||||||||||||||||||||||||||
return false; | ||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||
match expr.kind { | ||||||||||||||||||||||||||||||||
ast::ExprKind::Ret(..) | ast::ExprKind::Continue(..) | ast::ExprKind::Break(..) => { | ||||||||||||||||||||||||||||||||
context.config.trailing_semicolon() | ||||||||||||||||||||||||||||||||
match context.config.trailing_semicolon() { | ||||||||||||||||||||||||||||||||
TrailingSemicolon::Always => true, | ||||||||||||||||||||||||||||||||
TrailingSemicolon::Never | TrailingSemicolon::Preserve => false, | ||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||
_ => false, | ||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||
/// Previously, we used to have `trailing_semicolon = always` enabled, and due to | ||||||||||||||||||||||||||||||||
/// a bug between `format_stmt` and `format_expr`, we used to subtract the size of | ||||||||||||||||||||||||||||||||
/// `;` *TWICE* from the shape. This means that an expr that would fit onto a line | ||||||||||||||||||||||||||||||||
/// of, e.g. 99 (limit 100) after subtracting one for the semicolon would still be | ||||||||||||||||||||||||||||||||
/// wrapped. | ||||||||||||||||||||||||||||||||
/// | ||||||||||||||||||||||||||||||||
/// This function reimplements the old heuristic of double counting the "phantom" | ||||||||||||||||||||||||||||||||
/// semicolon that should have already been accounted for, to not break existing | ||||||||||||||||||||||||||||||||
/// formatting with the `trailing_semicolon = preserve` behavior. | ||||||||||||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Would you mind showing an example where things are wrapping early, maybe even adding a There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
The return statement line is exactly 100 chars long. When formatting the expression, we first subtract one from the shape here: Lines 119 to 128 in 7289391
(See And then once again here: Lines 67 to 71 in 7289391
(in In practice, for example, we need to format I can add it as a There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. For the record, i discovered this because it happens twice in practice in the rustfmt codebase, so the self-formatting test failed. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yeah, we use |
||||||||||||||||||||||||||||||||
#[inline] | ||||||||||||||||||||||||||||||||
pub(crate) fn semicolon_for_expr_extra_hacky_double_counted_spacing( | ||||||||||||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Do we still need this function if we're version gating the fix and only applying the old behavior for |
||||||||||||||||||||||||||||||||
context: &RewriteContext<'_>, | ||||||||||||||||||||||||||||||||
expr: &ast::Expr, | ||||||||||||||||||||||||||||||||
) -> bool { | ||||||||||||||||||||||||||||||||
match expr.kind { | ||||||||||||||||||||||||||||||||
ast::ExprKind::Ret(..) | ast::ExprKind::Continue(..) | ast::ExprKind::Break(..) => { | ||||||||||||||||||||||||||||||||
match context.config.trailing_semicolon() { | ||||||||||||||||||||||||||||||||
TrailingSemicolon::Always | TrailingSemicolon::Preserve => true, | ||||||||||||||||||||||||||||||||
TrailingSemicolon::Never => false, | ||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||
_ => false, | ||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||
|
@@ -301,7 +329,14 @@ pub(crate) fn semicolon_for_stmt( | |||||||||||||||||||||||||||||||
ast::ExprKind::Break(..) | ast::ExprKind::Continue(..) | ast::ExprKind::Ret(..) => { | ||||||||||||||||||||||||||||||||
// The only time we can skip the semi-colon is if the config option is set to false | ||||||||||||||||||||||||||||||||
// **and** this is the last expr (even though any following exprs are unreachable) | ||||||||||||||||||||||||||||||||
context.config.trailing_semicolon() || !is_last_expr | ||||||||||||||||||||||||||||||||
if !is_last_expr { | ||||||||||||||||||||||||||||||||
true | ||||||||||||||||||||||||||||||||
} else { | ||||||||||||||||||||||||||||||||
match context.config.trailing_semicolon() { | ||||||||||||||||||||||||||||||||
TrailingSemicolon::Always | TrailingSemicolon::Preserve => true, | ||||||||||||||||||||||||||||||||
TrailingSemicolon::Never => false, | ||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||
_ => true, | ||||||||||||||||||||||||||||||||
}, | ||||||||||||||||||||||||||||||||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1,4 @@ | ||
// rustfmt-trailing_semicolon: true | ||
// rustfmt-trailing_semicolon: always | ||
|
||
#![feature(loop_break_value)] | ||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1,4 @@ | ||
// rustfmt-trailing_semicolon: false | ||
// rustfmt-trailing_semicolon: never | ||
|
||
#![feature(loop_break_value)] | ||
|
||
|
Uh oh!
There was an error while loading. Please reload this page.