Merge commit 'dca1cf90ad6b8e45afbed2061803befbb2d159e9' into sync-rustfmt

This commit is contained in:
Caleb Cartwright 2023-07-01 02:49:12 -05:00
parent 80bf3ea542
commit 78331eefaf
25 changed files with 1081 additions and 49 deletions

View File

@ -2,6 +2,17 @@
## [Unreleased]
## [1.6.0] 2023-07-02
### Added
- Support for formatting let-else statements [#5690]
- New config option, `single_line_let_else_max_width`, that allows users to configure the maximum length of single line `let-else` statements. `let-else` statements that otherwise meet the requirements to be formatted on a single line will have their divergent`else` block formatted over multiple lines if they exceed this length [#5684]
[#5690]: (https://github.com/rust-lang/rustfmt/pulls/5690)
[#5684]: https://github.com/rust-lang/rustfmt/issues/5684
## [1.5.3] 2023-06-20
### Fixed

6
Cargo.lock generated
View File

@ -481,9 +481,9 @@ dependencies = [
[[package]]
name = "proc-macro2"
version = "1.0.56"
version = "1.0.63"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2b63bdb0cd06f1f4dedf69b254734f9b45af66e4a031e42a7480257d9898b435"
checksum = "7b368fba921b0dce7e60f5e04ec15e565b3303972b42bcfde1d0713b881959eb"
dependencies = [
"unicode-ident",
]
@ -545,7 +545,7 @@ dependencies = [
[[package]]
name = "rustfmt-nightly"
version = "1.5.3"
version = "1.6.0"
dependencies = [
"annotate-snippets",
"anyhow",

View File

@ -1,7 +1,7 @@
[package]
name = "rustfmt-nightly"
version = "1.5.3"
version = "1.6.0"
description = "Tool to find and fix Rust formatting issues"
repository = "https://github.com/rust-lang/rustfmt"
readme = "README.md"

View File

@ -2392,6 +2392,78 @@ By default this option is set as a percentage of [`max_width`](#max_width) provi
See also [`max_width`](#max_width) and [`use_small_heuristics`](#use_small_heuristics)
## `single_line_let_else_max_width`
Maximum line length for single line let-else statements.
See the [let-else statement section of the Rust Style Guide](https://github.com/rust-lang/rust/blob/master/src/doc/style-guide/src/statements.md#else-blocks-let-else-statements) for more details on when a let-else statement may be written on a single line.
A value of `0` (zero) means the divergent `else` block will always be formatted over multiple lines.
Note this occurs when `use_small_heuristics` is set to `Off`.
By default this option is set as a percentage of [`max_width`](#max_width) provided by [`use_small_heuristics`](#use_small_heuristics), but a value set directly for `single_line_let_else_max_width` will take precedence.
- **Default value**: `50`
- **Possible values**: any positive integer that is less than or equal to the value specified for [`max_width`](#max_width)
- **Stable**: Yes
#### `50` (default):
```rust
fn main() {
let Some(w) = opt else { return Ok(()) };
let Some(x) = opt else { return };
let Some(y) = opt else {
return;
};
let Some(z) = some_very_very_very_very_long_name else {
return;
};
}
```
#### `0`:
```rust
fn main() {
let Some(w) = opt else {
return Ok(());
};
let Some(x) = opt else {
return;
};
let Some(y) = opt else {
return;
};
let Some(z) = some_very_very_very_very_long_name else {
return;
};
}
```
#### `100`:
```rust
fn main() {
let Some(w) = opt else { return Ok(()) };
let Some(x) = opt else { return };
let Some(y) = opt else {
return;
};
let Some(z) = some_very_very_very_very_long_name else { return };
}
```
See also [`max_width`](#max_width) and [`use_small_heuristics`](#use_small_heuristics)
## `space_after_colon`
Leave a space after the colon.
@ -2804,6 +2876,7 @@ The ratios are:
* [`array_width`](#array_width) - `60%`
* [`chain_width`](#chain_width) - `60%`
* [`single_line_if_else_max_width`](#single_line_if_else_max_width) - `50%`
* [`single_line_let_else_max_width`](#single_line_let_else_max_width) - `50%`
For example when `max_width` is set to `100`, the width settings are:
* `fn_call_width=60`
@ -2813,6 +2886,7 @@ For example when `max_width` is set to `100`, the width settings are:
* `array_width=60`
* `chain_width=60`
* `single_line_if_else_max_width=50`
* `single_line_let_else_max_width=50`
and when `max_width` is set to `200`:
* `fn_call_width=120`
@ -2822,6 +2896,7 @@ and when `max_width` is set to `200`:
* `array_width=120`
* `chain_width=120`
* `single_line_if_else_max_width=100`
* `single_line_let_else_max_width=100`
```rust
enum Lorem {
@ -2891,6 +2966,7 @@ So if `max_width` is set to `200`, then all the width settings are also set to `
* `array_width=200`
* `chain_width=200`
* `single_line_if_else_max_width=200`
* `single_line_let_else_max_width=200`
```rust
enum Lorem {
@ -2918,6 +2994,7 @@ See also:
* [`array_width`](#array_width)
* [`chain_width`](#chain_width)
* [`single_line_if_else_max_width`](#single_line_if_else_max_width)
* [`single_line_let_else_max_width`](#single_line_let_else_max_width)
## `use_try_shorthand`

View File

@ -4,9 +4,9 @@ version = 3
[[package]]
name = "proc-macro2"
version = "1.0.56"
version = "1.0.63"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2b63bdb0cd06f1f4dedf69b254734f9b45af66e4a031e42a7480257d9898b435"
checksum = "7b368fba921b0dce7e60f5e04ec15e565b3303972b42bcfde1d0713b881959eb"
dependencies = [
"unicode-ident",
]

View File

@ -1,3 +1,3 @@
[toolchain]
channel = "nightly-2023-06-19"
channel = "nightly-2023-07-01"
components = ["llvm-tools", "rustc-dev"]

View File

@ -121,6 +121,7 @@ pub fn $i(&mut self, value: $ty) {
| "use_small_heuristics"
| "fn_call_width"
| "single_line_if_else_max_width"
| "single_line_let_else_max_width"
| "attr_fn_like_width"
| "struct_lit_width"
| "struct_variant_width"
@ -269,6 +270,7 @@ pub fn override_value(&mut self, key: &str, val: &str)
| "use_small_heuristics"
| "fn_call_width"
| "single_line_if_else_max_width"
| "single_line_let_else_max_width"
| "attr_fn_like_width"
| "struct_lit_width"
| "struct_variant_width"
@ -407,6 +409,14 @@ fn set_width_heuristics(&mut self, heuristics: WidthHeuristics) {
"single_line_if_else_max_width",
);
self.single_line_if_else_max_width.2 = single_line_if_else_max_width;
let single_line_let_else_max_width = get_width_value(
self.was_set().single_line_let_else_max_width(),
self.single_line_let_else_max_width.2,
heuristics.single_line_let_else_max_width,
"single_line_let_else_max_width",
);
self.single_line_let_else_max_width.2 = single_line_let_else_max_width;
}
fn set_heuristics(&mut self) {

View File

@ -58,6 +58,9 @@
chain_width: usize, 60, true, "Maximum length of a chain to fit on a single line.";
single_line_if_else_max_width: usize, 50, true, "Maximum line length for single line if-else \
expressions. A value of zero means always break if-else expressions.";
single_line_let_else_max_width: usize, 50, true, "Maximum line length for single line \
let-else statements. A value of zero means always format the divergent `else` block \
over multiple lines.";
// Comments. macros, and strings
wrap_comments: bool, false, false, "Break comments to fit on the line";
@ -473,6 +476,9 @@ pub(crate) enum PartiallyUnstableOption {
chain_width: usize, 60, true, "Maximum length of a chain to fit on a single line.";
single_line_if_else_max_width: usize, 50, true, "Maximum line length for single \
line if-else expressions. A value of zero means always break if-else expressions.";
single_line_let_else_max_width: usize, 50, false, "Maximum line length for single \
line let-else statements. A value of zero means always format the divergent \
`else` block over multiple lines.";
// Options that are used by the tests
stable_option: bool, false, true, "A stable option";
@ -619,6 +625,7 @@ fn test_dump_default_config() {
array_width = 60
chain_width = 60
single_line_if_else_max_width = 50
single_line_let_else_max_width = 50
wrap_comments = false
format_code_in_doc_comments = false
doc_comment_code_block_width = 100

View File

@ -236,6 +236,9 @@ pub struct WidthHeuristics {
// Maximum line length for single line if-else expressions. A value
// of zero means always break if-else expressions.
pub(crate) single_line_if_else_max_width: usize,
// Maximum line length for single line let-else statements. A value of zero means
// always format the divergent `else` block over multiple lines.
pub(crate) single_line_let_else_max_width: usize,
}
impl fmt::Display for WidthHeuristics {
@ -255,6 +258,7 @@ pub fn null() -> WidthHeuristics {
array_width: usize::max_value(),
chain_width: usize::max_value(),
single_line_if_else_max_width: 0,
single_line_let_else_max_width: 0,
}
}
@ -267,6 +271,7 @@ pub fn set(max_width: usize) -> WidthHeuristics {
array_width: max_width,
chain_width: max_width,
single_line_if_else_max_width: max_width,
single_line_let_else_max_width: max_width,
}
}
@ -288,6 +293,7 @@ pub fn scaled(max_width: usize) -> WidthHeuristics {
array_width: (60.0 * max_width_ratio).round() as usize,
chain_width: (60.0 * max_width_ratio).round() as usize,
single_line_if_else_max_width: (50.0 * max_width_ratio).round() as usize,
single_line_let_else_max_width: (50.0 * max_width_ratio).round() as usize,
}
}
}

View File

@ -576,6 +576,17 @@ fn rewrite_block(
label: Option<ast::Label>,
context: &RewriteContext<'_>,
shape: Shape,
) -> Option<String> {
rewrite_block_inner(block, attrs, label, true, context, shape)
}
fn rewrite_block_inner(
block: &ast::Block,
attrs: Option<&[ast::Attribute]>,
label: Option<ast::Label>,
allow_single_line: bool,
context: &RewriteContext<'_>,
shape: Shape,
) -> Option<String> {
let prefix = block_prefix(context, block, shape)?;
@ -587,7 +598,7 @@ fn rewrite_block(
let result = rewrite_block_with_visitor(context, &prefix, block, attrs, label, shape, true);
if let Some(ref result_str) = result {
if result_str.lines().count() <= 3 {
if allow_single_line && result_str.lines().count() <= 3 {
if let rw @ Some(_) =
rewrite_single_line_block(context, &prefix, block, attrs, label, shape)
{
@ -599,6 +610,16 @@ fn rewrite_block(
result
}
/// Rewrite the divergent block of a `let-else` statement.
pub(crate) fn rewrite_let_else_block(
block: &ast::Block,
allow_single_line: bool,
context: &RewriteContext<'_>,
shape: Shape,
) -> Option<String> {
rewrite_block_inner(block, None, None, allow_single_line, context, shape)
}
// Rewrite condition if the given expression has one.
pub(crate) fn rewrite_cond(
context: &RewriteContext<'_>,
@ -1005,6 +1026,49 @@ fn rewrite_cond(
}
}
/// Rewrite the `else` keyword with surrounding comments.
///
/// force_newline_else: whether or not to rewrite the `else` keyword on a newline.
/// is_last: true if this is an `else` and `false` if this is an `else if` block.
/// context: rewrite context
/// span: Span between the end of the last expression and the start of the else block,
/// which contains the `else` keyword
/// shape: Shape
pub(crate) fn rewrite_else_kw_with_comments(
force_newline_else: bool,
is_last: bool,
context: &RewriteContext<'_>,
span: Span,
shape: Shape,
) -> String {
let else_kw_lo = context.snippet_provider.span_before(span, "else");
let before_else_kw = mk_sp(span.lo(), else_kw_lo);
let before_else_kw_comment = extract_comment(before_else_kw, context, shape);
let else_kw_hi = context.snippet_provider.span_after(span, "else");
let after_else_kw = mk_sp(else_kw_hi, span.hi());
let after_else_kw_comment = extract_comment(after_else_kw, context, shape);
let newline_sep = &shape.indent.to_string_with_newline(context.config);
let before_sep = match context.config.control_brace_style() {
_ if force_newline_else => newline_sep.as_ref(),
ControlBraceStyle::AlwaysNextLine | ControlBraceStyle::ClosingNextLine => {
newline_sep.as_ref()
}
ControlBraceStyle::AlwaysSameLine => " ",
};
let after_sep = match context.config.control_brace_style() {
ControlBraceStyle::AlwaysNextLine if is_last => newline_sep.as_ref(),
_ => " ",
};
format!(
"{}else{}",
before_else_kw_comment.as_ref().map_or(before_sep, |s| &**s),
after_else_kw_comment.as_ref().map_or(after_sep, |s| &**s),
)
}
impl<'a> Rewrite for ControlFlow<'a> {
fn rewrite(&self, context: &RewriteContext<'_>, shape: Shape) -> Option<String> {
debug!("ControlFlow::rewrite {:?} {:?}", self, shape);
@ -1071,41 +1135,14 @@ fn rewrite(&self, context: &RewriteContext<'_>, shape: Shape) -> Option<String>
}
};
let between_kwd_else_block = mk_sp(
self.block.span.hi(),
context
.snippet_provider
.span_before(mk_sp(self.block.span.hi(), else_block.span.lo()), "else"),
let else_kw = rewrite_else_kw_with_comments(
false,
last_in_chain,
context,
self.block.span.between(else_block.span),
shape,
);
let between_kwd_else_block_comment =
extract_comment(between_kwd_else_block, context, shape);
let after_else = mk_sp(
context
.snippet_provider
.span_after(mk_sp(self.block.span.hi(), else_block.span.lo()), "else"),
else_block.span.lo(),
);
let after_else_comment = extract_comment(after_else, context, shape);
let between_sep = match context.config.control_brace_style() {
ControlBraceStyle::AlwaysNextLine | ControlBraceStyle::ClosingNextLine => {
&*alt_block_sep
}
ControlBraceStyle::AlwaysSameLine => " ",
};
let after_sep = match context.config.control_brace_style() {
ControlBraceStyle::AlwaysNextLine if last_in_chain => &*alt_block_sep,
_ => " ",
};
result.push_str(&format!(
"{}else{}",
between_kwd_else_block_comment
.as_ref()
.map_or(between_sep, |s| &**s),
after_else_comment.as_ref().map_or(after_sep, |s| &**s),
));
result.push_str(&else_kw);
result.push_str(&rewrite?);
}

View File

@ -18,7 +18,8 @@
use crate::config::{BraceStyle, Config, IndentStyle, Version};
use crate::expr::{
is_empty_block, is_simple_block_stmt, rewrite_assign_rhs, rewrite_assign_rhs_with,
rewrite_assign_rhs_with_comments, RhsAssignKind, RhsTactics,
rewrite_assign_rhs_with_comments, rewrite_else_kw_with_comments, rewrite_let_else_block,
RhsAssignKind, RhsTactics,
};
use crate::lists::{definitive_tactic, itemize_list, write_list, ListFormatting, Separator};
use crate::macros::{rewrite_macro, MacroPosition};
@ -44,7 +45,7 @@ fn type_annotation_separator(config: &Config) -> &str {
}
// Statements of the form
// let pat: ty = init;
// let pat: ty = init; or let pat: ty = init else { .. };
impl Rewrite for ast::Local {
fn rewrite(&self, context: &RewriteContext<'_>, shape: Shape) -> Option<String> {
debug!(
@ -54,7 +55,7 @@ fn rewrite(&self, context: &RewriteContext<'_>, shape: Shape) -> Option<String>
skip_out_of_file_lines_range!(context, self.span);
if contains_skip(&self.attrs) || matches!(self.kind, ast::LocalKind::InitElse(..)) {
if contains_skip(&self.attrs) {
return None;
}
@ -112,7 +113,7 @@ fn rewrite(&self, context: &RewriteContext<'_>, shape: Shape) -> Option<String>
result.push_str(&infix);
if let Some((init, _els)) = self.kind.init_else_opt() {
if let Some((init, else_block)) = self.kind.init_else_opt() {
// 1 = trailing semicolon;
let nested_shape = shape.sub_width(1)?;
@ -123,7 +124,49 @@ fn rewrite(&self, context: &RewriteContext<'_>, shape: Shape) -> Option<String>
&RhsAssignKind::Expr(&init.kind, init.span),
nested_shape,
)?;
// todo else
if let Some(block) = else_block {
let else_kw_span = init.span.between(block.span);
let force_newline_else = pat_str.contains('\n')
|| !same_line_else_kw_and_brace(&result, context, else_kw_span, nested_shape);
let else_kw = rewrite_else_kw_with_comments(
force_newline_else,
true,
context,
else_kw_span,
shape,
);
result.push_str(&else_kw);
// At this point we've written `let {pat} = {expr} else' into the buffer, and we
// want to calculate up front if there's room to write the divergent block on the
// same line. The available space varies based on indentation so we clamp the width
// on the smaller of `shape.width` and `single_line_let_else_max_width`.
let max_width =
std::cmp::min(shape.width, context.config.single_line_let_else_max_width());
// If available_space hits zero we know for sure this will be a multi-lined block
let available_space = max_width.saturating_sub(result.len());
let allow_single_line = !force_newline_else
&& available_space > 0
&& allow_single_line_let_else_block(&result, block);
let mut rw_else_block =
rewrite_let_else_block(block, allow_single_line, context, shape)?;
let single_line_else = !rw_else_block.contains('\n');
// +1 for the trailing `;`
let else_block_exceeds_width = rw_else_block.len() + 1 > available_space;
if allow_single_line && single_line_else && else_block_exceeds_width {
// writing this on one line would exceed the available width
// so rewrite the else block over multiple lines.
rw_else_block = rewrite_let_else_block(block, false, context, shape)?;
}
result.push_str(&rw_else_block);
};
}
result.push(';');
@ -131,6 +174,61 @@ fn rewrite(&self, context: &RewriteContext<'_>, shape: Shape) -> Option<String>
}
}
/// When the initializer expression is multi-lined, then the else keyword and opening brace of the
/// block ( i.e. "else {") should be put on the same line as the end of the initializer expression
/// if all the following are true:
///
/// 1. The initializer expression ends with one or more closing parentheses, square brackets,
/// or braces
/// 2. There is nothing else on that line
/// 3. That line is not indented beyond the indent on the first line of the let keyword
fn same_line_else_kw_and_brace(
init_str: &str,
context: &RewriteContext<'_>,
else_kw_span: Span,
init_shape: Shape,
) -> bool {
if !init_str.contains('\n') {
// initializer expression is single lined. The "else {" can only be placed on the same line
// as the initializer expression if there is enough room for it.
// 7 = ` else {`
return init_shape.width.saturating_sub(init_str.len()) >= 7;
}
// 1. The initializer expression ends with one or more `)`, `]`, `}`.
if !init_str.ends_with([')', ']', '}']) {
return false;
}
// 2. There is nothing else on that line
// For example, there are no comments
let else_kw_snippet = context.snippet(else_kw_span).trim();
if else_kw_snippet != "else" {
return false;
}
// 3. The last line of the initializer expression is not indented beyond the `let` keyword
let indent = init_shape.indent.to_string(context.config);
init_str
.lines()
.last()
.expect("initializer expression is multi-lined")
.strip_prefix(indent.as_ref())
.map_or(false, |l| !l.starts_with(char::is_whitespace))
}
fn allow_single_line_let_else_block(result: &str, block: &ast::Block) -> bool {
if result.contains('\n') {
return false;
}
if block.stmts.len() <= 1 {
return true;
}
false
}
// FIXME convert to using rewrite style rather than visitor
// FIXME format modules in this style
#[allow(dead_code)]

View File

@ -0,0 +1,40 @@
// rustfmt-single_line_let_else_max_width: 100
fn main() {
let Some(a) = opt else {};
let Some(b) = opt else { return };
let Some(c) = opt else {
return
};
let Some(c) = opt else {
// a comment should always force the block to be multi-lined
return
};
let Some(c) = opt else { /* a comment should always force the block to be multi-lined */ return };
let Some(d) = some_very_very_very_very_long_name else { return };
let Expr::Slice(ast::ExprSlice { lower, upper, step, range: _ }) = slice.as_ref() else {
return
};
let Some((base_place, current)) = self.lower_expr_as_place(current, *base, true)? else {
return Ok(None)
};
let Some(doc_attr) = variant.attrs.iter().find(|attr| attr.path().is_ident("doc")) else {
return Err(Error::new(variant.span(), r#"expected a doc comment"#))
};
let Some((base_place, current)) = self.lower_expr_as_place(current, *base, true) else {
return Ok(None)
};
let Stmt::Expr(Expr::Call(ExprCall { args: some_args, .. }), _) = last_stmt else {
return Err(Error::new(last_stmt.span(), "expected last expression to be `Some(match (..) { .. })`"))
};
}

View File

@ -0,0 +1,40 @@
// rustfmt-single_line_let_else_max_width: 50
fn main() {
let Some(a) = opt else {};
let Some(b) = opt else { return };
let Some(c) = opt else {
return
};
let Some(c) = opt else {
// a comment should always force the block to be multi-lined
return
};
let Some(c) = opt else { /* a comment should always force the block to be multi-lined */ return };
let Some(d) = some_very_very_very_very_long_name else { return };
let Expr::Slice(ast::ExprSlice { lower, upper, step, range: _ }) = slice.as_ref() else {
return
};
let Some((base_place, current)) = self.lower_expr_as_place(current, *base, true)? else {
return Ok(None)
};
let Some(doc_attr) = variant.attrs.iter().find(|attr| attr.path().is_ident("doc")) else {
return Err(Error::new(variant.span(), r#"expected a doc comment"#))
};
let Some((base_place, current)) = self.lower_expr_as_place(current, *base, true) else {
return Ok(None)
};
let Stmt::Expr(Expr::Call(ExprCall { args: some_args, .. }), _) = last_stmt else {
return Err(Error::new(last_stmt.span(), "expected last expression to be `Some(match (..) { .. })`"))
};
}

View File

@ -0,0 +1,40 @@
// rustfmt-single_line_let_else_max_width: 0
fn main() {
let Some(a) = opt else {};
let Some(b) = opt else { return };
let Some(c) = opt else {
return
};
let Some(c) = opt else {
// a comment should always force the block to be multi-lined
return
};
let Some(c) = opt else { /* a comment should always force the block to be multi-lined */ return };
let Some(d) = some_very_very_very_very_long_name else { return };
let Expr::Slice(ast::ExprSlice { lower, upper, step, range: _ }) = slice.as_ref() else {
return
};
let Some((base_place, current)) = self.lower_expr_as_place(current, *base, true)? else {
return Ok(None)
};
let Some(doc_attr) = variant.attrs.iter().find(|attr| attr.path().is_ident("doc")) else {
return Err(Error::new(variant.span(), r#"expected a doc comment"#))
};
let Some((base_place, current)) = self.lower_expr_as_place(current, *base, true) else {
return Ok(None)
};
let Stmt::Expr(Expr::Call(ExprCall { args: some_args, .. }), _) = last_stmt else {
return Err(Error::new(last_stmt.span(), "expected last expression to be `Some(match (..) { .. })`"))
};
}

View File

@ -23,3 +23,13 @@ fn main() {
sit
};
}
fn format_let_else() {
let Some(a) = opt else {};
let Some(b) = opt else { return };
let Some(c) = opt else { return };
let Some(d) = some_very_very_very_very_long_name else { return };
}

View File

@ -23,3 +23,13 @@ fn main() {
sit
};
}
fn format_let_else() {
let Some(a) = opt else {};
let Some(b) = opt else { return };
let Some(c) = opt else { return };
let Some(d) = some_very_very_very_very_long_name else { return };
}

View File

@ -23,3 +23,13 @@ fn main() {
sit
};
}
fn format_let_else() {
let Some(a) = opt else {};
let Some(b) = opt else { return };
let Some(c) = opt else { return };
let Some(d) = some_very_very_very_very_long_name else { return };
}

View File

@ -1,3 +1,162 @@
// rustfmt-single_line_let_else_max_width: 100
fn main() {
let Some(1) = Some(1) else { return };
// Although this won't compile it still parses so make sure we can format empty else blocks
let Some(x) = opt else {};
// let-else may be formatted on a single line if they are "short"
// and only contain a single expression
let Some(x) = opt else { return };
let Some(x) = opt else {
return
};
let Some(x) = opt else { return; };
let Some(x) = opt else {
// nope
return;
};
let Some(x) = opt else { let y = 1; return y };
let Some(x) = y.foo("abc", fairly_long_identifier, "def", "123456", "string", "cheese") else { bar() };
let Some(x) = abcdef().foo("abc", some_really_really_really_long_ident, "ident", "123456").bar().baz().qux("fffffffffffffffff") else { foo_bar() };
}
fn with_comments_around_else_keyword() {
let Some(x) = opt /* pre else keyword block-comment */ else { return };
let Some(x) = opt else /* post else keyword block-comment */ { return };
let Some(x) = opt /* pre else keyword block-comment */ else /* post else keyword block-comment */ { return };
let Some(x) = opt // pre else keyword line-comment
else { return };
let Some(x) = opt else
// post else keyword line-comment
{ return };
let Some(x) = opt // pre else keyword line-comment
else
// post else keyword line-comment
{ return };
}
fn unbreakable_initializer_expr_pre_formatting_let_else_length_near_max_width() {
// Pre Formatting:
// The length of `(indent)let pat = init else block;` is 100 (max_width)
// Post Formatting:
// The formatting is left unchanged!
let Some(x) = some_really_really_really_really_really_really_really_long_name_A else { return };
// Pre Formatting:
// The length of `(indent)let pat = init else block;` is 100 (max_width)
// Post Formatting:
// The else keyword and opening brace remain on the same line as the initializer expr,
// and the else block is formatted over multiple lines because we can't fit the
// else block on the same line as the initializer expr.
let Some(x) = some_really_really_really_really_really_really_really_long_name___B else {return};
// Pre Formatting:
// The length of `(indent)let pat = init else block;` is 100 (max_width)
// Post Formatting:
// The else keyword and opening brace remain on the same line as the initializer expr,
// and the else block is formatted over multiple lines because we can't fit the
// else block on the same line as the initializer expr.
let Some(x) = some_really_really_really_really_long_name_____C else {some_divergent_function()};
// Pre Formatting:
// The length of `(indent)let pat = init else block;` is 101 (> max_width)
// Post Formatting:
// The else keyword and opening brace remain on the same line as the initializer expr,
// and the else block is formatted over multiple lines because we can't fit the
// else block on the same line as the initializer expr.
let Some(x) = some_really_really_really_really_really_really_really_long_name__D else { return };
}
fn unbreakable_initializer_expr_pre_formatting_length_up_to_opening_brace_near_max_width() {
// Pre Formatting:
// The length of `(indent)let pat = init else {` is 99 (< max_width)
// Post Formatting:
// The else keyword and opening brace remain on the same line as the initializer expr,
// and the else block is formatted over multiple lines because we can't fit the
// else block on the same line as the initializer expr.
let Some(x) = some_really_really_really_really_really_really_really_really_long_name___E else {return};
// Pre Formatting:
// The length of `(indent)let pat = init else {` is 101 (> max_width)
// Post Formatting:
// The else keyword and opening brace cannot fit on the same line as the initializer expr.
// They are formatted on the next line.
let Some(x) = some_really_really_really_really_really_really_really_really_long_name_____F else {return};
}
fn unbreakable_initializer_expr_pre_formatting_length_through_initializer_expr_near_max_width() {
// Pre Formatting:
// The length of `(indent)let pat = init` is 99 (< max_width)
// Post Formatting:
// The else keyword and opening brace cannot fit on the same line as the initializer expr.
// They are formatted on the next line.
let Some(x) = some_really_really_really_really_really_really_really_really_really_long_name___G else {return};
// Pre Formatting:
// The length of `(indent)let pat = init` is 100 (max_width)
// Post Formatting:
// Break after the `=` and put the initializer expr on it's own line.
// Because the initializer expr is multi-lined the else is placed on it's own line.
let Some(x) = some_really_really_really_really_really_really_really_really_really_long_name____H else {return};
// Pre Formatting:
// The length of `(indent)let pat = init` is 109 (> max_width)
// Post Formatting:
// Break after the `=` and put the initializer expr on it's own line.
// Because the initializer expr is multi-lined the else is placed on it's own line.
// The initializer expr has a length of 91, which when indented on the next line
// The `(indent)init` line has a lengh of 99. This is the max length that the `init` can be
// before we start running into max_width issues. I suspect this is becuase the shape is
// accounting for the `;` at the end of the `let-else` statement.
let Some(x) = some_really_really_really_really_really_really_really_really_really_really_long_name______I else {return};
// Pre Formatting:
// The length of `(indent)let pat = init` is 110 (> max_width)
// Post Formatting:
// Max length issues prevent us from formatting.
// The initializer expr has a length of 92, which if it would be indented on the next line
// the `(indent)init` line has a lengh of 100 which == max_width of 100.
// One might expect formatting to succeed, but I suspect the reason we hit max_width issues is
// because the Shape is accounting for the `;` at the end of the `let-else` statement.
let Some(x) = some_really_really_really_really_really_really_really_really_really_really_really_long_nameJ else {return};
}
fn long_patterns() {
let Foo {x: Bar(..), y: FooBar(..), z: Baz(..)} = opt else {
return;
};
// with version=One we don't wrap long array patterns
let [aaaaaaaaaaaaaaaa, bbbbbbbbbbbbbbb, cccccccccccccccccc, dddddddddddddddddd] = opt else {
return;
};
let ("aaaaaaaaaaaaaaaaaaa" | "bbbbbbbbbbbbbbbbb" | "cccccccccccccccccccccccc" | "dddddddddddddddd" | "eeeeeeeeeeeeeeee") = opt else {
return;
};
let Some(Ok((Message::ChangeColor(super::color::Color::Rgb(r, g, b)), Point { x, y, z }))) = opt else {
return;
};
}
fn with_trailing_try_operator() {
// Currently the trailing ? forces the else on the next line
// This may be revisited in style edition 2024
let Some(next_bucket) = ranking_rules[cur_ranking_rule_index].next_bucket(ctx, logger, &ranking_rule_universes[cur_ranking_rule_index])? else { return };
// Maybe this is a workaround?
let Ok(Some(next_bucket)) = ranking_rules[cur_ranking_rule_index].next_bucket(ctx, logger, &ranking_rule_universes[cur_ranking_rule_index]) else { return };
}

View File

@ -0,0 +1,60 @@
// rustfmt-single_line_let_else_max_width: 100
fn main() {
let Some(a) = opt else {};
let Some(b) = opt else { return };
let Some(c) = opt else { return };
let Some(c) = opt else {
// a comment should always force the block to be multi-lined
return;
};
let Some(c) = opt else {
/* a comment should always force the block to be multi-lined */
return;
};
let Some(d) = some_very_very_very_very_long_name else { return };
let Expr::Slice(ast::ExprSlice {
lower,
upper,
step,
range: _,
}) = slice.as_ref()
else {
return;
};
let Some((base_place, current)) = self.lower_expr_as_place(current, *base, true)? else {
return Ok(None);
};
let Some(doc_attr) = variant
.attrs
.iter()
.find(|attr| attr.path().is_ident("doc"))
else {
return Err(Error::new(variant.span(), r#"expected a doc comment"#));
};
let Some((base_place, current)) = self.lower_expr_as_place(current, *base, true) else {
return Ok(None);
};
let Stmt::Expr(
Expr::Call(ExprCall {
args: some_args, ..
}),
_,
) = last_stmt
else {
return Err(Error::new(
last_stmt.span(),
"expected last expression to be `Some(match (..) { .. })`",
));
};
}

View File

@ -0,0 +1,62 @@
// rustfmt-single_line_let_else_max_width: 50
fn main() {
let Some(a) = opt else {};
let Some(b) = opt else { return };
let Some(c) = opt else { return };
let Some(c) = opt else {
// a comment should always force the block to be multi-lined
return;
};
let Some(c) = opt else {
/* a comment should always force the block to be multi-lined */
return;
};
let Some(d) = some_very_very_very_very_long_name else {
return;
};
let Expr::Slice(ast::ExprSlice {
lower,
upper,
step,
range: _,
}) = slice.as_ref()
else {
return;
};
let Some((base_place, current)) = self.lower_expr_as_place(current, *base, true)? else {
return Ok(None);
};
let Some(doc_attr) = variant
.attrs
.iter()
.find(|attr| attr.path().is_ident("doc"))
else {
return Err(Error::new(variant.span(), r#"expected a doc comment"#));
};
let Some((base_place, current)) = self.lower_expr_as_place(current, *base, true) else {
return Ok(None);
};
let Stmt::Expr(
Expr::Call(ExprCall {
args: some_args, ..
}),
_,
) = last_stmt
else {
return Err(Error::new(
last_stmt.span(),
"expected last expression to be `Some(match (..) { .. })`",
));
};
}

View File

@ -0,0 +1,66 @@
// rustfmt-single_line_let_else_max_width: 0
fn main() {
let Some(a) = opt else {};
let Some(b) = opt else {
return;
};
let Some(c) = opt else {
return;
};
let Some(c) = opt else {
// a comment should always force the block to be multi-lined
return;
};
let Some(c) = opt else {
/* a comment should always force the block to be multi-lined */
return;
};
let Some(d) = some_very_very_very_very_long_name else {
return;
};
let Expr::Slice(ast::ExprSlice {
lower,
upper,
step,
range: _,
}) = slice.as_ref()
else {
return;
};
let Some((base_place, current)) = self.lower_expr_as_place(current, *base, true)? else {
return Ok(None);
};
let Some(doc_attr) = variant
.attrs
.iter()
.find(|attr| attr.path().is_ident("doc"))
else {
return Err(Error::new(variant.span(), r#"expected a doc comment"#));
};
let Some((base_place, current)) = self.lower_expr_as_place(current, *base, true) else {
return Ok(None);
};
let Stmt::Expr(
Expr::Call(ExprCall {
args: some_args, ..
}),
_,
) = last_stmt
else {
return Err(Error::new(
last_stmt.span(),
"expected last expression to be `Some(match (..) { .. })`",
));
};
}

View File

@ -24,3 +24,15 @@ fn main() {
let lorem = if ipsum { dolor } else { sit };
}
fn format_let_else() {
let Some(a) = opt else {};
let Some(b) = opt else { return };
let Some(c) = opt else { return };
let Some(d) = some_very_very_very_very_long_name else {
return;
};
}

View File

@ -13,3 +13,13 @@ fn main() {
let lorem = if ipsum { dolor } else { sit };
}
fn format_let_else() {
let Some(a) = opt else {};
let Some(b) = opt else { return };
let Some(c) = opt else { return };
let Some(d) = some_very_very_very_very_long_name else { return };
}

View File

@ -23,3 +23,19 @@ fn main() {
sit
};
}
fn format_let_else() {
let Some(a) = opt else {};
let Some(b) = opt else {
return;
};
let Some(c) = opt else {
return;
};
let Some(d) = some_very_very_very_very_long_name else {
return;
};
}

View File

@ -1,3 +1,254 @@
// rustfmt-single_line_let_else_max_width: 100
fn main() {
let Some(1) = Some(1) else { return };
// Although this won't compile it still parses so make sure we can format empty else blocks
let Some(x) = opt else {};
// let-else may be formatted on a single line if they are "short"
// and only contain a single expression
let Some(x) = opt else { return };
let Some(x) = opt else { return };
let Some(x) = opt else {
return;
};
let Some(x) = opt else {
// nope
return;
};
let Some(x) = opt else {
let y = 1;
return y;
};
let Some(x) = y.foo(
"abc",
fairly_long_identifier,
"def",
"123456",
"string",
"cheese",
) else {
bar()
};
let Some(x) = abcdef()
.foo(
"abc",
some_really_really_really_long_ident,
"ident",
"123456",
)
.bar()
.baz()
.qux("fffffffffffffffff")
else {
foo_bar()
};
}
fn with_comments_around_else_keyword() {
let Some(x) = opt
/* pre else keyword block-comment */
else {
return;
};
let Some(x) = opt else
/* post else keyword block-comment */
{
return;
};
let Some(x) = opt
/* pre else keyword block-comment */
else
/* post else keyword block-comment */
{
return;
};
let Some(x) = opt
// pre else keyword line-comment
else {
return;
};
let Some(x) = opt else
// post else keyword line-comment
{
return;
};
let Some(x) = opt
// pre else keyword line-comment
else
// post else keyword line-comment
{
return;
};
}
fn unbreakable_initializer_expr_pre_formatting_let_else_length_near_max_width() {
// Pre Formatting:
// The length of `(indent)let pat = init else block;` is 100 (max_width)
// Post Formatting:
// The formatting is left unchanged!
let Some(x) = some_really_really_really_really_really_really_really_long_name_A else { return };
// Pre Formatting:
// The length of `(indent)let pat = init else block;` is 100 (max_width)
// Post Formatting:
// The else keyword and opening brace remain on the same line as the initializer expr,
// and the else block is formatted over multiple lines because we can't fit the
// else block on the same line as the initializer expr.
let Some(x) = some_really_really_really_really_really_really_really_long_name___B else {
return;
};
// Pre Formatting:
// The length of `(indent)let pat = init else block;` is 100 (max_width)
// Post Formatting:
// The else keyword and opening brace remain on the same line as the initializer expr,
// and the else block is formatted over multiple lines because we can't fit the
// else block on the same line as the initializer expr.
let Some(x) = some_really_really_really_really_long_name_____C else {
some_divergent_function()
};
// Pre Formatting:
// The length of `(indent)let pat = init else block;` is 101 (> max_width)
// Post Formatting:
// The else keyword and opening brace remain on the same line as the initializer expr,
// and the else block is formatted over multiple lines because we can't fit the
// else block on the same line as the initializer expr.
let Some(x) = some_really_really_really_really_really_really_really_long_name__D else {
return;
};
}
fn unbreakable_initializer_expr_pre_formatting_length_up_to_opening_brace_near_max_width() {
// Pre Formatting:
// The length of `(indent)let pat = init else {` is 99 (< max_width)
// Post Formatting:
// The else keyword and opening brace remain on the same line as the initializer expr,
// and the else block is formatted over multiple lines because we can't fit the
// else block on the same line as the initializer expr.
let Some(x) = some_really_really_really_really_really_really_really_really_long_name___E else {
return;
};
// Pre Formatting:
// The length of `(indent)let pat = init else {` is 101 (> max_width)
// Post Formatting:
// The else keyword and opening brace cannot fit on the same line as the initializer expr.
// They are formatted on the next line.
let Some(x) = some_really_really_really_really_really_really_really_really_long_name_____F
else {
return;
};
}
fn unbreakable_initializer_expr_pre_formatting_length_through_initializer_expr_near_max_width() {
// Pre Formatting:
// The length of `(indent)let pat = init` is 99 (< max_width)
// Post Formatting:
// The else keyword and opening brace cannot fit on the same line as the initializer expr.
// They are formatted on the next line.
let Some(x) = some_really_really_really_really_really_really_really_really_really_long_name___G
else {
return;
};
// Pre Formatting:
// The length of `(indent)let pat = init` is 100 (max_width)
// Post Formatting:
// Break after the `=` and put the initializer expr on it's own line.
// Because the initializer expr is multi-lined the else is placed on it's own line.
let Some(x) =
some_really_really_really_really_really_really_really_really_really_long_name____H
else {
return;
};
// Pre Formatting:
// The length of `(indent)let pat = init` is 109 (> max_width)
// Post Formatting:
// Break after the `=` and put the initializer expr on it's own line.
// Because the initializer expr is multi-lined the else is placed on it's own line.
// The initializer expr has a length of 91, which when indented on the next line
// The `(indent)init` line has a lengh of 99. This is the max length that the `init` can be
// before we start running into max_width issues. I suspect this is becuase the shape is
// accounting for the `;` at the end of the `let-else` statement.
let Some(x) =
some_really_really_really_really_really_really_really_really_really_really_long_name______I
else {
return;
};
// Pre Formatting:
// The length of `(indent)let pat = init` is 110 (> max_width)
// Post Formatting:
// Max length issues prevent us from formatting.
// The initializer expr has a length of 92, which if it would be indented on the next line
// the `(indent)init` line has a lengh of 100 which == max_width of 100.
// One might expect formatting to succeed, but I suspect the reason we hit max_width issues is
// because the Shape is accounting for the `;` at the end of the `let-else` statement.
let Some(x) = some_really_really_really_really_really_really_really_really_really_really_really_long_nameJ else {return};
}
fn long_patterns() {
let Foo {
x: Bar(..),
y: FooBar(..),
z: Baz(..),
} = opt
else {
return;
};
// with version=One we don't wrap long array patterns
let [aaaaaaaaaaaaaaaa, bbbbbbbbbbbbbbb, cccccccccccccccccc, dddddddddddddddddd] = opt else {
return;
};
let ("aaaaaaaaaaaaaaaaaaa"
| "bbbbbbbbbbbbbbbbb"
| "cccccccccccccccccccccccc"
| "dddddddddddddddd"
| "eeeeeeeeeeeeeeee") = opt
else {
return;
};
let Some(Ok((Message::ChangeColor(super::color::Color::Rgb(r, g, b)), Point { x, y, z }))) =
opt
else {
return;
};
}
fn with_trailing_try_operator() {
// Currently the trailing ? forces the else on the next line
// This may be revisited in style edition 2024
let Some(next_bucket) = ranking_rules[cur_ranking_rule_index].next_bucket(
ctx,
logger,
&ranking_rule_universes[cur_ranking_rule_index],
)?
else {
return;
};
// Maybe this is a workaround?
let Ok(Some(next_bucket)) = ranking_rules[cur_ranking_rule_index].next_bucket(
ctx,
logger,
&ranking_rule_universes[cur_ranking_rule_index],
) else {
return;
};
}