Unnamed repository; edit this file 'description' to name the repository.
Auto merge of #13545 - Veykril:adjustment-hints, r=Veykril
Generalize reborrow hints as adjustment hints Like reborrow hints, these are still mainly useful for teaching/learning ![image](https://user-images.githubusercontent.com/3757771/200073606-b5cd3b95-a9ad-454d-a3c4-d4d89bf45928.png)
bors 2022-11-07
parent 3a839ea · parent ee2dd93 · commit b0e56ef
-rw-r--r--crates/hir-ty/src/lib.rs2
-rw-r--r--crates/hir/src/lib.rs24
-rw-r--r--crates/hir/src/semantics.rs37
-rw-r--r--crates/hir/src/source_analyzer.rs16
-rw-r--r--crates/ide/src/inlay_hints.rs233
-rw-r--r--crates/ide/src/lib.rs4
-rw-r--r--crates/ide/src/static_index.rs2
-rw-r--r--crates/rust-analyzer/src/config.rs44
-rw-r--r--crates/rust-analyzer/src/to_proto.rs22
-rw-r--r--docs/user/generated_config.adoc8
-rw-r--r--editors/code/package.json17
11 files changed, 304 insertions, 105 deletions
diff --git a/crates/hir-ty/src/lib.rs b/crates/hir-ty/src/lib.rs
index b68c764bdc..ad33053ad0 100644
--- a/crates/hir-ty/src/lib.rs
+++ b/crates/hir-ty/src/lib.rs
@@ -53,7 +53,7 @@ pub use builder::{ParamKind, TyBuilder};
pub use chalk_ext::*;
pub use infer::{
could_coerce, could_unify, Adjust, Adjustment, AutoBorrow, BindingMode, InferenceDiagnostic,
- InferenceResult,
+ InferenceResult, OverloadedDeref, PointerCast,
};
pub use interner::Interner;
pub use lower::{
diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs
index cbd9bf32a5..9d77f343bc 100644
--- a/crates/hir/src/lib.rs
+++ b/crates/hir/src/lib.rs
@@ -117,7 +117,7 @@ pub use {
name::{known, Name},
ExpandResult, HirFileId, InFile, MacroFile, Origin,
},
- hir_ty::display::HirDisplay,
+ hir_ty::{display::HirDisplay, PointerCast, Safety},
};
// These are negative re-exports: pub using these names is forbidden, they
@@ -3651,6 +3651,28 @@ impl From<ItemInNs> for ScopeDef {
}
}
+#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
+pub enum Adjust {
+ /// Go from ! to any type.
+ NeverToAny,
+ /// Dereference once, producing a place.
+ Deref(Option<OverloadedDeref>),
+ /// Take the address and produce either a `&` or `*` pointer.
+ Borrow(AutoBorrow),
+ Pointer(PointerCast),
+}
+
+#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
+pub enum AutoBorrow {
+ /// Converts from T to &T.
+ Ref(Mutability),
+ /// Converts from T to *T.
+ RawPtr(Mutability),
+}
+
+#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
+pub struct OverloadedDeref(pub Mutability);
+
pub trait HasVisibility {
fn visibility(&self, db: &dyn HirDatabase) -> Visibility;
fn is_visible_from(&self, db: &dyn HirDatabase, module: Module) -> bool {
diff --git a/crates/hir/src/semantics.rs b/crates/hir/src/semantics.rs
index 119ec3210e..2e1f88ba09 100644
--- a/crates/hir/src/semantics.rs
+++ b/crates/hir/src/semantics.rs
@@ -29,9 +29,10 @@ use crate::{
db::HirDatabase,
semantics::source_to_def::{ChildContainer, SourceToDefCache, SourceToDefCtx},
source_analyzer::{resolve_hir_path, SourceAnalyzer},
- Access, BindingMode, BuiltinAttr, Callable, ConstParam, Crate, DeriveHelper, Field, Function,
- HasSource, HirFileId, Impl, InFile, Label, LifetimeParam, Local, Macro, Module, ModuleDef,
- Name, Path, ScopeDef, ToolModule, Trait, Type, TypeAlias, TypeParam, VariantDef,
+ Access, Adjust, AutoBorrow, BindingMode, BuiltinAttr, Callable, ConstParam, Crate,
+ DeriveHelper, Field, Function, HasSource, HirFileId, Impl, InFile, Label, LifetimeParam, Local,
+ Macro, Module, ModuleDef, Name, OverloadedDeref, Path, ScopeDef, ToolModule, Trait, Type,
+ TypeAlias, TypeParam, VariantDef,
};
#[derive(Debug, Clone, PartialEq, Eq)]
@@ -333,9 +334,8 @@ impl<'db, DB: HirDatabase> Semantics<'db, DB> {
self.imp.resolve_trait(trait_)
}
- // FIXME: Figure out a nice interface to inspect adjustments
- pub fn is_implicit_reborrow(&self, expr: &ast::Expr) -> Option<Mutability> {
- self.imp.is_implicit_reborrow(expr)
+ pub fn expr_adjustments(&self, expr: &ast::Expr) -> Option<Vec<Adjust>> {
+ self.imp.expr_adjustments(expr)
}
pub fn type_of_expr(&self, expr: &ast::Expr) -> Option<TypeInfo> {
@@ -1067,8 +1067,29 @@ impl<'db> SemanticsImpl<'db> {
}
}
- fn is_implicit_reborrow(&self, expr: &ast::Expr) -> Option<Mutability> {
- self.analyze(expr.syntax())?.is_implicit_reborrow(self.db, expr)
+ fn expr_adjustments(&self, expr: &ast::Expr) -> Option<Vec<Adjust>> {
+ let mutability = |m| match m {
+ hir_ty::Mutability::Not => Mutability::Shared,
+ hir_ty::Mutability::Mut => Mutability::Mut,
+ };
+ self.analyze(expr.syntax())?.expr_adjustments(self.db, expr).map(|it| {
+ it.iter()
+ .map(|adjust| match adjust.kind {
+ hir_ty::Adjust::NeverToAny => Adjust::NeverToAny,
+ hir_ty::Adjust::Deref(Some(hir_ty::OverloadedDeref(m))) => {
+ Adjust::Deref(Some(OverloadedDeref(mutability(m))))
+ }
+ hir_ty::Adjust::Deref(None) => Adjust::Deref(None),
+ hir_ty::Adjust::Borrow(hir_ty::AutoBorrow::RawPtr(m)) => {
+ Adjust::Borrow(AutoBorrow::RawPtr(mutability(m)))
+ }
+ hir_ty::Adjust::Borrow(hir_ty::AutoBorrow::Ref(m)) => {
+ Adjust::Borrow(AutoBorrow::Ref(mutability(m)))
+ }
+ hir_ty::Adjust::Pointer(pc) => Adjust::Pointer(pc),
+ })
+ .collect()
+ })
}
fn type_of_expr(&self, expr: &ast::Expr) -> Option<TypeInfo> {
diff --git a/crates/hir/src/source_analyzer.rs b/crates/hir/src/source_analyzer.rs
index f86c571005..91ea1c24d1 100644
--- a/crates/hir/src/source_analyzer.rs
+++ b/crates/hir/src/source_analyzer.rs
@@ -38,8 +38,7 @@ use hir_ty::{
UnsafeExpr,
},
method_resolution::{self, lang_names_for_bin_op},
- Adjust, Adjustment, AutoBorrow, InferenceResult, Interner, Substitution, Ty, TyExt, TyKind,
- TyLoweringContext,
+ Adjustment, InferenceResult, Interner, Substitution, Ty, TyExt, TyKind, TyLoweringContext,
};
use itertools::Itertools;
use smallvec::SmallVec;
@@ -156,21 +155,14 @@ impl SourceAnalyzer {
Some(res)
}
- pub(crate) fn is_implicit_reborrow(
+ pub(crate) fn expr_adjustments(
&self,
db: &dyn HirDatabase,
expr: &ast::Expr,
- ) -> Option<Mutability> {
+ ) -> Option<&[Adjustment]> {
let expr_id = self.expr_id(db, expr)?;
let infer = self.infer.as_ref()?;
- let adjustments = infer.expr_adjustments.get(&expr_id)?;
- adjustments.windows(2).find_map(|slice| match slice {
- &[Adjustment {kind: Adjust::Deref(None), ..}, Adjustment {kind: Adjust::Borrow(AutoBorrow::Ref(m)), ..}] => Some(match m {
- hir_ty::Mutability::Mut => Mutability::Mut,
- hir_ty::Mutability::Not => Mutability::Shared,
- }),
- _ => None,
- })
+ infer.expr_adjustments.get(&expr_id).map(|v| &**v)
}
pub(crate) fn type_of_expr(
diff --git a/crates/ide/src/inlay_hints.rs b/crates/ide/src/inlay_hints.rs
index 34d8bf67a3..325e609054 100644
--- a/crates/ide/src/inlay_hints.rs
+++ b/crates/ide/src/inlay_hints.rs
@@ -1,7 +1,10 @@
use std::fmt;
use either::Either;
-use hir::{known, Callable, HasVisibility, HirDisplay, Mutability, Semantics, TypeInfo};
+use hir::{
+ known, Adjust, AutoBorrow, Callable, HasVisibility, HirDisplay, Mutability, OverloadedDeref,
+ PointerCast, Safety, Semantics, TypeInfo,
+};
use ide_db::{
base_db::FileRange, famous_defs::FamousDefs, syntax_helpers::node_ext::walk_ty, FxHashMap,
RootDatabase,
@@ -22,7 +25,7 @@ pub struct InlayHintsConfig {
pub type_hints: bool,
pub parameter_hints: bool,
pub chaining_hints: bool,
- pub reborrow_hints: ReborrowHints,
+ pub adjustment_hints: AdjustmentHints,
pub closure_return_type_hints: ClosureReturnTypeHints,
pub binding_mode_hints: bool,
pub lifetime_elision_hints: LifetimeElisionHints,
@@ -48,9 +51,9 @@ pub enum LifetimeElisionHints {
}
#[derive(Clone, Debug, PartialEq, Eq)]
-pub enum ReborrowHints {
+pub enum AdjustmentHints {
Always,
- MutableOnly,
+ ReborrowOnly,
Never,
}
@@ -61,7 +64,8 @@ pub enum InlayKind {
ClosingBraceHint,
ClosureReturnTypeHint,
GenericParamListHint,
- ImplicitReborrowHint,
+ AdjustmentHint,
+ AdjustmentHintClosingParenthesis,
LifetimeHint,
ParameterHint,
TypeHint,
@@ -115,6 +119,12 @@ impl From<String> for InlayHintLabel {
}
}
+impl From<&str> for InlayHintLabel {
+ fn from(s: &str) -> Self {
+ Self { parts: vec![InlayHintLabelPart { text: s.into(), linked_location: None }] }
+ }
+}
+
impl fmt::Display for InlayHintLabel {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.parts.iter().map(|part| &part.text).format(""))
@@ -221,6 +231,7 @@ fn hints(
match node {
ast::Expr(expr) => {
chaining_hints(hints, sema, &famous_defs, config, file_id, &expr);
+ adjustment_hints(hints, sema, config, &expr);
match expr {
ast::Expr::CallExpr(it) => param_name_hints(hints, sema, config, ast::Expr::from(it)),
ast::Expr::MethodCallExpr(it) => {
@@ -229,7 +240,7 @@ fn hints(
ast::Expr::ClosureExpr(it) => closure_ret_hints(hints, sema, &famous_defs, config, file_id, it),
// We could show reborrows for all expressions, but usually that is just noise to the user
// and the main point here is to show why "moving" a mutable reference doesn't necessarily move it
- ast::Expr::PathExpr(_) => reborrow_hints(hints, sema, config, &expr),
+ // ast::Expr::PathExpr(_) => reborrow_hints(hints, sema, config, &expr),
_ => None,
}
},
@@ -617,30 +628,95 @@ fn closure_ret_hints(
Some(())
}
-fn reborrow_hints(
+fn adjustment_hints(
acc: &mut Vec<InlayHint>,
sema: &Semantics<'_, RootDatabase>,
config: &InlayHintsConfig,
expr: &ast::Expr,
) -> Option<()> {
- if config.reborrow_hints == ReborrowHints::Never {
+ if config.adjustment_hints == AdjustmentHints::Never {
+ return None;
+ }
+
+ if let ast::Expr::ParenExpr(_) = expr {
+ // These inherit from the inner expression which would result in duplicate 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 mutability = sema.is_implicit_reborrow(desc_expr)?;
- let label = match mutability {
- hir::Mutability::Shared if config.reborrow_hints != ReborrowHints::MutableOnly => "&*",
- hir::Mutability::Mut => "&mut *",
- _ => return None,
+ 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,
};
- acc.push(InlayHint {
- range: expr.syntax().text_range(),
- kind: InlayKind::ImplicitReborrowHint,
- label: label.to_string().into(),
- tooltip: Some(InlayTooltip::String("Compiler inserted reborrow".into())),
- });
+ if needs_parens {
+ acc.push(InlayHint {
+ range: expr.syntax().text_range(),
+ kind: InlayKind::AdjustmentHint,
+ label: "(".into(),
+ tooltip: None,
+ });
+ }
+ for adjustment in adjustments.into_iter().rev() {
+ // FIXME: Add some nicer tooltips to each of these
+ let text = match adjustment {
+ Adjust::NeverToAny if config.adjustment_hints == AdjustmentHints::Always => {
+ "<never-to-any>"
+ }
+ Adjust::Deref(None) => "*",
+ Adjust::Deref(Some(OverloadedDeref(Mutability::Mut))) => "*",
+ Adjust::Deref(Some(OverloadedDeref(Mutability::Shared))) => "*",
+ Adjust::Borrow(AutoBorrow::Ref(Mutability::Shared)) => "&",
+ Adjust::Borrow(AutoBorrow::Ref(Mutability::Mut)) => "&mut ",
+ Adjust::Borrow(AutoBorrow::RawPtr(Mutability::Shared)) => "&raw const ",
+ Adjust::Borrow(AutoBorrow::RawPtr(Mutability::Mut)) => "&raw mut ",
+ // some of these could be represented via `as` casts, but that's not too nice and
+ // handling everything as a prefix expr makes the `(` and `)` insertion easier
+ Adjust::Pointer(cast) if config.adjustment_hints == AdjustmentHints::Always => {
+ match cast {
+ PointerCast::ReifyFnPointer => "<fn-item-to-fn-pointer>",
+ PointerCast::UnsafeFnPointer => "<safe-fn-pointer-to-unsafe-fn-pointer>",
+ PointerCast::ClosureFnPointer(Safety::Unsafe) => {
+ "<closure-to-unsafe-fn-pointer>"
+ }
+ PointerCast::ClosureFnPointer(Safety::Safe) => "<closure-to-fn-pointer>",
+ PointerCast::MutToConstPointer => "<mut-ptr-to-const-ptr>",
+ PointerCast::ArrayToPointer => "<array-ptr-to-element-ptr>",
+ PointerCast::Unsize => "<unsize>",
+ }
+ }
+ _ => continue,
+ };
+ acc.push(InlayHint {
+ range: expr.syntax().text_range(),
+ kind: InlayKind::AdjustmentHint,
+ label: text.into(),
+ tooltip: None,
+ });
+ }
+ if needs_parens {
+ acc.push(InlayHint {
+ range: expr.syntax().text_range(),
+ kind: InlayKind::AdjustmentHintClosingParenthesis,
+ label: ")".into(),
+ tooltip: None,
+ });
+ }
Some(())
}
@@ -1218,7 +1294,7 @@ mod tests {
use syntax::{TextRange, TextSize};
use test_utils::extract_annotations;
- use crate::inlay_hints::ReborrowHints;
+ use crate::inlay_hints::AdjustmentHints;
use crate::{fixture, inlay_hints::InlayHintsConfig, LifetimeElisionHints};
use super::ClosureReturnTypeHints;
@@ -1230,7 +1306,7 @@ mod tests {
chaining_hints: false,
lifetime_elision_hints: LifetimeElisionHints::Never,
closure_return_type_hints: ClosureReturnTypeHints::Never,
- reborrow_hints: ReborrowHints::Always,
+ adjustment_hints: AdjustmentHints::Never,
binding_mode_hints: false,
hide_named_constructor_hints: false,
hide_closure_initialization_hints: false,
@@ -1242,7 +1318,6 @@ mod tests {
type_hints: true,
parameter_hints: true,
chaining_hints: true,
- reborrow_hints: ReborrowHints::Always,
closure_return_type_hints: ClosureReturnTypeHints::WithBlock,
binding_mode_hints: true,
lifetime_elision_hints: LifetimeElisionHints::Always,
@@ -2846,48 +2921,6 @@ impl () {
}
#[test]
- fn hints_implicit_reborrow() {
- check_with_config(
- InlayHintsConfig {
- reborrow_hints: ReborrowHints::Always,
- parameter_hints: true,
- ..DISABLED_CONFIG
- },
- r#"
-fn __() {
- let unique = &mut ();
- let r_mov = unique;
- let foo: &mut _ = unique;
- //^^^^^^ &mut *
- ref_mut_id(unique);
- //^^^^^^ mut_ref
- //^^^^^^ &mut *
- let shared = ref_id(unique);
- //^^^^^^ shared_ref
- //^^^^^^ &*
- let mov = shared;
- let r_mov: &_ = shared;
- ref_id(shared);
- //^^^^^^ shared_ref
-
- identity(unique);
- identity(shared);
-}
-fn identity<T>(t: T) -> T {
- t
-}
-fn ref_mut_id(mut_ref: &mut ()) -> &mut () {
- mut_ref
- //^^^^^^^ &mut *
-}
-fn ref_id(shared_ref: &()) -> &() {
- shared_ref
-}
-"#,
- );
- }
-
- #[test]
fn hints_binding_modes() {
check_with_config(
InlayHintsConfig { binding_mode_hints: true, ..DISABLED_CONFIG },
@@ -2994,4 +3027,76 @@ fn f() {
"#,
);
}
+
+ #[test]
+ fn adjustment_hints() {
+ check_with_config(
+ InlayHintsConfig { adjustment_hints: AdjustmentHints::Always, ..DISABLED_CONFIG },
+ r#"
+//- minicore: coerce_unsized
+fn main() {
+ let _: u32 = loop {};
+ //^^^^^^^<never-to-any>
+ let _: &u32 = &mut 0;
+ //^^^^^^&
+ //^^^^^^*
+ let _: &mut u32 = &mut 0;
+ //^^^^^^&mut $
+ //^^^^^^*
+ let _: *const u32 = &mut 0;
+ //^^^^^^&raw const $
+ //^^^^^^*
+ let _: *mut u32 = &mut 0;
+ //^^^^^^&raw mut $
+ //^^^^^^*
+ let _: fn() = main;
+ //^^^^<fn-item-to-fn-pointer>
+ let _: unsafe fn() = main;
+ //^^^^<safe-fn-pointer-to-unsafe-fn-pointer>
+ //^^^^<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 $
+ //^^^^^^^^^^^*
+
+ 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();
+}
+
+#[derive(Copy, Clone)]
+struct Struct;
+impl Struct {
+ fn consume(self) {}
+ fn by_ref(&self) {}
+ fn by_ref_mut(&mut self) {}
+}
+"#,
+ )
+ }
}
diff --git a/crates/ide/src/lib.rs b/crates/ide/src/lib.rs
index 416817ca0b..568c53f8bd 100644
--- a/crates/ide/src/lib.rs
+++ b/crates/ide/src/lib.rs
@@ -81,8 +81,8 @@ pub use crate::{
highlight_related::{HighlightRelatedConfig, HighlightedRange},
hover::{HoverAction, HoverConfig, HoverDocFormat, HoverGotoTypeData, HoverResult},
inlay_hints::{
- ClosureReturnTypeHints, InlayHint, InlayHintLabel, InlayHintsConfig, InlayKind,
- InlayTooltip, LifetimeElisionHints, ReborrowHints,
+ AdjustmentHints, ClosureReturnTypeHints, InlayHint, InlayHintLabel, InlayHintsConfig,
+ InlayKind, InlayTooltip, LifetimeElisionHints,
},
join_lines::JoinLinesConfig,
markup::Markup,
diff --git a/crates/ide/src/static_index.rs b/crates/ide/src/static_index.rs
index 27ad1a948d..6ebd6f713f 100644
--- a/crates/ide/src/static_index.rs
+++ b/crates/ide/src/static_index.rs
@@ -111,7 +111,7 @@ impl StaticIndex<'_> {
chaining_hints: true,
closure_return_type_hints: crate::ClosureReturnTypeHints::WithBlock,
lifetime_elision_hints: crate::LifetimeElisionHints::Never,
- reborrow_hints: crate::ReborrowHints::Never,
+ adjustment_hints: crate::AdjustmentHints::Never,
hide_named_constructor_hints: false,
hide_closure_initialization_hints: false,
param_names_for_lifetime_elision_hints: false,
diff --git a/crates/rust-analyzer/src/config.rs b/crates/rust-analyzer/src/config.rs
index c278ba2d7c..d642cd9b92 100644
--- a/crates/rust-analyzer/src/config.rs
+++ b/crates/rust-analyzer/src/config.rs
@@ -261,6 +261,7 @@ config_data! {
files_excludeDirs: Vec<PathBuf> = "[]",
/// Controls file watching implementation.
files_watcher: FilesWatcherDef = "\"client\"",
+
/// Enables highlighting of related references while the cursor is on `break`, `loop`, `while`, or `for` keywords.
highlightRelated_breakPoints_enable: bool = "true",
/// Enables highlighting of all exit points while the cursor is on any `return`, `?`, `fn`, or return type arrow (`->`).
@@ -320,6 +321,8 @@ config_data! {
inlayHints_closingBraceHints_minLines: usize = "25",
/// Whether to show inlay type hints for return types of closures.
inlayHints_closureReturnTypeHints_enable: ClosureReturnTypeHintsDef = "\"never\"",
+ /// Whether to show inlay hints for type adjustments.
+ inlayHints_expressionAdjustmentHints_enable: AdjustmentHintsDef = "\"never\"",
/// 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.
@@ -329,7 +332,8 @@ config_data! {
/// Whether to show function parameter name inlay hints at the call
/// site.
inlayHints_parameterHints_enable: bool = "true",
- /// Whether to show inlay type hints for compiler inserted reborrows.
+ /// Whether to show inlay hints for compiler inserted reborrows.
+ /// This setting is deprecated in favor of #rust-analyzer.inlayHints.expressionAdjustmentHints.enable#.
inlayHints_reborrowHints_enable: ReborrowHintsDef = "\"never\"",
/// Whether to render leading colons for type hints, and trailing colons for parameter hints.
inlayHints_renderColons: bool = "true",
@@ -1200,10 +1204,15 @@ impl Config {
hide_closure_initialization_hints: self
.data
.inlayHints_typeHints_hideClosureInitialization,
- reborrow_hints: match self.data.inlayHints_reborrowHints_enable {
- ReborrowHintsDef::Always => ide::ReborrowHints::Always,
- ReborrowHintsDef::Never => ide::ReborrowHints::Never,
- ReborrowHintsDef::Mutable => ide::ReborrowHints::MutableOnly,
+ adjustment_hints: match self.data.inlayHints_expressionAdjustmentHints_enable {
+ AdjustmentHintsDef::Always => ide::AdjustmentHints::Always,
+ AdjustmentHintsDef::Never => match self.data.inlayHints_reborrowHints_enable {
+ ReborrowHintsDef::Always | ReborrowHintsDef::Mutable => {
+ ide::AdjustmentHints::ReborrowOnly
+ }
+ ReborrowHintsDef::Never => ide::AdjustmentHints::Never,
+ },
+ AdjustmentHintsDef::Reborrow => ide::AdjustmentHints::ReborrowOnly,
},
binding_mode_hints: self.data.inlayHints_bindingModeHints_enable,
param_names_for_lifetime_elision_hints: self
@@ -1538,6 +1547,7 @@ mod de_unit_v {
named_unit_variant!(all);
named_unit_variant!(skip_trivial);
named_unit_variant!(mutable);
+ named_unit_variant!(reborrow);
named_unit_variant!(with_block);
}
@@ -1688,6 +1698,17 @@ enum ReborrowHintsDef {
}
#[derive(Deserialize, Debug, Clone)]
+#[serde(untagged)]
+enum AdjustmentHintsDef {
+ #[serde(deserialize_with = "true_or_always")]
+ Always,
+ #[serde(deserialize_with = "false_or_never")]
+ Never,
+ #[serde(deserialize_with = "de_unit_v::reborrow")]
+ Reborrow,
+}
+
+#[derive(Deserialize, Debug, Clone)]
#[serde(rename_all = "snake_case")]
enum FilesWatcherDef {
Client,
@@ -1996,6 +2017,19 @@ fn field_props(field: &str, ty: &str, doc: &[&str], default: &str) -> serde_json
"Only show mutable reborrow hints."
]
},
+ "AdjustmentHintsDef" => set! {
+ "type": "string",
+ "enum": [
+ "always",
+ "never",
+ "reborrow"
+ ],
+ "enumDescriptions": [
+ "Always show all adjustment hints.",
+ "Never show adjustment hints.",
+ "Only show auto borrow and dereference adjustment hints."
+ ]
+ },
"CargoFeaturesDef" => set! {
"anyOf": [
{
diff --git a/crates/rust-analyzer/src/to_proto.rs b/crates/rust-analyzer/src/to_proto.rs
index 6c84a2069c..6f44a1de63 100644
--- a/crates/rust-analyzer/src/to_proto.rs
+++ b/crates/rust-analyzer/src/to_proto.rs
@@ -440,32 +440,35 @@ pub(crate) fn inlay_hint(
Ok(lsp_types::InlayHint {
position: match inlay_hint.kind {
// before annotated thing
- InlayKind::ParameterHint
- | InlayKind::ImplicitReborrowHint
- | InlayKind::BindingModeHint => position(line_index, inlay_hint.range.start()),
+ InlayKind::ParameterHint | InlayKind::AdjustmentHint | InlayKind::BindingModeHint => {
+ position(line_index, inlay_hint.range.start())
+ }
// after annotated thing
InlayKind::ClosureReturnTypeHint
| InlayKind::TypeHint
| InlayKind::ChainingHint
| InlayKind::GenericParamListHint
+ | InlayKind::AdjustmentHintClosingParenthesis
| InlayKind::LifetimeHint
| InlayKind::ClosingBraceHint => position(line_index, inlay_hint.range.end()),
},
padding_left: Some(match inlay_hint.kind {
InlayKind::TypeHint => !render_colons,
InlayKind::ChainingHint | InlayKind::ClosingBraceHint => true,
- InlayKind::BindingModeHint
+ InlayKind::AdjustmentHintClosingParenthesis
+ | InlayKind::BindingModeHint
| InlayKind::ClosureReturnTypeHint
| InlayKind::GenericParamListHint
- | InlayKind::ImplicitReborrowHint
+ | InlayKind::AdjustmentHint
| InlayKind::LifetimeHint
| InlayKind::ParameterHint => false,
}),
padding_right: Some(match inlay_hint.kind {
- InlayKind::ChainingHint
+ InlayKind::AdjustmentHintClosingParenthesis
+ | InlayKind::ChainingHint
| InlayKind::ClosureReturnTypeHint
| InlayKind::GenericParamListHint
- | InlayKind::ImplicitReborrowHint
+ | InlayKind::AdjustmentHint
| InlayKind::TypeHint
| InlayKind::ClosingBraceHint => false,
InlayKind::BindingModeHint => inlay_hint.label.as_simple_str() != Some("&"),
@@ -476,10 +479,11 @@ pub(crate) fn inlay_hint(
InlayKind::ClosureReturnTypeHint | InlayKind::TypeHint | InlayKind::ChainingHint => {
Some(lsp_types::InlayHintKind::TYPE)
}
- InlayKind::BindingModeHint
+ InlayKind::AdjustmentHintClosingParenthesis
+ | InlayKind::BindingModeHint
| InlayKind::GenericParamListHint
| InlayKind::LifetimeHint
- | InlayKind::ImplicitReborrowHint
+ | InlayKind::AdjustmentHint
| InlayKind::ClosingBraceHint => None,
},
text_edits: None,
diff --git a/docs/user/generated_config.adoc b/docs/user/generated_config.adoc
index f171eb41bf..da8e629807 100644
--- a/docs/user/generated_config.adoc
+++ b/docs/user/generated_config.adoc
@@ -450,6 +450,11 @@ to always show them).
--
Whether to show inlay type hints for return types of closures.
--
+[[rust-analyzer.inlayHints.expressionAdjustmentHints.enable]]rust-analyzer.inlayHints.expressionAdjustmentHints.enable (default: `"never"`)::
++
+--
+Whether to show inlay hints for type adjustments.
+--
[[rust-analyzer.inlayHints.lifetimeElisionHints.enable]]rust-analyzer.inlayHints.lifetimeElisionHints.enable (default: `"never"`)::
+
--
@@ -474,7 +479,8 @@ site.
[[rust-analyzer.inlayHints.reborrowHints.enable]]rust-analyzer.inlayHints.reborrowHints.enable (default: `"never"`)::
+
--
-Whether to show inlay type hints for compiler inserted reborrows.
+Whether to show inlay hints for compiler inserted reborrows.
+This setting is deprecated in favor of #rust-analyzer.inlayHints.expressionAdjustmentHints.enable#.
--
[[rust-analyzer.inlayHints.renderColons]]rust-analyzer.inlayHints.renderColons (default: `true`)::
+
diff --git a/editors/code/package.json b/editors/code/package.json
index 4357dc7306..75e94af6fd 100644
--- a/editors/code/package.json
+++ b/editors/code/package.json
@@ -935,6 +935,21 @@
"Only show type hints for return types of closures with blocks."
]
},
+ "rust-analyzer.inlayHints.expressionAdjustmentHints.enable": {
+ "markdownDescription": "Whether to show inlay hints for type adjustments.",
+ "default": "never",
+ "type": "string",
+ "enum": [
+ "always",
+ "never",
+ "reborrow"
+ ],
+ "enumDescriptions": [
+ "Always show all adjustment hints.",
+ "Never show adjustment hints.",
+ "Only show auto borrow and dereference adjustment hints."
+ ]
+ },
"rust-analyzer.inlayHints.lifetimeElisionHints.enable": {
"markdownDescription": "Whether to show inlay type hints for elided lifetimes in function signatures.",
"default": "never",
@@ -970,7 +985,7 @@
"type": "boolean"
},
"rust-analyzer.inlayHints.reborrowHints.enable": {
- "markdownDescription": "Whether to show inlay type hints for compiler inserted reborrows.",
+ "markdownDescription": "Whether to show inlay hints for compiler inserted reborrows.\nThis setting is deprecated in favor of #rust-analyzer.inlayHints.expressionAdjustmentHints.enable#.",
"default": "never",
"type": "string",
"enum": [