Auto merge of #91486 - matthiaskrgr:rollup-699fo18, r=matthiaskrgr

Rollup of 10 pull requests

Successful merges:

 - #88906 (Implement write() method for Box<MaybeUninit<T>>)
 - #90269 (Make `Option::expect` unstably const)
 - #90854 (Type can be unsized and uninhabited)
 - #91170 (rustdoc: preload fonts)
 - #91273 (Fix ICE #91268 by checking that the snippet ends with a `)`)
 - #91381 (Android: -ldl must appear after -lgcc when linking)
 - #91453 (Document Windows TLS drop behaviour)
 - #91462 (Use try_normalize_erasing_regions in needs_drop)
 - #91474 (suppress warning about set_errno being unused on DragonFly)
 - #91483 (Sync rustfmt subtree)

Failed merges:

r? `@ghost`
`@rustbot` modify labels: rollup
This commit is contained in:
bors 2021-12-03 07:12:36 +00:00
commit 3e21768a0a
63 changed files with 1971 additions and 477 deletions

View File

@ -229,15 +229,19 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
if let Ok(snippet) = self.sess.source_map().span_to_snippet(data.span) {
// Do not suggest going from `Trait()` to `Trait<>`
if !data.inputs.is_empty() {
if let Some(split) = snippet.find('(') {
let trait_name = &snippet[0..split];
let args = &snippet[split + 1..snippet.len() - 1];
err.span_suggestion(
data.span,
"use angle brackets instead",
format!("{}<{}>", trait_name, args),
Applicability::MaybeIncorrect,
);
// Suggest replacing `(` and `)` with `<` and `>`
// The snippet may be missing the closing `)`, skip that case
if snippet.ends_with(')') {
if let Some(split) = snippet.find('(') {
let trait_name = &snippet[0..split];
let args = &snippet[split + 1..snippet.len() - 1];
err.span_suggestion(
data.span,
"use angle brackets instead",
format!("{}<{}>", trait_name, args),
Applicability::MaybeIncorrect,
);
}
}
}
};

View File

@ -23,11 +23,9 @@ impl<T> IdFunctor for Box<T> {
let value = raw.read();
// SAFETY: Converts `Box<T>` to `Box<MaybeUninit<T>>` which is the
// inverse of `Box::assume_init()` and should be safe.
let mut raw: Box<mem::MaybeUninit<T>> = Box::from_raw(raw.cast());
let raw: Box<mem::MaybeUninit<T>> = Box::from_raw(raw.cast());
// SAFETY: Write the mapped value back into the `Box`.
raw.write(f(value)?);
// SAFETY: We just initialized `raw`.
raw.assume_init()
Box::write(raw, f(value)?)
})
}
}

View File

@ -533,7 +533,7 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> {
}
}
if sized && fields.iter().any(|f| f.abi.is_uninhabited()) {
if fields.iter().any(|f| f.abi.is_uninhabited()) {
abi = Abi::Uninhabited;
}

View File

@ -788,10 +788,14 @@ impl<'tcx> ty::TyS<'tcx> {
[component_ty] => component_ty,
_ => self,
};
// This doesn't depend on regions, so try to minimize distinct
// query keys used.
let erased = tcx.normalize_erasing_regions(param_env, query_ty);
tcx.needs_drop_raw(param_env.and(erased))
// If normalization fails, we just use `query_ty`.
let query_ty =
tcx.try_normalize_erasing_regions(param_env, query_ty).unwrap_or(query_ty);
tcx.needs_drop_raw(param_env.and(query_ty))
}
}
}

View File

@ -147,8 +147,10 @@ where
Ok(tys) => tys,
};
for required_ty in tys {
let required =
tcx.normalize_erasing_regions(self.param_env, required_ty);
let required = tcx
.try_normalize_erasing_regions(self.param_env, required_ty)
.unwrap_or(required_ty);
queue_type(self, required);
}
}

View File

@ -763,6 +763,42 @@ impl<T, A: Allocator> Box<mem::MaybeUninit<T>, A> {
let (raw, alloc) = Box::into_raw_with_allocator(self);
unsafe { Box::from_raw_in(raw as *mut T, alloc) }
}
/// Writes the value and converts to `Box<T, A>`.
///
/// This method converts the box similarly to [`Box::assume_init`] but
/// writes `value` into it before conversion thus guaranteeing safety.
/// In some scenarios use of this method may improve performance because
/// the compiler may be able to optimize copying from stack.
///
/// # Examples
///
/// ```
/// #![feature(new_uninit)]
///
/// let big_box = Box::<[usize; 1024]>::new_uninit();
///
/// let mut array = [0; 1024];
/// for (i, place) in array.iter_mut().enumerate() {
/// *place = i;
/// }
///
/// // The optimizer may be able to elide this copy, so previous code writes
/// // to heap directly.
/// let big_box = Box::write(big_box, array);
///
/// for (i, x) in big_box.iter().enumerate() {
/// assert_eq!(*x, i);
/// }
/// ```
#[unstable(feature = "new_uninit", issue = "63291")]
#[inline]
pub fn write(mut boxed: Self, value: T) -> Box<T, A> {
unsafe {
(*boxed).write(value);
boxed.assume_init()
}
}
}
impl<T, A: Allocator> Box<[mem::MaybeUninit<T>], A> {

View File

@ -703,7 +703,8 @@ impl<T> Option<T> {
#[inline]
#[track_caller]
#[stable(feature = "rust1", since = "1.0.0")]
pub fn expect(self, msg: &str) -> T {
#[rustc_const_unstable(feature = "const_option", issue = "67441")]
pub const fn expect(self, msg: &str) -> T {
match self {
Some(val) => val,
None => expect_failed(msg),
@ -1658,7 +1659,7 @@ impl<T, E> Option<Result<T, E>> {
#[inline(never)]
#[cold]
#[track_caller]
fn expect_failed(msg: &str) -> ! {
const fn expect_failed(msg: &str) -> ! {
panic!("{}", msg)
}

View File

@ -97,6 +97,7 @@ pub fn errno() -> i32 {
}
#[cfg(target_os = "dragonfly")]
#[allow(dead_code)]
pub fn set_errno(e: i32) {
extern "C" {
#[thread_local]

View File

@ -76,7 +76,21 @@ use crate::fmt;
/// destroyed, but not all platforms have this guard. Those platforms that do
/// not guard typically have a synthetic limit after which point no more
/// destructors are run.
/// 3. When the process exits on Windows systems, TLS destructors may only be
/// run on the thread that causes the process to exit. This is because the
/// other threads may be forcibly terminated.
///
/// ## Synchronization in thread-local destructors
///
/// On Windows, synchronization operations (such as [`JoinHandle::join`]) in
/// thread local destructors are prone to deadlocks and so should be avoided.
/// This is because the [loader lock] is held while a destructor is run. The
/// lock is acquired whenever a thread starts or exits or when a DLL is loaded
/// or unloaded. Therefore these events are blocked for as long as a thread
/// local destructor is running.
///
/// [loader lock]: https://docs.microsoft.com/en-us/windows/win32/dlls/dynamic-link-library-best-practices
/// [`JoinHandle::join`]: crate::thread::JoinHandle::join
/// [`with`]: LocalKey::with
#[stable(feature = "rust1", since = "1.0.0")]
pub struct LocalKey<T: 'static> {

View File

@ -17,6 +17,9 @@ fn main() {
} else {
println!("cargo:rustc-link-lib=gcc");
}
// Android's unwinding library depends on dl_iterate_phdr in `libdl`.
println!("cargo:rustc-link-lib=dl");
} else if target.contains("freebsd") {
println!("cargo:rustc-link-lib=gcc_s");
} else if target.contains("netbsd") {

View File

@ -7,6 +7,12 @@
<meta name="description" content="{{page.description}}"> {#- -#}
<meta name="keywords" content="{{page.keywords}}"> {#- -#}
<title>{{page.title}}</title> {#- -#}
<link rel="preload" as="font" type="font/woff2" crossorigin href="{{static_root_path | safe}}SourceSerif4-Regular.ttf.woff2"> {#- -#}
<link rel="preload" as="font" type="font/woff2" crossorigin href="{{static_root_path | safe}}FiraSans-Regular.woff2"> {#- -#}
<link rel="preload" as="font" type="font/woff2" crossorigin href="{{static_root_path | safe}}FiraSans-Medium.woff2"> {#- -#}
<link rel="preload" as="font" type="font/woff2" crossorigin href="{{static_root_path | safe}}SourceCodePro-Regular.ttf.woff2"> {#- -#}
<link rel="preload" as="font" type="font/woff2" crossorigin href="{{static_root_path | safe}}SourceSerif4-Bold.ttf.woff2"> {#- -#}
<link rel="preload" as="font" type="font/woff2" crossorigin href="{{static_root_path | safe}}SourceCodePro-Semibold.ttf.woff2"> {#- -#}
<link rel="stylesheet" type="text/css" {# -#}
href="{{static_root_path | safe}}normalize{{page.resource_suffix}}.css"> {#- -#}
<link rel="stylesheet" type="text/css" {# -#}

View File

@ -0,0 +1,21 @@
// run-pass
// compile-flags:-C debuginfo=2
// edition:2018
use core::marker::PhantomData;
pub struct Foo<T: ?Sized, A>(
PhantomData<(A, T)>,
);
enum Never {}
impl<T: ?Sized> Foo<T, Never> {
fn new_foo() -> Foo<T, Never> {
Foo(PhantomData)
}
}
fn main() {
let _ = Foo::<[()], Never>::new_foo();
}

View File

@ -0,0 +1,9 @@
// error-pattern: this file contains an unclosed delimiter
// error-pattern: cannot find type `ţ` in this scope
// error-pattern: parenthesized type parameters may only be used with a `Fn` trait
// error-pattern: type arguments are not allowed for this type
// error-pattern: mismatched types
// ignore-tidy-trailing-newlines
// `ţ` must be the last character in this file, it cannot be followed by a newline
fn main() {
0: u8(ţ

View File

@ -0,0 +1,50 @@
error: this file contains an unclosed delimiter
--> $DIR/issue-91268.rs:9:12
|
LL | fn main() {
| - unclosed delimiter
LL | 0: u8(ţ
| - ^
| |
| unclosed delimiter
error: this file contains an unclosed delimiter
--> $DIR/issue-91268.rs:9:12
|
LL | fn main() {
| - unclosed delimiter
LL | 0: u8(ţ
| - ^
| |
| unclosed delimiter
error[E0412]: cannot find type `ţ` in this scope
--> $DIR/issue-91268.rs:9:11
|
LL | 0: u8(ţ
| ^ expecting a type here because of type ascription
error[E0214]: parenthesized type parameters may only be used with a `Fn` trait
--> $DIR/issue-91268.rs:9:8
|
LL | 0: u8(ţ
| ^^^^ only `Fn` traits may use parentheses
error[E0109]: type arguments are not allowed for this type
--> $DIR/issue-91268.rs:9:11
|
LL | 0: u8(ţ
| ^ type argument not allowed
error[E0308]: mismatched types
--> $DIR/issue-91268.rs:9:5
|
LL | fn main() {
| - expected `()` because of default return type
LL | 0: u8(ţ
| ^^^^^^^ expected `()`, found `u8`
error: aborting due to 6 previous errors
Some errors have detailed explanations: E0109, E0214, E0308, E0412.
For more information about an error, try `rustc --explain E0109`.

View File

@ -0,0 +1,21 @@
#[repr(C)]
union PtrRepr<T: ?Sized> {
const_ptr: *const T,
mut_ptr: *mut T,
components: PtrComponents<T>,
//~^ ERROR the trait bound
}
#[repr(C)]
struct PtrComponents<T: Pointee + ?Sized> {
data_address: *const (),
metadata: <T as Pointee>::Metadata,
}
pub trait Pointee {
type Metadata;
}
fn main() {}

View File

@ -0,0 +1,29 @@
error[E0277]: the trait bound `T: Pointee` is not satisfied in `PtrComponents<T>`
--> $DIR/issue-81199.rs:5:17
|
LL | components: PtrComponents<T>,
| ^^^^^^^^^^^^^^^^ within `PtrComponents<T>`, the trait `Pointee` is not implemented for `T`
|
note: required because it appears within the type `PtrComponents<T>`
--> $DIR/issue-81199.rs:10:8
|
LL | struct PtrComponents<T: Pointee + ?Sized> {
| ^^^^^^^^^^^^^
= note: no field of a union may have a dynamically sized type
= help: change the field's type to have a statically known size
help: consider further restricting this bound
|
LL | union PtrRepr<T: ?Sized + Pointee> {
| +++++++++
help: borrowed types always have a statically known size
|
LL | components: &PtrComponents<T>,
| +
help: the `Box` type always has a statically known size and allocates its contents in the heap
|
LL | components: Box<PtrComponents<T>>,
| ++++ +
error: aborting due to previous error
For more information about this error, try `rustc --explain E0277`.

View File

@ -8,7 +8,9 @@ on:
jobs:
test:
runs-on: ubuntu-latest
name: (${{ matrix.target }}, nightly)
name: (${{ matrix.target }}, ${{ matrix.cfg_release_channel }})
env:
CFG_RELEASE_CHANNEL: ${{ matrix.cfg_release_channel }}
strategy:
# https://help.github.com/en/actions/getting-started-with-github-actions/about-github-actions#usage-limits
# There's a limit of 60 concurrent jobs across all repos in the rust-lang organization.
@ -20,6 +22,7 @@ jobs:
target: [
x86_64-unknown-linux-gnu,
]
cfg_release_channel: [nightly, stable]
steps:
- name: checkout

View File

@ -10,13 +10,16 @@ jobs:
# https://help.github.com/en/actions/automating-your-workflow-with-github-actions/virtual-environments-for-github-hosted-runners#supported-runners-and-hardware-resources
# macOS Catalina 10.15
runs-on: macos-latest
name: (${{ matrix.target }}, nightly)
name: (${{ matrix.target }}, ${{ matrix.cfg_release_channel }})
env:
CFG_RELEASE_CHANNEL: ${{ matrix.cfg_release_channel }}
strategy:
fail-fast: false
matrix:
target: [
x86_64-apple-darwin,
]
cfg_release_channel: [nightly, stable]
steps:
- name: checkout

View File

@ -8,7 +8,9 @@ on:
jobs:
test:
runs-on: windows-latest
name: (${{ matrix.target }}, nightly)
name: (${{ matrix.target }}, ${{ matrix.cfg_release_channel }})
env:
CFG_RELEASE_CHANNEL: ${{ matrix.cfg_release_channel }}
strategy:
# https://help.github.com/en/actions/getting-started-with-github-actions/about-github-actions#usage-limits
# There's a limit of 60 concurrent jobs across all repos in the rust-lang organization.
@ -23,6 +25,7 @@ jobs:
x86_64-pc-windows-gnu,
x86_64-pc-windows-msvc,
]
cfg_release_channel: [nightly, stable]
steps:
# The Windows runners have autocrlf enabled by default

View File

@ -47,7 +47,7 @@ Where to put a binary operator when a binary expression goes multiline.
- **Default value**: `"Front"`
- **Possible values**: `"Front"`, `"Back"`
- **Stable**: No (tracking issue: #3368)
- **Stable**: No (tracking issue: [#3368](https://github.com/rust-lang/rustfmt/issues/3368))
#### `"Front"` (default):
@ -88,7 +88,7 @@ them, additional blank lines are inserted.
- **Default value**: `0`
- **Possible values**: *unsigned integer*
- **Stable**: No (tracking issue: #3382)
- **Stable**: No (tracking issue: [#3382](https://github.com/rust-lang/rustfmt/issues/3382))
### Example
Original Code (rustfmt will not change it with the default value of `0`):
@ -128,7 +128,7 @@ lines are found, they are trimmed down to match this integer.
- **Default value**: `1`
- **Possible values**: any non-negative integer
- **Stable**: No (tracking issue: #3381)
- **Stable**: No (tracking issue: [#3381](https://github.com/rust-lang/rustfmt/issues/3381))
### Example
Original Code:
@ -186,7 +186,7 @@ Brace style for items
- **Default value**: `"SameLineWhere"`
- **Possible values**: `"AlwaysNextLine"`, `"PreferSameLine"`, `"SameLineWhere"`
- **Stable**: No (tracking issue: #3376)
- **Stable**: No (tracking issue: [#3376](https://github.com/rust-lang/rustfmt/issues/3376))
### Functions
@ -313,7 +313,7 @@ Whether to use colored output or not.
- **Default value**: `"Auto"`
- **Possible values**: "Auto", "Always", "Never"
- **Stable**: No (tracking issue: #3385)
- **Stable**: No (tracking issue: [#3385](https://github.com/rust-lang/rustfmt/issues/3385))
## `combine_control_expr`
@ -321,7 +321,7 @@ Combine control expressions with function calls.
- **Default value**: `true`
- **Possible values**: `true`, `false`
- **Stable**: No (tracking issue: #3369)
- **Stable**: No (tracking issue: [#3369](https://github.com/rust-lang/rustfmt/issues/3369))
#### `true` (default):
@ -429,7 +429,7 @@ Maximum length of comments. No effect unless`wrap_comments = true`.
- **Default value**: `80`
- **Possible values**: any positive integer
- **Stable**: No (tracking issue: #3349)
- **Stable**: No (tracking issue: [#3349](https://github.com/rust-lang/rustfmt/issues/3349))
**Note:** A value of `0` results in [`wrap_comments`](#wrap_comments) being applied regardless of a line's width.
@ -452,7 +452,7 @@ Replace strings of _ wildcards by a single .. in tuple patterns
- **Default value**: `false`
- **Possible values**: `true`, `false`
- **Stable**: No (tracking issue: #3384)
- **Stable**: No (tracking issue: [#3384](https://github.com/rust-lang/rustfmt/issues/3384))
#### `false` (default):
@ -477,7 +477,7 @@ Brace style for control flow constructs
- **Default value**: `"AlwaysSameLine"`
- **Possible values**: `"AlwaysNextLine"`, `"AlwaysSameLine"`, `"ClosingNextLine"`
- **Stable**: No (tracking issue: #3377)
- **Stable**: No (tracking issue: [#3377](https://github.com/rust-lang/rustfmt/issues/3377))
#### `"AlwaysSameLine"` (default):
@ -551,7 +551,7 @@ Put empty-body functions and impls on a single line
- **Default value**: `true`
- **Possible values**: `true`, `false`
- **Stable**: No (tracking issue: #3356)
- **Stable**: No (tracking issue: [#3356](https://github.com/rust-lang/rustfmt/issues/3356))
#### `true` (default):
@ -584,7 +584,7 @@ doesn't get ignored when aligning.
- **Default value** : 0
- **Possible values**: any positive integer
- **Stable**: No (tracking issue: #3372)
- **Stable**: No (tracking issue: [#3372](https://github.com/rust-lang/rustfmt/issues/3372))
#### `0` (default):
@ -630,7 +630,7 @@ using a shorter name.
- **Default value**: `false`
- **Possible values**: `true`, `false`
- **Stable**: No (tracking issue: #3391)
- **Stable**: No (tracking issue: [#3391](https://github.com/rust-lang/rustfmt/issues/3391))
See also [`max_width`](#max_width).
@ -641,7 +641,7 @@ trailing whitespaces.
- **Default value**: `false`
- **Possible values**: `true`, `false`
- **Stable**: No (tracking issue: #3392)
- **Stable**: No (tracking issue: [#3392](https://github.com/rust-lang/rustfmt/issues/3392))
## `fn_args_layout`
@ -771,7 +771,7 @@ Put single-expression functions on a single line
- **Default value**: `false`
- **Possible values**: `true`, `false`
- **Stable**: No (tracking issue: #3358)
- **Stable**: No (tracking issue: [#3358](https://github.com/rust-lang/rustfmt/issues/3358))
#### `false` (default):
@ -832,7 +832,7 @@ Force multiline closure and match arm bodies to be wrapped in a block
- **Default value**: `false`
- **Possible values**: `false`, `true`
- **Stable**: No (tracking issue: #3374)
- **Stable**: No (tracking issue: [#3374](https://github.com/rust-lang/rustfmt/issues/3374))
#### `false` (default):
@ -881,7 +881,7 @@ Format code snippet included in doc comments.
- **Default value**: `false`
- **Possible values**: `true`, `false`
- **Stable**: No (tracking issue: #3348)
- **Stable**: No (tracking issue: [#3348](https://github.com/rust-lang/rustfmt/issues/3348))
#### `false` (default):
@ -933,7 +933,7 @@ if any of the first five lines contains `@generated` marker.
- **Default value**: `false`
- **Possible values**: `true`, `false`
- **Stable**: No
- **Stable**: No (tracking issue: [#5080](https://github.com/rust-lang/rustfmt/issues/5080))
## `format_macro_matchers`
@ -941,7 +941,7 @@ Format the metavariable matching patterns in macros.
- **Default value**: `false`
- **Possible values**: `true`, `false`
- **Stable**: No (tracking issue: #3354)
- **Stable**: No (tracking issue: [#3354](https://github.com/rust-lang/rustfmt/issues/3354))
#### `false` (default):
@ -978,7 +978,7 @@ Format the bodies of macros.
- **Default value**: `true`
- **Possible values**: `true`, `false`
- **Stable**: No (tracking issue: #3355)
- **Stable**: No (tracking issue: [#3355](https://github.com/rust-lang/rustfmt/issues/3355))
#### `true` (default):
@ -1011,7 +1011,7 @@ Format string literals where necessary
- **Default value**: `false`
- **Possible values**: `true`, `false`
- **Stable**: No (tracking issue: #3353)
- **Stable**: No (tracking issue: [#3353](https://github.com/rust-lang/rustfmt/issues/3353))
#### `false` (default):
@ -1064,7 +1064,7 @@ Control the case of the letters in hexadecimal literal values
- **Default value**: `Preserve`
- **Possible values**: `Upper`, `Lower`
- **Stable**: No
- **Stable**: No (tracking issue: [#5081](https://github.com/rust-lang/rustfmt/issues/5081))
## `hide_parse_errors`
@ -1072,7 +1072,7 @@ Do not show parse errors if the parser failed to parse files.
- **Default value**: `false`
- **Possible values**: `true`, `false`
- **Stable**: No (tracking issue: #3390)
- **Stable**: No (tracking issue: [#3390](https://github.com/rust-lang/rustfmt/issues/3390))
## `ignore`
@ -1081,7 +1081,7 @@ The pattern format is the same as [.gitignore](https://git-scm.com/docs/gitignor
- **Default value**: format every file
- **Possible values**: See an example below
- **Stable**: No (tracking issue: #3395)
- **Stable**: No (tracking issue: [#3395](https://github.com/rust-lang/rustfmt/issues/3395))
### Example
@ -1114,7 +1114,7 @@ Indent style of imports
- **Default Value**: `"Block"`
- **Possible values**: `"Block"`, `"Visual"`
- **Stable**: No (tracking issue: #3360)
- **Stable**: No (tracking issue: [#3360](https://github.com/rust-lang/rustfmt/issues/3360))
#### `"Block"` (default):
@ -1140,7 +1140,7 @@ Item layout inside a imports block
- **Default value**: "Mixed"
- **Possible values**: "Horizontal", "HorizontalVertical", "Mixed", "Vertical"
- **Stable**: No (tracking issue: #3361)
- **Stable**: No (tracking issue: [#3361](https://github.com/rust-lang/rustfmt/issues/3361))
#### `"Mixed"` (default):
@ -1203,7 +1203,7 @@ Indent on expressions or items.
- **Default value**: `"Block"`
- **Possible values**: `"Block"`, `"Visual"`
- **Stable**: No (tracking issue: #3346)
- **Stable**: No (tracking issue: [#3346](https://github.com/rust-lang/rustfmt/issues/3346))
### Array
@ -1456,7 +1456,7 @@ Write an item and its attribute on the same line if their combined width is belo
- **Default value**: 0
- **Possible values**: any positive integer
- **Stable**: No (tracking issue: #3343)
- **Stable**: No (tracking issue: [#3343](https://github.com/rust-lang/rustfmt/issues/3343))
### Example
@ -1477,7 +1477,7 @@ Check whether beginnings of files match a license template.
- **Default value**: `""`
- **Possible values**: path to a license template file
- **Stable**: No (tracking issue: #3352)
- **Stable**: No (tracking issue: [#3352](https://github.com/rust-lang/rustfmt/issues/3352))
A license template is a plain text file which is matched literally against the
beginning of each source file, except for `{}`-delimited blocks, which are
@ -1499,7 +1499,7 @@ The Style Guide requires that bodies are block wrapped by default if a line brea
- **Default value**: `true`
- **Possible values**: `true`, `false`
- **Stable**: No (tracking issue: #3373)
- **Stable**: No (tracking issue: [#3373](https://github.com/rust-lang/rustfmt/issues/3373))
#### `true` (default):
@ -1701,7 +1701,7 @@ How imports should be grouped into `use` statements. Imports will be merged or s
- **Default value**: `Preserve`
- **Possible values**: `Preserve`, `Crate`, `Module`, `Item`, `One`
- **Stable**: No
- **Stable**: No (tracking issue: [#4991](https://github.com/rust-lang/rustfmt/issues/4991))
#### `Preserve` (default):
@ -1826,7 +1826,7 @@ Convert /* */ comments to // comments where possible
- **Default value**: `false`
- **Possible values**: `true`, `false`
- **Stable**: No (tracking issue: #3350)
- **Stable**: No (tracking issue: [#3350](https://github.com/rust-lang/rustfmt/issues/3350))
#### `false` (default):
@ -1854,7 +1854,7 @@ Convert `#![doc]` and `#[doc]` attributes to `//!` and `///` doc comments.
- **Default value**: `false`
- **Possible values**: `true`, `false`
- **Stable**: No (tracking issue: #3351)
- **Stable**: No (tracking issue: [#3351](https://github.com/rust-lang/rustfmt/issues/3351))
#### `false` (default):
@ -1885,7 +1885,7 @@ instead of being indented on a new line.
- **Default value**: `false`
- **Possible values**: `true`, `false`
- **Stable**: No (tracking issue: #3370)
- **Stable**: No (tracking issue: [#3370](https://github.com/rust-lang/rustfmt/issues/3370))
#### `false` (default):
@ -1992,7 +1992,7 @@ Reorder impl items. `type` and `const` are put first, then macros and methods.
- **Default value**: `false`
- **Possible values**: `true`, `false`
- **Stable**: No (tracking issue: #3363)
- **Stable**: No (tracking issue: [#3363](https://github.com/rust-lang/rustfmt/issues/3363))
#### `false` (default)
@ -2063,7 +2063,7 @@ Controls the strategy for how imports are grouped together.
- **Default value**: `Preserve`
- **Possible values**: `Preserve`, `StdExternalCrate`, `One`
- **Stable**: No
- **Stable**: No (tracking issue: [#5083](https://github.com/rust-lang/rustfmt/issues/5083))
#### `Preserve` (default):
@ -2166,7 +2166,7 @@ Report `FIXME` items in comments.
- **Default value**: `"Never"`
- **Possible values**: `"Always"`, `"Unnumbered"`, `"Never"`
- **Stable**: No (tracking issue: #3394)
- **Stable**: No (tracking issue: [#3394](https://github.com/rust-lang/rustfmt/issues/3394))
Warns about any comments containing `FIXME` in them when set to `"Always"`. If
it contains a `#X` (with `X` being a number) in parentheses following the
@ -2181,7 +2181,7 @@ Report `TODO` items in comments.
- **Default value**: `"Never"`
- **Possible values**: `"Always"`, `"Unnumbered"`, `"Never"`
- **Stable**: No (tracking issue: #3393)
- **Stable**: No (tracking issue: [#3393](https://github.com/rust-lang/rustfmt/issues/3393))
Warns about any comments containing `TODO` in them when set to `"Always"`. If
it contains a `#X` (with `X` being a number) in parentheses following the
@ -2196,7 +2196,7 @@ specific version of rustfmt is used in your CI, use this option.
- **Default value**: `CARGO_PKG_VERSION`
- **Possible values**: any published version (e.g. `"0.3.8"`)
- **Stable**: No (tracking issue: #3386)
- **Stable**: No (tracking issue: [#3386](https://github.com/rust-lang/rustfmt/issues/3386))
## `skip_children`
@ -2204,7 +2204,7 @@ Don't reformat out of line modules
- **Default value**: `false`
- **Possible values**: `true`, `false`
- **Stable**: No (tracking issue: #3389)
- **Stable**: No (tracking issue: [#3389](https://github.com/rust-lang/rustfmt/issues/3386))
## `single_line_if_else_max_width`
@ -2224,7 +2224,7 @@ Leave a space after the colon.
- **Default value**: `true`
- **Possible values**: `true`, `false`
- **Stable**: No (tracking issue: #3366)
- **Stable**: No (tracking issue: [#3366](https://github.com/rust-lang/rustfmt/issues/3366))
#### `true` (default):
@ -2256,7 +2256,7 @@ Leave a space before the colon.
- **Default value**: `false`
- **Possible values**: `true`, `false`
- **Stable**: No (tracking issue: #3365)
- **Stable**: No (tracking issue: [#3365](https://github.com/rust-lang/rustfmt/issues/3365))
#### `false` (default):
@ -2288,7 +2288,7 @@ Put spaces around the .., ..=, and ... range operators
- **Default value**: `false`
- **Possible values**: `true`, `false`
- **Stable**: No (tracking issue: #3367)
- **Stable**: No (tracking issue: [#3367](https://github.com/rust-lang/rustfmt/issues/3367))
#### `false` (default):
@ -2344,7 +2344,7 @@ The maximum diff of width between struct fields to be aligned with each other.
- **Default value** : 0
- **Possible values**: any non-negative integer
- **Stable**: No (tracking issue: #3371)
- **Stable**: No (tracking issue: [#3371](https://github.com/rust-lang/rustfmt/issues/3371))
#### `0` (default):
@ -2372,7 +2372,7 @@ Put small struct literals on a single line
- **Default value**: `true`
- **Possible values**: `true`, `false`
- **Stable**: No (tracking issue: #3357)
- **Stable**: No (tracking issue: [#3357](https://github.com/rust-lang/rustfmt/issues/3357))
#### `true` (default):
@ -2460,7 +2460,7 @@ How to handle trailing commas for lists
- **Default value**: `"Vertical"`
- **Possible values**: `"Always"`, `"Never"`, `"Vertical"`
- **Stable**: No (tracking issue: #3379)
- **Stable**: No (tracking issue: [#3379](https://github.com/rust-lang/rustfmt/issues/3379))
#### `"Vertical"` (default):
@ -2518,7 +2518,7 @@ Add trailing semicolon after break, continue and return
- **Default value**: `true`
- **Possible values**: `true`, `false`
- **Stable**: No (tracking issue: #3378)
- **Stable**: No (tracking issue: [#3378](https://github.com/rust-lang/rustfmt/issues/3378))
#### `true` (default):
```rust
@ -2540,7 +2540,7 @@ Determines if `+` or `=` are wrapped in spaces in the punctuation of types
- **Default value**: `"Wide"`
- **Possible values**: `"Compressed"`, `"Wide"`
- **Stable**: No (tracking issue: #3364)
- **Stable**: No (tracking issue: [#3364](https://github.com/rust-lang/rustfmt/issues/3364))
#### `"Wide"` (default):
@ -2564,7 +2564,7 @@ Enable unstable features on the unstable channel.
- **Default value**: `false`
- **Possible values**: `true`, `false`
- **Stable**: No (tracking issue: #3387)
- **Stable**: No (tracking issue: [#3387](https://github.com/rust-lang/rustfmt/issues/3387))
## `use_field_init_shorthand`
@ -2779,7 +2779,7 @@ version number.
- **Default value**: `One`
- **Possible values**: `One`, `Two`
- **Stable**: No (tracking issue: #3383)
- **Stable**: No (tracking issue: [#3383](https://github.com/rust-lang/rustfmt/issues/3383))
### Example
@ -2793,7 +2793,7 @@ Forces the `where` clause to be laid out on a single line.
- **Default value**: `false`
- **Possible values**: `true`, `false`
- **Stable**: No (tracking issue: #3359)
- **Stable**: No (tracking issue: [#3359](https://github.com/rust-lang/rustfmt/issues/3359))
#### `false` (default):
@ -2825,7 +2825,7 @@ Break comments to fit on the line
- **Default value**: `false`
- **Possible values**: `true`, `false`
- **Stable**: No (tracking issue: #3347)
- **Stable**: No (tracking issue: [#3347](https://github.com/rust-lang/rustfmt/issues/3347))
#### `false` (default):

View File

@ -48,12 +48,11 @@ cargo +nightly fmt
## Limitations
Rustfmt tries to work on as much Rust code as possible. Sometimes, the code
doesn't even need to compile! As we approach a 1.0 release we are also looking
to limit areas of instability; in particular, post-1.0, the formatting of most
code should not change as Rustfmt improves. However, there are some things that
Rustfmt can't do or can't do well (and thus where formatting might change
significantly, even post-1.0). We would like to reduce the list of limitations
over time.
doesn't even need to compile! In general, we are looking to limit areas of
instability; in particular, post-1.0, the formatting of most code should not
change as Rustfmt improves. However, there are some things that Rustfmt can't
do or can't do well (and thus where formatting might change significantly,
even post-1.0). We would like to reduce the list of limitations over time.
The following list enumerates areas where Rustfmt does not work or where the
stability guarantees do not apply (we don't make a distinction between the two

View File

@ -8,6 +8,8 @@ mod item_enum;
mod item_struct;
mod utils;
use std::str::FromStr;
use proc_macro::TokenStream;
use syn::parse_macro_input;
@ -23,3 +25,43 @@ pub fn config_type(_args: TokenStream, input: TokenStream) -> TokenStream {
TokenStream::from(output)
}
/// Used to conditionally output the TokenStream for tests that need to be run on nightly only.
///
/// ```rust
/// #[nightly_only_test]
/// #[test]
/// fn test_needs_nightly_rustfmt() {
/// assert!(true);
/// }
/// ```
#[proc_macro_attribute]
pub fn nightly_only_test(_args: TokenStream, input: TokenStream) -> TokenStream {
// if CFG_RELEASE_CHANNEL is not set we default to nightly, hence why the default is true
if option_env!("CFG_RELEASE_CHANNEL").map_or(true, |c| c == "nightly" || c == "dev") {
input
} else {
// output an empty token stream if CFG_RELEASE_CHANNEL is not set to "nightly" or "dev"
TokenStream::from_str("").unwrap()
}
}
/// Used to conditionally output the TokenStream for tests that need to be run on stable only.
///
/// ```rust
/// #[stable_only_test]
/// #[test]
/// fn test_needs_stable_rustfmt() {
/// assert!(true);
/// }
/// ```
#[proc_macro_attribute]
pub fn stable_only_test(_args: TokenStream, input: TokenStream) -> TokenStream {
// if CFG_RELEASE_CHANNEL is not set we default to nightly, hence why the default is false
if option_env!("CFG_RELEASE_CHANNEL").map_or(false, |c| c == "stable") {
input
} else {
// output an empty token stream if CFG_RELEASE_CHANNEL is not set or is not 'stable'
TokenStream::from_str("").unwrap()
}
}

View File

@ -3,6 +3,8 @@
use std::{self, borrow::Cow, iter};
use itertools::{multipeek, MultiPeek};
use lazy_static::lazy_static;
use regex::Regex;
use rustc_span::Span;
use crate::config::Config;
@ -15,6 +17,17 @@ use crate::utils::{
};
use crate::{ErrorKind, FormattingError};
lazy_static! {
/// A regex matching reference doc links.
///
/// ```markdown
/// /// An [example].
/// ///
/// /// [example]: this::is::a::link
/// ```
static ref REFERENCE_LINK_URL: Regex = Regex::new(r"^\[.+\]\s?:").unwrap();
}
fn is_custom_comment(comment: &str) -> bool {
if !comment.starts_with("//") {
false
@ -506,6 +519,7 @@ struct CommentRewrite<'a> {
opener: String,
closer: String,
line_start: String,
style: CommentStyle<'a>,
}
impl<'a> CommentRewrite<'a> {
@ -515,10 +529,14 @@ impl<'a> CommentRewrite<'a> {
shape: Shape,
config: &'a Config,
) -> CommentRewrite<'a> {
let (opener, closer, line_start) = if block_style {
CommentStyle::SingleBullet.to_str_tuplet()
let ((opener, closer, line_start), style) = if block_style {
(
CommentStyle::SingleBullet.to_str_tuplet(),
CommentStyle::SingleBullet,
)
} else {
comment_style(orig, config.normalize_comments()).to_str_tuplet()
let style = comment_style(orig, config.normalize_comments());
(style.to_str_tuplet(), style)
};
let max_width = shape
@ -551,6 +569,7 @@ impl<'a> CommentRewrite<'a> {
opener: opener.to_owned(),
closer: closer.to_owned(),
line_start: line_start.to_owned(),
style,
};
cr.result.push_str(opener);
cr
@ -570,6 +589,15 @@ impl<'a> CommentRewrite<'a> {
result
}
/// Check if any characters were written to the result buffer after the start of the comment.
/// when calling [`CommentRewrite::new()`] the result buffer is initiazlied with the opening
/// characters for the comment.
fn buffer_contains_comment(&self) -> bool {
// if self.result.len() < self.opener.len() then an empty comment is in the buffer
// if self.result.len() > self.opener.len() then a non empty comment is in the buffer
self.result.len() != self.opener.len()
}
fn finish(mut self) -> String {
if !self.code_block_buffer.is_empty() {
// There is a code block that is not properly enclosed by backticks.
@ -585,7 +613,12 @@ impl<'a> CommentRewrite<'a> {
// the last few lines are part of an itemized block
self.fmt.shape = Shape::legacy(self.max_width, self.fmt_indent);
let item_fmt = ib.create_string_format(&self.fmt);
self.result.push_str(&self.comment_line_separator);
// only push a comment_line_separator for ItemizedBlocks if the comment is not empty
if self.buffer_contains_comment() {
self.result.push_str(&self.comment_line_separator);
}
self.result.push_str(&ib.opener);
match rewrite_string(
&ib.trimmed_block_as_string(),
@ -619,7 +652,13 @@ impl<'a> CommentRewrite<'a> {
line: &'a str,
has_leading_whitespace: bool,
) -> bool {
let is_last = i == count_newlines(orig);
let num_newlines = count_newlines(orig);
let is_last = i == num_newlines;
let needs_new_comment_line = if self.style.is_block_comment() {
num_newlines > 0 || self.buffer_contains_comment()
} else {
self.buffer_contains_comment()
};
if let Some(ref mut ib) = self.item_block {
if ib.add_line(line) {
@ -628,7 +667,12 @@ impl<'a> CommentRewrite<'a> {
self.is_prev_line_multi_line = false;
self.fmt.shape = Shape::legacy(self.max_width, self.fmt_indent);
let item_fmt = ib.create_string_format(&self.fmt);
self.result.push_str(&self.comment_line_separator);
// only push a comment_line_separator if we need to start a new comment line
if needs_new_comment_line {
self.result.push_str(&self.comment_line_separator);
}
self.result.push_str(&ib.opener);
match rewrite_string(
&ib.trimmed_block_as_string(),
@ -842,7 +886,11 @@ fn trim_custom_comment_prefix(s: &str) -> String {
/// Returns `true` if the given string MAY include URLs or alike.
fn has_url(s: &str) -> bool {
// This function may return false positive, but should get its job done in most cases.
s.contains("https://") || s.contains("http://") || s.contains("ftp://") || s.contains("file://")
s.contains("https://")
|| s.contains("http://")
|| s.contains("ftp://")
|| s.contains("file://")
|| REFERENCE_LINK_URL.is_match(s)
}
/// Given the span, rewrite the missing comment inside it if available.

View File

@ -405,6 +405,8 @@ mod test {
use super::*;
use std::str;
use rustfmt_config_proc_macro::{nightly_only_test, stable_only_test};
#[allow(dead_code)]
mod mock {
use super::super::*;
@ -525,21 +527,17 @@ mod test {
assert!(config.license_template.is_none());
}
#[nightly_only_test]
#[test]
fn test_valid_license_template_path() {
if !crate::is_nightly_channel!() {
return;
}
let toml = r#"license_template_path = "tests/license-template/lt.txt""#;
let config = Config::from_toml(toml, Path::new("")).unwrap();
assert!(config.license_template.is_some());
}
#[nightly_only_test]
#[test]
fn test_override_existing_license_with_no_license() {
if !crate::is_nightly_channel!() {
return;
}
let toml = r#"license_template_path = "tests/license-template/lt.txt""#;
let mut config = Config::from_toml(toml, Path::new("")).unwrap();
assert!(config.license_template.is_some());
@ -634,48 +632,42 @@ make_backup = false
assert_eq!(&toml, &default_config);
}
// FIXME(#2183): these tests cannot be run in parallel because they use env vars.
// #[test]
// fn test_as_not_nightly_channel() {
// let mut config = Config::default();
// assert_eq!(config.was_set().unstable_features(), false);
// config.set().unstable_features(true);
// assert_eq!(config.was_set().unstable_features(), false);
// }
#[stable_only_test]
#[test]
fn test_as_not_nightly_channel() {
let mut config = Config::default();
assert_eq!(config.was_set().unstable_features(), false);
config.set().unstable_features(true);
assert_eq!(config.was_set().unstable_features(), false);
}
// #[test]
// fn test_as_nightly_channel() {
// let v = ::std::env::var("CFG_RELEASE_CHANNEL").unwrap_or(String::from(""));
// ::std::env::set_var("CFG_RELEASE_CHANNEL", "nightly");
// let mut config = Config::default();
// config.set().unstable_features(true);
// assert_eq!(config.was_set().unstable_features(), false);
// config.set().unstable_features(true);
// assert_eq!(config.unstable_features(), true);
// ::std::env::set_var("CFG_RELEASE_CHANNEL", v);
// }
#[nightly_only_test]
#[test]
fn test_as_nightly_channel() {
let mut config = Config::default();
config.set().unstable_features(true);
// When we don't set the config from toml or command line options it
// doesn't get marked as set by the user.
assert_eq!(config.was_set().unstable_features(), false);
config.set().unstable_features(true);
assert_eq!(config.unstable_features(), true);
}
// #[test]
// fn test_unstable_from_toml() {
// let mut config = Config::from_toml("unstable_features = true").unwrap();
// assert_eq!(config.was_set().unstable_features(), false);
// let v = ::std::env::var("CFG_RELEASE_CHANNEL").unwrap_or(String::from(""));
// ::std::env::set_var("CFG_RELEASE_CHANNEL", "nightly");
// config = Config::from_toml("unstable_features = true").unwrap();
// assert_eq!(config.was_set().unstable_features(), true);
// assert_eq!(config.unstable_features(), true);
// ::std::env::set_var("CFG_RELEASE_CHANNEL", v);
// }
#[nightly_only_test]
#[test]
fn test_unstable_from_toml() {
let config = Config::from_toml("unstable_features = true", Path::new("")).unwrap();
assert_eq!(config.was_set().unstable_features(), true);
assert_eq!(config.unstable_features(), true);
}
#[cfg(test)]
mod deprecated_option_merge_imports {
use super::*;
#[nightly_only_test]
#[test]
fn test_old_option_set() {
if !crate::is_nightly_channel!() {
return;
}
let toml = r#"
unstable_features = true
merge_imports = true
@ -684,11 +676,9 @@ make_backup = false
assert_eq!(config.imports_granularity(), ImportGranularity::Crate);
}
#[nightly_only_test]
#[test]
fn test_both_set() {
if !crate::is_nightly_channel!() {
return;
}
let toml = r#"
unstable_features = true
merge_imports = true
@ -698,11 +688,9 @@ make_backup = false
assert_eq!(config.imports_granularity(), ImportGranularity::Preserve);
}
#[nightly_only_test]
#[test]
fn test_new_overridden() {
if !crate::is_nightly_channel!() {
return;
}
let toml = r#"
unstable_features = true
merge_imports = true
@ -712,11 +700,9 @@ make_backup = false
assert_eq!(config.imports_granularity(), ImportGranularity::Preserve);
}
#[nightly_only_test]
#[test]
fn test_old_overridden() {
if !crate::is_nightly_channel!() {
return;
}
let toml = r#"
unstable_features = true
imports_granularity = "Module"

View File

@ -196,9 +196,10 @@ pub(crate) fn format_expr(
capture, is_async, movability, fn_decl, body, expr.span, context, shape,
)
}
ast::ExprKind::Try(..) | ast::ExprKind::Field(..) | ast::ExprKind::MethodCall(..) => {
rewrite_chain(expr, context, shape)
}
ast::ExprKind::Try(..)
| ast::ExprKind::Field(..)
| ast::ExprKind::MethodCall(..)
| ast::ExprKind::Await(_) => rewrite_chain(expr, context, shape),
ast::ExprKind::MacCall(ref mac) => {
rewrite_macro(mac, None, context, shape, MacroPosition::Expression).or_else(|| {
wrap_str(
@ -377,7 +378,6 @@ pub(crate) fn format_expr(
))
}
}
ast::ExprKind::Await(_) => rewrite_chain(expr, context, shape),
ast::ExprKind::Underscore => Some("_".to_owned()),
ast::ExprKind::Err => None,
};
@ -829,6 +829,7 @@ impl<'a> ControlFlow<'a> {
&format!("{}{}{}", matcher, pat_string, self.connector),
expr,
cond_shape,
&RhsAssignKind::Expr(&expr.kind, expr.span),
RhsTactics::Default,
comments_span,
true,
@ -1839,6 +1840,34 @@ fn rewrite_unary_op(
rewrite_unary_prefix(context, ast::UnOp::to_string(op), expr, shape)
}
pub(crate) enum RhsAssignKind<'ast> {
Expr(&'ast ast::ExprKind, Span),
Bounds,
Ty,
}
impl<'ast> RhsAssignKind<'ast> {
// TODO(calebcartwright)
// Preemptive addition for handling RHS with chains, not yet utilized.
// It may make more sense to construct the chain first and then check
// whether there are actually chain elements.
#[allow(dead_code)]
fn is_chain(&self) -> bool {
match self {
RhsAssignKind::Expr(kind, _) => {
matches!(
kind,
ast::ExprKind::Try(..)
| ast::ExprKind::Field(..)
| ast::ExprKind::MethodCall(..)
| ast::ExprKind::Await(_)
)
}
_ => false,
}
}
}
fn rewrite_assignment(
context: &RewriteContext<'_>,
lhs: &ast::Expr,
@ -1855,7 +1884,13 @@ fn rewrite_assignment(
let lhs_shape = shape.sub_width(operator_str.len() + 1)?;
let lhs_str = format!("{} {}", lhs.rewrite(context, lhs_shape)?, operator_str);
rewrite_assign_rhs(context, lhs_str, rhs, shape)
rewrite_assign_rhs(
context,
lhs_str,
rhs,
&RhsAssignKind::Expr(&rhs.kind, rhs.span),
shape,
)
}
/// Controls where to put the rhs.
@ -1876,9 +1911,10 @@ pub(crate) fn rewrite_assign_rhs<S: Into<String>, R: Rewrite>(
context: &RewriteContext<'_>,
lhs: S,
ex: &R,
rhs_kind: &RhsAssignKind<'_>,
shape: Shape,
) -> Option<String> {
rewrite_assign_rhs_with(context, lhs, ex, shape, RhsTactics::Default)
rewrite_assign_rhs_with(context, lhs, ex, shape, rhs_kind, RhsTactics::Default)
}
pub(crate) fn rewrite_assign_rhs_expr<R: Rewrite>(
@ -1886,6 +1922,7 @@ pub(crate) fn rewrite_assign_rhs_expr<R: Rewrite>(
lhs: &str,
ex: &R,
shape: Shape,
rhs_kind: &RhsAssignKind<'_>,
rhs_tactics: RhsTactics,
) -> Option<String> {
let last_line_width = last_line_width(lhs).saturating_sub(if lhs.contains('\n') {
@ -1910,6 +1947,7 @@ pub(crate) fn rewrite_assign_rhs_expr<R: Rewrite>(
ex,
orig_shape,
ex.rewrite(context, orig_shape),
rhs_kind,
rhs_tactics,
has_rhs_comment,
)
@ -1920,10 +1958,11 @@ pub(crate) fn rewrite_assign_rhs_with<S: Into<String>, R: Rewrite>(
lhs: S,
ex: &R,
shape: Shape,
rhs_kind: &RhsAssignKind<'_>,
rhs_tactics: RhsTactics,
) -> Option<String> {
let lhs = lhs.into();
let rhs = rewrite_assign_rhs_expr(context, &lhs, ex, shape, rhs_tactics)?;
let rhs = rewrite_assign_rhs_expr(context, &lhs, ex, shape, rhs_kind, rhs_tactics)?;
Some(lhs + &rhs)
}
@ -1932,6 +1971,7 @@ pub(crate) fn rewrite_assign_rhs_with_comments<S: Into<String>, R: Rewrite>(
lhs: S,
ex: &R,
shape: Shape,
rhs_kind: &RhsAssignKind<'_>,
rhs_tactics: RhsTactics,
between_span: Span,
allow_extend: bool,
@ -1943,7 +1983,7 @@ pub(crate) fn rewrite_assign_rhs_with_comments<S: Into<String>, R: Rewrite>(
} else {
shape
};
let rhs = rewrite_assign_rhs_expr(context, &lhs, ex, shape, rhs_tactics)?;
let rhs = rewrite_assign_rhs_expr(context, &lhs, ex, shape, rhs_kind, rhs_tactics)?;
if contains_comment {
let rhs = rhs.trim_start();
@ -1958,6 +1998,7 @@ fn choose_rhs<R: Rewrite>(
expr: &R,
shape: Shape,
orig_rhs: Option<String>,
_rhs_kind: &RhsAssignKind<'_>,
rhs_tactics: RhsTactics,
has_rhs_comment: bool,
) -> Option<String> {

View File

@ -37,21 +37,17 @@ mod test {
use crate::config::{Config, FileName};
use crate::ignore_path::IgnorePathSet;
use rustfmt_config_proc_macro::nightly_only_test;
#[nightly_only_test]
#[test]
fn test_ignore_path_set() {
match option_env!("CFG_RELEASE_CHANNEL") {
// this test requires nightly
None | Some("nightly") => {
let config =
Config::from_toml(r#"ignore = ["foo.rs", "bar_dir/*"]"#, Path::new(""))
.unwrap();
let ignore_path_set = IgnorePathSet::from_ignore_list(&config.ignore()).unwrap();
let config =
Config::from_toml(r#"ignore = ["foo.rs", "bar_dir/*"]"#, Path::new("")).unwrap();
let ignore_path_set = IgnorePathSet::from_ignore_list(&config.ignore()).unwrap();
assert!(ignore_path_set.is_match(&FileName::Real(PathBuf::from("src/foo.rs"))));
assert!(ignore_path_set.is_match(&FileName::Real(PathBuf::from("bar_dir/baz.rs"))));
assert!(!ignore_path_set.is_match(&FileName::Real(PathBuf::from("src/bar.rs"))));
}
_ => (),
};
assert!(ignore_path_set.is_match(&FileName::Real(PathBuf::from("src/foo.rs"))));
assert!(ignore_path_set.is_match(&FileName::Real(PathBuf::from("bar_dir/baz.rs"))));
assert!(!ignore_path_set.is_match(&FileName::Real(PathBuf::from("src/bar.rs"))));
}
}

View File

@ -18,7 +18,7 @@ use crate::config::lists::*;
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, RhsTactics,
rewrite_assign_rhs_with_comments, RhsAssignKind, RhsTactics,
};
use crate::lists::{definitive_tactic, itemize_list, write_list, ListFormatting, Separator};
use crate::macros::{rewrite_macro, MacroPosition};
@ -28,6 +28,7 @@ use crate::shape::{Indent, Shape};
use crate::source_map::{LineRangeUtils, SpanUtils};
use crate::spanned::Spanned;
use crate::stmt::Stmt;
use crate::types::opaque_ty;
use crate::utils::*;
use crate::vertical::rewrite_with_alignment;
use crate::visitor::FmtVisitor;
@ -115,7 +116,13 @@ impl Rewrite for ast::Local {
// 1 = trailing semicolon;
let nested_shape = shape.sub_width(1)?;
result = rewrite_assign_rhs(context, result, init, nested_shape)?;
result = rewrite_assign_rhs(
context,
result,
init,
&RhsAssignKind::Expr(&init.kind, init.span),
nested_shape,
)?;
// todo else
}
@ -563,11 +570,13 @@ impl<'a> FmtVisitor<'a> {
let variant_body = if let Some(ref expr) = field.disr_expr {
let lhs = format!("{:1$} =", variant_body, pad_discrim_ident_to);
let ex = &*expr.value;
rewrite_assign_rhs_with(
&context,
lhs,
&*expr.value,
ex,
shape,
&RhsAssignKind::Expr(&ex.kind, ex.span),
RhsTactics::AllowOverflow,
)?
} else {
@ -579,6 +588,22 @@ impl<'a> FmtVisitor<'a> {
fn visit_impl_items(&mut self, items: &[ptr::P<ast::AssocItem>]) {
if self.get_context().config.reorder_impl_items() {
type TyOpt = Option<ptr::P<ast::Ty>>;
use crate::ast::AssocItemKind::*;
let is_type = |ty: &TyOpt| opaque_ty(ty).is_none();
let is_opaque = |ty: &TyOpt| opaque_ty(ty).is_some();
let both_type = |l: &TyOpt, r: &TyOpt| is_type(l) && is_type(r);
let both_opaque = |l: &TyOpt, r: &TyOpt| is_opaque(l) && is_opaque(r);
let need_empty_line = |a: &ast::AssocItemKind, b: &ast::AssocItemKind| match (a, b) {
(TyAlias(lty), TyAlias(rty))
if both_type(&lty.ty, &rty.ty) || both_opaque(&lty.ty, &rty.ty) =>
{
false
}
(Const(..), Const(..)) => false,
_ => true,
};
// Create visitor for each items, then reorder them.
let mut buffer = vec![];
for item in items {
@ -587,50 +612,6 @@ impl<'a> FmtVisitor<'a> {
self.buffer.clear();
}
fn is_type(ty: &Option<rustc_ast::ptr::P<ast::Ty>>) -> bool {
if let Some(lty) = ty {
if let ast::TyKind::ImplTrait(..) = lty.kind {
return false;
}
}
true
}
fn is_opaque(ty: &Option<rustc_ast::ptr::P<ast::Ty>>) -> bool {
!is_type(ty)
}
fn both_type(
a: &Option<rustc_ast::ptr::P<ast::Ty>>,
b: &Option<rustc_ast::ptr::P<ast::Ty>>,
) -> bool {
is_type(a) && is_type(b)
}
fn both_opaque(
a: &Option<rustc_ast::ptr::P<ast::Ty>>,
b: &Option<rustc_ast::ptr::P<ast::Ty>>,
) -> bool {
is_opaque(a) && is_opaque(b)
}
// In rustc-ap-v638 the `OpaqueTy` AssocItemKind variant was removed but
// we still need to differentiate to maintain sorting order.
// type -> opaque -> const -> macro -> method
use crate::ast::AssocItemKind::*;
fn need_empty_line(a: &ast::AssocItemKind, b: &ast::AssocItemKind) -> bool {
match (a, b) {
(TyAlias(lty), TyAlias(rty))
if both_type(&lty.ty, &rty.ty) || both_opaque(&lty.ty, &rty.ty) =>
{
false
}
(Const(..), Const(..)) => false,
_ => true,
}
}
buffer.sort_by(|(_, a), (_, b)| match (&a.kind, &b.kind) {
(TyAlias(lty), TyAlias(rty))
if both_type(&lty.ty, &rty.ty) || both_opaque(&lty.ty, &rty.ty) =>
@ -676,136 +657,133 @@ impl<'a> FmtVisitor<'a> {
pub(crate) fn format_impl(
context: &RewriteContext<'_>,
item: &ast::Item,
iimpl: &ast::Impl,
offset: Indent,
) -> Option<String> {
if let ast::ItemKind::Impl(impl_kind) = &item.kind {
let ast::Impl {
ref generics,
ref self_ty,
ref items,
..
} = **impl_kind;
let mut result = String::with_capacity(128);
let ref_and_type = format_impl_ref_and_type(context, item, offset)?;
let sep = offset.to_string_with_newline(context.config);
result.push_str(&ref_and_type);
let ast::Impl {
generics,
self_ty,
items,
..
} = iimpl;
let mut result = String::with_capacity(128);
let ref_and_type = format_impl_ref_and_type(context, item, iimpl, offset)?;
let sep = offset.to_string_with_newline(context.config);
result.push_str(&ref_and_type);
let where_budget = if result.contains('\n') {
context.config.max_width()
} else {
context.budget(last_line_width(&result))
};
let mut option = WhereClauseOption::snuggled(&ref_and_type);
let snippet = context.snippet(item.span);
let open_pos = snippet.find_uncommented("{")? + 1;
if !contains_comment(&snippet[open_pos..])
&& items.is_empty()
&& generics.where_clause.predicates.len() == 1
&& !result.contains('\n')
{
option.suppress_comma();
option.snuggle();
option.allow_single_line();
}
let missing_span = mk_sp(self_ty.span.hi(), item.span.hi());
let where_span_end = context.snippet_provider.opt_span_before(missing_span, "{");
let where_clause_str = rewrite_where_clause(
context,
&generics.where_clause,
context.config.brace_style(),
Shape::legacy(where_budget, offset.block_only()),
false,
"{",
where_span_end,
self_ty.span.hi(),
option,
)?;
// If there is no where-clause, we may have missing comments between the trait name and
// the opening brace.
if generics.where_clause.predicates.is_empty() {
if let Some(hi) = where_span_end {
match recover_missing_comment_in_span(
mk_sp(self_ty.span.hi(), hi),
Shape::indented(offset, context.config),
context,
last_line_width(&result),
) {
Some(ref missing_comment) if !missing_comment.is_empty() => {
result.push_str(missing_comment);
}
_ => (),
}
}
}
if is_impl_single_line(context, items.as_slice(), &result, &where_clause_str, item)? {
result.push_str(&where_clause_str);
if where_clause_str.contains('\n') || last_line_contains_single_line_comment(&result) {
// if the where_clause contains extra comments AND
// there is only one where-clause predicate
// recover the suppressed comma in single line where_clause formatting
if generics.where_clause.predicates.len() == 1 {
result.push(',');
}
result.push_str(&format!("{}{{{}}}", sep, sep));
} else {
result.push_str(" {}");
}
return Some(result);
}
result.push_str(&where_clause_str);
let need_newline = last_line_contains_single_line_comment(&result) || result.contains('\n');
match context.config.brace_style() {
_ if need_newline => result.push_str(&sep),
BraceStyle::AlwaysNextLine => result.push_str(&sep),
BraceStyle::PreferSameLine => result.push(' '),
BraceStyle::SameLineWhere => {
if !where_clause_str.is_empty() {
result.push_str(&sep);
} else {
result.push(' ');
}
}
}
result.push('{');
// this is an impl body snippet(impl SampleImpl { /* here */ })
let lo = max(self_ty.span.hi(), generics.where_clause.span.hi());
let snippet = context.snippet(mk_sp(lo, item.span.hi()));
let open_pos = snippet.find_uncommented("{")? + 1;
if !items.is_empty() || contains_comment(&snippet[open_pos..]) {
let mut visitor = FmtVisitor::from_context(context);
let item_indent = offset.block_only().block_indent(context.config);
visitor.block_indent = item_indent;
visitor.last_pos = lo + BytePos(open_pos as u32);
visitor.visit_attrs(&item.attrs, ast::AttrStyle::Inner);
visitor.visit_impl_items(items);
visitor.format_missing(item.span.hi() - BytePos(1));
let inner_indent_str = visitor.block_indent.to_string_with_newline(context.config);
let outer_indent_str = offset.block_only().to_string_with_newline(context.config);
result.push_str(&inner_indent_str);
result.push_str(visitor.buffer.trim());
result.push_str(&outer_indent_str);
} else if need_newline || !context.config.empty_item_single_line() {
result.push_str(&sep);
}
result.push('}');
Some(result)
let where_budget = if result.contains('\n') {
context.config.max_width()
} else {
unreachable!();
context.budget(last_line_width(&result))
};
let mut option = WhereClauseOption::snuggled(&ref_and_type);
let snippet = context.snippet(item.span);
let open_pos = snippet.find_uncommented("{")? + 1;
if !contains_comment(&snippet[open_pos..])
&& items.is_empty()
&& generics.where_clause.predicates.len() == 1
&& !result.contains('\n')
{
option.suppress_comma();
option.snuggle();
option.allow_single_line();
}
let missing_span = mk_sp(self_ty.span.hi(), item.span.hi());
let where_span_end = context.snippet_provider.opt_span_before(missing_span, "{");
let where_clause_str = rewrite_where_clause(
context,
&generics.where_clause,
context.config.brace_style(),
Shape::legacy(where_budget, offset.block_only()),
false,
"{",
where_span_end,
self_ty.span.hi(),
option,
)?;
// If there is no where-clause, we may have missing comments between the trait name and
// the opening brace.
if generics.where_clause.predicates.is_empty() {
if let Some(hi) = where_span_end {
match recover_missing_comment_in_span(
mk_sp(self_ty.span.hi(), hi),
Shape::indented(offset, context.config),
context,
last_line_width(&result),
) {
Some(ref missing_comment) if !missing_comment.is_empty() => {
result.push_str(missing_comment);
}
_ => (),
}
}
}
if is_impl_single_line(context, items.as_slice(), &result, &where_clause_str, item)? {
result.push_str(&where_clause_str);
if where_clause_str.contains('\n') || last_line_contains_single_line_comment(&result) {
// if the where_clause contains extra comments AND
// there is only one where-clause predicate
// recover the suppressed comma in single line where_clause formatting
if generics.where_clause.predicates.len() == 1 {
result.push(',');
}
result.push_str(&format!("{}{{{}}}", sep, sep));
} else {
result.push_str(" {}");
}
return Some(result);
}
result.push_str(&where_clause_str);
let need_newline = last_line_contains_single_line_comment(&result) || result.contains('\n');
match context.config.brace_style() {
_ if need_newline => result.push_str(&sep),
BraceStyle::AlwaysNextLine => result.push_str(&sep),
BraceStyle::PreferSameLine => result.push(' '),
BraceStyle::SameLineWhere => {
if !where_clause_str.is_empty() {
result.push_str(&sep);
} else {
result.push(' ');
}
}
}
result.push('{');
// this is an impl body snippet(impl SampleImpl { /* here */ })
let lo = max(self_ty.span.hi(), generics.where_clause.span.hi());
let snippet = context.snippet(mk_sp(lo, item.span.hi()));
let open_pos = snippet.find_uncommented("{")? + 1;
if !items.is_empty() || contains_comment(&snippet[open_pos..]) {
let mut visitor = FmtVisitor::from_context(context);
let item_indent = offset.block_only().block_indent(context.config);
visitor.block_indent = item_indent;
visitor.last_pos = lo + BytePos(open_pos as u32);
visitor.visit_attrs(&item.attrs, ast::AttrStyle::Inner);
visitor.visit_impl_items(items);
visitor.format_missing(item.span.hi() - BytePos(1));
let inner_indent_str = visitor.block_indent.to_string_with_newline(context.config);
let outer_indent_str = offset.block_only().to_string_with_newline(context.config);
result.push_str(&inner_indent_str);
result.push_str(visitor.buffer.trim());
result.push_str(&outer_indent_str);
} else if need_newline || !context.config.empty_item_single_line() {
result.push_str(&sep);
}
result.push('}');
Some(result)
}
fn is_impl_single_line(
@ -830,111 +808,106 @@ fn is_impl_single_line(
fn format_impl_ref_and_type(
context: &RewriteContext<'_>,
item: &ast::Item,
iimpl: &ast::Impl,
offset: Indent,
) -> Option<String> {
if let ast::ItemKind::Impl(impl_kind) = &item.kind {
let ast::Impl {
unsafety,
polarity,
defaultness,
constness,
ref generics,
of_trait: ref trait_ref,
ref self_ty,
..
} = **impl_kind;
let mut result = String::with_capacity(128);
let ast::Impl {
unsafety,
polarity,
defaultness,
constness,
ref generics,
of_trait: ref trait_ref,
ref self_ty,
..
} = *iimpl;
let mut result = String::with_capacity(128);
result.push_str(&format_visibility(context, &item.vis));
result.push_str(format_defaultness(defaultness));
result.push_str(format_unsafety(unsafety));
result.push_str(&format_visibility(context, &item.vis));
result.push_str(format_defaultness(defaultness));
result.push_str(format_unsafety(unsafety));
let shape = if context.config.version() == Version::Two {
Shape::indented(offset + last_line_width(&result), context.config)
} else {
generics_shape_from_config(
context.config,
Shape::indented(offset + last_line_width(&result), context.config),
0,
)?
};
let generics_str = rewrite_generics(context, "impl", generics, shape)?;
result.push_str(&generics_str);
result.push_str(format_constness_right(constness));
let polarity_str = match polarity {
ast::ImplPolarity::Negative(_) => "!",
ast::ImplPolarity::Positive => "",
};
let polarity_overhead;
let trait_ref_overhead;
if let Some(ref trait_ref) = *trait_ref {
let result_len = last_line_width(&result);
result.push_str(&rewrite_trait_ref(
context,
trait_ref,
offset,
polarity_str,
result_len,
)?);
polarity_overhead = 0; // already written
trait_ref_overhead = " for".len();
} else {
polarity_overhead = polarity_str.len();
trait_ref_overhead = 0;
}
// Try to put the self type in a single line.
let curly_brace_overhead = if generics.where_clause.predicates.is_empty() {
// If there is no where-clause adapt budget for type formatting to take space and curly
// brace into account.
match context.config.brace_style() {
BraceStyle::AlwaysNextLine => 0,
_ => 2,
}
} else {
0
};
let used_space = last_line_width(&result)
+ polarity_overhead
+ trait_ref_overhead
+ curly_brace_overhead;
// 1 = space before the type.
let budget = context.budget(used_space + 1);
if let Some(self_ty_str) = self_ty.rewrite(context, Shape::legacy(budget, offset)) {
if !self_ty_str.contains('\n') {
if trait_ref.is_some() {
result.push_str(" for ");
} else {
result.push(' ');
result.push_str(polarity_str);
}
result.push_str(&self_ty_str);
return Some(result);
}
}
// Couldn't fit the self type on a single line, put it on a new line.
result.push('\n');
// Add indentation of one additional tab.
let new_line_offset = offset.block_indent(context.config);
result.push_str(&new_line_offset.to_string(context.config));
if trait_ref.is_some() {
result.push_str("for ");
} else {
result.push_str(polarity_str);
}
let budget = context.budget(last_line_width(&result) + polarity_overhead);
let type_offset = match context.config.indent_style() {
IndentStyle::Visual => new_line_offset + trait_ref_overhead,
IndentStyle::Block => new_line_offset,
};
result.push_str(&*self_ty.rewrite(context, Shape::legacy(budget, type_offset))?);
Some(result)
let shape = if context.config.version() == Version::Two {
Shape::indented(offset + last_line_width(&result), context.config)
} else {
unreachable!();
generics_shape_from_config(
context.config,
Shape::indented(offset + last_line_width(&result), context.config),
0,
)?
};
let generics_str = rewrite_generics(context, "impl", generics, shape)?;
result.push_str(&generics_str);
result.push_str(format_constness_right(constness));
let polarity_str = match polarity {
ast::ImplPolarity::Negative(_) => "!",
ast::ImplPolarity::Positive => "",
};
let polarity_overhead;
let trait_ref_overhead;
if let Some(ref trait_ref) = *trait_ref {
let result_len = last_line_width(&result);
result.push_str(&rewrite_trait_ref(
context,
trait_ref,
offset,
polarity_str,
result_len,
)?);
polarity_overhead = 0; // already written
trait_ref_overhead = " for".len();
} else {
polarity_overhead = polarity_str.len();
trait_ref_overhead = 0;
}
// Try to put the self type in a single line.
let curly_brace_overhead = if generics.where_clause.predicates.is_empty() {
// If there is no where-clause adapt budget for type formatting to take space and curly
// brace into account.
match context.config.brace_style() {
BraceStyle::AlwaysNextLine => 0,
_ => 2,
}
} else {
0
};
let used_space =
last_line_width(&result) + polarity_overhead + trait_ref_overhead + curly_brace_overhead;
// 1 = space before the type.
let budget = context.budget(used_space + 1);
if let Some(self_ty_str) = self_ty.rewrite(context, Shape::legacy(budget, offset)) {
if !self_ty_str.contains('\n') {
if trait_ref.is_some() {
result.push_str(" for ");
} else {
result.push(' ');
result.push_str(polarity_str);
}
result.push_str(&self_ty_str);
return Some(result);
}
}
// Couldn't fit the self type on a single line, put it on a new line.
result.push('\n');
// Add indentation of one additional tab.
let new_line_offset = offset.block_indent(context.config);
result.push_str(&new_line_offset.to_string(context.config));
if trait_ref.is_some() {
result.push_str("for ");
} else {
result.push_str(polarity_str);
}
let budget = context.budget(last_line_width(&result) + polarity_overhead);
let type_offset = match context.config.indent_style() {
IndentStyle::Visual => new_line_offset + trait_ref_overhead,
IndentStyle::Block => new_line_offset,
};
result.push_str(&*self_ty.rewrite(context, Shape::legacy(budget, type_offset))?);
Some(result)
}
fn rewrite_trait_ref(
@ -1068,6 +1041,7 @@ pub(crate) fn format_trait(
result + ":",
bounds,
shape,
&RhsAssignKind::Bounds,
RhsTactics::ForceNextLineWithoutIndent,
)?;
}
@ -1248,7 +1222,14 @@ pub(crate) fn format_trait_alias(
generic_bounds,
generics,
};
rewrite_assign_rhs(context, lhs, &trait_alias_bounds, shape.sub_width(1)?).map(|s| s + ";")
rewrite_assign_rhs(
context,
lhs,
&trait_alias_bounds,
&RhsAssignKind::Bounds,
shape.sub_width(1)?,
)
.map(|s| s + ";")
}
fn format_unit_struct(
@ -1541,43 +1522,38 @@ pub(crate) fn rewrite_type_alias<'a, 'b>(
ref bounds,
ref ty,
} = *ty_alias_kind;
let ty_opt = ty.as_ref().map(|t| &**t);
let ty_opt = ty.as_ref();
let (ident, vis) = match visitor_kind {
Item(i) => (i.ident, &i.vis),
AssocTraitItem(i) | AssocImplItem(i) => (i.ident, &i.vis),
ForeignItem(i) => (i.ident, &i.vis),
};
let rw_info = &TyAliasRewriteInfo(context, indent, generics, ident, span);
let op_ty = opaque_ty(ty);
// Type Aliases are formatted slightly differently depending on the context
// in which they appear, whether they are opaque, and whether they are associated.
// https://rustc-dev-guide.rust-lang.org/opaque-types-type-alias-impl-trait.html
// https://github.com/rust-dev-tools/fmt-rfcs/blob/master/guide/items.md#type-aliases
match (visitor_kind, ty_opt) {
(Item(_), None) => {
let op_ty = OpaqueType { bounds };
rewrite_ty(rw_info, Some(bounds), Some(&op_ty), vis)
match (visitor_kind, &op_ty) {
(Item(_) | AssocTraitItem(_) | ForeignItem(_), Some(ref op_bounds)) => {
let op = OpaqueType { bounds: op_bounds };
rewrite_ty(rw_info, Some(bounds), Some(&op), vis)
}
(Item(_) | AssocTraitItem(_) | ForeignItem(_), None) => {
rewrite_ty(rw_info, Some(bounds), ty_opt, vis)
}
(Item(_), Some(ty)) => rewrite_ty(rw_info, Some(bounds), Some(&*ty), vis),
(AssocImplItem(_), _) => {
let result = if let Some(ast::Ty {
kind: ast::TyKind::ImplTrait(_, ref bounds),
..
}) = ty_opt
{
let op_ty = OpaqueType { bounds };
rewrite_ty(rw_info, None, Some(&op_ty), &DEFAULT_VISIBILITY)
let result = if let Some(ref op_bounds) = op_ty {
let op = OpaqueType { bounds: op_bounds };
rewrite_ty(rw_info, Some(bounds), Some(&op), &DEFAULT_VISIBILITY)
} else {
rewrite_ty(rw_info, None, ty.as_ref(), vis)
rewrite_ty(rw_info, Some(bounds), ty_opt, vis)
}?;
match defaultness {
ast::Defaultness::Default(..) => Some(format!("default {}", result)),
_ => Some(result),
}
}
(AssocTraitItem(_), _) | (ForeignItem(_), _) => {
rewrite_ty(rw_info, Some(bounds), ty.as_ref(), vis)
}
}
}
@ -1670,7 +1646,7 @@ fn rewrite_ty<R: Rewrite>(
// 1 = `;`
let shape = Shape::indented(indent, context.config).sub_width(1)?;
rewrite_assign_rhs(context, lhs, &*ty, shape).map(|s| s + ";")
rewrite_assign_rhs(context, lhs, &*ty, &RhsAssignKind::Ty, shape).map(|s| s + ";")
} else {
Some(format!("{};", result))
}
@ -1760,7 +1736,7 @@ pub(crate) fn rewrite_struct_field(
let is_prefix_empty = prefix.is_empty();
// We must use multiline. We are going to put attributes and a field on different lines.
let field_str = rewrite_assign_rhs(context, prefix, &*field.ty, shape)?;
let field_str = rewrite_assign_rhs(context, prefix, &*field.ty, &RhsAssignKind::Ty, shape)?;
// Remove a leading white-space from `rewrite_assign_rhs()` when rewriting a tuple struct.
let field_str = if is_prefix_empty {
field_str.trim_start()
@ -1890,6 +1866,7 @@ fn rewrite_static(
&lhs,
&**expr,
Shape::legacy(remaining_width, offset.block_only()),
&RhsAssignKind::Expr(&expr.kind, expr.span),
RhsTactics::Default,
comments_span,
true,
@ -1900,6 +1877,12 @@ fn rewrite_static(
Some(format!("{}{};", prefix, ty_str))
}
}
// FIXME(calebcartwright) - This is a hack around a bug in the handling of TyKind::ImplTrait.
// This should be removed once that bug is resolved, with the type alias formatting using the
// defined Ty for the RHS directly.
// https://github.com/rust-lang/rustfmt/issues/4373
// https://github.com/rust-lang/rustfmt/issues/5027
struct OpaqueType<'a> {
bounds: &'a ast::GenericBounds,
}
@ -3173,7 +3156,14 @@ impl Rewrite for ast::ForeignItem {
rewrite_ident(context, self.ident)
);
// 1 = ;
rewrite_assign_rhs(context, prefix, &**ty, shape.sub_width(1)?).map(|s| s + ";")
rewrite_assign_rhs(
context,
prefix,
&**ty,
&RhsAssignKind::Ty,
shape.sub_width(1)?,
)
.map(|s| s + ";")
}
ast::ForeignItemKind::TyAlias(ref ty_alias) => {
let (kind, span) = (&ItemVisitorKind::ForeignItem(&self), self.span);

View File

@ -444,10 +444,15 @@ where
let offset = formatting.shape.indent + overhead;
let comment_shape = Shape::legacy(width, offset);
// Use block-style only for the last item or multiline comments.
let block_style = !formatting.ends_with_newline && last
|| comment.trim().contains('\n')
|| comment.trim().len() > width;
let block_style = if !formatting.ends_with_newline && last {
true
} else if starts_with_newline(comment) {
false
} else if comment.trim().contains('\n') || comment.trim().len() > width {
true
} else {
false
};
rewrite_comment(
comment.trim_start(),

View File

@ -27,7 +27,7 @@ use crate::comment::{
contains_comment, CharClasses, FindUncommented, FullCodeCharKind, LineClasses,
};
use crate::config::lists::*;
use crate::expr::rewrite_array;
use crate::expr::{rewrite_array, rewrite_assign_rhs, RhsAssignKind};
use crate::lists::{itemize_list, write_list, ListFormatting};
use crate::overflow;
use crate::rewrite::{Rewrite, RewriteContext};
@ -1468,10 +1468,11 @@ fn format_lazy_static(
id,
ty.rewrite(context, nested_shape)?
));
result.push_str(&crate::expr::rewrite_assign_rhs(
result.push_str(&rewrite_assign_rhs(
context,
stmt,
&*expr,
&RhsAssignKind::Expr(&expr.kind, expr.span),
nested_shape.sub_width(1)?,
)?);
result.push(';');

View File

@ -286,10 +286,11 @@ impl LineRangeUtils for ParseSess {
mod tests {
use super::*;
use rustfmt_config_proc_macro::nightly_only_test;
mod emitter {
use super::*;
use crate::config::IgnoreList;
use crate::is_nightly_channel;
use crate::utils::mk_sp;
use rustc_span::{FileName as SourceMapFileName, MultiSpan, RealFileName, DUMMY_SP};
use std::path::PathBuf;
@ -371,11 +372,9 @@ mod tests {
assert_eq!(can_reset_errors.load(Ordering::Acquire), false);
}
#[nightly_only_test]
#[test]
fn handles_recoverable_parse_error_in_ignored_file() {
if !is_nightly_channel!() {
return;
}
let num_emitted_errors = Lrc::new(AtomicU32::new(0));
let can_reset_errors = Lrc::new(AtomicBool::new(false));
let ignore_list = get_ignore_list(r#"ignore = ["foo.rs"]"#);
@ -398,11 +397,9 @@ mod tests {
assert_eq!(can_reset_errors.load(Ordering::Acquire), true);
}
#[nightly_only_test]
#[test]
fn handles_recoverable_parse_error_in_non_ignored_file() {
if !is_nightly_channel!() {
return;
}
let num_emitted_errors = Lrc::new(AtomicU32::new(0));
let can_reset_errors = Lrc::new(AtomicBool::new(false));
let source_map = Lrc::new(SourceMap::new(FilePathMapping::empty()));
@ -424,11 +421,9 @@ mod tests {
assert_eq!(can_reset_errors.load(Ordering::Acquire), false);
}
#[nightly_only_test]
#[test]
fn handles_mix_of_recoverable_parse_error() {
if !is_nightly_channel!() {
return;
}
let num_emitted_errors = Lrc::new(AtomicU32::new(0));
let can_reset_errors = Lrc::new(AtomicBool::new(false));
let source_map = Lrc::new(SourceMap::new(FilePathMapping::empty()));

View File

@ -15,6 +15,8 @@ use crate::rustfmt_diff::{make_diff, print_diff, DiffLine, Mismatch, ModifiedChu
use crate::source_file;
use crate::{is_nightly_channel, FormatReport, FormatReportFormatterBuilder, Input, Session};
use rustfmt_config_proc_macro::nightly_only_test;
mod configuration_snippet;
mod mod_resolver;
mod parser;
@ -307,14 +309,11 @@ fn assert_output(source: &Path, expected_filename: &Path) {
// Idempotence tests. Files in tests/target are checked to be unaltered by
// rustfmt.
#[nightly_only_test]
#[test]
fn idempotence_tests() {
init_log();
run_test_with(&TestSetting::default(), || {
// these tests require nightly
if !is_nightly_channel!() {
return;
}
// Get all files in the tests/target directory.
let files = get_test_files(Path::new("tests/target"), true);
let (_reports, count, fails) = check_files(files, &None);
@ -332,13 +331,11 @@ fn idempotence_tests() {
// Run rustfmt on itself. This operation must be idempotent. We also check that
// no warnings are emitted.
// Issue-3443: these tests require nightly
#[nightly_only_test]
#[test]
fn self_tests() {
init_log();
// Issue-3443: these tests require nightly
if !is_nightly_channel!() {
return;
}
let mut files = get_test_files(Path::new("tests"), false);
let bin_directories = vec!["cargo-fmt", "git-rustfmt", "bin", "format-diff"];
for dir in bin_directories {

View File

@ -2,6 +2,7 @@ use std::iter::ExactSizeIterator;
use std::ops::Deref;
use rustc_ast::ast::{self, FnRetTy, Mutability};
use rustc_ast::ptr;
use rustc_span::{symbol::kw, BytePos, Pos, Span};
use crate::comment::{combine_strs_with_missing_comments, contains_comment};
@ -9,6 +10,7 @@ use crate::config::lists::*;
use crate::config::{IndentStyle, TypeDensity, Version};
use crate::expr::{
format_expr, rewrite_assign_rhs, rewrite_call, rewrite_tuple, rewrite_unary_prefix, ExprType,
RhsAssignKind,
};
use crate::lists::{
definitive_tactic, itemize_list, write_list, ListFormatting, ListItem, Separator,
@ -429,7 +431,7 @@ impl Rewrite for ast::WherePredicate {
format!("{}{}", type_str, colon)
};
rewrite_assign_rhs(context, lhs, bounds, shape)?
rewrite_assign_rhs(context, lhs, bounds, &RhsAssignKind::Bounds, shape)?
}
ast::WherePredicate::RegionPredicate(ast::WhereRegionPredicate {
ref lifetime,
@ -442,7 +444,7 @@ impl Rewrite for ast::WherePredicate {
..
}) => {
let lhs_ty_str = lhs_ty.rewrite(context, shape).map(|lhs| lhs + " =")?;
rewrite_assign_rhs(context, lhs_ty_str, &**rhs_ty, shape)?
rewrite_assign_rhs(context, lhs_ty_str, &**rhs_ty, &RhsAssignKind::Ty, shape)?
}
};
@ -1031,6 +1033,13 @@ fn join_bounds_inner(
}
}
pub(crate) fn opaque_ty(ty: &Option<ptr::P<ast::Ty>>) -> Option<&ast::GenericBounds> {
ty.as_ref().and_then(|t| match &t.kind {
ast::TyKind::ImplTrait(_, bounds) => Some(bounds),
_ => None,
})
}
pub(crate) fn can_be_overflowed_type(
context: &RewriteContext<'_>,
ty: &ast::Ty,

View File

@ -485,9 +485,9 @@ impl<'b, 'a: 'b> FmtVisitor<'a> {
if should_visit_node_again {
match item.kind {
ast::ItemKind::Use(ref tree) => self.format_import(item, tree),
ast::ItemKind::Impl { .. } => {
ast::ItemKind::Impl(ref iimpl) => {
let block_indent = self.block_indent;
let rw = self.with_context(|ctx| format_impl(ctx, item, block_indent));
let rw = self.with_context(|ctx| format_impl(ctx, item, iimpl, block_indent));
self.push_rewrite(item.span, rw);
}
ast::ItemKind::Trait(..) => {

View File

@ -0,0 +1,129 @@
// rustfmt-wrap_comments: true
// https://github.com/rust-lang/rustfmt/issues/4909
pub enum E {
// Expand as needed, numbers should be ascending according to the stage
// through the inclusion pipeline, or according to the descriptions
Variant1,
// Expand as needed, numbers should be ascending according to the stage
// through the inclusion pipeline, or according to the descriptions
Variant2,
// Expand as needed, numbers should be ascending according to the stage
// through the inclusion pipeline, or according to the descriptions
}
pub enum E2 {
// This can be changed once https://github.com/rust-lang/rustfmt/issues/4854 is fixed
// Expand as needed, numbers should be ascending according to the stage
// through the inclusion pipeline, or according to the descriptions
}
pub enum E3 {
// Expand as needed, numbers should be ascending according to the stage through the inclusion pipeline, or according to the descriptions
Variant1,
// Expand as needed, numbers should be ascending according to the stage through the inclusion pipeline, or according to the descriptions
Variant2,
// Expand as needed, numbers should be ascending according to the stage through the inclusion pipeline, or according to the descriptions
}
pub struct S {
// Expand as needed, numbers should be ascending according to the stage
// through the inclusion pipeline, or according to the descriptions
some_field: usize,
// Expand as needed, numbers should be ascending according to the stage
// through the inclusion pipeline, or according to the descriptions
last_field: usize,
// Expand as needed, numbers should be ascending according to the stage
// through the inclusion pipeline, or according to the descriptions
}
pub struct S2 {
// This can be changed once https://github.com/rust-lang/rustfmt/issues/4854 is fixed
// Expand as needed, numbers should be ascending according to the stage
// through the inclusion pipeline, or according to the descriptions
}
pub struct S3 {
// Expand as needed, numbers should be ascending according to the stage through the inclusion pipeline, or according to the descriptions
some_field: usize,
// Expand as needed, numbers should be ascending according to the stage through the inclusion pipeline, or according to the descriptions
last_field: usize,
// Expand as needed, numbers should be ascending according to the stage through the inclusion pipeline, or according to the descriptions
}
fn foo(
// Expand as needed, numbers should be ascending according to the stage
// through the inclusion pipeline, or according to the descriptions
a: usize,
// Expand as needed, numbers should be ascending according to the stage
// through the inclusion pipeline, or according to the descriptions
b: usize,
// Expand as needed, numbers should be ascending according to the stage
// through the inclusion pipeline, or according to the descriptions
) -> usize {
5
}
fn foo2(// Expand as needed, numbers should be ascending according to the stage
// through the inclusion pipeline, or according to the descriptions
) -> usize {
5
}
fn foo3(
// Expand as needed, numbers should be ascending according to the stage through the inclusion pipeline, or according to the descriptions
a: usize,
// Expand as needed, numbers should be ascending according to the stage through the inclusion pipeline, or according to the descriptions
b: usize,
// Expand as needed, numbers should be ascending according to the stage through the inclusion pipeline, or according to the descriptions
) -> usize {
5
}
fn main() {
let v = vec![
// Expand as needed, numbers should be ascending according to the stage
// through the inclusion pipeline, or according to the descriptions
1,
// Expand as needed, numbers should be ascending according to the stage
// through the inclusion pipeline, or according to the descriptions
2,
// Expand as needed, numbers should be ascending according to the stage
// through the inclusion pipeline, or according to the descriptions
];
let v2: Vec<i32> = vec![
// Expand as needed, numbers should be ascending according to the stage
// through the inclusion pipeline, or according to the descriptions
];
let v3 = vec![
// Expand as needed, numbers should be ascending according to the stage through the inclusion pipeline, or according to the descriptions
1,
// Expand as needed, numbers should be ascending according to the stage through the inclusion pipeline, or according to the descriptions
2,
// Expand as needed, numbers should be ascending according to the stage through the inclusion pipeline, or according to the descriptions
];
// https://github.com/rust-lang/rustfmt/issues/4430
match a {
// Expand as needed, numbers should be ascending according to the stage
// through the inclusion pipeline, or according to the descriptions
b => c,
// Expand as needed, numbers should be ascending according to the stage
// through the inclusion pipeline, or according to the descriptions
d => e,
// Expand as needed, numbers should be ascending according to the stage
// through the inclusion pipeline, or according to the descriptions
}
match a {
// Expand as needed, numbers should be ascending according to the stage through the inclusion pipeline, or according to the descriptions
b => c,
// Expand as needed, numbers should be ascending according to the stage through the inclusion pipeline, or according to the descriptions
d => e,
// Expand as needed, numbers should be ascending according to the stage through the inclusion pipeline, or according to the descriptions
}
}

View File

@ -0,0 +1,130 @@
// rustfmt-normalize_comments: true
// rustfmt-wrap_comments: true
// https://github.com/rust-lang/rustfmt/issues/4909
pub enum E {
// Expand as needed, numbers should be ascending according to the stage
// through the inclusion pipeline, or according to the descriptions
Variant1,
// Expand as needed, numbers should be ascending according to the stage
// through the inclusion pipeline, or according to the descriptions
Variant2,
// Expand as needed, numbers should be ascending according to the stage
// through the inclusion pipeline, or according to the descriptions
}
pub enum E2 {
// This can be changed once https://github.com/rust-lang/rustfmt/issues/4854 is fixed
// Expand as needed, numbers should be ascending according to the stage
// through the inclusion pipeline, or according to the descriptions
}
pub enum E3 {
// Expand as needed, numbers should be ascending according to the stage through the inclusion pipeline, or according to the descriptions
Variant1,
// Expand as needed, numbers should be ascending according to the stage through the inclusion pipeline, or according to the descriptions
Variant2,
// Expand as needed, numbers should be ascending according to the stage through the inclusion pipeline, or according to the descriptions
}
pub struct S {
// Expand as needed, numbers should be ascending according to the stage
// through the inclusion pipeline, or according to the descriptions
some_field: usize,
// Expand as needed, numbers should be ascending according to the stage
// through the inclusion pipeline, or according to the descriptions
last_field: usize,
// Expand as needed, numbers should be ascending according to the stage
// through the inclusion pipeline, or according to the descriptions
}
pub struct S2 {
// This can be changed once https://github.com/rust-lang/rustfmt/issues/4854 is fixed
// Expand as needed, numbers should be ascending according to the stage
// through the inclusion pipeline, or according to the descriptions
}
pub struct S3 {
// Expand as needed, numbers should be ascending according to the stage through the inclusion pipeline, or according to the descriptions
some_field: usize,
// Expand as needed, numbers should be ascending according to the stage through the inclusion pipeline, or according to the descriptions
last_field: usize,
// Expand as needed, numbers should be ascending according to the stage through the inclusion pipeline, or according to the descriptions
}
fn foo(
// Expand as needed, numbers should be ascending according to the stage
// through the inclusion pipeline, or according to the descriptions
a: usize,
// Expand as needed, numbers should be ascending according to the stage
// through the inclusion pipeline, or according to the descriptions
b: usize,
// Expand as needed, numbers should be ascending according to the stage
// through the inclusion pipeline, or according to the descriptions
) -> usize {
5
}
fn foo2(// Expand as needed, numbers should be ascending according to the stage
// through the inclusion pipeline, or according to the descriptions
) -> usize {
5
}
fn foo3(
// Expand as needed, numbers should be ascending according to the stage through the inclusion pipeline, or according to the descriptions
a: usize,
// Expand as needed, numbers should be ascending according to the stage through the inclusion pipeline, or according to the descriptions
b: usize,
// Expand as needed, numbers should be ascending according to the stage through the inclusion pipeline, or according to the descriptions
) -> usize {
5
}
fn main() {
let v = vec![
// Expand as needed, numbers should be ascending according to the stage
// through the inclusion pipeline, or according to the descriptions
1,
// Expand as needed, numbers should be ascending according to the stage
// through the inclusion pipeline, or according to the descriptions
2,
// Expand as needed, numbers should be ascending according to the stage
// through the inclusion pipeline, or according to the descriptions
];
let v2: Vec<i32> = vec![
// Expand as needed, numbers should be ascending according to the stage
// through the inclusion pipeline, or according to the descriptions
];
let v3 = vec![
// Expand as needed, numbers should be ascending according to the stage through the inclusion pipeline, or according to the descriptions
1,
// Expand as needed, numbers should be ascending according to the stage through the inclusion pipeline, or according to the descriptions
2,
// Expand as needed, numbers should be ascending according to the stage through the inclusion pipeline, or according to the descriptions
];
// https://github.com/rust-lang/rustfmt/issues/4430
match a {
// Expand as needed, numbers should be ascending according to the stage
// through the inclusion pipeline, or according to the descriptions
b => c,
// Expand as needed, numbers should be ascending according to the stage
// through the inclusion pipeline, or according to the descriptions
d => e,
// Expand as needed, numbers should be ascending according to the stage
// through the inclusion pipeline, or according to the descriptions
}
match a {
// Expand as needed, numbers should be ascending according to the stage through the inclusion pipeline, or according to the descriptions
b => c,
// Expand as needed, numbers should be ascending according to the stage through the inclusion pipeline, or according to the descriptions
d => e,
// Expand as needed, numbers should be ascending according to the stage through the inclusion pipeline, or according to the descriptions
}
}

View File

@ -0,0 +1,33 @@
// rustfmt-wrap_comments: true
fn main() {
{
{
{
{
{
{
{
{
{
{
{
// - aaaa aaaaaaaaa aaaaaaaaa aaaaaaaaa aaaaaaaaa bbbbbbbbbb bbbbbbbbb bbbbbbbbb ccc cccccccccc ccccccc cccccccc
// * aaaa aaaaaaaaa aaaaaaaaa aaaaaaaaa aaaaaaaaa bbbbbbbbbb bbbbbbbbb bbbbbbbbb ccc cccccccccc ccccccc cccccccc
/* - aaaa aaaaaaaaa aaaaaaaaa aaaaaaaaa aaaaaaaaa bbbbbbbbbb bbbbbbbbb bbbbbbbbb ccc cccccccccc ccccccc cccccccc */
/* * aaaa aaaaaaaaa aaaaaaaaa aaaaaaaaa aaaaaaaaa bbbbbbbbbb bbbbbbbbb bbbbbbbbb ccc cccccccccc ccccccc cccccccc */
};
};
};
};
};
};
};
};
};
};
};
}

View File

@ -0,0 +1,19 @@
// rustfmt-wrap_comments: true
//
// - Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
// - Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
//
// * Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
// * Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
/*
* - Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.*/
/*
* - Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.*/
/*
* * Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.*/
/*
* * Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.*/

View File

@ -0,0 +1,13 @@
// rustfmt-wrap_comments: true
// - Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
// - Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
// * Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
// * Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
/* - Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.*/
/* - Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.*/
/* * Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.*/
/* * Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.*/

View File

@ -0,0 +1,5 @@
macro_rules! m {
() => {
type Type;
};
}

View File

@ -0,0 +1,7 @@
// rustfmt-version: Two
pub type Iter<'a, D> = impl DoubleEndedIterator<Item = (SomethingSomethingSomethingLongType<D>)>+ ExactSizeIterator+ 'a;
trait FOo {pub type Iter<'a, D> = impl DoubleEndedIterator<Item = (SomethingSomethingSomethingLongType<D>)>+ ExactSizeIterator+ 'a;}
impl Bar {pub type Iter<'a, D> = impl DoubleEndedIterator<Item = (SomethingSomethingSomethingLongType<D>)>+ ExactSizeIterator+ 'a;}

View File

@ -0,0 +1,2 @@
#[cfg(any())]
type Type : Bound ;

View File

@ -0,0 +1,96 @@
// rustfmt-format_code_in_doc_comments: true
// https://github.com/rust-lang/rustfmt/issues/4420
enum Minimal {
Example,
//[thisisremoved thatsleft
// canbeanything
}
struct Minimal2 {
Example: usize,
//[thisisremoved thatsleft
// canbeanything
}
pub enum E {
// Expand as needed, numbers should be ascending according to the stage
// through the inclusion pipeline, or according to the descriptions
Variant1,
// Expand as needed, numbers should be ascending according to the stage
// through the inclusion pipeline, or according to the descriptions
Variant2,
// Expand as needed, numbers should be ascending according to the stage
// through the inclusion pipeline, or according to the descriptions
}
pub enum E2 {
// This can be changed once https://github.com/rust-lang/rustfmt/issues/4854 is fixed
// Expand as needed, numbers should be ascending according to the stage
// through the inclusion pipeline, or according to the descriptions
}
pub struct S {
// Expand as needed, numbers should be ascending according to the stage
// through the inclusion pipeline, or according to the descriptions
some_field: usize,
// Expand as needed, numbers should be ascending according to the stage
// through the inclusion pipeline, or according to the descriptions
last_field: usize,
// Expand as needed, numbers should be ascending according to the stage
// through the inclusion pipeline, or according to the descriptions
}
pub struct S2 {
// This can be changed once https://github.com/rust-lang/rustfmt/issues/4854 is fixed
// Expand as needed, numbers should be ascending according to the stage
// through the inclusion pipeline, or according to the descriptions
}
fn foo(
// Expand as needed, numbers should be ascending according to the stage
// through the inclusion pipeline, or according to the descriptions
a: usize,
// Expand as needed, numbers should be ascending according to the stage
// through the inclusion pipeline, or according to the descriptions
b: usize,
// Expand as needed, numbers should be ascending according to the stage
// through the inclusion pipeline, or according to the descriptions
) -> usize {
5
}
fn foo2(// Expand as needed, numbers should be ascending according to the stage
// through the inclusion pipeline, or according to the descriptions
) -> usize {
5
}
fn main() {
let v = vec![
// Expand as needed, numbers should be ascending according to the stage
// through the inclusion pipeline, or according to the descriptions
1,
// Expand as needed, numbers should be ascending according to the stage
// through the inclusion pipeline, or according to the descriptions
2,
// Expand as needed, numbers should be ascending according to the stage
// through the inclusion pipeline, or according to the descriptions
];
let v2: Vec<i32> = vec![
// Expand as needed, numbers should be ascending according to the stage
// through the inclusion pipeline, or according to the descriptions
];
match a {
// Expand as needed, numbers should be ascending according to the stage
// through the inclusion pipeline, or according to the descriptions
b => c,
// Expand as needed, numbers should be ascending according to the stage
// through the inclusion pipeline, or according to the descriptions
d => e,
// Expand as needed, numbers should be ascending according to the stage
// through the inclusion pipeline, or according to the descriptions
}
}

View File

@ -0,0 +1,85 @@
// rustfmt-normalize_comments: true
// https://github.com/rust-lang/rustfmt/issues/4909
pub enum E {
// Expand as needed, numbers should be ascending according to the stage
// through the inclusion pipeline, or according to the descriptions
Variant1,
// Expand as needed, numbers should be ascending according to the stage
// through the inclusion pipeline, or according to the descriptions
Variant2,
// Expand as needed, numbers should be ascending according to the stage
// through the inclusion pipeline, or according to the descriptions
}
pub enum E2 {
// This can be changed once https://github.com/rust-lang/rustfmt/issues/4854 is fixed
// Expand as needed, numbers should be ascending according to the stage
// through the inclusion pipeline, or according to the descriptions
}
pub struct S {
// Expand as needed, numbers should be ascending according to the stage
// through the inclusion pipeline, or according to the descriptions
some_field: usize,
// Expand as needed, numbers should be ascending according to the stage
// through the inclusion pipeline, or according to the descriptions
last_field: usize,
// Expand as needed, numbers should be ascending according to the stage
// through the inclusion pipeline, or according to the descriptions
}
pub struct S2 {
// This can be changed once https://github.com/rust-lang/rustfmt/issues/4854 is fixed
// Expand as needed, numbers should be ascending according to the stage
// through the inclusion pipeline, or according to the descriptions
}
fn foo(
// Expand as needed, numbers should be ascending according to the stage
// through the inclusion pipeline, or according to the descriptions
a: usize,
// Expand as needed, numbers should be ascending according to the stage
// through the inclusion pipeline, or according to the descriptions
b: usize,
// Expand as needed, numbers should be ascending according to the stage
// through the inclusion pipeline, or according to the descriptions
) -> usize {
5
}
fn foo2(// Expand as needed, numbers should be ascending according to the stage
// through the inclusion pipeline, or according to the descriptions
) -> usize {
5
}
fn main() {
let v = vec![
// Expand as needed, numbers should be ascending according to the stage
// through the inclusion pipeline, or according to the descriptions
1,
// Expand as needed, numbers should be ascending according to the stage
// through the inclusion pipeline, or according to the descriptions
2,
// Expand as needed, numbers should be ascending according to the stage
// through the inclusion pipeline, or according to the descriptions
];
let v2: Vec<i32> = vec![
// Expand as needed, numbers should be ascending according to the stage
// through the inclusion pipeline, or according to the descriptions
];
// https://github.com/rust-lang/rustfmt/issues/4430
match a {
// Expand as needed, numbers should be ascending according to the stage
// through the inclusion pipeline, or according to the descriptions
b => c,
// Expand as needed, numbers should be ascending according to the stage
// through the inclusion pipeline, or according to the descriptions
d => e,
// Expand as needed, numbers should be ascending according to the stage
// through the inclusion pipeline, or according to the descriptions
}
}

View File

@ -0,0 +1,142 @@
// rustfmt-wrap_comments: true
// https://github.com/rust-lang/rustfmt/issues/4909
pub enum E {
// Expand as needed, numbers should be ascending according to the stage
// through the inclusion pipeline, or according to the descriptions
Variant1,
// Expand as needed, numbers should be ascending according to the stage
// through the inclusion pipeline, or according to the descriptions
Variant2,
// Expand as needed, numbers should be ascending according to the stage
// through the inclusion pipeline, or according to the descriptions
}
pub enum E2 {
// This can be changed once https://github.com/rust-lang/rustfmt/issues/4854 is fixed
// Expand as needed, numbers should be ascending according to the stage
// through the inclusion pipeline, or according to the descriptions
}
pub enum E3 {
// Expand as needed, numbers should be ascending according to the stage through the inclusion
// pipeline, or according to the descriptions
Variant1,
// Expand as needed, numbers should be ascending according to the stage through the inclusion
// pipeline, or according to the descriptions
Variant2,
// Expand as needed, numbers should be ascending according to the stage through the inclusion
// pipeline, or according to the descriptions
}
pub struct S {
// Expand as needed, numbers should be ascending according to the stage
// through the inclusion pipeline, or according to the descriptions
some_field: usize,
// Expand as needed, numbers should be ascending according to the stage
// through the inclusion pipeline, or according to the descriptions
last_field: usize,
// Expand as needed, numbers should be ascending according to the stage
// through the inclusion pipeline, or according to the descriptions
}
pub struct S2 {
// This can be changed once https://github.com/rust-lang/rustfmt/issues/4854 is fixed
// Expand as needed, numbers should be ascending according to the stage
// through the inclusion pipeline, or according to the descriptions
}
pub struct S3 {
// Expand as needed, numbers should be ascending according to the stage through the inclusion
// pipeline, or according to the descriptions
some_field: usize,
// Expand as needed, numbers should be ascending according to the stage through the inclusion
// pipeline, or according to the descriptions
last_field: usize,
// Expand as needed, numbers should be ascending according to the stage through the inclusion
// pipeline, or according to the descriptions
}
fn foo(
// Expand as needed, numbers should be ascending according to the stage
// through the inclusion pipeline, or according to the descriptions
a: usize,
// Expand as needed, numbers should be ascending according to the stage
// through the inclusion pipeline, or according to the descriptions
b: usize,
// Expand as needed, numbers should be ascending according to the stage
// through the inclusion pipeline, or according to the descriptions
) -> usize {
5
}
fn foo2(// Expand as needed, numbers should be ascending according to the stage
// through the inclusion pipeline, or according to the descriptions
) -> usize {
5
}
fn foo3(
// Expand as needed, numbers should be ascending according to the stage through the inclusion
// pipeline, or according to the descriptions
a: usize,
// Expand as needed, numbers should be ascending according to the stage through the inclusion
// pipeline, or according to the descriptions
b: usize,
// Expand as needed, numbers should be ascending according to the stage through the inclusion
// pipeline, or according to the descriptions
) -> usize {
5
}
fn main() {
let v = vec![
// Expand as needed, numbers should be ascending according to the stage
// through the inclusion pipeline, or according to the descriptions
1,
// Expand as needed, numbers should be ascending according to the stage
// through the inclusion pipeline, or according to the descriptions
2,
// Expand as needed, numbers should be ascending according to the stage
// through the inclusion pipeline, or according to the descriptions
];
let v2: Vec<i32> = vec![
// Expand as needed, numbers should be ascending according to the stage
// through the inclusion pipeline, or according to the descriptions
];
let v3 = vec![
// Expand as needed, numbers should be ascending according to the stage through the
// inclusion pipeline, or according to the descriptions
1,
// Expand as needed, numbers should be ascending according to the stage through the
// inclusion pipeline, or according to the descriptions
2,
// Expand as needed, numbers should be ascending according to the stage through the
// inclusion pipeline, or according to the descriptions
];
// https://github.com/rust-lang/rustfmt/issues/4430
match a {
// Expand as needed, numbers should be ascending according to the stage
// through the inclusion pipeline, or according to the descriptions
b => c,
// Expand as needed, numbers should be ascending according to the stage
// through the inclusion pipeline, or according to the descriptions
d => e,
// Expand as needed, numbers should be ascending according to the stage
// through the inclusion pipeline, or according to the descriptions
}
match a {
// Expand as needed, numbers should be ascending according to the stage through the
// inclusion pipeline, or according to the descriptions
b => c,
// Expand as needed, numbers should be ascending according to the stage through the
// inclusion pipeline, or according to the descriptions
d => e,
// Expand as needed, numbers should be ascending according to the stage through the
// inclusion pipeline, or according to the descriptions
}
}

View File

@ -0,0 +1,143 @@
// rustfmt-normalize_comments: true
// rustfmt-wrap_comments: true
// https://github.com/rust-lang/rustfmt/issues/4909
pub enum E {
// Expand as needed, numbers should be ascending according to the stage
// through the inclusion pipeline, or according to the descriptions
Variant1,
// Expand as needed, numbers should be ascending according to the stage
// through the inclusion pipeline, or according to the descriptions
Variant2,
// Expand as needed, numbers should be ascending according to the stage
// through the inclusion pipeline, or according to the descriptions
}
pub enum E2 {
// This can be changed once https://github.com/rust-lang/rustfmt/issues/4854 is fixed
// Expand as needed, numbers should be ascending according to the stage
// through the inclusion pipeline, or according to the descriptions
}
pub enum E3 {
// Expand as needed, numbers should be ascending according to the stage through the inclusion
// pipeline, or according to the descriptions
Variant1,
// Expand as needed, numbers should be ascending according to the stage through the inclusion
// pipeline, or according to the descriptions
Variant2,
// Expand as needed, numbers should be ascending according to the stage through the inclusion
// pipeline, or according to the descriptions
}
pub struct S {
// Expand as needed, numbers should be ascending according to the stage
// through the inclusion pipeline, or according to the descriptions
some_field: usize,
// Expand as needed, numbers should be ascending according to the stage
// through the inclusion pipeline, or according to the descriptions
last_field: usize,
// Expand as needed, numbers should be ascending according to the stage
// through the inclusion pipeline, or according to the descriptions
}
pub struct S2 {
// This can be changed once https://github.com/rust-lang/rustfmt/issues/4854 is fixed
// Expand as needed, numbers should be ascending according to the stage
// through the inclusion pipeline, or according to the descriptions
}
pub struct S3 {
// Expand as needed, numbers should be ascending according to the stage through the inclusion
// pipeline, or according to the descriptions
some_field: usize,
// Expand as needed, numbers should be ascending according to the stage through the inclusion
// pipeline, or according to the descriptions
last_field: usize,
// Expand as needed, numbers should be ascending according to the stage through the inclusion
// pipeline, or according to the descriptions
}
fn foo(
// Expand as needed, numbers should be ascending according to the stage
// through the inclusion pipeline, or according to the descriptions
a: usize,
// Expand as needed, numbers should be ascending according to the stage
// through the inclusion pipeline, or according to the descriptions
b: usize,
// Expand as needed, numbers should be ascending according to the stage
// through the inclusion pipeline, or according to the descriptions
) -> usize {
5
}
fn foo2(// Expand as needed, numbers should be ascending according to the stage
// through the inclusion pipeline, or according to the descriptions
) -> usize {
5
}
fn foo3(
// Expand as needed, numbers should be ascending according to the stage through the inclusion
// pipeline, or according to the descriptions
a: usize,
// Expand as needed, numbers should be ascending according to the stage through the inclusion
// pipeline, or according to the descriptions
b: usize,
// Expand as needed, numbers should be ascending according to the stage through the inclusion
// pipeline, or according to the descriptions
) -> usize {
5
}
fn main() {
let v = vec![
// Expand as needed, numbers should be ascending according to the stage
// through the inclusion pipeline, or according to the descriptions
1,
// Expand as needed, numbers should be ascending according to the stage
// through the inclusion pipeline, or according to the descriptions
2,
// Expand as needed, numbers should be ascending according to the stage
// through the inclusion pipeline, or according to the descriptions
];
let v2: Vec<i32> = vec![
// Expand as needed, numbers should be ascending according to the stage
// through the inclusion pipeline, or according to the descriptions
];
let v3 = vec![
// Expand as needed, numbers should be ascending according to the stage through the
// inclusion pipeline, or according to the descriptions
1,
// Expand as needed, numbers should be ascending according to the stage through the
// inclusion pipeline, or according to the descriptions
2,
// Expand as needed, numbers should be ascending according to the stage through the
// inclusion pipeline, or according to the descriptions
];
// https://github.com/rust-lang/rustfmt/issues/4430
match a {
// Expand as needed, numbers should be ascending according to the stage
// through the inclusion pipeline, or according to the descriptions
b => c,
// Expand as needed, numbers should be ascending according to the stage
// through the inclusion pipeline, or according to the descriptions
d => e,
// Expand as needed, numbers should be ascending according to the stage
// through the inclusion pipeline, or according to the descriptions
}
match a {
// Expand as needed, numbers should be ascending according to the stage through the
// inclusion pipeline, or according to the descriptions
b => c,
// Expand as needed, numbers should be ascending according to the stage through the
// inclusion pipeline, or according to the descriptions
d => e,
// Expand as needed, numbers should be ascending according to the stage through the
// inclusion pipeline, or according to the descriptions
}
}

View File

@ -0,0 +1,33 @@
// rustfmt-wrap_comments: false
fn main() {
{
{
{
{
{
{
{
{
{
{
{
// - aaaa aaaaaaaaa aaaaaaaaa aaaaaaaaa aaaaaaaaa bbbbbbbbbb bbbbbbbbb bbbbbbbbb ccc cccccccccc ccccccc cccccccc
// * aaaa aaaaaaaaa aaaaaaaaa aaaaaaaaa aaaaaaaaa bbbbbbbbbb bbbbbbbbb bbbbbbbbb ccc cccccccccc ccccccc cccccccc
/* - aaaa aaaaaaaaa aaaaaaaaa aaaaaaaaa aaaaaaaaa bbbbbbbbbb bbbbbbbbb bbbbbbbbb ccc cccccccccc ccccccc cccccccc */
/* * aaaa aaaaaaaaa aaaaaaaaa aaaaaaaaa aaaaaaaaa bbbbbbbbbb bbbbbbbbb bbbbbbbbb ccc cccccccccc ccccccc cccccccc */
};
};
};
};
};
};
};
};
};
};
};
}

View File

@ -0,0 +1,49 @@
// rustfmt-wrap_comments: true
fn main() {
{
{
{
{
{
{
{
{
{
{
{
// - aaaa aaaaaaaaa aaaaaaaaa
// aaaaaaaaa aaaaaaaaa
// bbbbbbbbbb bbbbbbbbb
// bbbbbbbbb ccc cccccccccc
// ccccccc cccccccc
// * aaaa aaaaaaaaa aaaaaaaaa
// aaaaaaaaa aaaaaaaaa
// bbbbbbbbbb bbbbbbbbb
// bbbbbbbbb ccc cccccccccc
// ccccccc cccccccc
/* - aaaa aaaaaaaaa aaaaaaaaa
* aaaaaaaaa aaaaaaaaa
* bbbbbbbbbb bbbbbbbbb
* bbbbbbbbb ccc cccccccccc
* ccccccc cccccccc */
/* * aaaa aaaaaaaaa aaaaaaaaa
* aaaaaaaaa aaaaaaaaa
* bbbbbbbbbb bbbbbbbbb
* bbbbbbbbb ccc cccccccccc
* ccccccc cccccccc */
};
};
};
};
};
};
};
};
};
};
};
}

View File

@ -0,0 +1,17 @@
// rustfmt-wrap_comments: false
// - some itemized block 1
// - some itemized block 2
// * some itemized block 3
// * some itemized block 4
/*
* - some itemized block 5
* - some itemized block 6
*/
/*
* * some itemized block 7
* * some itemized block 8
*/

View File

@ -0,0 +1,17 @@
// rustfmt-wrap_comments: true
// - some itemized block 1
// - some itemized block 2
// * some itemized block 3
// * some itemized block 4
/*
* - some itemized block 5
* - some itemized block 6
*/
/*
* * some itemized block 7
* * some itemized block 8
*/

View File

@ -0,0 +1,37 @@
// rustfmt-wrap_comments: false
// Some text
// - some itemized block 1
// - some itemized block 2
// Some more text
// - some itemized block 3
// - some itemized block 4
// Even more text
// Some text
// * some itemized block 5
// * some itemized block 6
// Some more text
// * some itemized block 7
// * some itemized block 8
// Even more text
/*
* Some text
* - some itemized block 9
* - some itemized block 10
* Some more text
* - some itemized block 11
* - some itemized block 12
* Even more text
*/
/*
* Some text
* * some itemized block 13
* * some itemized block 14
* Some more text
* * some itemized block 15
* * some itemized block 16
* Even more text
*/

View File

@ -0,0 +1,37 @@
// rustfmt-wrap_comments: true
// Some text
// - some itemized block 1
// - some itemized block 2
// Some more text
// - some itemized block 3
// - some itemized block 4
// Even more text
// Some text
// * some itemized block 5
// * some itemized block 6
// Some more text
// * some itemized block 7
// * some itemized block 8
// Even more text
/*
* Some text
* - some itemized block 9
* - some itemized block 10
* Some more text
* - some itemized block 11
* - some itemized block 12
* Even more text
*/
/*
* Some text
* * some itemized block 13
* * some itemized block 14
* Some more text
* * some itemized block 15
* * some itemized block 16
* Even more text
*/

View File

@ -0,0 +1,9 @@
// rustfmt-wrap_comments: false
// - some itemized block 1
// * some itemized block 2
/* - some itemized block 3 */
/* * some itemized block 4 */

View File

@ -0,0 +1,9 @@
// rustfmt-wrap_comments: true
// - some itemized block 1
// * some itemized block 2
/* - some itemized block 3 */
/* * some itemized block 4 */

View File

@ -0,0 +1,19 @@
// rustfmt-wrap_comments: false
//
// - Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
// - Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
//
// * Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
// * Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
/*
* - Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.*/
/*
* - Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.*/
/*
* * Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.*/
/*
* * Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.*/

View File

@ -0,0 +1,27 @@
// rustfmt-wrap_comments: true
//
// - Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod
// tempor incididunt ut labore et dolore magna aliqua.
// - Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod
// tempor incididunt ut labore et dolore magna aliqua.
//
// * Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod
// tempor incididunt ut labore et dolore magna aliqua.
// * Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod
// tempor incididunt ut labore et dolore magna aliqua.
/*
* - Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod
* tempor incididunt ut labore et dolore magna aliqua. */
/*
* - Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod
* tempor incididunt ut labore et dolore magna aliqua. */
/*
* * Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod
* tempor incididunt ut labore et dolore magna aliqua. */
/*
* * Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod
* tempor incididunt ut labore et dolore magna aliqua. */

View File

@ -0,0 +1,17 @@
// rustfmt-wrap_comments: false
//
// - some itemized block 1
// - some itemized block 2
//
// * some itemized block 3
// * some itemized block 4
/*
* - some itemized block 5
* - some itemized block 6 */
/*
* * some itemized block 7
* * some itemized block 8 */

View File

@ -0,0 +1,17 @@
// rustfmt-wrap_comments: true
//
// - some itemized block 1
// - some itemized block 2
//
// * some itemized block 3
// * some itemized block 4
/*
* - some itemized block 5
* - some itemized block 6 */
/*
* * some itemized block 7
* * some itemized block 8 */

View File

@ -0,0 +1,13 @@
// rustfmt-wrap_comments: false
// - Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
// - Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
// * Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
// * Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
/* - Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.*/
/* - Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.*/
/* * Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.*/
/* * Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.*/

View File

@ -0,0 +1,21 @@
// rustfmt-wrap_comments: true
// - Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod
// tempor incididunt ut labore et dolore magna aliqua.
// - Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod
// tempor incididunt ut labore et dolore magna aliqua.
// * Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod
// tempor incididunt ut labore et dolore magna aliqua.
// * Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod
// tempor incididunt ut labore et dolore magna aliqua.
/* - Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod
* tempor incididunt ut labore et dolore magna aliqua. */
/* - Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod
* tempor incididunt ut labore et dolore magna aliqua. */
/* * Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod
* tempor incididunt ut labore et dolore magna aliqua. */
/* * Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod
* tempor incididunt ut labore et dolore magna aliqua. */

View File

@ -0,0 +1,27 @@
// rustfmt-wrap_comments: true
pub mod a_long_name {
pub mod b_long_name {
pub mod c_long_name {
pub mod d_long_name {
pub mod e_long_name {
pub struct Bananas;
impl Bananas {
pub fn fantastic() {}
}
pub mod f_long_name {
pub struct Apples;
}
}
}
}
}
}
/// Check out [my other struct] ([`Bananas`]) and [the method it has].
///
/// [my other struct]: a_long_name::b_long_name::c_long_name::d_long_name::e_long_name::f_long_name::Apples
/// [`Bananas`]: a_long_name::b_long_name::c_long_name::d_long_name::e_long_name::Bananas::fantastic()
/// [the method it has]: a_long_name::b_long_name::c_long_name::d_long_name::e_long_name::Bananas::fantastic()
pub struct A;

View File

@ -0,0 +1,5 @@
macro_rules! m {
() => {
type Type;
};
}

View File

@ -0,0 +1,17 @@
// rustfmt-version: Two
pub type Iter<'a, D> = impl DoubleEndedIterator<Item = (SomethingSomethingSomethingLongType<D>)>
+ ExactSizeIterator
+ 'a;
trait FOo {
pub type Iter<'a, D> = impl DoubleEndedIterator<Item = (SomethingSomethingSomethingLongType<D>)>
+ ExactSizeIterator
+ 'a;
}
impl Bar {
type Iter<'a, D> = impl DoubleEndedIterator<Item = (SomethingSomethingSomethingLongType<D>)>
+ ExactSizeIterator
+ 'a;
}

View File

@ -0,0 +1,2 @@
#[cfg(any())]
type Type: Bound;