Unnamed repository; edit this file 'description' to name the repository.
-rw-r--r--crates/hir-ty/src/diagnostics/match_check.rs2
-rw-r--r--crates/hir-ty/src/infer.rs4
-rw-r--r--crates/hir-ty/src/infer/pat.rs9
-rw-r--r--crates/hir-ty/src/lib.rs3
-rw-r--r--crates/hir/src/lib.rs6
-rw-r--r--crates/hir/src/semantics.rs24
-rw-r--r--crates/hir/src/source_analyzer.rs41
-rw-r--r--crates/ide/src/inlay_hints.rs114
-rw-r--r--crates/ide/src/static_index.rs1
-rw-r--r--crates/rust-analyzer/src/config.rs3
-rw-r--r--crates/rust-analyzer/src/to_proto.rs35
-rw-r--r--crates/syntax/src/ast/expr_ext.rs2
-rw-r--r--docs/user/generated_config.adoc5
-rw-r--r--editors/code/package.json5
14 files changed, 212 insertions, 42 deletions
diff --git a/crates/hir-ty/src/diagnostics/match_check.rs b/crates/hir-ty/src/diagnostics/match_check.rs
index d21ea32d9e..e00dfdf2fa 100644
--- a/crates/hir-ty/src/diagnostics/match_check.rs
+++ b/crates/hir-ty/src/diagnostics/match_check.rs
@@ -105,7 +105,7 @@ impl<'a> PatCtxt<'a> {
self.infer.pat_adjustments.get(&pat).map(|it| &**it).unwrap_or_default().iter().rev().fold(
unadjusted_pat,
|subpattern, ref_ty| Pat {
- ty: ref_ty.target.clone(),
+ ty: ref_ty.clone(),
kind: Box::new(PatKind::Deref { subpattern }),
},
)
diff --git a/crates/hir-ty/src/infer.rs b/crates/hir-ty/src/infer.rs
index 2a11c9d9bf..a19ff8bf60 100644
--- a/crates/hir-ty/src/infer.rs
+++ b/crates/hir-ty/src/infer.rs
@@ -297,7 +297,7 @@ pub struct InferenceResult {
/// Interned Unknown to return references to.
standard_types: InternedStandardTypes,
/// Stores the types which were implicitly dereferenced in pattern binding modes.
- pub pat_adjustments: FxHashMap<PatId, Vec<Adjustment>>,
+ pub pat_adjustments: FxHashMap<PatId, Vec<Ty>>,
pub pat_binding_modes: FxHashMap<PatId, BindingMode>,
pub expr_adjustments: FxHashMap<ExprId, Vec<Adjustment>>,
}
@@ -445,7 +445,7 @@ impl<'a> InferenceContext<'a> {
adjustment.target = table.resolve_completely(adjustment.target.clone());
}
for adjustment in result.pat_adjustments.values_mut().flatten() {
- adjustment.target = table.resolve_completely(adjustment.target.clone());
+ *adjustment = table.resolve_completely(adjustment.clone());
}
result
}
diff --git a/crates/hir-ty/src/infer/pat.rs b/crates/hir-ty/src/infer/pat.rs
index 600b82ca41..f8131314c6 100644
--- a/crates/hir-ty/src/infer/pat.rs
+++ b/crates/hir-ty/src/infer/pat.rs
@@ -11,9 +11,7 @@ use hir_def::{
use hir_expand::name::Name;
use crate::{
- infer::{
- Adjust, Adjustment, AutoBorrow, BindingMode, Expectation, InferenceContext, TypeMismatch,
- },
+ infer::{BindingMode, Expectation, InferenceContext, TypeMismatch},
lower::lower_to_chalk_mutability,
static_lifetime, ConcreteConst, ConstValue, Interner, Substitution, Ty, TyBuilder, TyExt,
TyKind,
@@ -105,10 +103,7 @@ impl<'a> InferenceContext<'a> {
if is_non_ref_pat(&self.body, pat) {
let mut pat_adjustments = Vec::new();
while let Some((inner, _lifetime, mutability)) = expected.as_reference() {
- pat_adjustments.push(Adjustment {
- target: expected.clone(),
- kind: Adjust::Borrow(AutoBorrow::Ref(mutability)),
- });
+ pat_adjustments.push(expected.clone());
expected = self.resolve_ty_shallow(inner);
default_bm = match default_bm {
BindingMode::Move => BindingMode::Ref(mutability),
diff --git a/crates/hir-ty/src/lib.rs b/crates/hir-ty/src/lib.rs
index 85d8ccc077..15bcbda25d 100644
--- a/crates/hir-ty/src/lib.rs
+++ b/crates/hir-ty/src/lib.rs
@@ -47,7 +47,8 @@ pub use autoderef::autoderef;
pub use builder::{ParamKind, TyBuilder};
pub use chalk_ext::*;
pub use infer::{
- could_coerce, could_unify, Adjust, Adjustment, AutoBorrow, InferenceDiagnostic, InferenceResult,
+ could_coerce, could_unify, Adjust, Adjustment, AutoBorrow, BindingMode, InferenceDiagnostic,
+ InferenceResult,
};
pub use interner::Interner;
pub use lower::{
diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs
index 39f88937d6..4f8fc6bf56 100644
--- a/crates/hir/src/lib.rs
+++ b/crates/hir/src/lib.rs
@@ -3332,6 +3332,12 @@ impl Callable {
}
}
+#[derive(Copy, Clone, Debug, Eq, PartialEq)]
+pub enum BindingMode {
+ Move,
+ Ref(Mutability),
+}
+
/// For IDE only
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
pub enum ScopeDef {
diff --git a/crates/hir/src/semantics.rs b/crates/hir/src/semantics.rs
index d887dae99c..48661ec4eb 100644
--- a/crates/hir/src/semantics.rs
+++ b/crates/hir/src/semantics.rs
@@ -30,9 +30,9 @@ use crate::{
db::HirDatabase,
semantics::source_to_def::{ChildContainer, SourceToDefCache, SourceToDefCtx},
source_analyzer::{resolve_hir_path, SourceAnalyzer},
- Access, BuiltinAttr, Callable, ConstParam, Crate, Field, Function, HasSource, HirFileId, Impl,
- InFile, Label, LifetimeParam, Local, Macro, Module, ModuleDef, Name, Path, ScopeDef,
- ToolModule, Trait, Type, TypeAlias, TypeParam, VariantDef,
+ Access, BindingMode, BuiltinAttr, Callable, ConstParam, Crate, Field, Function, HasSource,
+ HirFileId, Impl, InFile, Label, LifetimeParam, Local, Macro, Module, ModuleDef, Name, Path,
+ ScopeDef, ToolModule, Trait, Type, TypeAlias, TypeParam, VariantDef,
};
#[derive(Debug, Clone, PartialEq, Eq)]
@@ -336,6 +336,14 @@ impl<'db, DB: HirDatabase> Semantics<'db, DB> {
self.imp.type_of_self(param)
}
+ pub fn pattern_adjustments(&self, pat: &ast::Pat) -> SmallVec<[Type; 1]> {
+ self.imp.pattern_adjustments(pat)
+ }
+
+ pub fn binding_mode_of_pat(&self, pat: &ast::IdentPat) -> Option<BindingMode> {
+ self.imp.binding_mode_of_pat(pat)
+ }
+
pub fn resolve_method_call(&self, call: &ast::MethodCallExpr) -> Option<Function> {
self.imp.resolve_method_call(call).map(Function::from)
}
@@ -951,6 +959,16 @@ impl<'db> SemanticsImpl<'db> {
self.analyze(param.syntax())?.type_of_self(self.db, param)
}
+ fn pattern_adjustments(&self, pat: &ast::Pat) -> SmallVec<[Type; 1]> {
+ self.analyze(pat.syntax())
+ .and_then(|it| it.pattern_adjustments(self.db, pat))
+ .unwrap_or_default()
+ }
+
+ fn binding_mode_of_pat(&self, pat: &ast::IdentPat) -> Option<BindingMode> {
+ self.analyze(pat.syntax())?.binding_mode_of_pat(self.db, pat)
+ }
+
fn resolve_method_call(&self, call: &ast::MethodCallExpr) -> Option<FunctionId> {
self.analyze(call.syntax())?.resolve_method_call(self.db, call).map(|(id, _)| id)
}
diff --git a/crates/hir/src/source_analyzer.rs b/crates/hir/src/source_analyzer.rs
index 7a65fd99cf..b5e6d99093 100644
--- a/crates/hir/src/source_analyzer.rs
+++ b/crates/hir/src/source_analyzer.rs
@@ -34,15 +34,16 @@ use hir_ty::{
Adjust, Adjustment, AutoBorrow, InferenceResult, Interner, Substitution, TyExt,
TyLoweringContext,
};
+use smallvec::SmallVec;
use syntax::{
ast::{self, AstNode},
SyntaxKind, SyntaxNode, TextRange, TextSize,
};
use crate::{
- db::HirDatabase, semantics::PathResolution, Adt, AssocItem, BuiltinAttr, BuiltinType, Const,
- Field, Function, Local, Macro, ModuleDef, Static, Struct, ToolModule, Trait, Type, TypeAlias,
- Variant,
+ db::HirDatabase, semantics::PathResolution, Adt, AssocItem, BindingMode, BuiltinAttr,
+ BuiltinType, Const, Field, Function, Local, Macro, ModuleDef, Static, Struct, ToolModule,
+ Trait, Type, TypeAlias, Variant,
};
/// `SourceAnalyzer` is a convenience wrapper which exposes HIR API in terms of
@@ -182,7 +183,7 @@ impl SourceAnalyzer {
let coerced = infer
.pat_adjustments
.get(&pat_id)
- .and_then(|adjusts| adjusts.last().map(|adjust| adjust.target.clone()));
+ .and_then(|adjusts| adjusts.last().map(|adjust| adjust.clone()));
let ty = infer[pat_id].clone();
let mk_ty = |ty| Type::new_with_resolver(db, &self.resolver, ty);
Some((mk_ty(ty), coerced.map(mk_ty)))
@@ -199,6 +200,38 @@ impl SourceAnalyzer {
Some(Type::new_with_resolver(db, &self.resolver, ty))
}
+ pub(crate) fn binding_mode_of_pat(
+ &self,
+ _db: &dyn HirDatabase,
+ pat: &ast::IdentPat,
+ ) -> Option<BindingMode> {
+ let pat_id = self.pat_id(&pat.clone().into())?;
+ let infer = self.infer.as_ref()?;
+ infer.pat_binding_modes.get(&pat_id).map(|bm| match bm {
+ hir_ty::BindingMode::Move => BindingMode::Move,
+ hir_ty::BindingMode::Ref(hir_ty::Mutability::Mut) => BindingMode::Ref(Mutability::Mut),
+ hir_ty::BindingMode::Ref(hir_ty::Mutability::Not) => {
+ BindingMode::Ref(Mutability::Shared)
+ }
+ })
+ }
+ pub(crate) fn pattern_adjustments(
+ &self,
+ db: &dyn HirDatabase,
+ pat: &ast::Pat,
+ ) -> Option<SmallVec<[Type; 1]>> {
+ let pat_id = self.pat_id(&pat)?;
+ let infer = self.infer.as_ref()?;
+ Some(
+ infer
+ .pat_adjustments
+ .get(&pat_id)?
+ .iter()
+ .map(|ty| Type::new_with_resolver(db, &self.resolver, ty.clone()))
+ .collect(),
+ )
+ }
+
pub(crate) fn resolve_method_call(
&self,
db: &dyn HirDatabase,
diff --git a/crates/ide/src/inlay_hints.rs b/crates/ide/src/inlay_hints.rs
index a7cb1a599f..23a46c0276 100644
--- a/crates/ide/src/inlay_hints.rs
+++ b/crates/ide/src/inlay_hints.rs
@@ -1,5 +1,5 @@
use either::Either;
-use hir::{known, Callable, HasVisibility, HirDisplay, Semantics, TypeInfo};
+use hir::{known, Callable, HasVisibility, HirDisplay, Mutability, Semantics, TypeInfo};
use ide_db::{
base_db::FileRange, famous_defs::FamousDefs, syntax_helpers::node_ext::walk_ty, FxHashMap,
RootDatabase,
@@ -21,6 +21,7 @@ pub struct InlayHintsConfig {
pub chaining_hints: bool,
pub reborrow_hints: ReborrowHints,
pub closure_return_type_hints: bool,
+ pub binding_mode_hints: bool,
pub lifetime_elision_hints: LifetimeElisionHints,
pub param_names_for_lifetime_elision_hints: bool,
pub hide_named_constructor_hints: bool,
@@ -43,10 +44,11 @@ pub enum ReborrowHints {
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum InlayKind {
+ BindingModeHint,
ChainingHint,
ClosureReturnTypeHint,
GenericParamListHint,
- ImplicitReborrow,
+ ImplicitReborrowHint,
LifetimeHint,
ParameterHint,
TypeHint,
@@ -135,8 +137,11 @@ fn hints(
ast::Expr::PathExpr(_) => reborrow_hints(hints, sema, config, &expr),
_ => None,
};
- } else if let Some(it) = ast::IdentPat::cast(node.clone()) {
- bind_pat_hints(hints, sema, config, &it);
+ } else if let Some(it) = ast::Pat::cast(node.clone()) {
+ binding_mode_hints(hints, sema, config, &it);
+ if let ast::Pat::IdentPat(it) = it {
+ bind_pat_hints(hints, sema, config, &it);
+ }
} else if let Some(it) = ast::Fn::cast(node) {
lifetime_hints(hints, config, it);
}
@@ -383,7 +388,9 @@ fn reborrow_hints(
return None;
}
- let mutability = sema.is_implicit_reborrow(expr)?;
+ 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 *",
@@ -391,7 +398,7 @@ fn reborrow_hints(
};
acc.push(InlayHint {
range: expr.syntax().text_range(),
- kind: InlayKind::ImplicitReborrow,
+ kind: InlayKind::ImplicitReborrowHint,
label: SmolStr::new_inline(label),
});
Some(())
@@ -497,6 +504,51 @@ fn param_name_hints(
Some(())
}
+fn binding_mode_hints(
+ acc: &mut Vec<InlayHint>,
+ sema: &Semantics<RootDatabase>,
+ config: &InlayHintsConfig,
+ pat: &ast::Pat,
+) -> Option<()> {
+ if !config.binding_mode_hints {
+ return None;
+ }
+
+ let range = pat.syntax().text_range();
+ sema.pattern_adjustments(&pat).iter().for_each(|ty| {
+ let reference = ty.is_reference();
+ let mut_reference = ty.is_mutable_reference();
+ let r = match (reference, mut_reference) {
+ (true, true) => "&mut",
+ (true, false) => "&",
+ _ => return,
+ };
+ acc.push(InlayHint {
+ range,
+ kind: InlayKind::BindingModeHint,
+ label: SmolStr::new_inline(r),
+ });
+ });
+ match pat {
+ ast::Pat::IdentPat(pat) if pat.ref_token().is_none() && pat.mut_token().is_none() => {
+ let bm = sema.binding_mode_of_pat(pat)?;
+ let bm = match bm {
+ hir::BindingMode::Move => return None,
+ hir::BindingMode::Ref(Mutability::Mut) => "ref mut",
+ hir::BindingMode::Ref(Mutability::Shared) => "ref",
+ };
+ acc.push(InlayHint {
+ range,
+ kind: InlayKind::BindingModeHint,
+ label: SmolStr::new_inline(bm),
+ });
+ }
+ _ => (),
+ }
+
+ Some(())
+}
+
fn bind_pat_hints(
acc: &mut Vec<InlayHint>,
sema: &Semantics<RootDatabase>,
@@ -681,6 +733,7 @@ fn should_not_display_type_hint(
match_ast! {
match node {
ast::LetStmt(it) => return it.ty().is_some(),
+ // FIXME: We might wanna show type hints in parameters for non-top level patterns as well
ast::Param(it) => return it.ty().is_some(),
ast::MatchArm(_) => return pat_is_enum_variant(db, bind_pat, pat_ty),
ast::LetExpr(_) => return pat_is_enum_variant(db, bind_pat, pat_ty),
@@ -866,9 +919,10 @@ mod tests {
parameter_hints: false,
chaining_hints: false,
lifetime_elision_hints: LifetimeElisionHints::Never,
- hide_named_constructor_hints: false,
closure_return_type_hints: false,
reborrow_hints: ReborrowHints::Always,
+ binding_mode_hints: false,
+ hide_named_constructor_hints: false,
param_names_for_lifetime_elision_hints: false,
max_length: None,
};
@@ -878,6 +932,7 @@ mod tests {
chaining_hints: true,
reborrow_hints: ReborrowHints::Always,
closure_return_type_hints: true,
+ binding_mode_hints: true,
lifetime_elision_hints: LifetimeElisionHints::Always,
..DISABLED_CONFIG
};
@@ -2194,4 +2249,49 @@ fn ref_id(shared_ref: &()) -> &() {
"#,
);
}
+
+ #[test]
+ fn hints_binding_modes() {
+ check_with_config(
+ InlayHintsConfig { binding_mode_hints: true, ..DISABLED_CONFIG },
+ r#"
+fn __(
+ (x,): (u32,),
+ (x,): &(u32,),
+ //^^^^&
+ //^ ref
+ (x,): &mut (u32,)
+ //^^^^&mut
+ //^ ref mut
+) {
+ let (x,) = (0,);
+ let (x,) = &(0,);
+ //^^^^ &
+ //^ ref
+ let (x,) = &mut (0,);
+ //^^^^ &mut
+ //^ ref mut
+ let &mut (x,) = &mut (0,);
+ let (ref mut x,) = &mut (0,);
+ //^^^^^^^^^^^^ &mut
+ let &mut (ref mut x,) = &mut (0,);
+ let (mut x,) = &mut (0,);
+ //^^^^^^^^ &mut
+ match (0,) {
+ (x,) => ()
+ }
+ match &(0,) {
+ (x,) => ()
+ //^^^^ &
+ //^ ref
+ }
+ match &mut (0,) {
+ (x,) => ()
+ //^^^^ &mut
+ //^ ref mut
+ }
+}
+"#,
+ );
+ }
}
diff --git a/crates/ide/src/static_index.rs b/crates/ide/src/static_index.rs
index 48159f5958..53820860f5 100644
--- a/crates/ide/src/static_index.rs
+++ b/crates/ide/src/static_index.rs
@@ -114,6 +114,7 @@ impl StaticIndex<'_> {
reborrow_hints: crate::ReborrowHints::Never,
hide_named_constructor_hints: false,
param_names_for_lifetime_elision_hints: false,
+ binding_mode_hints: false,
max_length: Some(25),
},
file_id,
diff --git a/crates/rust-analyzer/src/config.rs b/crates/rust-analyzer/src/config.rs
index 3e5561ad38..623f5ec943 100644
--- a/crates/rust-analyzer/src/config.rs
+++ b/crates/rust-analyzer/src/config.rs
@@ -255,6 +255,8 @@ config_data! {
/// The path structure for newly inserted paths to use.
imports_prefix: ImportPrefixDef = "\"plain\"",
+ /// Whether to show inlay type hints for binding modes.
+ inlayHints_bindingModeHints_enable: bool = "false",
/// Whether to show inlay type hints for method chains.
inlayHints_chainingHints_enable: bool = "true",
/// Whether to show inlay type hints for return types of closures with blocks.
@@ -998,6 +1000,7 @@ impl Config {
ReborrowHintsDef::Never => ide::ReborrowHints::Never,
ReborrowHintsDef::Mutable => ide::ReborrowHints::MutableOnly,
},
+ binding_mode_hints: self.data.inlayHints_bindingModeHints_enable,
param_names_for_lifetime_elision_hints: self
.data
.inlayHints_lifetimeElisionHints_useParameterNames,
diff --git a/crates/rust-analyzer/src/to_proto.rs b/crates/rust-analyzer/src/to_proto.rs
index ff348959ad..cd9226d03d 100644
--- a/crates/rust-analyzer/src/to_proto.rs
+++ b/crates/rust-analyzer/src/to_proto.rs
@@ -418,9 +418,9 @@ pub(crate) fn inlay_hint(
lsp_types::InlayHint {
position: match inlay_hint.kind {
// before annotated thing
- InlayKind::ParameterHint | InlayKind::ImplicitReborrow => {
- position(line_index, inlay_hint.range.start())
- }
+ InlayKind::ParameterHint
+ | InlayKind::ImplicitReborrowHint
+ | InlayKind::BindingModeHint => position(line_index, inlay_hint.range.start()),
// after annotated thing
InlayKind::ClosureReturnTypeHint
| InlayKind::TypeHint
@@ -439,27 +439,30 @@ pub(crate) fn inlay_hint(
InlayKind::ClosureReturnTypeHint | InlayKind::TypeHint | InlayKind::ChainingHint => {
Some(lsp_types::InlayHintKind::TYPE)
}
- InlayKind::GenericParamListHint
+ InlayKind::BindingModeHint
+ | InlayKind::GenericParamListHint
| InlayKind::LifetimeHint
- | InlayKind::ImplicitReborrow => None,
+ | InlayKind::ImplicitReborrowHint => None,
},
tooltip: None,
padding_left: Some(match inlay_hint.kind {
InlayKind::TypeHint => !render_colons,
- InlayKind::ParameterHint | InlayKind::ClosureReturnTypeHint => false,
InlayKind::ChainingHint => true,
- InlayKind::GenericParamListHint => false,
- InlayKind::LifetimeHint => false,
- InlayKind::ImplicitReborrow => false,
+ InlayKind::BindingModeHint
+ | InlayKind::ClosureReturnTypeHint
+ | InlayKind::GenericParamListHint
+ | InlayKind::ImplicitReborrowHint
+ | InlayKind::LifetimeHint
+ | InlayKind::ParameterHint => false,
}),
padding_right: Some(match inlay_hint.kind {
- InlayKind::TypeHint | InlayKind::ChainingHint | InlayKind::ClosureReturnTypeHint => {
- false
- }
- InlayKind::ParameterHint => true,
- InlayKind::LifetimeHint => true,
- InlayKind::GenericParamListHint => false,
- InlayKind::ImplicitReborrow => false,
+ InlayKind::ChainingHint
+ | InlayKind::ClosureReturnTypeHint
+ | InlayKind::GenericParamListHint
+ | InlayKind::ImplicitReborrowHint
+ | InlayKind::TypeHint => false,
+ InlayKind::BindingModeHint => inlay_hint.label != "&",
+ InlayKind::ParameterHint | InlayKind::LifetimeHint => true,
}),
text_edits: None,
data: None,
diff --git a/crates/syntax/src/ast/expr_ext.rs b/crates/syntax/src/ast/expr_ext.rs
index 17785152bc..db66d08a73 100644
--- a/crates/syntax/src/ast/expr_ext.rs
+++ b/crates/syntax/src/ast/expr_ext.rs
@@ -273,7 +273,7 @@ impl ast::ArrayExpr {
}
fn is_repeat(&self) -> bool {
- self.syntax().children_with_tokens().any(|it| it.kind() == T![;])
+ self.semicolon_token().is_some()
}
}
diff --git a/docs/user/generated_config.adoc b/docs/user/generated_config.adoc
index f2c8cb95c9..57f04067a3 100644
--- a/docs/user/generated_config.adoc
+++ b/docs/user/generated_config.adoc
@@ -345,6 +345,11 @@ Whether to allow import insertion to merge new imports into single path glob imp
--
The path structure for newly inserted paths to use.
--
+[[rust-analyzer.inlayHints.bindingModeHints.enable]]rust-analyzer.inlayHints.bindingModeHints.enable (default: `false`)::
++
+--
+Whether to show inlay type hints for binding modes.
+--
[[rust-analyzer.inlayHints.chainingHints.enable]]rust-analyzer.inlayHints.chainingHints.enable (default: `true`)::
+
--
diff --git a/editors/code/package.json b/editors/code/package.json
index a69d224659..f34f9354e6 100644
--- a/editors/code/package.json
+++ b/editors/code/package.json
@@ -782,6 +782,11 @@
"Force import paths to be absolute by always starting them with `crate` or the extern crate name they come from."
]
},
+ "rust-analyzer.inlayHints.bindingModeHints.enable": {
+ "markdownDescription": "Whether to show inlay type hints for binding modes.",
+ "default": false,
+ "type": "boolean"
+ },
"rust-analyzer.inlayHints.chainingHints.enable": {
"markdownDescription": "Whether to show inlay type hints for method chains.",
"default": true,