Repository: rust-lang/rustfmt (Rust)

Issue:
`...` operator spacing not enforced when `spaces_around_ranges=true`
Configurations.md has this to say about `spaces_around_ranges`:
> Put spaces around the .. and ... range operators

This is not working in the `true` case for `...`.

**Reproduction:**
1. Create a rustfmt.toml containing `spaces_around_ranges=true`.
1. Run rustfmt on the following file.
```rust
fn main() {
    match x {
        1...5 => foo(),
        _ => bar(),
    }
}
```

**Expected:**
The following diff.
```diff
 fn main() {⏎
     match x {⏎
-        1...5 => foo(),⏎
+        1 ... 5 => foo(),⏎
         _ => bar(),⏎
     }⏎
 }⏎
```

**Actual:**
rustfmt generates no diff.

Note: the reverse situation (`spaces_around_ranges=false`) with starting code containing spaces does generate a diff.


Discussion:
From the code, it looks like this applies to `..=`. For instance, the following should generate a diff when `spaces_around_ranges=true`.
```rust
let lorem = 0..=10;
```
Relevant commit: 2886000.
Since `...` is still legal rust, it would be nice if it is still formatted, especially for projects targeting older rust versions. Could both be supported concurrently?
Just testing now, I found that the `...` syntax is an error, as of [Rust v1.23](https://github.com/rust-lang/rust/releases/tag/1.23.0), which was tagged on January 4. The relevant commit is rust-lang/rust@3c41c28.

**Examples:**
Compiling this:
```rust
fn main() {
    let lorem = 0...5;
}
```

Gets this:
```
error: `...` syntax cannot be used in expressions
 --> /Users/davidalber/dev/rustfmt/c.rs:2:18
  |
2 |     let lorem = 0...5;
  |                  ^^^
  |
  = help: Use `..` if you need an exclusive range (a < b)
  = help: or `..=` if you need an inclusive range (a <= b)
```

Compiling this:
```rust
fn main() {
    for i in 1 ... 5 {
        // something
    }
}
```

Gets this:
```
error: `...` syntax cannot be used in expressions
 --> /Users/davidalber/dev/rustfmt/c.rs:2:16
  |
2 |     for i in 1 ... 5 {
  |                ^^^
  |
  = help: Use `..` if you need an exclusive range (a < b)
  = help: or `..=` if you need an inclusive range (a <= b)
```
@davidalber for ranges, sure, but it's always been supported in patterns, like the OP example.

This compiles with no warnings nor errors on rust 1.23.0 stable and 1.25.0 nightly:

```rust
fn main() {
    let x = 10;
    
    match x {
        1...5 => println!("1-5"),
        _ => println!("other"),
    }
}
```

https://play.rust-lang.org/?gist=0d3ee61a1486a12995e0053a36ed0792&version=stable

`...` will eventually be replaced with `..=` in patterns too, but currently, `...` is the de facto solution. 

Crates supporting stable rust versions need to use  `...` now, and crates supporting older rust versions will need it far into the future (`..=` isn't even stabilized yet). These crates should not be abandoned by rustfmt just because it supports nightly features.
Since beginning to investigate this it's become clear that this configuration option does not affect ranges in match arms. That may be a bug, but you might be happy to know that `...` is handled in [the code that formats match arm ranges](https://github.com/rust-lang-nursery/rustfmt/blob/master/src/patterns.rs#L64). I'll probably set up a PR to extend `spaces_around_ranges` to that case.
We can support `...` for as long as it can be parsed by the Rust parser. That is likely to be at least as long as it is a warning rather than an error, and maybe for some time afterwards, but we are somewhat at the mercy of the compiler.



Patch:
diff --git a/Configurations.md b/Configurations.md
index 1b9c13ae39d..659784bfd78 100644
--- a/Configurations.md
+++ b/Configurations.md
@@ -1468,7 +1468,7 @@ struct Foo {
 
 ## `spaces_around_ranges`
 
-Put spaces around the .. and ... range operators
+Put spaces around the .., ..=, and ... range operators
 
 - **Default value**: `false`
 - **Possible values**: `true`, `false`
@@ -1477,13 +1477,49 @@ Put spaces around the .. and ... range operators
 #### `false` (default):
 
 ```rust
-let lorem = 0..10;
+fn main() {
+    let lorem = 0..10;
+    let ipsum = 0..=10;
+
+    match lorem {
+        1..5 => foo(),
+        _ => bar,
+    }
+
+    match lorem {
+        1..=5 => foo(),
+        _ => bar,
+    }
+
+    match lorem {
+        1...5 => foo(),
+        _ => bar,
+    }
+}
 ```
 
 #### `true`:
 
 ```rust
-let lorem = 0 .. 10;
+fn main() {
+    let lorem = 0 .. 10;
+    let ipsum = 0 ..= 10;
+
+    match lorem {
+        1 .. 5 => foo(),
+        _ => bar,
+    }
+
+    match lorem {
+        1 ..= 5 => foo(),
+        _ => bar,
+    }
+
+    match lorem {
+        1 ... 5 => foo(),
+        _ => bar,
+    }
+}
 ```
 
 ## `spaces_within_parens_and_brackets`
diff --git a/src/patterns.rs b/src/patterns.rs
index f877239f518..4719160061b 100644
--- a/src/patterns.rs
+++ b/src/patterns.rs
@@ -65,10 +65,15 @@ impl Rewrite for Pat {
                     RangeEnd::Included(RangeSyntax::DotDotEq) => "..=",
                     RangeEnd::Excluded => "..",
                 };
+                let infix = if context.config.spaces_around_ranges() {
+                    format!(" {} ", infix)
+                } else {
+                    infix.to_owned()
+                };
                 rewrite_pair(
                     &**lhs,
                     &**rhs,
-                    PairParts::new("", infix, ""),
+                    PairParts::new("", &infix, ""),
                     context,
                     shape,
                     SeparatorPlace::Front,


Test patch:
diff --git a/tests/source/configs/spaces_around_ranges/false.rs b/tests/source/configs/spaces_around_ranges/false.rs
index 3d431e4d1ce..11ca76b1345 100644
--- a/tests/source/configs/spaces_around_ranges/false.rs
+++ b/tests/source/configs/spaces_around_ranges/false.rs
@@ -2,5 +2,21 @@
 // Spaces around ranges
 
 fn main() {
-    let lorem = 0..10;
+    let lorem = 0 .. 10;
+    let ipsum = 0 ..= 10;
+
+    match lorem {
+        1 .. 5 => foo(),
+        _ => bar,
+    }
+
+    match lorem {
+        1 ..= 5 => foo(),
+        _ => bar,
+    }
+
+    match lorem {
+        1 ... 5 => foo(),
+        _ => bar,
+    }
 }
diff --git a/tests/source/configs/spaces_around_ranges/true.rs b/tests/source/configs/spaces_around_ranges/true.rs
index 8e9a311abf3..50170892130 100644
--- a/tests/source/configs/spaces_around_ranges/true.rs
+++ b/tests/source/configs/spaces_around_ranges/true.rs
@@ -3,4 +3,20 @@
 
 fn main() {
     let lorem = 0..10;
+    let ipsum = 0..=10;
+
+    match lorem {
+        1..5 => foo(),
+        _ => bar,
+    }
+
+    match lorem {
+        1..=5 => foo(),
+        _ => bar,
+    }
+
+    match lorem {
+        1...5 => foo(),
+        _ => bar,
+    }
 }
diff --git a/tests/target/configs/spaces_around_ranges/false.rs b/tests/target/configs/spaces_around_ranges/false.rs
index 3d431e4d1ce..6319da98572 100644
--- a/tests/target/configs/spaces_around_ranges/false.rs
+++ b/tests/target/configs/spaces_around_ranges/false.rs
@@ -3,4 +3,20 @@
 
 fn main() {
     let lorem = 0..10;
+    let ipsum = 0..=10;
+
+    match lorem {
+        1..5 => foo(),
+        _ => bar,
+    }
+
+    match lorem {
+        1..=5 => foo(),
+        _ => bar,
+    }
+
+    match lorem {
+        1...5 => foo(),
+        _ => bar,
+    }
 }
diff --git a/tests/target/configs/spaces_around_ranges/true.rs b/tests/target/configs/spaces_around_ranges/true.rs
index 2a456a6daea..7bfcc23c8ea 100644
--- a/tests/target/configs/spaces_around_ranges/true.rs
+++ b/tests/target/configs/spaces_around_ranges/true.rs
@@ -3,4 +3,20 @@
 
 fn main() {
     let lorem = 0 .. 10;
+    let ipsum = 0 ..= 10;
+
+    match lorem {
+        1 .. 5 => foo(),
+        _ => bar,
+    }
+
+    match lorem {
+        1 ..= 5 => foo(),
+        _ => bar,
+    }
+
+    match lorem {
+        1 ... 5 => foo(),
+        _ => bar,
+    }
 }