about summary refs log tree commit diff
diff options
context:
space:
mode:
authorLukas Wirth <lukastw97@gmail.com>2023-05-13 10:42:26 +0200
committerLukas Wirth <lukastw97@gmail.com>2023-05-13 10:42:26 +0200
commit730286b523c23170630142b6ebba0677a9aedae9 (patch)
tree08174c303066cd65e52b19ad299030216da16e9e
parent4c5fd19ee5734992344827b11c0d0e864b020b25 (diff)
downloadrust-730286b523c23170630142b6ebba0677a9aedae9.tar.gz
rust-730286b523c23170630142b6ebba0677a9aedae9.zip
Restructure InlayHint, no longer derive properties from its kind
-rw-r--r--crates/ide/src/inlay_hints.rs47
-rw-r--r--crates/ide/src/inlay_hints/adjustment.rs41
-rw-r--r--crates/ide/src/inlay_hints/bind_pat.rs310
-rw-r--r--crates/ide/src/inlay_hints/binding_mode.rs18
-rw-r--r--crates/ide/src/inlay_hints/chaining.rs57
-rw-r--r--crates/ide/src/inlay_hints/closing_brace.rs5
-rw-r--r--crates/ide/src/inlay_hints/closure_captures.rs17
-rw-r--r--crates/ide/src/inlay_hints/closure_ret.rs56
-rw-r--r--crates/ide/src/inlay_hints/discriminant.rs91
-rw-r--r--crates/ide/src/inlay_hints/fn_lifetime_fn.rs11
-rw-r--r--crates/ide/src/inlay_hints/implicit_static.rs5
-rw-r--r--crates/ide/src/inlay_hints/param_name.rs16
-rw-r--r--crates/ide/src/lib.rs4
-rw-r--r--crates/rust-analyzer/src/handlers/request.rs4
-rw-r--r--crates/rust-analyzer/src/to_proto.rs82
15 files changed, 416 insertions, 348 deletions
diff --git a/crates/ide/src/inlay_hints.rs b/crates/ide/src/inlay_hints.rs
index c326688ae6a..29259167419 100644
--- a/crates/ide/src/inlay_hints.rs
+++ b/crates/ide/src/inlay_hints.rs
@@ -90,32 +90,34 @@ pub enum AdjustmentHintsMode {
     PreferPostfix,
 }
 
-// FIXME: Clean up this mess, the kinds are mainly used for setting different rendering properties in the lsp layer
-// We should probably turns this into such a property holding struct. Or clean this up in some other form.
 #[derive(Copy, Clone, Debug, PartialEq, Eq)]
 pub enum InlayKind {
+    Adjustment,
     BindingMode,
     Chaining,
     ClosingBrace,
-    ClosureReturnType,
+    ClosureCapture,
+    Discriminant,
     GenericParamList,
-    Adjustment,
-    AdjustmentPostfix,
     Lifetime,
-    ClosureCapture,
     Parameter,
     Type,
-    Discriminant,
-    OpeningParenthesis,
-    ClosingParenthesis,
+}
+
+#[derive(Debug)]
+pub enum InlayHintPosition {
+    Before,
+    After,
 }
 
 #[derive(Debug)]
 pub struct InlayHint {
     /// The text range this inlay hint applies to.
     pub range: TextRange,
-    /// The kind of this inlay hint. This is used to determine side and padding of the hint for
-    /// rendering purposes.
+    pub position: InlayHintPosition,
+    pub pad_left: bool,
+    pub pad_right: bool,
+    /// The kind of this inlay hint.
     pub kind: InlayKind,
     /// The actual label to show in the inlay hint.
     pub label: InlayHintLabel,
@@ -124,20 +126,26 @@ pub struct InlayHint {
 }
 
 impl InlayHint {
-    fn closing_paren(range: TextRange) -> InlayHint {
+    fn closing_paren_after(kind: InlayKind, range: TextRange) -> InlayHint {
         InlayHint {
             range,
-            kind: InlayKind::ClosingParenthesis,
+            kind,
             label: InlayHintLabel::from(")"),
             text_edit: None,
+            position: InlayHintPosition::After,
+            pad_left: false,
+            pad_right: false,
         }
     }
-    fn opening_paren(range: TextRange) -> InlayHint {
+    fn opening_paren_before(kind: InlayKind, range: TextRange) -> InlayHint {
         InlayHint {
             range,
-            kind: InlayKind::OpeningParenthesis,
+            kind,
             label: InlayHintLabel::from("("),
             text_edit: None,
+            position: InlayHintPosition::Before,
+            pad_left: false,
+            pad_right: false,
         }
     }
 }
@@ -303,13 +311,13 @@ impl InlayHintLabelBuilder<'_> {
 fn label_of_ty(
     famous_defs @ FamousDefs(sema, _): &FamousDefs<'_, '_>,
     config: &InlayHintsConfig,
-    ty: hir::Type,
+    ty: &hir::Type,
 ) -> Option<InlayHintLabel> {
     fn rec(
         sema: &Semantics<'_, RootDatabase>,
         famous_defs: &FamousDefs<'_, '_>,
         mut max_length: Option<usize>,
-        ty: hir::Type,
+        ty: &hir::Type,
         label_builder: &mut InlayHintLabelBuilder<'_>,
         config: &InlayHintsConfig,
     ) -> Result<(), HirDisplayError> {
@@ -342,7 +350,7 @@ fn label_of_ty(
                 label_builder.write_str(LABEL_ITEM)?;
                 label_builder.end_location_link();
                 label_builder.write_str(LABEL_MIDDLE2)?;
-                rec(sema, famous_defs, max_length, ty, label_builder, config)?;
+                rec(sema, famous_defs, max_length, &ty, label_builder, config)?;
                 label_builder.write_str(LABEL_END)?;
                 Ok(())
             }
@@ -574,7 +582,8 @@ mod tests {
         let inlay_hints = analysis.inlay_hints(&config, file_id, None).unwrap();
         let actual = inlay_hints
             .into_iter()
-            .map(|it| (it.range, it.label.to_string()))
+            // FIXME: We trim the start because some inlay produces leading whitespace which is not properly supported by our annotation extraction
+            .map(|it| (it.range, it.label.to_string().trim_start().to_owned()))
             .sorted_by_key(|(range, _)| range.start())
             .collect::<Vec<_>>();
         expected.sort_by_key(|(range, _)| range.start());
diff --git a/crates/ide/src/inlay_hints/adjustment.rs b/crates/ide/src/inlay_hints/adjustment.rs
index 27e9ba3c36b..10bee2a6acc 100644
--- a/crates/ide/src/inlay_hints/adjustment.rs
+++ b/crates/ide/src/inlay_hints/adjustment.rs
@@ -3,6 +3,7 @@
 //! let _: u32  = /* <never-to-any> */ loop {};
 //! let _: &u32 = /* &* */ &mut 0;
 //! ```
+use either::Either;
 use hir::{
     Adjust, Adjustment, AutoBorrow, HirDisplay, Mutability, OverloadedDeref, PointerCast, Safety,
     Semantics,
@@ -16,8 +17,8 @@ use syntax::{
 };
 
 use crate::{
-    AdjustmentHints, AdjustmentHintsMode, InlayHint, InlayHintLabel, InlayHintsConfig, InlayKind,
-    InlayTooltip,
+    AdjustmentHints, AdjustmentHintsMode, InlayHint, InlayHintLabel, InlayHintPosition,
+    InlayHintsConfig, InlayKind, InlayTooltip,
 };
 
 pub(super) fn hints(
@@ -63,22 +64,26 @@ pub(super) fn hints(
         mode_and_needs_parens_for_adjustment_hints(expr, config.adjustment_hints_mode);
 
     if needs_outer_parens {
-        acc.push(InlayHint::opening_paren(expr.syntax().text_range()));
+        acc.push(InlayHint::opening_paren_before(
+            InlayKind::Adjustment,
+            expr.syntax().text_range(),
+        ));
     }
 
     if postfix && needs_inner_parens {
-        acc.push(InlayHint::opening_paren(expr.syntax().text_range()));
-        acc.push(InlayHint::closing_paren(expr.syntax().text_range()));
+        acc.push(InlayHint::opening_paren_before(
+            InlayKind::Adjustment,
+            expr.syntax().text_range(),
+        ));
+        acc.push(InlayHint::closing_paren_after(InlayKind::Adjustment, expr.syntax().text_range()));
     }
 
-    let (mut tmp0, mut tmp1);
-    let iter: &mut dyn Iterator<Item = _> = if postfix {
-        tmp0 = adjustments.into_iter();
-        &mut tmp0
+    let mut iter = if postfix {
+        Either::Left(adjustments.into_iter())
     } else {
-        tmp1 = adjustments.into_iter().rev();
-        &mut tmp1
+        Either::Right(adjustments.into_iter().rev())
     };
+    let iter: &mut dyn Iterator<Item = _> = iter.as_mut().either(|it| it as _, |it| it as _);
 
     for Adjustment { source, target, kind } in iter {
         if source == target {
@@ -134,7 +139,10 @@ pub(super) fn hints(
         };
         acc.push(InlayHint {
             range: expr.syntax().text_range(),
-            kind: if postfix { InlayKind::AdjustmentPostfix } else { InlayKind::Adjustment },
+            pad_left: false,
+            pad_right: false,
+            position: if postfix { InlayHintPosition::After } else { InlayHintPosition::Before },
+            kind: InlayKind::Adjustment,
             label: InlayHintLabel::simple(
                 if postfix { format!(".{}", text.trim_end()) } else { text.to_owned() },
                 Some(InlayTooltip::Markdown(format!(
@@ -148,11 +156,14 @@ pub(super) fn hints(
         });
     }
     if !postfix && needs_inner_parens {
-        acc.push(InlayHint::opening_paren(expr.syntax().text_range()));
-        acc.push(InlayHint::closing_paren(expr.syntax().text_range()));
+        acc.push(InlayHint::opening_paren_before(
+            InlayKind::Adjustment,
+            expr.syntax().text_range(),
+        ));
+        acc.push(InlayHint::closing_paren_after(InlayKind::Adjustment, expr.syntax().text_range()));
     }
     if needs_outer_parens {
-        acc.push(InlayHint::closing_paren(expr.syntax().text_range()));
+        acc.push(InlayHint::closing_paren_after(InlayKind::Adjustment, expr.syntax().text_range()));
     }
     Some(())
 }
diff --git a/crates/ide/src/inlay_hints/bind_pat.rs b/crates/ide/src/inlay_hints/bind_pat.rs
index 6991a66c7c2..f98cc129a93 100644
--- a/crates/ide/src/inlay_hints/bind_pat.rs
+++ b/crates/ide/src/inlay_hints/bind_pat.rs
@@ -14,7 +14,7 @@ use syntax::{
 
 use crate::{
     inlay_hints::{closure_has_block_body, label_of_ty, ty_to_text_edit},
-    InlayHint, InlayHintsConfig, InlayKind,
+    InlayHint, InlayHintPosition, InlayHintsConfig, InlayKind,
 };
 
 pub(super) fn hints(
@@ -36,7 +36,7 @@ pub(super) fn hints(
         return None;
     }
 
-    let label = label_of_ty(famous_defs, config, ty.clone())?;
+    let mut label = label_of_ty(famous_defs, config, &ty)?;
 
     if config.hide_named_constructor_hints
         && is_named_constructor(sema, pat, &label.to_string()).is_some()
@@ -44,31 +44,46 @@ pub(super) fn hints(
         return None;
     }
 
-    let type_annotation_is_valid = desc_pat
-        .syntax()
-        .parent()
-        .map(|it| ast::LetStmt::can_cast(it.kind()) || ast::Param::can_cast(it.kind()))
-        .unwrap_or(false);
-    let text_edit = if type_annotation_is_valid {
+    let type_ascriptable = desc_pat.syntax().parent().and_then(|it| {
+        ast::LetStmt::cast(it.clone())
+            .map(|it| it.colon_token())
+            .or_else(|| ast::Param::cast(it).map(|it| it.colon_token()))
+    });
+    let text_edit = if let Some(colon_token) = &type_ascriptable {
         ty_to_text_edit(
             sema,
             desc_pat.syntax(),
             &ty,
-            pat.syntax().text_range().end(),
-            String::from(": "),
+            colon_token
+                .as_ref()
+                .map_or_else(|| pat.syntax().text_range(), |t| t.text_range())
+                .end(),
+            if colon_token.is_some() { String::new() } else { String::from(": ") },
         )
     } else {
         None
     };
 
+    let has_colon = matches!(type_ascriptable, Some(Some(_))) && !config.render_colons;
+    if !has_colon {
+        label.prepend_str(": ");
+    }
+
+    let text_range = match pat.name() {
+        Some(name) => name.syntax().text_range(),
+        None => pat.syntax().text_range(),
+    };
     acc.push(InlayHint {
-        range: match pat.name() {
-            Some(name) => name.syntax().text_range(),
-            None => pat.syntax().text_range(),
+        range: match type_ascriptable {
+            Some(Some(t)) => text_range.cover(t.text_range()),
+            _ => text_range,
         },
         kind: InlayKind::Type,
         label,
         text_edit,
+        position: InlayHintPosition::Before,
+        pad_left: !has_colon,
+        pad_right: false,
     });
 
     Some(())
@@ -218,7 +233,7 @@ mod tests {
 fn foo(a: i32, b: i32) -> i32 { a + b }
 fn main() {
     let _x = foo(4, 4);
-      //^^ i32
+      //^^ : i32
 }"#,
         );
     }
@@ -230,17 +245,17 @@ fn main() {
 //- minicore: option
 fn main() {
     let ref foo @ bar @ ref mut baz = 0;
-          //^^^ &i32
-                //^^^ i32
-                              //^^^ &mut i32
+          //^^^ : &i32
+                //^^^ : i32
+                              //^^^ : &mut i32
     let [x @ ..] = [0];
-       //^ [i32; 1]
+       //^ : [i32; 1]
     if let x @ Some(_) = Some(0) {}
-         //^ Option<i32>
+         //^ : Option<i32>
     let foo @ (bar, baz) = (3, 3);
-      //^^^ (i32, i32)
-             //^^^ i32
-                  //^^^ i32
+      //^^^ : (i32, i32)
+             //^^^ : i32
+                  //^^^ : i32
 }"#,
         );
     }
@@ -253,11 +268,11 @@ struct Test<K, T = u8> { k: K, t: T }
 
 fn main() {
     let zz = Test { t: 23u8, k: 33 };
-      //^^ Test<i32>
+      //^^ : Test<i32>
     let zz_ref = &zz;
-      //^^^^^^ &Test<i32>
+      //^^^^^^ : &Test<i32>
     let test = || zz;
-      //^^^^ impl FnOnce() -> Test<i32>
+      //^^^^ : impl FnOnce() -> Test<i32>
 }"#,
         );
     }
@@ -285,10 +300,10 @@ impl<T> Iterator for SomeIter<T> {
 
 fn main() {
     let mut some_iter = SomeIter::new();
-          //^^^^^^^^^ SomeIter<Take<Repeat<i32>>>
+          //^^^^^^^^^ : SomeIter<Take<Repeat<i32>>>
       some_iter.push(iter::repeat(2).take(2));
     let iter_of_iters = some_iter.take(2);
-      //^^^^^^^^^^^^^ impl Iterator<Item = impl Iterator<Item = i32>>
+      //^^^^^^^^^^^^^ : impl Iterator<Item = impl Iterator<Item = i32>>
 }
 "#,
         );
@@ -347,7 +362,7 @@ fn main(a: SliceIter<'_, Container>) {
 
             pub fn quux<T: Foo>() -> T::Bar {
                 let y = Default::default();
-                  //^ <T as Foo>::Bar
+                  //^ : <T as Foo>::Bar
 
                 y
             }
@@ -371,21 +386,21 @@ fn foo7() -> *const (impl Fn(f64, f64) -> u32 + Sized) { loop {} }
 
 fn main() {
     let foo = foo();
-     // ^^^ impl Fn()
+     // ^^^ : impl Fn()
     let foo = foo1();
-     // ^^^ impl Fn(f64)
+     // ^^^ : impl Fn(f64)
     let foo = foo2();
-     // ^^^ impl Fn(f64, f64)
+     // ^^^ : impl Fn(f64, f64)
     let foo = foo3();
-     // ^^^ impl Fn(f64, f64) -> u32
+     // ^^^ : impl Fn(f64, f64) -> u32
     let foo = foo4();
-     // ^^^ &dyn Fn(f64, f64) -> u32
+     // ^^^ : &dyn Fn(f64, f64) -> u32
     let foo = foo5();
-     // ^^^ &dyn Fn(&dyn Fn(f64, f64) -> u32, f64) -> u32
+     // ^^^ : &dyn Fn(&dyn Fn(f64, f64) -> u32, f64) -> u32
     let foo = foo6();
-     // ^^^ impl Fn(f64, f64) -> u32
+     // ^^^ : impl Fn(f64, f64) -> u32
     let foo = foo7();
-     // ^^^ *const impl Fn(f64, f64) -> u32
+     // ^^^ : *const impl Fn(f64, f64) -> u32
 }
 "#,
         )
@@ -408,9 +423,9 @@ fn main() {
             let foo = foo();
             let foo = foo1();
             let foo = foo2();
-             // ^^^ impl Fn(f64, f64)
+             // ^^^ : impl Fn(f64, f64)
             let foo = foo3();
-             // ^^^ impl Fn(f64, f64) -> u32
+             // ^^^ : impl Fn(f64, f64) -> u32
             let foo = foo4();
             let foo = foo5();
             let foo = foo6();
@@ -451,25 +466,25 @@ fn foo10() -> *const (impl Fn() + Sized + ?Sized) { loop {} }
 
 fn main() {
     let foo = foo1();
-    //  ^^^ *const impl Fn()
+    //  ^^^ : *const impl Fn()
     let foo = foo2();
-    //  ^^^ *const impl Fn()
+    //  ^^^ : *const impl Fn()
     let foo = foo3();
-    //  ^^^ *const (impl Fn() + ?Sized)
+    //  ^^^ : *const (impl Fn() + ?Sized)
     let foo = foo4();
-    //  ^^^ *const impl Fn()
+    //  ^^^ : *const impl Fn()
     let foo = foo5();
-    //  ^^^ *const (impl Fn() + ?Sized)
+    //  ^^^ : *const (impl Fn() + ?Sized)
     let foo = foo6();
-    //  ^^^ *const (impl Fn() + Trait)
+    //  ^^^ : *const (impl Fn() + Trait)
     let foo = foo7();
-    //  ^^^ *const (impl Fn() + Trait)
+    //  ^^^ : *const (impl Fn() + Trait)
     let foo = foo8();
-    //  ^^^ *const (impl Fn() + Trait + ?Sized)
+    //  ^^^ : *const (impl Fn() + Trait + ?Sized)
     let foo = foo9();
-    //  ^^^ *const (impl Fn() -> u8 + ?Sized)
+    //  ^^^ : *const (impl Fn() -> u8 + ?Sized)
     let foo = foo10();
-    //  ^^^ *const impl Fn()
+    //  ^^^ : *const impl Fn()
 }
 "#,
         )
@@ -520,24 +535,24 @@ fn main() {
     struct InnerStruct {}
 
     let test = 54;
-      //^^^^ i32
+      //^^^^ : i32
     let test: i32 = 33;
     let mut test = 33;
-          //^^^^ i32
+          //^^^^ : i32
     let _ = 22;
     let test = "test";
-      //^^^^ &str
+      //^^^^ : &str
     let test = InnerStruct {};
-      //^^^^ InnerStruct
+      //^^^^ : InnerStruct
 
     let test = unresolved();
 
     let test = (42, 'a');
-      //^^^^ (i32, char)
-    let (a,    (b,     (c,)) = (2, (3, (9.2,));
-       //^ i32  ^ i32   ^ f64
+      //^^^^ : (i32, char)
+    let (a,      (b,       (c,)) = (2, (3, (9.2,));
+       //^ : i32  ^ : i32   ^ : f64
     let &x = &92;
-       //^ i32
+       //^ : i32
 }"#,
         );
     }
@@ -551,22 +566,22 @@ struct Test { a: Option<u32>, b: u8 }
 
 fn main() {
     let test = Some(Test { a: Some(3), b: 1 });
-      //^^^^ Option<Test>
+      //^^^^ : Option<Test>
     if let None = &test {};
     if let test = &test {};
-         //^^^^ &Option<Test>
+         //^^^^ : &Option<Test>
     if let Some(test) = &test {};
-              //^^^^ &Test
-    if let Some(Test { a,             b }) = &test {};
-                     //^ &Option<u32> ^ &u8
-    if let Some(Test { a: x,             b: y }) = &test {};
-                        //^ &Option<u32>    ^ &u8
-    if let Some(Test { a: Some(x),  b: y }) = &test {};
-                             //^ &u32  ^ &u8
+              //^^^^ : &Test
+    if let Some(Test { a,               b }) = &test {};
+                     //^ : &Option<u32> ^ : &u8
+    if let Some(Test { a: x,               b: y }) = &test {};
+                        //^ : &Option<u32>    ^ : &u8
+    if let Some(Test { a: Some(x),    b: y }) = &test {};
+                             //^ : &u32  ^ : &u8
     if let Some(Test { a: None,  b: y }) = &test {};
-                                  //^ &u8
+                                  //^ : &u8
     if let Some(Test { b: y, .. }) = &test {};
-                        //^ &u8
+                        //^ : &u8
     if test == None {}
 }"#,
         );
@@ -581,9 +596,9 @@ struct Test { a: Option<u32>, b: u8 }
 
 fn main() {
     let test = Some(Test { a: Some(3), b: 1 });
-      //^^^^ Option<Test>
-    while let Some(Test { a: Some(x),  b: y }) = &test {};
-                                //^ &u32  ^ &u8
+      //^^^^ : Option<Test>
+    while let Some(Test { a: Some(x),    b: y }) = &test {};
+                                //^ : &u32  ^ : &u8
 }"#,
         );
     }
@@ -599,9 +614,9 @@ fn main() {
     match Some(Test { a: Some(3), b: 1 }) {
         None => (),
         test => (),
-      //^^^^ Option<Test>
-        Some(Test { a: Some(x), b: y }) => (),
-                          //^ u32  ^ u8
+      //^^^^ : Option<Test>
+        Some(Test { a: Some(x),   b: y }) => (),
+                          //^ : u32  ^ : u8
         _ => {}
     }
 }"#,
@@ -633,12 +648,12 @@ impl<T> Iterator for IntoIter<T> {
 
 fn main() {
     let mut data = Vec::new();
-          //^^^^ Vec<&str>
+          //^^^^ : Vec<&str>
     data.push("foo");
     for i in data {
-      //^ &str
+      //^ : &str
       let z = i;
-        //^ &str
+        //^ : &str
     }
 }
 "#,
@@ -663,11 +678,11 @@ auto trait Sync {}
 fn main() {
     // The block expression wrapping disables the constructor hint hiding logic
     let _v = { Vec::<Box<&(dyn Display + Sync)>>::new() };
-      //^^ Vec<Box<&(dyn Display + Sync)>>
+      //^^ : Vec<Box<&(dyn Display + Sync)>>
     let _v = { Vec::<Box<*const (dyn Display + Sync)>>::new() };
-      //^^ Vec<Box<*const (dyn Display + Sync)>>
+      //^^ : Vec<Box<*const (dyn Display + Sync)>>
     let _v = { Vec::<Box<dyn Display + Sync>>::new() };
-      //^^ Vec<Box<dyn Display + Sync>>
+      //^^ : Vec<Box<dyn Display + Sync>>
 }
 "#,
         );
@@ -691,14 +706,14 @@ impl Iterator for MyIter {
 
 fn main() {
     let _x = MyIter;
-      //^^ MyIter
+      //^^ : MyIter
     let _x = iter::repeat(0);
-      //^^ impl Iterator<Item = i32>
+      //^^ : impl Iterator<Item = i32>
     fn generic<T: Clone>(t: T) {
         let _x = iter::repeat(t);
-          //^^ impl Iterator<Item = T>
+          //^^ : impl Iterator<Item = T>
         let _chained = iter::repeat(t).take(10);
-          //^^^^^^^^ impl Iterator<Item = T>
+          //^^^^^^^^ : impl Iterator<Item = T>
     }
 }
 "#,
@@ -762,20 +777,20 @@ fn main() {
     let tuple_struct = TupleStruct();
 
     let generic0 = Generic::new();
-    //  ^^^^^^^^ Generic<i32>
+    //  ^^^^^^^^ : Generic<i32>
     let generic1 = Generic(0);
-    //  ^^^^^^^^ Generic<i32>
+    //  ^^^^^^^^ : Generic<i32>
     let generic2 = Generic::<i32>::new();
     let generic3 = <Generic<i32>>::new();
     let generic4 = Generic::<i32>(0);
 
 
     let option = Some(0);
-    //  ^^^^^^ Option<i32>
+    //  ^^^^^^ : Option<i32>
     let func = times2;
-    //  ^^^^ fn times2(i32) -> i32
+    //  ^^^^ : fn times2(i32) -> i32
     let closure = |x: i32| x * 2;
-    //  ^^^^^^^ impl Fn(i32) -> i32
+    //  ^^^^^^^ : impl Fn(i32) -> i32
 }
 
 fn fallible() -> ControlFlow<()> {
@@ -813,73 +828,26 @@ impl Generic<i32> {
 
 fn main() {
     let strukt = Struct::new();
-     // ^^^^^^ Struct
+     // ^^^^^^ : Struct
     let tuple_struct = TupleStruct();
-     // ^^^^^^^^^^^^ TupleStruct
+     // ^^^^^^^^^^^^ : TupleStruct
     let generic0 = Generic::new();
-     // ^^^^^^^^ Generic<i32>
+     // ^^^^^^^^ : Generic<i32>
     let generic1 = Generic::<i32>::new();
-     // ^^^^^^^^ Generic<i32>
+     // ^^^^^^^^ : Generic<i32>
     let generic2 = <Generic<i32>>::new();
-     // ^^^^^^^^ Generic<i32>
+     // ^^^^^^^^ : Generic<i32>
 }
 
 fn fallible() -> ControlFlow<()> {
     let strukt = Struct::try_new()?;
-     // ^^^^^^ Struct
+     // ^^^^^^ : Struct
 }
 "#,
         );
     }
 
     #[test]
-    fn closures() {
-        check(
-            r#"
-fn main() {
-    let mut start = 0;
-          //^^^^^ i32
-    (0..2).for_each(|increment      | { start += increment; });
-                   //^^^^^^^^^ i32
-
-    let multiply =
-      //^^^^^^^^ impl Fn(i32, i32) -> i32
-      | a,     b| a * b
-      //^ i32  ^ i32
-
-    ;
-
-    let _: i32 = multiply(1,  2);
-                        //^ a ^ b
-    let multiply_ref = &multiply;
-      //^^^^^^^^^^^^ &impl Fn(i32, i32) -> i32
-
-    let return_42 = || 42;
-      //^^^^^^^^^ impl Fn() -> i32
-      || { 42 };
-    //^^ i32
-}"#,
-        );
-    }
-
-    #[test]
-    fn return_type_hints_for_closure_without_block() {
-        check_with_config(
-            InlayHintsConfig {
-                closure_return_type_hints: ClosureReturnTypeHints::Always,
-                ..DISABLED_CONFIG
-            },
-            r#"
-fn main() {
-    let a = || { 0 };
-          //^^ i32
-    let b = || 0;
-          //^^ i32
-}"#,
-        );
-    }
-
-    #[test]
     fn closure_style() {
         check_with_config(
             InlayHintsConfig { type_hints: true, ..DISABLED_CONFIG },
@@ -887,15 +855,15 @@ fn main() {
 //- minicore: fn
 fn main() {
     let x = || 2;
-      //^ impl Fn() -> i32
+      //^ : impl Fn() -> i32
     let y = |t: i32| x() + t;
-      //^ impl Fn(i32) -> i32
+      //^ : impl Fn(i32) -> i32
     let mut t = 5;
-          //^ i32
+          //^ : i32
     let z = |k: i32| { t += k; };
-      //^ impl FnMut(i32)
+      //^ : impl FnMut(i32)
     let p = (y, z);
-      //^ (impl Fn(i32) -> i32, impl FnMut(i32))
+      //^ : (impl Fn(i32) -> i32, impl FnMut(i32))
 }
             "#,
         );
@@ -909,15 +877,15 @@ fn main() {
 //- minicore: fn
 fn main() {
     let x = || 2;
-      //^ || -> i32
+      //^ : || -> i32
     let y = |t: i32| x() + t;
-      //^ |i32| -> i32
+      //^ : |i32| -> i32
     let mut t = 5;
-          //^ i32
+          //^ : i32
     let z = |k: i32| { t += k; };
-      //^ |i32| -> ()
+      //^ : |i32| -> ()
     let p = (y, z);
-      //^ (|i32| -> i32, |i32| -> ())
+      //^ : (|i32| -> i32, |i32| -> ())
 }
             "#,
         );
@@ -931,15 +899,15 @@ fn main() {
 //- minicore: fn
 fn main() {
     let x = || 2;
-      //^ {closure#0}
+      //^ : {closure#0}
     let y = |t: i32| x() + t;
-      //^ {closure#1}
+      //^ : {closure#1}
     let mut t = 5;
-          //^ i32
+          //^ : i32
     let z = |k: i32| { t += k; };
-      //^ {closure#2}
+      //^ : {closure#2}
     let p = (y, z);
-      //^ ({closure#1}, {closure#2})
+      //^ : ({closure#1}, {closure#2})
 }
             "#,
         );
@@ -953,15 +921,15 @@ fn main() {
 //- minicore: fn
 fn main() {
     let x = || 2;
-      //^ …
+      //^ : …
     let y = |t: i32| x() + t;
-      //^ …
+      //^ : …
     let mut t = 5;
-          //^ i32
+          //^ : i32
     let z = |k: i32| { t += k; };
-      //^ …
+      //^ : …
     let p = (y, z);
-      //^ (…, …)
+      //^ : (…, …)
 }
             "#,
         );
@@ -981,24 +949,24 @@ fn main() {
     let multiple_2 = |x: i32| { x * 2 };
 
     let multiple_2 = |x: i32| x * 2;
-    //  ^^^^^^^^^^ impl Fn(i32) -> i32
+    //  ^^^^^^^^^^ : impl Fn(i32) -> i32
 
     let (not) = (|x: bool| { !x });
-    //   ^^^ impl Fn(bool) -> bool
+    //   ^^^ : impl Fn(bool) -> bool
 
     let (is_zero, _b) = (|x: usize| { x == 0 }, false);
-    //   ^^^^^^^ impl Fn(usize) -> bool
-    //            ^^ bool
+    //   ^^^^^^^ : impl Fn(usize) -> bool
+    //            ^^ : bool
 
     let plus_one = |x| { x + 1 };
-    //              ^ u8
+    //              ^ : u8
     foo(plus_one);
 
     let add_mul = bar(|x: u8| { x + 1 });
-    //  ^^^^^^^ impl FnOnce(u8) -> u8 + ?Sized
+    //  ^^^^^^^ : impl FnOnce(u8) -> u8 + ?Sized
 
     let closure = if let Some(6) = add_mul(2).checked_sub(1) {
-    //  ^^^^^^^ fn(i32) -> i32
+    //  ^^^^^^^ : fn(i32) -> i32
         |x: i32| { x * 2 }
     } else {
         |x: i32| { x * 3 }
@@ -1025,11 +993,11 @@ struct VeryLongOuterName<T>(T);
 
 fn main() {
     let a = Smol(0u32);
-      //^ Smol<u32>
+      //^ : Smol<u32>
     let b = VeryLongOuterName(0usize);
-      //^ VeryLongOuterName<…>
+      //^ : VeryLongOuterName<…>
     let c = Smol(Smol(0u32))
-      //^ Smol<Smol<…>>
+      //^ : Smol<Smol<…>>
 }"#,
         );
     }
diff --git a/crates/ide/src/inlay_hints/binding_mode.rs b/crates/ide/src/inlay_hints/binding_mode.rs
index dada4dd0485..343cf17e50e 100644
--- a/crates/ide/src/inlay_hints/binding_mode.rs
+++ b/crates/ide/src/inlay_hints/binding_mode.rs
@@ -7,7 +7,7 @@ use ide_db::RootDatabase;
 
 use syntax::ast::{self, AstNode};
 
-use crate::{InlayHint, InlayHintsConfig, InlayKind};
+use crate::{InlayHint, InlayHintPosition, InlayHintsConfig, InlayKind};
 
 pub(super) fn hints(
     acc: &mut Vec<InlayHint>,
@@ -54,6 +54,9 @@ pub(super) fn hints(
             kind: InlayKind::BindingMode,
             label: r.to_string().into(),
             text_edit: None,
+            position: InlayHintPosition::Before,
+            pad_left: false,
+            pad_right: mut_reference,
         });
     });
     match pat {
@@ -69,11 +72,20 @@ pub(super) fn hints(
                 kind: InlayKind::BindingMode,
                 label: bm.to_string().into(),
                 text_edit: None,
+                position: InlayHintPosition::Before,
+                pad_left: false,
+                pad_right: true,
             });
         }
         ast::Pat::OrPat(pat) if !pattern_adjustments.is_empty() && outer_paren_pat.is_none() => {
-            acc.push(InlayHint::opening_paren(pat.syntax().text_range()));
-            acc.push(InlayHint::closing_paren(pat.syntax().text_range()));
+            acc.push(InlayHint::opening_paren_before(
+                InlayKind::BindingMode,
+                pat.syntax().text_range(),
+            ));
+            acc.push(InlayHint::closing_paren_after(
+                InlayKind::BindingMode,
+                pat.syntax().text_range(),
+            ));
         }
         _ => (),
     }
diff --git a/crates/ide/src/inlay_hints/chaining.rs b/crates/ide/src/inlay_hints/chaining.rs
index d8c8401af77..cd1ac1e55e8 100644
--- a/crates/ide/src/inlay_hints/chaining.rs
+++ b/crates/ide/src/inlay_hints/chaining.rs
@@ -5,7 +5,7 @@ use syntax::{
     Direction, NodeOrToken, SyntaxKind, T,
 };
 
-use crate::{FileId, InlayHint, InlayHintsConfig, InlayKind};
+use crate::{FileId, InlayHint, InlayHintPosition, InlayHintsConfig, InlayKind};
 
 use super::label_of_ty;
 
@@ -60,8 +60,11 @@ pub(super) fn hints(
             acc.push(InlayHint {
                 range: expr.syntax().text_range(),
                 kind: InlayKind::Chaining,
-                label: label_of_ty(famous_defs, config, ty)?,
+                label: label_of_ty(famous_defs, config, &ty)?,
                 text_edit: None,
+                position: InlayHintPosition::After,
+                pad_left: true,
+                pad_right: false,
             });
         }
     }
@@ -104,6 +107,9 @@ fn main() {
                 [
                     InlayHint {
                         range: 147..172,
+                        position: After,
+                        pad_left: true,
+                        pad_right: false,
                         kind: Chaining,
                         label: [
                             "",
@@ -125,6 +131,9 @@ fn main() {
                     },
                     InlayHint {
                         range: 147..154,
+                        position: After,
+                        pad_left: true,
+                        pad_right: false,
                         kind: Chaining,
                         label: [
                             "",
@@ -191,6 +200,9 @@ fn main() {
                 [
                     InlayHint {
                         range: 143..190,
+                        position: After,
+                        pad_left: true,
+                        pad_right: false,
                         kind: Chaining,
                         label: [
                             "",
@@ -212,6 +224,9 @@ fn main() {
                     },
                     InlayHint {
                         range: 143..179,
+                        position: After,
+                        pad_left: true,
+                        pad_right: false,
                         kind: Chaining,
                         label: [
                             "",
@@ -262,6 +277,9 @@ fn main() {
                 [
                     InlayHint {
                         range: 143..190,
+                        position: After,
+                        pad_left: true,
+                        pad_right: false,
                         kind: Chaining,
                         label: [
                             "",
@@ -283,6 +301,9 @@ fn main() {
                     },
                     InlayHint {
                         range: 143..179,
+                        position: After,
+                        pad_left: true,
+                        pad_right: false,
                         kind: Chaining,
                         label: [
                             "",
@@ -334,6 +355,9 @@ fn main() {
                 [
                     InlayHint {
                         range: 246..283,
+                        position: After,
+                        pad_left: true,
+                        pad_right: false,
                         kind: Chaining,
                         label: [
                             "",
@@ -368,6 +392,9 @@ fn main() {
                     },
                     InlayHint {
                         range: 246..265,
+                        position: After,
+                        pad_left: true,
+                        pad_right: false,
                         kind: Chaining,
                         label: [
                             "",
@@ -434,6 +461,9 @@ fn main() {
                 [
                     InlayHint {
                         range: 174..241,
+                        position: After,
+                        pad_left: true,
+                        pad_right: false,
                         kind: Chaining,
                         label: [
                             "impl ",
@@ -468,6 +498,9 @@ fn main() {
                     },
                     InlayHint {
                         range: 174..224,
+                        position: After,
+                        pad_left: true,
+                        pad_right: false,
                         kind: Chaining,
                         label: [
                             "impl ",
@@ -502,6 +535,9 @@ fn main() {
                     },
                     InlayHint {
                         range: 174..206,
+                        position: After,
+                        pad_left: true,
+                        pad_right: false,
                         kind: Chaining,
                         label: [
                             "impl ",
@@ -536,6 +572,9 @@ fn main() {
                     },
                     InlayHint {
                         range: 174..189,
+                        position: After,
+                        pad_left: true,
+                        pad_right: false,
                         kind: Chaining,
                         label: [
                             "&mut ",
@@ -586,9 +625,12 @@ fn main() {
                 [
                     InlayHint {
                         range: 124..130,
+                        position: Before,
+                        pad_left: true,
+                        pad_right: false,
                         kind: Type,
                         label: [
-                            "",
+                            ": ",
                             InlayHintLabelPart {
                                 text: "Struct",
                                 linked_location: Some(
@@ -616,6 +658,9 @@ fn main() {
                     },
                     InlayHint {
                         range: 145..185,
+                        position: After,
+                        pad_left: true,
+                        pad_right: false,
                         kind: Chaining,
                         label: [
                             "",
@@ -637,6 +682,9 @@ fn main() {
                     },
                     InlayHint {
                         range: 145..168,
+                        position: After,
+                        pad_left: true,
+                        pad_right: false,
                         kind: Chaining,
                         label: [
                             "",
@@ -658,6 +706,9 @@ fn main() {
                     },
                     InlayHint {
                         range: 222..228,
+                        position: Before,
+                        pad_left: false,
+                        pad_right: true,
                         kind: Parameter,
                         label: [
                             InlayHintLabelPart {
diff --git a/crates/ide/src/inlay_hints/closing_brace.rs b/crates/ide/src/inlay_hints/closing_brace.rs
index 10b5acd064e..cd5a815abb0 100644
--- a/crates/ide/src/inlay_hints/closing_brace.rs
+++ b/crates/ide/src/inlay_hints/closing_brace.rs
@@ -10,7 +10,7 @@ use syntax::{
     match_ast, SyntaxKind, SyntaxNode, T,
 };
 
-use crate::{FileId, InlayHint, InlayHintLabel, InlayHintsConfig, InlayKind};
+use crate::{FileId, InlayHint, InlayHintLabel, InlayHintPosition, InlayHintsConfig, InlayKind};
 
 pub(super) fn hints(
     acc: &mut Vec<InlayHint>,
@@ -113,6 +113,9 @@ pub(super) fn hints(
         kind: InlayKind::ClosingBrace,
         label: InlayHintLabel::simple(label, None, linked_location),
         text_edit: None,
+        position: InlayHintPosition::After,
+        pad_left: true,
+        pad_right: false,
     });
 
     None
diff --git a/crates/ide/src/inlay_hints/closure_captures.rs b/crates/ide/src/inlay_hints/closure_captures.rs
index 60c4fe411f4..3ee118f6e8c 100644
--- a/crates/ide/src/inlay_hints/closure_captures.rs
+++ b/crates/ide/src/inlay_hints/closure_captures.rs
@@ -5,7 +5,7 @@ use ide_db::{base_db::FileId, famous_defs::FamousDefs};
 use syntax::ast::{self, AstNode};
 use text_edit::{TextRange, TextSize};
 
-use crate::{InlayHint, InlayHintLabel, InlayHintsConfig, InlayKind};
+use crate::{InlayHint, InlayHintLabel, InlayHintPosition, InlayHintsConfig, InlayKind};
 
 pub(super) fn hints(
     acc: &mut Vec<InlayHint>,
@@ -35,6 +35,9 @@ pub(super) fn hints(
                 kind: InlayKind::ClosureCapture,
                 label: InlayHintLabel::simple("move", None, None),
                 text_edit: None,
+                position: InlayHintPosition::After,
+                pad_left: false,
+                pad_right: false,
             });
             range
         }
@@ -44,6 +47,9 @@ pub(super) fn hints(
         kind: InlayKind::ClosureCapture,
         label: InlayHintLabel::from("("),
         text_edit: None,
+        position: InlayHintPosition::After,
+        pad_left: false,
+        pad_right: false,
     });
     let last = captures.len() - 1;
     for (idx, capture) in captures.into_iter().enumerate() {
@@ -71,6 +77,9 @@ pub(super) fn hints(
                 source.name().and_then(|name| sema.original_range_opt(name.syntax())),
             ),
             text_edit: None,
+            position: InlayHintPosition::After,
+            pad_left: false,
+            pad_right: false,
         });
 
         if idx != last {
@@ -79,6 +88,9 @@ pub(super) fn hints(
                 kind: InlayKind::ClosureCapture,
                 label: InlayHintLabel::simple(", ", None, None),
                 text_edit: None,
+                position: InlayHintPosition::After,
+                pad_left: false,
+                pad_right: false,
             });
         }
     }
@@ -87,6 +99,9 @@ pub(super) fn hints(
         kind: InlayKind::ClosureCapture,
         label: InlayHintLabel::from(")"),
         text_edit: None,
+        position: InlayHintPosition::After,
+        pad_left: false,
+        pad_right: true,
     });
 
     Some(())
diff --git a/crates/ide/src/inlay_hints/closure_ret.rs b/crates/ide/src/inlay_hints/closure_ret.rs
index 6214e9c8e7f..3b41db0f13d 100644
--- a/crates/ide/src/inlay_hints/closure_ret.rs
+++ b/crates/ide/src/inlay_hints/closure_ret.rs
@@ -6,7 +6,7 @@ use syntax::ast::{self, AstNode};
 
 use crate::{
     inlay_hints::{closure_has_block_body, label_of_ty, ty_to_text_edit},
-    ClosureReturnTypeHints, InlayHint, InlayHintsConfig, InlayKind,
+    ClosureReturnTypeHints, InlayHint, InlayHintPosition, InlayHintsConfig, InlayKind,
 };
 
 pub(super) fn hints(
@@ -20,9 +20,12 @@ pub(super) fn hints(
         return None;
     }
 
-    if closure.ret_type().is_some() {
-        return None;
-    }
+    let ret_type = closure.ret_type().map(|rt| (rt.thin_arrow_token(), rt.ty().is_some()));
+    let arrow = match ret_type {
+        Some((_, true)) => return None,
+        Some((arrow, _)) => arrow,
+        None => None,
+    };
 
     let has_block_body = closure_has_block_body(&closure);
     if !has_block_body && config.closure_return_type_hints == ClosureReturnTypeHints::WithBlock {
@@ -35,18 +38,26 @@ pub(super) fn hints(
     let ty = sema.type_of_expr(&ast::Expr::ClosureExpr(closure.clone()))?.adjusted();
     let callable = ty.as_callable(sema.db)?;
     let ty = callable.return_type();
-    if ty.is_unit() {
+    if arrow.is_none() && ty.is_unit() {
         return None;
     }
 
+    let mut label = label_of_ty(famous_defs, config, &ty)?;
+
+    if arrow.is_none() {
+        label.prepend_str(" -> ");
+    }
     // FIXME?: We could provide text edit to insert braces for closures with non-block body.
     let text_edit = if has_block_body {
         ty_to_text_edit(
             sema,
             closure.syntax(),
             &ty,
-            param_list.syntax().text_range().end(),
-            String::from(" -> "),
+            arrow
+                .as_ref()
+                .map_or_else(|| param_list.syntax().text_range(), |t| t.text_range())
+                .end(),
+            if arrow.is_none() { String::from(" -> ") } else { String::new() },
         )
     } else {
         None
@@ -54,9 +65,36 @@ pub(super) fn hints(
 
     acc.push(InlayHint {
         range: param_list.syntax().text_range(),
-        kind: InlayKind::ClosureReturnType,
-        label: label_of_ty(famous_defs, config, ty)?,
+        kind: InlayKind::Type,
+        label,
         text_edit,
+        position: InlayHintPosition::After,
+        pad_left: false,
+        pad_right: false,
     });
     Some(())
 }
+
+#[cfg(test)]
+mod tests {
+    use crate::inlay_hints::tests::{check_with_config, DISABLED_CONFIG};
+
+    use super::*;
+
+    #[test]
+    fn return_type_hints_for_closure_without_block() {
+        check_with_config(
+            InlayHintsConfig {
+                closure_return_type_hints: ClosureReturnTypeHints::Always,
+                ..DISABLED_CONFIG
+            },
+            r#"
+fn main() {
+    let a = || { 0 };
+          //^^ -> i32
+    let b = || 0;
+          //^^ -> i32
+}"#,
+        );
+    }
+}
diff --git a/crates/ide/src/inlay_hints/discriminant.rs b/crates/ide/src/inlay_hints/discriminant.rs
index f9047efaf1a..9bff98f6110 100644
--- a/crates/ide/src/inlay_hints/discriminant.rs
+++ b/crates/ide/src/inlay_hints/discriminant.rs
@@ -9,7 +9,8 @@ use ide_db::{base_db::FileId, famous_defs::FamousDefs, RootDatabase};
 use syntax::ast::{self, AstNode, HasName};
 
 use crate::{
-    DiscriminantHints, InlayHint, InlayHintLabel, InlayHintsConfig, InlayKind, InlayTooltip,
+    DiscriminantHints, InlayHint, InlayHintLabel, InlayHintPosition, InlayHintsConfig, InlayKind,
+    InlayTooltip,
 };
 
 pub(super) fn enum_hints(
@@ -41,10 +42,11 @@ fn variant_hints(
     sema: &Semantics<'_, RootDatabase>,
     variant: &ast::Variant,
 ) -> Option<()> {
-    if variant.eq_token().is_some() {
+    if variant.expr().is_some() {
         return None;
     }
 
+    let eq_token = variant.eq_token();
     let name = variant.name()?;
 
     let descended = sema.descend_node_into_attributes(variant.clone()).pop();
@@ -52,30 +54,39 @@ fn variant_hints(
     let v = sema.to_def(desc_pat)?;
     let d = v.eval(sema.db);
 
+    let range = match variant.field_list() {
+        Some(field_list) => name.syntax().text_range().cover(field_list.syntax().text_range()),
+        None => name.syntax().text_range(),
+    };
+    let eq_ = if eq_token.is_none() { " =" } else { "" };
+    let label = InlayHintLabel::simple(
+        match d {
+            Ok(x) => {
+                if x >= 10 {
+                    format!("{eq_} {x} ({x:#X})")
+                } else {
+                    format!("{eq_} {x}")
+                }
+            }
+            Err(_) => format!("{eq_} ?"),
+        },
+        Some(InlayTooltip::String(match &d {
+            Ok(_) => "enum variant discriminant".into(),
+            Err(e) => format!("{e:?}").into(),
+        })),
+        None,
+    );
     acc.push(InlayHint {
-        range: match variant.field_list() {
-            Some(field_list) => name.syntax().text_range().cover(field_list.syntax().text_range()),
-            None => name.syntax().text_range(),
+        range: match eq_token {
+            Some(t) => range.cover(t.text_range()),
+            _ => range,
         },
         kind: InlayKind::Discriminant,
-        label: InlayHintLabel::simple(
-            match d {
-                Ok(x) => {
-                    if x >= 10 {
-                        format!("{x} ({x:#X})")
-                    } else {
-                        format!("{x}")
-                    }
-                }
-                Err(_) => "?".into(),
-            },
-            Some(InlayTooltip::String(match &d {
-                Ok(_) => "enum variant discriminant".into(),
-                Err(e) => format!("{e:?}").into(),
-            })),
-            None,
-        ),
+        label,
         text_edit: None,
+        position: InlayHintPosition::After,
+        pad_left: false,
+        pad_right: false,
     });
 
     Some(())
@@ -113,14 +124,14 @@ mod tests {
             r#"
 enum Enum {
   Variant,
-//^^^^^^^0
+//^^^^^^^ = 0$
   Variant1,
-//^^^^^^^^1
+//^^^^^^^^ = 1$
   Variant2,
-//^^^^^^^^2
+//^^^^^^^^ = 2$
   Variant5 = 5,
   Variant6,
-//^^^^^^^^6
+//^^^^^^^^ = 6$
 }
 "#,
         );
@@ -128,14 +139,14 @@ enum Enum {
             r#"
 enum Enum {
   Variant,
-//^^^^^^^0
+//^^^^^^^ = 0
   Variant1,
-//^^^^^^^^1
+//^^^^^^^^ = 1
   Variant2,
-//^^^^^^^^2
+//^^^^^^^^ = 2
   Variant5 = 5,
   Variant6,
-//^^^^^^^^6
+//^^^^^^^^ = 6
 }
 "#,
         );
@@ -147,16 +158,16 @@ enum Enum {
             r#"
 enum Enum {
     Variant(),
-  //^^^^^^^^^0
+  //^^^^^^^^^ = 0
     Variant1,
-  //^^^^^^^^1
+  //^^^^^^^^ = 1
     Variant2 {},
-  //^^^^^^^^^^^2
+  //^^^^^^^^^^^ = 2
     Variant3,
-  //^^^^^^^^3
+  //^^^^^^^^ = 3
     Variant5 = 5,
     Variant6,
-  //^^^^^^^^6
+  //^^^^^^^^ = 6
 }
 "#,
         );
@@ -180,16 +191,16 @@ enum Enum {
             r#"
 enum Enum {
     Variant(),
-  //^^^^^^^^^0
+  //^^^^^^^^^ = 0
     Variant1,
-  //^^^^^^^^1
+  //^^^^^^^^ = 1
     Variant2 {},
-  //^^^^^^^^^^^2
+  //^^^^^^^^^^^ = 2
     Variant3,
-  //^^^^^^^^3
+  //^^^^^^^^ = 3
     Variant5 = 5,
     Variant6,
-  //^^^^^^^^6
+  //^^^^^^^^ = 6
 }
 "#,
         );
diff --git a/crates/ide/src/inlay_hints/fn_lifetime_fn.rs b/crates/ide/src/inlay_hints/fn_lifetime_fn.rs
index 34eb5eb94c4..5fce11b785a 100644
--- a/crates/ide/src/inlay_hints/fn_lifetime_fn.rs
+++ b/crates/ide/src/inlay_hints/fn_lifetime_fn.rs
@@ -10,7 +10,7 @@ use syntax::{
     SyntaxToken,
 };
 
-use crate::{InlayHint, InlayHintsConfig, InlayKind, LifetimeElisionHints};
+use crate::{InlayHint, InlayHintPosition, InlayHintsConfig, InlayKind, LifetimeElisionHints};
 
 pub(super) fn hints(
     acc: &mut Vec<InlayHint>,
@@ -26,6 +26,9 @@ pub(super) fn hints(
         kind: InlayKind::Lifetime,
         label: label.into(),
         text_edit: None,
+        position: InlayHintPosition::After,
+        pad_left: false,
+        pad_right: true,
     };
 
     let param_list = func.param_list()?;
@@ -191,6 +194,9 @@ pub(super) fn hints(
                 )
                 .into(),
                 text_edit: None,
+                position: InlayHintPosition::After,
+                pad_left: false,
+                pad_right: true,
             });
         }
         (None, allocated_lifetimes) => acc.push(InlayHint {
@@ -198,6 +204,9 @@ pub(super) fn hints(
             kind: InlayKind::GenericParamList,
             label: format!("<{}>", allocated_lifetimes.iter().format(", "),).into(),
             text_edit: None,
+            position: InlayHintPosition::After,
+            pad_left: false,
+            pad_right: false,
         }),
     }
     Some(())
diff --git a/crates/ide/src/inlay_hints/implicit_static.rs b/crates/ide/src/inlay_hints/implicit_static.rs
index ba875649f79..fc297a8d824 100644
--- a/crates/ide/src/inlay_hints/implicit_static.rs
+++ b/crates/ide/src/inlay_hints/implicit_static.rs
@@ -8,7 +8,7 @@ use syntax::{
     SyntaxKind,
 };
 
-use crate::{InlayHint, InlayHintsConfig, InlayKind, LifetimeElisionHints};
+use crate::{InlayHint, InlayHintPosition, InlayHintsConfig, InlayKind, LifetimeElisionHints};
 
 pub(super) fn hints(
     acc: &mut Vec<InlayHint>,
@@ -35,6 +35,9 @@ pub(super) fn hints(
                 kind: InlayKind::Lifetime,
                 label: "'static".to_owned().into(),
                 text_edit: None,
+                position: InlayHintPosition::After,
+                pad_left: false,
+                pad_right: true,
             });
         }
     }
diff --git a/crates/ide/src/inlay_hints/param_name.rs b/crates/ide/src/inlay_hints/param_name.rs
index 9729a43c220..c4f43f41175 100644
--- a/crates/ide/src/inlay_hints/param_name.rs
+++ b/crates/ide/src/inlay_hints/param_name.rs
@@ -10,7 +10,7 @@ use ide_db::{base_db::FileRange, RootDatabase};
 use stdx::to_lower_snake_case;
 use syntax::ast::{self, AstNode, HasArgList, HasName, UnaryOp};
 
-use crate::{InlayHint, InlayHintLabel, InlayHintsConfig, InlayKind};
+use crate::{InlayHint, InlayHintLabel, InlayHintPosition, InlayHintsConfig, InlayKind};
 
 pub(super) fn hints(
     acc: &mut Vec<InlayHint>,
@@ -31,16 +31,16 @@ pub(super) fn hints(
             // Only annotate hints for expressions that exist in the original file
             let range = sema.original_range_opt(arg.syntax())?;
             let (param_name, name_syntax) = match param.as_ref()? {
-                Either::Left(pat) => ("self".to_string(), pat.name()),
+                Either::Left(pat) => (pat.name()?, pat.name()),
                 Either::Right(pat) => match pat {
-                    ast::Pat::IdentPat(it) => (it.name()?.to_string(), it.name()),
+                    ast::Pat::IdentPat(it) => (it.name()?, it.name()),
                     _ => return None,
                 },
             };
             Some((name_syntax, param_name, arg, range))
         })
         .filter(|(_, param_name, arg, _)| {
-            !should_hide_param_name_hint(sema, &callable, param_name, arg)
+            !should_hide_param_name_hint(sema, &callable, &param_name.text(), arg)
         })
         .map(|(param, param_name, _, FileRange { range, .. })| {
             let mut linked_location = None;
@@ -53,11 +53,17 @@ pub(super) fn hints(
                 }
             }
 
+            let colon = if config.render_colons { ":" } else { "" };
+            let label =
+                InlayHintLabel::simple(format!("{param_name}{colon}"), None, linked_location);
             InlayHint {
                 range,
                 kind: InlayKind::Parameter,
-                label: InlayHintLabel::simple(param_name, None, linked_location),
+                label,
                 text_edit: None,
+                position: InlayHintPosition::Before,
+                pad_left: false,
+                pad_right: true,
             }
         });
 
diff --git a/crates/ide/src/lib.rs b/crates/ide/src/lib.rs
index b84d5df8107..72d20af6637 100644
--- a/crates/ide/src/lib.rs
+++ b/crates/ide/src/lib.rs
@@ -87,8 +87,8 @@ pub use crate::{
     hover::{HoverAction, HoverConfig, HoverDocFormat, HoverGotoTypeData, HoverResult},
     inlay_hints::{
         AdjustmentHints, AdjustmentHintsMode, ClosureReturnTypeHints, DiscriminantHints, InlayHint,
-        InlayHintLabel, InlayHintLabelPart, InlayHintsConfig, InlayKind, InlayTooltip,
-        LifetimeElisionHints,
+        InlayHintLabel, InlayHintLabelPart, InlayHintPosition, InlayHintsConfig, InlayKind,
+        InlayTooltip, LifetimeElisionHints,
     },
     join_lines::JoinLinesConfig,
     markup::Markup,
diff --git a/crates/rust-analyzer/src/handlers/request.rs b/crates/rust-analyzer/src/handlers/request.rs
index 9e9dfaaf5a3..96629b90ef5 100644
--- a/crates/rust-analyzer/src/handlers/request.rs
+++ b/crates/rust-analyzer/src/handlers/request.rs
@@ -1349,9 +1349,7 @@ pub(crate) fn handle_inlay_hints(
         snap.analysis
             .inlay_hints(&inlay_hints_config, file_id, Some(range))?
             .into_iter()
-            .map(|it| {
-                to_proto::inlay_hint(&snap, &line_index, inlay_hints_config.render_colons, it)
-            })
+            .map(|it| to_proto::inlay_hint(&snap, &line_index, it))
             .collect::<Cancellable<Vec<_>>>()?,
     ))
 }
diff --git a/crates/rust-analyzer/src/to_proto.rs b/crates/rust-analyzer/src/to_proto.rs
index 1b7fd558906..521b7a76279 100644
--- a/crates/rust-analyzer/src/to_proto.rs
+++ b/crates/rust-analyzer/src/to_proto.rs
@@ -434,87 +434,21 @@ pub(crate) fn signature_help(
 pub(crate) fn inlay_hint(
     snap: &GlobalStateSnapshot,
     line_index: &LineIndex,
-    render_colons: bool,
-    mut inlay_hint: InlayHint,
+    inlay_hint: InlayHint,
 ) -> Cancellable<lsp_types::InlayHint> {
-    match inlay_hint.kind {
-        InlayKind::Parameter if render_colons => inlay_hint.label.append_str(":"),
-        InlayKind::Type if render_colons => inlay_hint.label.prepend_str(": "),
-        InlayKind::ClosureReturnType => inlay_hint.label.prepend_str(" -> "),
-        InlayKind::Discriminant => inlay_hint.label.prepend_str(" = "),
-        _ => {}
-    }
-
     let (label, tooltip) = inlay_hint_label(snap, inlay_hint.label)?;
 
     Ok(lsp_types::InlayHint {
-        position: match inlay_hint.kind {
-            // before annotated thing
-            InlayKind::OpeningParenthesis
-            | InlayKind::Parameter
-            | InlayKind::Adjustment
-            | InlayKind::BindingMode => position(line_index, inlay_hint.range.start()),
-            // after annotated thing
-            InlayKind::ClosureReturnType
-            | InlayKind::ClosureCapture
-            | InlayKind::Type
-            | InlayKind::Discriminant
-            | InlayKind::Chaining
-            | InlayKind::GenericParamList
-            | InlayKind::ClosingParenthesis
-            | InlayKind::AdjustmentPostfix
-            | InlayKind::Lifetime
-            | InlayKind::ClosingBrace => position(line_index, inlay_hint.range.end()),
+        position: match inlay_hint.position {
+            ide::InlayHintPosition::Before => position(line_index, inlay_hint.range.start()),
+            ide::InlayHintPosition::After => position(line_index, inlay_hint.range.end()),
         },
-        padding_left: Some(match inlay_hint.kind {
-            InlayKind::Type => !render_colons,
-            InlayKind::Chaining | InlayKind::ClosingBrace => true,
-            InlayKind::ClosingParenthesis
-            | InlayKind::ClosureCapture
-            | InlayKind::Discriminant
-            | InlayKind::OpeningParenthesis
-            | InlayKind::BindingMode
-            | InlayKind::ClosureReturnType
-            | InlayKind::GenericParamList
-            | InlayKind::Adjustment
-            | InlayKind::AdjustmentPostfix
-            | InlayKind::Lifetime
-            | InlayKind::Parameter => false,
-        }),
-        padding_right: Some(match inlay_hint.kind {
-            InlayKind::ClosingParenthesis
-            | InlayKind::OpeningParenthesis
-            | InlayKind::Chaining
-            | InlayKind::ClosureReturnType
-            | InlayKind::GenericParamList
-            | InlayKind::Adjustment
-            | InlayKind::AdjustmentPostfix
-            | InlayKind::Type
-            | InlayKind::Discriminant
-            | InlayKind::ClosingBrace => false,
-            InlayKind::ClosureCapture => {
-                matches!(&label, lsp_types::InlayHintLabel::String(s) if s == ")")
-            }
-            InlayKind::BindingMode => {
-                matches!(&label, lsp_types::InlayHintLabel::String(s) if s != "&")
-            }
-            InlayKind::Parameter | InlayKind::Lifetime => true,
-        }),
+        padding_left: Some(inlay_hint.pad_left),
+        padding_right: Some(inlay_hint.pad_right),
         kind: match inlay_hint.kind {
             InlayKind::Parameter => Some(lsp_types::InlayHintKind::PARAMETER),
-            InlayKind::ClosureReturnType | InlayKind::Type | InlayKind::Chaining => {
-                Some(lsp_types::InlayHintKind::TYPE)
-            }
-            InlayKind::ClosingParenthesis
-            | InlayKind::ClosureCapture
-            | InlayKind::Discriminant
-            | InlayKind::OpeningParenthesis
-            | InlayKind::BindingMode
-            | InlayKind::GenericParamList
-            | InlayKind::Lifetime
-            | InlayKind::Adjustment
-            | InlayKind::AdjustmentPostfix
-            | InlayKind::ClosingBrace => None,
+            InlayKind::Type | InlayKind::Chaining => Some(lsp_types::InlayHintKind::TYPE),
+            _ => None,
         },
         text_edits: inlay_hint.text_edit.map(|it| text_edit_vec(line_index, it)),
         data: None,