From 3bc17c4d7bf4c43ccae82d7e5e3330fa4ca32e79 Mon Sep 17 00:00:00 2001
From: Caleb Cartwright <caleb.cartwright@outlook.com>
Date: Mon, 30 Mar 2020 22:40:12 -0500
Subject: [PATCH 1/3] feat: support raw reference operator

---
 src/expr.rs          | 10 ++++++----
 tests/source/expr.rs |  4 ++++
 tests/target/expr.rs |  4 ++++
 3 files changed, 14 insertions(+), 4 deletions(-)

diff --git a/src/expr.rs b/src/expr.rs
index 8545b0f6f29..ed10a54c2a3 100644
--- a/src/expr.rs
+++ b/src/expr.rs
@@ -1988,14 +1988,16 @@ pub(crate) fn prefer_next_line(
 
 fn rewrite_expr_addrof(
     context: &RewriteContext<'_>,
-    _borrow_kind: ast::BorrowKind,
+    borrow_kind: ast::BorrowKind,
     mutability: ast::Mutability,
     expr: &ast::Expr,
     shape: Shape,
 ) -> Option<String> {
-    let operator_str = match mutability {
-        ast::Mutability::Not => "&",
-        ast::Mutability::Mut => "&mut ",
+    let operator_str = match (mutability, borrow_kind) {
+        (ast::Mutability::Not, ast::BorrowKind::Ref) => "&",
+        (ast::Mutability::Not, ast::BorrowKind::Raw) => "&raw const ",
+        (ast::Mutability::Mut, ast::BorrowKind::Ref) => "&mut ",
+        (ast::Mutability::Mut, ast::BorrowKind::Raw) => "&raw mut ",
     };
     rewrite_unary_prefix(context, operator_str, expr, shape)
 }
diff --git a/tests/source/expr.rs b/tests/source/expr.rs
index 05af07f231b..8a6e6f1aa2b 100644
--- a/tests/source/expr.rs
+++ b/tests/source/expr.rs
@@ -218,6 +218,10 @@ fn returns() {
 fn addrof() {
     &    mut(aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa+bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb);
     &    (aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa+bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb);
+
+    // raw reference operator
+    & raw   const  a;
+    & raw   mut    b;
 }
 
 fn casts() {
diff --git a/tests/target/expr.rs b/tests/target/expr.rs
index c50693049a2..5d9e972066c 100644
--- a/tests/target/expr.rs
+++ b/tests/target/expr.rs
@@ -253,6 +253,10 @@ fn addrof() {
         + bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb);
     &(aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
         + bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb);
+
+    // raw reference operator
+    &raw const a;
+    &raw mut b;
 }
 
 fn casts() {

From b2123e400cf1c5d217aeb7c8f44cbaefe69f2376 Mon Sep 17 00:00:00 2001
From: Caleb Cartwright <caleb.cartwright@outlook.com>
Date: Mon, 30 Mar 2020 22:44:36 -0500
Subject: [PATCH 2/3] feat: support const opt-out syntax

---
 src/types.rs         |  7 ++++++-
 tests/source/type.rs | 27 +++++++++++++++++++++++++++
 tests/target/type.rs | 33 +++++++++++++++++++++++++++++++++
 3 files changed, 66 insertions(+), 1 deletion(-)

diff --git a/src/types.rs b/src/types.rs
index 4f92ff6246f..96e331779c4 100644
--- a/src/types.rs
+++ b/src/types.rs
@@ -527,7 +527,12 @@ impl Rewrite for ast::GenericBound {
                     ast::TraitBoundModifier::Maybe => poly_trait_ref
                         .rewrite(context, shape.offset_left(1)?)
                         .map(|s| format!("?{}", s)),
-                    _ => unimplemented!(),
+                    ast::TraitBoundModifier::MaybeConst => poly_trait_ref
+                        .rewrite(context, shape.offset_left(7)?)
+                        .map(|s| format!("?const {}", s)),
+                    ast::TraitBoundModifier::MaybeConstMaybe => poly_trait_ref
+                        .rewrite(context, shape.offset_left(8)?)
+                        .map(|s| format!("?const ?{}", s)),
                 };
                 rewrite.map(|s| if has_paren { format!("({})", s) } else { s })
             }
diff --git a/tests/source/type.rs b/tests/source/type.rs
index 27387c5bdca..eb4600e5bce 100644
--- a/tests/source/type.rs
+++ b/tests/source/type.rs
@@ -139,3 +139,30 @@ fn foo(a: SomeLongComplexType, b: SomeOtherLongComplexType) -> Box<Future<Item =
 }
 
 type MyFn = fn(a: SomeLongComplexType, b: SomeOtherLongComplexType,) -> Box<Future<Item = AnotherLongType, Error = ALongErrorType>>;
+
+// Const opt-out
+
+trait T: ?   const  Super {}
+
+const fn maybe_const<S: ?   const    T>() -> i32 { <S as T>::CONST }
+
+struct S<T:?  const   ?  Sized>(std::marker::PhantomData<T>);
+
+impl ?    const T {}
+
+fn trait_object() -> &'static dyn ?  const T { &S }
+
+fn i(_: impl IntoIterator<Item = Box<dyn ?    const    T>>) {}
+
+fn apit(_: impl ?const T) {}
+
+fn rpit() -> impl ?  const T { S }
+
+pub struct Foo<T: Trait>(T);
+impl<T:   ?  const Trait> Foo<T> {
+    fn new(t: T) -> Self {
+        // not calling methods on `t`, so we opt out of requiring
+        // `<T as Trait>` to have const methods via `?const`
+        Self(t)
+    }
+}
diff --git a/tests/target/type.rs b/tests/target/type.rs
index 575bd3573bc..20e97440e7c 100644
--- a/tests/target/type.rs
+++ b/tests/target/type.rs
@@ -144,3 +144,36 @@ type MyFn = fn(
     a: SomeLongComplexType,
     b: SomeOtherLongComplexType,
 ) -> Box<Future<Item = AnotherLongType, Error = ALongErrorType>>;
+
+// Const opt-out
+
+trait T: ?const Super {}
+
+const fn maybe_const<S: ?const T>() -> i32 {
+    <S as T>::CONST
+}
+
+struct S<T: ?const ?Sized>(std::marker::PhantomData<T>);
+
+impl ?const T {}
+
+fn trait_object() -> &'static dyn ?const T {
+    &S
+}
+
+fn i(_: impl IntoIterator<Item = Box<dyn ?const T>>) {}
+
+fn apit(_: impl ?const T) {}
+
+fn rpit() -> impl ?const T {
+    S
+}
+
+pub struct Foo<T: Trait>(T);
+impl<T: ?const Trait> Foo<T> {
+    fn new(t: T) -> Self {
+        // not calling methods on `t`, so we opt out of requiring
+        // `<T as Trait>` to have const methods via `?const`
+        Self(t)
+    }
+}

From 90830056734acf7aa75f06a0eb767dc5ebf71e0a Mon Sep 17 00:00:00 2001
From: Caleb Cartwright <caleb.cartwright@outlook.com>
Date: Mon, 30 Mar 2020 22:50:34 -0500
Subject: [PATCH 3/3] feat: support half open range syntax

---
 src/patterns.rs                               | 58 ++++++++++++-------
 .../configs/spaces_around_ranges/false.rs     | 12 ++++
 .../configs/spaces_around_ranges/true.rs      | 12 ++++
 .../configs/spaces_around_ranges/false.rs     | 12 ++++
 .../configs/spaces_around_ranges/true.rs      | 12 ++++
 5 files changed, 85 insertions(+), 21 deletions(-)

diff --git a/src/patterns.rs b/src/patterns.rs
index 78292620232..5847bd08d80 100644
--- a/src/patterns.rs
+++ b/src/patterns.rs
@@ -55,6 +55,17 @@ fn is_short_pattern_inner(pat: &ast::Pat) -> bool {
     }
 }
 
+struct RangeOperand<'a>(&'a Option<ptr::P<ast::Expr>>);
+
+impl<'a> Rewrite for RangeOperand<'a> {
+    fn rewrite(&self, context: &RewriteContext<'_>, shape: Shape) -> Option<String> {
+        match &self.0 {
+            None => Some("".to_owned()),
+            Some(ref exp) => exp.rewrite(context, shape),
+        }
+    }
+}
+
 impl Rewrite for Pat {
     fn rewrite(&self, context: &RewriteContext<'_>, shape: Shape) -> Option<String> {
         match self.kind {
@@ -179,29 +190,34 @@ impl Rewrite for Pat {
                     None
                 }
             }
-            PatKind::Range(ref lhs, ref rhs, ref end_kind) => match (lhs, rhs) {
-                (Some(lhs), Some(rhs)) => {
-                    let infix = match end_kind.node {
-                        RangeEnd::Included(RangeSyntax::DotDotDot) => "...",
-                        RangeEnd::Included(RangeSyntax::DotDotEq) => "..=",
-                        RangeEnd::Excluded => "..",
+            PatKind::Range(ref lhs, ref rhs, ref end_kind) => {
+                let infix = match end_kind.node {
+                    RangeEnd::Included(RangeSyntax::DotDotDot) => "...",
+                    RangeEnd::Included(RangeSyntax::DotDotEq) => "..=",
+                    RangeEnd::Excluded => "..",
+                };
+                let infix = if context.config.spaces_around_ranges() {
+                    let lhs_spacing = match lhs {
+                        None => "",
+                        Some(_) => " ",
                     };
-                    let infix = if context.config.spaces_around_ranges() {
-                        format!(" {} ", infix)
-                    } else {
-                        infix.to_owned()
+                    let rhs_spacing = match rhs {
+                        None => "",
+                        Some(_) => " ",
                     };
-                    rewrite_pair(
-                        &**lhs,
-                        &**rhs,
-                        PairParts::infix(&infix),
-                        context,
-                        shape,
-                        SeparatorPlace::Front,
-                    )
-                }
-                (_, _) => unimplemented!(),
-            },
+                    format!("{}{}{}", lhs_spacing, infix, rhs_spacing)
+                } else {
+                    infix.to_owned()
+                };
+                rewrite_pair(
+                    &RangeOperand(lhs),
+                    &RangeOperand(rhs),
+                    PairParts::infix(&infix),
+                    context,
+                    shape,
+                    SeparatorPlace::Front,
+                )
+            }
             PatKind::Ref(ref pat, mutability) => {
                 let prefix = format!("&{}", format_mutability(mutability));
                 rewrite_unary_prefix(context, &prefix, &**pat, shape)
diff --git a/tests/source/configs/spaces_around_ranges/false.rs b/tests/source/configs/spaces_around_ranges/false.rs
index 11ca76b1345..1878c68a5a0 100644
--- a/tests/source/configs/spaces_around_ranges/false.rs
+++ b/tests/source/configs/spaces_around_ranges/false.rs
@@ -20,3 +20,15 @@ fn main() {
         _ => bar,
     }
 }
+
+fn half_open() {
+    match [5 .. 4, 99 .. 105, 43 .. 44] {
+        [_, 99 .., _] => {}
+        [_, .. 105, _] => {}
+        _ => {}
+    };
+
+    if let ..=   5 = 0 {}
+    if let .. 5 = 0 {}
+    if let 5 .. = 0 {}
+}
diff --git a/tests/source/configs/spaces_around_ranges/true.rs b/tests/source/configs/spaces_around_ranges/true.rs
index 50170892130..0eadfb28515 100644
--- a/tests/source/configs/spaces_around_ranges/true.rs
+++ b/tests/source/configs/spaces_around_ranges/true.rs
@@ -20,3 +20,15 @@ fn main() {
         _ => bar,
     }
 }
+
+fn half_open() {
+    match [5..4, 99..105, 43..44] {
+        [_, 99.., _] => {}
+        [_, ..105, _] => {}
+        _ => {}
+    };
+
+    if let ..=5 = 0 {}
+    if let ..5 = 0 {}
+    if let 5.. = 0 {}
+}
diff --git a/tests/target/configs/spaces_around_ranges/false.rs b/tests/target/configs/spaces_around_ranges/false.rs
index 6319da98572..72b1be4804c 100644
--- a/tests/target/configs/spaces_around_ranges/false.rs
+++ b/tests/target/configs/spaces_around_ranges/false.rs
@@ -20,3 +20,15 @@ fn main() {
         _ => bar,
     }
 }
+
+fn half_open() {
+    match [5..4, 99..105, 43..44] {
+        [_, 99.., _] => {}
+        [_, ..105, _] => {}
+        _ => {}
+    };
+
+    if let ..=5 = 0 {}
+    if let ..5 = 0 {}
+    if let 5.. = 0 {}
+}
diff --git a/tests/target/configs/spaces_around_ranges/true.rs b/tests/target/configs/spaces_around_ranges/true.rs
index 7bfcc23c8ea..c56fdbb02b6 100644
--- a/tests/target/configs/spaces_around_ranges/true.rs
+++ b/tests/target/configs/spaces_around_ranges/true.rs
@@ -20,3 +20,15 @@ fn main() {
         _ => bar,
     }
 }
+
+fn half_open() {
+    match [5 .. 4, 99 .. 105, 43 .. 44] {
+        [_, 99 .., _] => {}
+        [_, .. 105, _] => {}
+        _ => {}
+    };
+
+    if let ..= 5 = 0 {}
+    if let .. 5 = 0 {}
+    if let 5 .. = 0 {}
+}