mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-22 14:55:26 +00:00
Auto merge of #13816 - WaffleLapkin:postfix_adjustment_hints, r=Veykril
Postfix adjustment hints # Basic Description This PR implements "postfix" adjustment hints: ![2022-12-21_19-27](https://user-images.githubusercontent.com/38225716/208941721-d48d316f-a918-408a-9757-8d4e2b402a66.png) They are identical to normal adjustment hints, but are rendered _after_ the expression. E.g. `expr.*` instead of `*expr`. ~~This mirrors "postfix deref" feature that I'm planning to eventually propose to the compiler.~~ # Motivation The advantage of being postfix is that you need to add parentheses less often: ![2022-12-21_19-38](https://user-images.githubusercontent.com/38225716/208944302-16718112-14a4-4438-8aed-797766391c63.png) ![2022-12-21_19-37](https://user-images.githubusercontent.com/38225716/208944281-d9614888-6597-41ee-bf5d-a081d8048f94.png) This is because a lot of "reborrow" hints are caused by field access or method calls, both of which are postfix and have higher "precedence" than prefix `&` and `*`. Also IMHO it just looks nicer and it's more clear what is happening (order of operations). # Modes However, there are some cases where postfix hints need parentheses but prefix don't (for example `&x` being turned into `(&x).*.*.&` or `&**&x`). This PR allows users to choose which look they like more. There are 4 options (`rust-analyzer.inlayHints.expressionAdjustmentHints.mode` setting): - `prefix` — always use prefix hints (default, what was used before that PR) - `postfix` — always use postfix hints - `prefer_prefix` — try to minimize number of parentheses, breaking ties in favor of prefix - `prefer_postfix` — try to minimize number of parentheses, breaking ties in favor of postfix Comparison of all modes: ![2022-12-21_19-53](https://user-images.githubusercontent.com/38225716/208947482-26357c82-2b42-47d9-acec-835f5f03f6b4.png) ![2022-12-21_19-49](https://user-images.githubusercontent.com/38225716/208946731-fe566d3b-52b2-4846-994d-c2cecc769e0f.png) ![2022-12-21_19-48](https://user-images.githubusercontent.com/38225716/208946742-6e237f44-805e-469a-a3db-03d8f76e1317.png) ![2022-12-21_19-47](https://user-images.githubusercontent.com/38225716/208946747-79f25fae-e3ea-47d2-8d27-cb4eeac034fe.png) # Edge cases Where are some rare cases where chain hints weirdly interact with adjustment hints, for example (note `SourceAnalyzer.&`): ![image](https://user-images.githubusercontent.com/38225716/208947958-41c12971-f1f0-4a41-a930-47939cce9f58.png) This is pre-existing, you can get the same effect with prefix hints (`SourceAnalyzer)`). ---- Another weird thing is this: ![2022-12-21_20-00](https://user-images.githubusercontent.com/38225716/208948590-ea26d325-2108-4b35-abaa-716a65a1ae99.png) Here `.&` is a hint and `?` is written in the source code. It looks like `?` is part of the hint because `?.` is ligature in my font. IMO this is a bug in vscode, but still worth mentioning (I'm also too lazy to report it there...). # Fixed bugs I've used the "needs parens" API and this accidentally fixed a bug with parens around `as`, see the test diff: ```diff,rust let _: *const u32 = &mut 0u32 as *mut u32; //^^^^^^^^^^^^^^^^^^^^^<mut-ptr-to-const-ptr> + //^^^^^^^^^^^^^^^^^^^^^( + //^^^^^^^^^^^^^^^^^^^^^) ... let _: *const u32 = &mut 0u32 as *mut u32; //^^^^^^^^^^^^^^^^^^^^^<mut-ptr-to-const-ptr> + //^^^^^^^^^^^^^^^^^^^^^( + //^^^^^^^^^^^^^^^^^^^^^) ``` # Changelog changelog feature Add an option to make adjustment hints (aka reborrow hints) postfix changelog fix Fix placement of parentheses around `as` casts for adjustment hints
This commit is contained in:
commit
ec968198b9
@ -35,6 +35,7 @@ pub struct InlayHintsConfig {
|
||||
pub parameter_hints: bool,
|
||||
pub chaining_hints: bool,
|
||||
pub adjustment_hints: AdjustmentHints,
|
||||
pub adjustment_hints_mode: AdjustmentHintsMode,
|
||||
pub adjustment_hints_hide_outside_unsafe: bool,
|
||||
pub closure_return_type_hints: ClosureReturnTypeHints,
|
||||
pub binding_mode_hints: bool,
|
||||
@ -74,6 +75,14 @@ pub enum AdjustmentHints {
|
||||
Never,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
||||
pub enum AdjustmentHintsMode {
|
||||
Prefix,
|
||||
Postfix,
|
||||
PreferPrefix,
|
||||
PreferPostfix,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
pub enum InlayKind {
|
||||
BindingModeHint,
|
||||
@ -82,6 +91,7 @@ pub enum InlayKind {
|
||||
ClosureReturnTypeHint,
|
||||
GenericParamListHint,
|
||||
AdjustmentHint,
|
||||
AdjustmentHintPostfix,
|
||||
LifetimeHint,
|
||||
ParameterHint,
|
||||
TypeHint,
|
||||
@ -430,7 +440,7 @@ mod tests {
|
||||
use itertools::Itertools;
|
||||
use test_utils::extract_annotations;
|
||||
|
||||
use crate::inlay_hints::AdjustmentHints;
|
||||
use crate::inlay_hints::{AdjustmentHints, AdjustmentHintsMode};
|
||||
use crate::DiscriminantHints;
|
||||
use crate::{fixture, inlay_hints::InlayHintsConfig, LifetimeElisionHints};
|
||||
|
||||
@ -446,6 +456,7 @@ mod tests {
|
||||
lifetime_elision_hints: LifetimeElisionHints::Never,
|
||||
closure_return_type_hints: ClosureReturnTypeHints::Never,
|
||||
adjustment_hints: AdjustmentHints::Never,
|
||||
adjustment_hints_mode: AdjustmentHintsMode::Prefix,
|
||||
adjustment_hints_hide_outside_unsafe: false,
|
||||
binding_mode_hints: false,
|
||||
hide_named_constructor_hints: false,
|
||||
|
@ -5,9 +5,13 @@
|
||||
//! ```
|
||||
use hir::{Adjust, AutoBorrow, Mutability, OverloadedDeref, PointerCast, Safety, Semantics};
|
||||
use ide_db::RootDatabase;
|
||||
use syntax::ast::{self, AstNode};
|
||||
|
||||
use crate::{AdjustmentHints, InlayHint, InlayHintsConfig, InlayKind};
|
||||
use syntax::{
|
||||
ast::{self, make, AstNode},
|
||||
ted,
|
||||
};
|
||||
|
||||
use crate::{AdjustmentHints, AdjustmentHintsMode, InlayHint, InlayHintsConfig, InlayKind};
|
||||
|
||||
pub(super) fn hints(
|
||||
acc: &mut Vec<InlayHint>,
|
||||
@ -32,28 +36,14 @@ pub(super) fn hints(
|
||||
return None;
|
||||
}
|
||||
|
||||
let parent = expr.syntax().parent().and_then(ast::Expr::cast);
|
||||
let descended = sema.descend_node_into_attributes(expr.clone()).pop();
|
||||
let desc_expr = descended.as_ref().unwrap_or(expr);
|
||||
let adjustments = sema.expr_adjustments(desc_expr).filter(|it| !it.is_empty())?;
|
||||
let needs_parens = match parent {
|
||||
Some(parent) => {
|
||||
match parent {
|
||||
ast::Expr::AwaitExpr(_)
|
||||
| ast::Expr::CallExpr(_)
|
||||
| ast::Expr::CastExpr(_)
|
||||
| ast::Expr::FieldExpr(_)
|
||||
| ast::Expr::MethodCallExpr(_)
|
||||
| ast::Expr::TryExpr(_) => true,
|
||||
// FIXME: shorthands need special casing, though not sure if adjustments are even valid there
|
||||
ast::Expr::RecordExpr(_) => false,
|
||||
ast::Expr::IndexExpr(index) => index.base().as_ref() == Some(expr),
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
None => false,
|
||||
};
|
||||
if needs_parens {
|
||||
|
||||
let (postfix, needs_outer_parens, needs_inner_parens) =
|
||||
mode_and_needs_parens_for_adjustment_hints(expr, config.adjustment_hints_mode);
|
||||
|
||||
if needs_outer_parens {
|
||||
acc.push(InlayHint {
|
||||
range: expr.syntax().text_range(),
|
||||
kind: InlayKind::OpeningParenthesis,
|
||||
@ -61,7 +51,32 @@ pub(super) fn hints(
|
||||
tooltip: None,
|
||||
});
|
||||
}
|
||||
for adjustment in adjustments.into_iter().rev() {
|
||||
|
||||
if postfix && needs_inner_parens {
|
||||
acc.push(InlayHint {
|
||||
range: expr.syntax().text_range(),
|
||||
kind: InlayKind::OpeningParenthesis,
|
||||
label: "(".into(),
|
||||
tooltip: None,
|
||||
});
|
||||
acc.push(InlayHint {
|
||||
range: expr.syntax().text_range(),
|
||||
kind: InlayKind::ClosingParenthesis,
|
||||
label: ")".into(),
|
||||
tooltip: None,
|
||||
});
|
||||
}
|
||||
|
||||
let (mut tmp0, mut tmp1);
|
||||
let iter: &mut dyn Iterator<Item = _> = if postfix {
|
||||
tmp0 = adjustments.into_iter();
|
||||
&mut tmp0
|
||||
} else {
|
||||
tmp1 = adjustments.into_iter().rev();
|
||||
&mut tmp1
|
||||
};
|
||||
|
||||
for adjustment in iter {
|
||||
if adjustment.source == adjustment.target {
|
||||
continue;
|
||||
}
|
||||
@ -97,12 +112,30 @@ pub(super) fn hints(
|
||||
};
|
||||
acc.push(InlayHint {
|
||||
range: expr.syntax().text_range(),
|
||||
kind: InlayKind::AdjustmentHint,
|
||||
label: text.into(),
|
||||
kind: if postfix {
|
||||
InlayKind::AdjustmentHintPostfix
|
||||
} else {
|
||||
InlayKind::AdjustmentHint
|
||||
},
|
||||
label: if postfix { format!(".{}", text.trim_end()).into() } else { text.into() },
|
||||
tooltip: None,
|
||||
});
|
||||
}
|
||||
if needs_parens {
|
||||
if !postfix && needs_inner_parens {
|
||||
acc.push(InlayHint {
|
||||
range: expr.syntax().text_range(),
|
||||
kind: InlayKind::OpeningParenthesis,
|
||||
label: "(".into(),
|
||||
tooltip: None,
|
||||
});
|
||||
acc.push(InlayHint {
|
||||
range: expr.syntax().text_range(),
|
||||
kind: InlayKind::ClosingParenthesis,
|
||||
label: ")".into(),
|
||||
tooltip: None,
|
||||
});
|
||||
}
|
||||
if needs_outer_parens {
|
||||
acc.push(InlayHint {
|
||||
range: expr.syntax().text_range(),
|
||||
kind: InlayKind::ClosingParenthesis,
|
||||
@ -113,11 +146,111 @@ pub(super) fn hints(
|
||||
Some(())
|
||||
}
|
||||
|
||||
/// Returns whatever the hint should be postfix and if we need to add paretheses on the inside and/or outside of `expr`,
|
||||
/// if we are going to add (`postfix`) adjustments hints to it.
|
||||
fn mode_and_needs_parens_for_adjustment_hints(
|
||||
expr: &ast::Expr,
|
||||
mode: AdjustmentHintsMode,
|
||||
) -> (bool, bool, bool) {
|
||||
use {std::cmp::Ordering::*, AdjustmentHintsMode::*};
|
||||
|
||||
match mode {
|
||||
Prefix | Postfix => {
|
||||
let postfix = matches!(mode, Postfix);
|
||||
let (inside, outside) = needs_parens_for_adjustment_hints(expr, postfix);
|
||||
(postfix, inside, outside)
|
||||
}
|
||||
PreferPrefix | PreferPostfix => {
|
||||
let prefer_postfix = matches!(mode, PreferPostfix);
|
||||
|
||||
let (pre_inside, pre_outside) = needs_parens_for_adjustment_hints(expr, false);
|
||||
let prefix = (false, pre_inside, pre_outside);
|
||||
let pre_count = pre_inside as u8 + pre_outside as u8;
|
||||
|
||||
let (post_inside, post_outside) = needs_parens_for_adjustment_hints(expr, true);
|
||||
let postfix = (true, post_inside, post_outside);
|
||||
let post_count = post_inside as u8 + post_outside as u8;
|
||||
|
||||
match pre_count.cmp(&post_count) {
|
||||
Less => prefix,
|
||||
Greater => postfix,
|
||||
Equal if prefer_postfix => postfix,
|
||||
Equal => prefix,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns whatever we need to add paretheses on the inside and/or outside of `expr`,
|
||||
/// if we are going to add (`postfix`) adjustments hints to it.
|
||||
fn needs_parens_for_adjustment_hints(expr: &ast::Expr, postfix: bool) -> (bool, bool) {
|
||||
// This is a very miserable pile of hacks...
|
||||
//
|
||||
// `Expr::needs_parens_in` requires that the expression is the child of the other expression,
|
||||
// that is supposed to be its parent.
|
||||
//
|
||||
// But we want to check what would happen if we add `*`/`.*` to the inner expression.
|
||||
// To check for inner we need `` expr.needs_parens_in(`*expr`) ``,
|
||||
// to check for outer we need `` `*expr`.needs_parens_in(parent) ``,
|
||||
// where "expr" is the `expr` parameter, `*expr` is the editted `expr`,
|
||||
// and "parent" is the parent of the original expression...
|
||||
//
|
||||
// For this we utilize mutable mutable trees, which is a HACK, but it works.
|
||||
//
|
||||
// FIXME: comeup with a better API for `needs_parens_in`, so that we don't have to do *this*
|
||||
|
||||
// Make `&expr`/`expr?`
|
||||
let dummy_expr = {
|
||||
// `make::*` function go through a string, so they parse wrongly.
|
||||
// for example `` make::expr_try(`|| a`) `` would result in a
|
||||
// `|| (a?)` and not `(|| a)?`.
|
||||
//
|
||||
// Thus we need dummy parens to preserve the relationship we want.
|
||||
// The parens are then simply ignored by the following code.
|
||||
let dummy_paren = make::expr_paren(expr.clone());
|
||||
if postfix {
|
||||
make::expr_try(dummy_paren)
|
||||
} else {
|
||||
make::expr_ref(dummy_paren, false)
|
||||
}
|
||||
};
|
||||
|
||||
// Do the dark mutable tree magic.
|
||||
// This essentially makes `dummy_expr` and `expr` switch places (families),
|
||||
// so that `expr`'s parent is not `dummy_expr`'s parent.
|
||||
let dummy_expr = dummy_expr.clone_for_update();
|
||||
let expr = expr.clone_for_update();
|
||||
ted::replace(expr.syntax(), dummy_expr.syntax());
|
||||
|
||||
let parent = dummy_expr.syntax().parent();
|
||||
let expr = if postfix {
|
||||
let ast::Expr::TryExpr(e) = &dummy_expr else { unreachable!() };
|
||||
let Some(ast::Expr::ParenExpr(e)) = e.expr() else { unreachable!() };
|
||||
|
||||
e.expr().unwrap()
|
||||
} else {
|
||||
let ast::Expr::RefExpr(e) = &dummy_expr else { unreachable!() };
|
||||
let Some(ast::Expr::ParenExpr(e)) = e.expr() else { unreachable!() };
|
||||
|
||||
e.expr().unwrap()
|
||||
};
|
||||
|
||||
// At this point
|
||||
// - `parent` is the parrent of the original expression
|
||||
// - `dummy_expr` is the original expression wrapped in the operator we want (`*`/`.*`)
|
||||
// - `expr` is the clone of the original expression (with `dummy_expr` as the parent)
|
||||
|
||||
let needs_outer_parens = parent.map_or(false, |p| dummy_expr.needs_parens_in(p));
|
||||
let needs_inner_parens = expr.needs_parens_in(dummy_expr.syntax().clone());
|
||||
|
||||
(needs_outer_parens, needs_inner_parens)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::{
|
||||
inlay_hints::tests::{check_with_config, DISABLED_CONFIG},
|
||||
AdjustmentHints, InlayHintsConfig,
|
||||
AdjustmentHints, AdjustmentHintsMode, InlayHintsConfig,
|
||||
};
|
||||
|
||||
#[test]
|
||||
@ -125,7 +258,7 @@ mod tests {
|
||||
check_with_config(
|
||||
InlayHintsConfig { adjustment_hints: AdjustmentHints::Always, ..DISABLED_CONFIG },
|
||||
r#"
|
||||
//- minicore: coerce_unsized
|
||||
//- minicore: coerce_unsized, fn
|
||||
fn main() {
|
||||
let _: u32 = loop {};
|
||||
//^^^^^^^<never-to-any>
|
||||
@ -148,12 +281,16 @@ fn main() {
|
||||
//^^^^<fn-item-to-fn-pointer>
|
||||
let _: unsafe fn() = main as fn();
|
||||
//^^^^^^^^^^^^<safe-fn-pointer-to-unsafe-fn-pointer>
|
||||
//^^^^^^^^^^^^(
|
||||
//^^^^^^^^^^^^)
|
||||
let _: fn() = || {};
|
||||
//^^^^^<closure-to-fn-pointer>
|
||||
let _: unsafe fn() = || {};
|
||||
//^^^^^<closure-to-unsafe-fn-pointer>
|
||||
let _: *const u32 = &mut 0u32 as *mut u32;
|
||||
//^^^^^^^^^^^^^^^^^^^^^<mut-ptr-to-const-ptr>
|
||||
//^^^^^^^^^^^^^^^^^^^^^(
|
||||
//^^^^^^^^^^^^^^^^^^^^^)
|
||||
let _: &mut [_] = &mut [0; 0];
|
||||
//^^^^^^^^^^^<unsize>
|
||||
//^^^^^^^^^^^&mut $
|
||||
@ -206,6 +343,11 @@ fn main() {
|
||||
//^^^^^^^<unsize>
|
||||
//^^^^^^^&mut $
|
||||
//^^^^^^^*
|
||||
|
||||
let _: &mut dyn Fn() = &mut || ();
|
||||
//^^^^^^^^^^<unsize>
|
||||
//^^^^^^^^^^&mut $
|
||||
//^^^^^^^^^^*
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
@ -215,12 +357,153 @@ impl Struct {
|
||||
fn by_ref(&self) {}
|
||||
fn by_ref_mut(&mut self) {}
|
||||
}
|
||||
trait Trait {}
|
||||
impl Trait for Struct {}
|
||||
"#,
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn adjustment_hints_postfix() {
|
||||
check_with_config(
|
||||
InlayHintsConfig {
|
||||
adjustment_hints: AdjustmentHints::Always,
|
||||
adjustment_hints_mode: AdjustmentHintsMode::Postfix,
|
||||
..DISABLED_CONFIG
|
||||
},
|
||||
r#"
|
||||
//- minicore: coerce_unsized, fn
|
||||
fn main() {
|
||||
|
||||
Struct.consume();
|
||||
Struct.by_ref();
|
||||
//^^^^^^.&
|
||||
Struct.by_ref_mut();
|
||||
//^^^^^^.&mut
|
||||
|
||||
(&Struct).consume();
|
||||
//^^^^^^^(
|
||||
//^^^^^^^)
|
||||
//^^^^^^^.*
|
||||
(&Struct).by_ref();
|
||||
|
||||
(&mut Struct).consume();
|
||||
//^^^^^^^^^^^(
|
||||
//^^^^^^^^^^^)
|
||||
//^^^^^^^^^^^.*
|
||||
(&mut Struct).by_ref();
|
||||
//^^^^^^^^^^^(
|
||||
//^^^^^^^^^^^)
|
||||
//^^^^^^^^^^^.*
|
||||
//^^^^^^^^^^^.&
|
||||
(&mut Struct).by_ref_mut();
|
||||
|
||||
// Check that block-like expressions don't duplicate hints
|
||||
let _: &mut [u32] = (&mut []);
|
||||
//^^^^^^^(
|
||||
//^^^^^^^)
|
||||
//^^^^^^^.*
|
||||
//^^^^^^^.&mut
|
||||
//^^^^^^^.<unsize>
|
||||
let _: &mut [u32] = { &mut [] };
|
||||
//^^^^^^^(
|
||||
//^^^^^^^)
|
||||
//^^^^^^^.*
|
||||
//^^^^^^^.&mut
|
||||
//^^^^^^^.<unsize>
|
||||
let _: &mut [u32] = unsafe { &mut [] };
|
||||
//^^^^^^^(
|
||||
//^^^^^^^)
|
||||
//^^^^^^^.*
|
||||
//^^^^^^^.&mut
|
||||
//^^^^^^^.<unsize>
|
||||
let _: &mut [u32] = if true {
|
||||
&mut []
|
||||
//^^^^^^^(
|
||||
//^^^^^^^)
|
||||
//^^^^^^^.*
|
||||
//^^^^^^^.&mut
|
||||
//^^^^^^^.<unsize>
|
||||
} else {
|
||||
loop {}
|
||||
//^^^^^^^.<never-to-any>
|
||||
};
|
||||
let _: &mut [u32] = match () { () => &mut [] }
|
||||
//^^^^^^^(
|
||||
//^^^^^^^)
|
||||
//^^^^^^^.*
|
||||
//^^^^^^^.&mut
|
||||
//^^^^^^^.<unsize>
|
||||
|
||||
let _: &mut dyn Fn() = &mut || ();
|
||||
//^^^^^^^^^^(
|
||||
//^^^^^^^^^^)
|
||||
//^^^^^^^^^^.*
|
||||
//^^^^^^^^^^.&mut
|
||||
//^^^^^^^^^^.<unsize>
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
struct Struct;
|
||||
impl Struct {
|
||||
fn consume(self) {}
|
||||
fn by_ref(&self) {}
|
||||
fn by_ref_mut(&mut self) {}
|
||||
}
|
||||
"#,
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn adjustment_hints_prefer_prefix() {
|
||||
check_with_config(
|
||||
InlayHintsConfig {
|
||||
adjustment_hints: AdjustmentHints::Always,
|
||||
adjustment_hints_mode: AdjustmentHintsMode::PreferPrefix,
|
||||
..DISABLED_CONFIG
|
||||
},
|
||||
r#"
|
||||
fn main() {
|
||||
let _: u32 = loop {};
|
||||
//^^^^^^^<never-to-any>
|
||||
|
||||
Struct.by_ref();
|
||||
//^^^^^^.&
|
||||
|
||||
let (): () = return ();
|
||||
//^^^^^^^^^<never-to-any>
|
||||
|
||||
struct Struct;
|
||||
impl Struct { fn by_ref(&self) {} }
|
||||
}
|
||||
"#,
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn adjustment_hints_prefer_postfix() {
|
||||
check_with_config(
|
||||
InlayHintsConfig {
|
||||
adjustment_hints: AdjustmentHints::Always,
|
||||
adjustment_hints_mode: AdjustmentHintsMode::PreferPostfix,
|
||||
..DISABLED_CONFIG
|
||||
},
|
||||
r#"
|
||||
fn main() {
|
||||
let _: u32 = loop {};
|
||||
//^^^^^^^.<never-to-any>
|
||||
|
||||
Struct.by_ref();
|
||||
//^^^^^^.&
|
||||
|
||||
let (): () = return ();
|
||||
//^^^^^^^^^<never-to-any>
|
||||
|
||||
struct Struct;
|
||||
impl Struct { fn by_ref(&self) {} }
|
||||
}
|
||||
"#,
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn never_to_never_is_never_shown() {
|
||||
check_with_config(
|
||||
@ -328,4 +611,20 @@ fn a() {
|
||||
"#,
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn bug() {
|
||||
check_with_config(
|
||||
InlayHintsConfig { adjustment_hints: AdjustmentHints::Always, ..DISABLED_CONFIG },
|
||||
r#"
|
||||
fn main() {
|
||||
// These should be identical, but they are not...
|
||||
|
||||
let () = return;
|
||||
let (): () = return;
|
||||
//^^^^^^<never-to-any>
|
||||
}
|
||||
"#,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -81,8 +81,8 @@ pub use crate::{
|
||||
highlight_related::{HighlightRelatedConfig, HighlightedRange},
|
||||
hover::{HoverAction, HoverConfig, HoverDocFormat, HoverGotoTypeData, HoverResult},
|
||||
inlay_hints::{
|
||||
AdjustmentHints, ClosureReturnTypeHints, DiscriminantHints, InlayHint, InlayHintLabel,
|
||||
InlayHintsConfig, InlayKind, InlayTooltip, LifetimeElisionHints,
|
||||
AdjustmentHints, AdjustmentHintsMode, ClosureReturnTypeHints, DiscriminantHints, InlayHint,
|
||||
InlayHintLabel, InlayHintsConfig, InlayKind, InlayTooltip, LifetimeElisionHints,
|
||||
},
|
||||
join_lines::JoinLinesConfig,
|
||||
markup::Markup,
|
||||
|
@ -13,6 +13,7 @@ use syntax::{AstNode, SyntaxKind::*, SyntaxToken, TextRange, T};
|
||||
|
||||
use crate::{
|
||||
hover::hover_for_definition,
|
||||
inlay_hints::AdjustmentHintsMode,
|
||||
moniker::{def_to_moniker, MonikerResult},
|
||||
parent_module::crates_for,
|
||||
Analysis, Fold, HoverConfig, HoverDocFormat, HoverResult, InlayHint, InlayHintsConfig,
|
||||
@ -115,6 +116,7 @@ impl StaticIndex<'_> {
|
||||
closure_return_type_hints: crate::ClosureReturnTypeHints::WithBlock,
|
||||
lifetime_elision_hints: crate::LifetimeElisionHints::Never,
|
||||
adjustment_hints: crate::AdjustmentHints::Never,
|
||||
adjustment_hints_mode: AdjustmentHintsMode::Prefix,
|
||||
adjustment_hints_hide_outside_unsafe: false,
|
||||
hide_named_constructor_hints: false,
|
||||
hide_closure_initialization_hints: false,
|
||||
|
@ -333,6 +333,8 @@ config_data! {
|
||||
inlayHints_expressionAdjustmentHints_enable: AdjustmentHintsDef = "\"never\"",
|
||||
/// Whether to hide inlay hints for type adjustments outside of `unsafe` blocks.
|
||||
inlayHints_expressionAdjustmentHints_hideOutsideUnsafe: bool = "false",
|
||||
/// Whether to show inlay hints as postfix ops (`.*` instead of `*`, etc).
|
||||
inlayHints_expressionAdjustmentHints_mode: AdjustmentHintsModeDef = "\"prefix\"",
|
||||
/// Whether to show inlay type hints for elided lifetimes in function signatures.
|
||||
inlayHints_lifetimeElisionHints_enable: LifetimeElisionDef = "\"never\"",
|
||||
/// Whether to prefer using parameter names as the name for elided lifetime hints if possible.
|
||||
@ -1252,6 +1254,12 @@ impl Config {
|
||||
},
|
||||
AdjustmentHintsDef::Reborrow => ide::AdjustmentHints::ReborrowOnly,
|
||||
},
|
||||
adjustment_hints_mode: match self.data.inlayHints_expressionAdjustmentHints_mode {
|
||||
AdjustmentHintsModeDef::Prefix => ide::AdjustmentHintsMode::Prefix,
|
||||
AdjustmentHintsModeDef::Postfix => ide::AdjustmentHintsMode::Postfix,
|
||||
AdjustmentHintsModeDef::PreferPrefix => ide::AdjustmentHintsMode::PreferPrefix,
|
||||
AdjustmentHintsModeDef::PreferPostfix => ide::AdjustmentHintsMode::PreferPostfix,
|
||||
},
|
||||
adjustment_hints_hide_outside_unsafe: self
|
||||
.data
|
||||
.inlayHints_expressionAdjustmentHints_hideOutsideUnsafe,
|
||||
@ -1768,6 +1776,15 @@ enum DiscriminantHintsDef {
|
||||
Fieldless,
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Debug, Clone)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
enum AdjustmentHintsModeDef {
|
||||
Prefix,
|
||||
Postfix,
|
||||
PreferPrefix,
|
||||
PreferPostfix,
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Debug, Clone)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
enum FilesWatcherDef {
|
||||
@ -2101,6 +2118,21 @@ fn field_props(field: &str, ty: &str, doc: &[&str], default: &str) -> serde_json
|
||||
"Only show discriminant hints on fieldless enum variants."
|
||||
]
|
||||
},
|
||||
"AdjustmentHintsModeDef" => set! {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"prefix",
|
||||
"postfix",
|
||||
"prefer_prefix",
|
||||
"prefer_postfix",
|
||||
],
|
||||
"enumDescriptions": [
|
||||
"Always show adjustment hints as prefix (`*expr`).",
|
||||
"Always show adjustment hints as postfix (`expr.*`).",
|
||||
"Show prefix or postfix depending on which uses less parenthesis, prefering prefix.",
|
||||
"Show prefix or postfix depending on which uses less parenthesis, prefering postfix.",
|
||||
]
|
||||
},
|
||||
"CargoFeaturesDef" => set! {
|
||||
"anyOf": [
|
||||
{
|
||||
|
@ -452,6 +452,7 @@ pub(crate) fn inlay_hint(
|
||||
| InlayKind::ChainingHint
|
||||
| InlayKind::GenericParamListHint
|
||||
| InlayKind::ClosingParenthesis
|
||||
| InlayKind::AdjustmentHintPostfix
|
||||
| InlayKind::LifetimeHint
|
||||
| InlayKind::ClosingBraceHint => position(line_index, inlay_hint.range.end()),
|
||||
},
|
||||
@ -465,6 +466,7 @@ pub(crate) fn inlay_hint(
|
||||
| InlayKind::ClosureReturnTypeHint
|
||||
| InlayKind::GenericParamListHint
|
||||
| InlayKind::AdjustmentHint
|
||||
| InlayKind::AdjustmentHintPostfix
|
||||
| InlayKind::LifetimeHint
|
||||
| InlayKind::ParameterHint => false,
|
||||
}),
|
||||
@ -475,6 +477,7 @@ pub(crate) fn inlay_hint(
|
||||
| InlayKind::ClosureReturnTypeHint
|
||||
| InlayKind::GenericParamListHint
|
||||
| InlayKind::AdjustmentHint
|
||||
| InlayKind::AdjustmentHintPostfix
|
||||
| InlayKind::TypeHint
|
||||
| InlayKind::DiscriminantHint
|
||||
| InlayKind::ClosingBraceHint => false,
|
||||
@ -493,6 +496,7 @@ pub(crate) fn inlay_hint(
|
||||
| InlayKind::GenericParamListHint
|
||||
| InlayKind::LifetimeHint
|
||||
| InlayKind::AdjustmentHint
|
||||
| InlayKind::AdjustmentHintPostfix
|
||||
| InlayKind::ClosingBraceHint => None,
|
||||
},
|
||||
text_edits: None,
|
||||
|
@ -469,6 +469,11 @@ Whether to show inlay hints for type adjustments.
|
||||
--
|
||||
Whether to hide inlay hints for type adjustments outside of `unsafe` blocks.
|
||||
--
|
||||
[[rust-analyzer.inlayHints.expressionAdjustmentHints.mode]]rust-analyzer.inlayHints.expressionAdjustmentHints.mode (default: `"prefix"`)::
|
||||
+
|
||||
--
|
||||
Whether to show inlay hints as postfix ops (`.*` instead of `*`, etc).
|
||||
--
|
||||
[[rust-analyzer.inlayHints.lifetimeElisionHints.enable]]rust-analyzer.inlayHints.lifetimeElisionHints.enable (default: `"never"`)::
|
||||
+
|
||||
--
|
||||
|
@ -1000,6 +1000,23 @@
|
||||
"default": false,
|
||||
"type": "boolean"
|
||||
},
|
||||
"rust-analyzer.inlayHints.expressionAdjustmentHints.mode": {
|
||||
"markdownDescription": "Whether to show inlay hints as postfix ops (`.*` instead of `*`, etc).",
|
||||
"default": "prefix",
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"prefix",
|
||||
"postfix",
|
||||
"prefer_prefix",
|
||||
"prefer_postfix"
|
||||
],
|
||||
"enumDescriptions": [
|
||||
"Always show adjustment hints as prefix (`*expr`).",
|
||||
"Always show adjustment hints as postfix (`expr.*`).",
|
||||
"Show prefix or postfix depending on which uses less parenthesis, prefering prefix.",
|
||||
"Show prefix or postfix depending on which uses less parenthesis, prefering postfix."
|
||||
]
|
||||
},
|
||||
"rust-analyzer.inlayHints.lifetimeElisionHints.enable": {
|
||||
"markdownDescription": "Whether to show inlay type hints for elided lifetimes in function signatures.",
|
||||
"default": "never",
|
||||
|
Loading…
Reference in New Issue
Block a user