mirror of
https://github.com/rust-lang/rust-analyzer
synced 2024-12-27 21:43:37 +00:00
feat: Add binding mode inlay hints
This commit is contained in:
parent
06448c5548
commit
6b696fced8
12 changed files with 201 additions and 41 deletions
|
@ -105,7 +105,7 @@ impl<'a> PatCtxt<'a> {
|
||||||
self.infer.pat_adjustments.get(&pat).map(|it| &**it).unwrap_or_default().iter().rev().fold(
|
self.infer.pat_adjustments.get(&pat).map(|it| &**it).unwrap_or_default().iter().rev().fold(
|
||||||
unadjusted_pat,
|
unadjusted_pat,
|
||||||
|subpattern, ref_ty| Pat {
|
|subpattern, ref_ty| Pat {
|
||||||
ty: ref_ty.target.clone(),
|
ty: ref_ty.clone(),
|
||||||
kind: Box::new(PatKind::Deref { subpattern }),
|
kind: Box::new(PatKind::Deref { subpattern }),
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
|
@ -297,7 +297,7 @@ pub struct InferenceResult {
|
||||||
/// Interned Unknown to return references to.
|
/// Interned Unknown to return references to.
|
||||||
standard_types: InternedStandardTypes,
|
standard_types: InternedStandardTypes,
|
||||||
/// Stores the types which were implicitly dereferenced in pattern binding modes.
|
/// 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 pat_binding_modes: FxHashMap<PatId, BindingMode>,
|
||||||
pub expr_adjustments: FxHashMap<ExprId, Vec<Adjustment>>,
|
pub expr_adjustments: FxHashMap<ExprId, Vec<Adjustment>>,
|
||||||
}
|
}
|
||||||
|
@ -445,7 +445,7 @@ impl<'a> InferenceContext<'a> {
|
||||||
adjustment.target = table.resolve_completely(adjustment.target.clone());
|
adjustment.target = table.resolve_completely(adjustment.target.clone());
|
||||||
}
|
}
|
||||||
for adjustment in result.pat_adjustments.values_mut().flatten() {
|
for adjustment in result.pat_adjustments.values_mut().flatten() {
|
||||||
adjustment.target = table.resolve_completely(adjustment.target.clone());
|
*adjustment = table.resolve_completely(adjustment.clone());
|
||||||
}
|
}
|
||||||
result
|
result
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,9 +11,7 @@ use hir_def::{
|
||||||
use hir_expand::name::Name;
|
use hir_expand::name::Name;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
infer::{
|
infer::{BindingMode, Expectation, InferenceContext, TypeMismatch},
|
||||||
Adjust, Adjustment, AutoBorrow, BindingMode, Expectation, InferenceContext, TypeMismatch,
|
|
||||||
},
|
|
||||||
lower::lower_to_chalk_mutability,
|
lower::lower_to_chalk_mutability,
|
||||||
static_lifetime, ConcreteConst, ConstValue, Interner, Substitution, Ty, TyBuilder, TyExt,
|
static_lifetime, ConcreteConst, ConstValue, Interner, Substitution, Ty, TyBuilder, TyExt,
|
||||||
TyKind,
|
TyKind,
|
||||||
|
@ -105,10 +103,7 @@ impl<'a> InferenceContext<'a> {
|
||||||
if is_non_ref_pat(&self.body, pat) {
|
if is_non_ref_pat(&self.body, pat) {
|
||||||
let mut pat_adjustments = Vec::new();
|
let mut pat_adjustments = Vec::new();
|
||||||
while let Some((inner, _lifetime, mutability)) = expected.as_reference() {
|
while let Some((inner, _lifetime, mutability)) = expected.as_reference() {
|
||||||
pat_adjustments.push(Adjustment {
|
pat_adjustments.push(expected.clone());
|
||||||
target: expected.clone(),
|
|
||||||
kind: Adjust::Borrow(AutoBorrow::Ref(mutability)),
|
|
||||||
});
|
|
||||||
expected = self.resolve_ty_shallow(inner);
|
expected = self.resolve_ty_shallow(inner);
|
||||||
default_bm = match default_bm {
|
default_bm = match default_bm {
|
||||||
BindingMode::Move => BindingMode::Ref(mutability),
|
BindingMode::Move => BindingMode::Ref(mutability),
|
||||||
|
|
|
@ -47,7 +47,8 @@ pub use autoderef::autoderef;
|
||||||
pub use builder::{ParamKind, TyBuilder};
|
pub use builder::{ParamKind, TyBuilder};
|
||||||
pub use chalk_ext::*;
|
pub use chalk_ext::*;
|
||||||
pub use infer::{
|
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 interner::Interner;
|
||||||
pub use lower::{
|
pub use lower::{
|
||||||
|
|
|
@ -3332,6 +3332,12 @@ impl Callable {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
|
||||||
|
pub enum BindingMode {
|
||||||
|
Move,
|
||||||
|
Ref(Mutability),
|
||||||
|
}
|
||||||
|
|
||||||
/// For IDE only
|
/// For IDE only
|
||||||
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
|
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
|
||||||
pub enum ScopeDef {
|
pub enum ScopeDef {
|
||||||
|
|
|
@ -30,9 +30,9 @@ use crate::{
|
||||||
db::HirDatabase,
|
db::HirDatabase,
|
||||||
semantics::source_to_def::{ChildContainer, SourceToDefCache, SourceToDefCtx},
|
semantics::source_to_def::{ChildContainer, SourceToDefCache, SourceToDefCtx},
|
||||||
source_analyzer::{resolve_hir_path, SourceAnalyzer},
|
source_analyzer::{resolve_hir_path, SourceAnalyzer},
|
||||||
Access, BuiltinAttr, Callable, ConstParam, Crate, Field, Function, HasSource, HirFileId, Impl,
|
Access, BindingMode, BuiltinAttr, Callable, ConstParam, Crate, Field, Function, HasSource,
|
||||||
InFile, Label, LifetimeParam, Local, Macro, Module, ModuleDef, Name, Path, ScopeDef,
|
HirFileId, Impl, InFile, Label, LifetimeParam, Local, Macro, Module, ModuleDef, Name, Path,
|
||||||
ToolModule, Trait, Type, TypeAlias, TypeParam, VariantDef,
|
ScopeDef, ToolModule, Trait, Type, TypeAlias, TypeParam, VariantDef,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
|
@ -336,6 +336,14 @@ impl<'db, DB: HirDatabase> Semantics<'db, DB> {
|
||||||
self.imp.type_of_self(param)
|
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> {
|
pub fn resolve_method_call(&self, call: &ast::MethodCallExpr) -> Option<Function> {
|
||||||
self.imp.resolve_method_call(call).map(Function::from)
|
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)
|
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> {
|
fn resolve_method_call(&self, call: &ast::MethodCallExpr) -> Option<FunctionId> {
|
||||||
self.analyze(call.syntax())?.resolve_method_call(self.db, call).map(|(id, _)| id)
|
self.analyze(call.syntax())?.resolve_method_call(self.db, call).map(|(id, _)| id)
|
||||||
}
|
}
|
||||||
|
|
|
@ -34,15 +34,16 @@ use hir_ty::{
|
||||||
Adjust, Adjustment, AutoBorrow, InferenceResult, Interner, Substitution, TyExt,
|
Adjust, Adjustment, AutoBorrow, InferenceResult, Interner, Substitution, TyExt,
|
||||||
TyLoweringContext,
|
TyLoweringContext,
|
||||||
};
|
};
|
||||||
|
use smallvec::SmallVec;
|
||||||
use syntax::{
|
use syntax::{
|
||||||
ast::{self, AstNode},
|
ast::{self, AstNode},
|
||||||
SyntaxKind, SyntaxNode, TextRange, TextSize,
|
SyntaxKind, SyntaxNode, TextRange, TextSize,
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
db::HirDatabase, semantics::PathResolution, Adt, AssocItem, BuiltinAttr, BuiltinType, Const,
|
db::HirDatabase, semantics::PathResolution, Adt, AssocItem, BindingMode, BuiltinAttr,
|
||||||
Field, Function, Local, Macro, ModuleDef, Static, Struct, ToolModule, Trait, Type, TypeAlias,
|
BuiltinType, Const, Field, Function, Local, Macro, ModuleDef, Static, Struct, ToolModule,
|
||||||
Variant,
|
Trait, Type, TypeAlias, Variant,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// `SourceAnalyzer` is a convenience wrapper which exposes HIR API in terms of
|
/// `SourceAnalyzer` is a convenience wrapper which exposes HIR API in terms of
|
||||||
|
@ -182,7 +183,7 @@ impl SourceAnalyzer {
|
||||||
let coerced = infer
|
let coerced = infer
|
||||||
.pat_adjustments
|
.pat_adjustments
|
||||||
.get(&pat_id)
|
.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 ty = infer[pat_id].clone();
|
||||||
let mk_ty = |ty| Type::new_with_resolver(db, &self.resolver, ty);
|
let mk_ty = |ty| Type::new_with_resolver(db, &self.resolver, ty);
|
||||||
Some((mk_ty(ty), coerced.map(mk_ty)))
|
Some((mk_ty(ty), coerced.map(mk_ty)))
|
||||||
|
@ -199,6 +200,38 @@ impl SourceAnalyzer {
|
||||||
Some(Type::new_with_resolver(db, &self.resolver, ty))
|
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(
|
pub(crate) fn resolve_method_call(
|
||||||
&self,
|
&self,
|
||||||
db: &dyn HirDatabase,
|
db: &dyn HirDatabase,
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
use either::Either;
|
use either::Either;
|
||||||
use hir::{known, Callable, HasVisibility, HirDisplay, Semantics, TypeInfo};
|
use hir::{known, Callable, HasVisibility, HirDisplay, Mutability, Semantics, TypeInfo};
|
||||||
use ide_db::{
|
use ide_db::{
|
||||||
base_db::FileRange, famous_defs::FamousDefs, syntax_helpers::node_ext::walk_ty, FxHashMap,
|
base_db::FileRange, famous_defs::FamousDefs, syntax_helpers::node_ext::walk_ty, FxHashMap,
|
||||||
RootDatabase,
|
RootDatabase,
|
||||||
|
@ -21,6 +21,7 @@ pub struct InlayHintsConfig {
|
||||||
pub chaining_hints: bool,
|
pub chaining_hints: bool,
|
||||||
pub reborrow_hints: ReborrowHints,
|
pub reborrow_hints: ReborrowHints,
|
||||||
pub closure_return_type_hints: bool,
|
pub closure_return_type_hints: bool,
|
||||||
|
pub binding_mode_hints: bool,
|
||||||
pub lifetime_elision_hints: LifetimeElisionHints,
|
pub lifetime_elision_hints: LifetimeElisionHints,
|
||||||
pub param_names_for_lifetime_elision_hints: bool,
|
pub param_names_for_lifetime_elision_hints: bool,
|
||||||
pub hide_named_constructor_hints: bool,
|
pub hide_named_constructor_hints: bool,
|
||||||
|
@ -43,10 +44,11 @@ pub enum ReborrowHints {
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||||
pub enum InlayKind {
|
pub enum InlayKind {
|
||||||
|
BindingModeHint,
|
||||||
ChainingHint,
|
ChainingHint,
|
||||||
ClosureReturnTypeHint,
|
ClosureReturnTypeHint,
|
||||||
GenericParamListHint,
|
GenericParamListHint,
|
||||||
ImplicitReborrow,
|
ImplicitReborrowHint,
|
||||||
LifetimeHint,
|
LifetimeHint,
|
||||||
ParameterHint,
|
ParameterHint,
|
||||||
TypeHint,
|
TypeHint,
|
||||||
|
@ -135,8 +137,11 @@ fn hints(
|
||||||
ast::Expr::PathExpr(_) => reborrow_hints(hints, sema, config, &expr),
|
ast::Expr::PathExpr(_) => reborrow_hints(hints, sema, config, &expr),
|
||||||
_ => None,
|
_ => None,
|
||||||
};
|
};
|
||||||
} else if let Some(it) = ast::IdentPat::cast(node.clone()) {
|
} 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);
|
bind_pat_hints(hints, sema, config, &it);
|
||||||
|
}
|
||||||
} else if let Some(it) = ast::Fn::cast(node) {
|
} else if let Some(it) = ast::Fn::cast(node) {
|
||||||
lifetime_hints(hints, config, it);
|
lifetime_hints(hints, config, it);
|
||||||
}
|
}
|
||||||
|
@ -383,6 +388,8 @@ fn reborrow_hints(
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 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(expr)?;
|
let mutability = sema.is_implicit_reborrow(expr)?;
|
||||||
let label = match mutability {
|
let label = match mutability {
|
||||||
hir::Mutability::Shared if config.reborrow_hints != ReborrowHints::MutableOnly => "&*",
|
hir::Mutability::Shared if config.reborrow_hints != ReborrowHints::MutableOnly => "&*",
|
||||||
|
@ -391,7 +398,7 @@ fn reborrow_hints(
|
||||||
};
|
};
|
||||||
acc.push(InlayHint {
|
acc.push(InlayHint {
|
||||||
range: expr.syntax().text_range(),
|
range: expr.syntax().text_range(),
|
||||||
kind: InlayKind::ImplicitReborrow,
|
kind: InlayKind::ImplicitReborrowHint,
|
||||||
label: SmolStr::new_inline(label),
|
label: SmolStr::new_inline(label),
|
||||||
});
|
});
|
||||||
Some(())
|
Some(())
|
||||||
|
@ -497,6 +504,51 @@ fn param_name_hints(
|
||||||
Some(())
|
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(
|
fn bind_pat_hints(
|
||||||
acc: &mut Vec<InlayHint>,
|
acc: &mut Vec<InlayHint>,
|
||||||
sema: &Semantics<RootDatabase>,
|
sema: &Semantics<RootDatabase>,
|
||||||
|
@ -681,6 +733,7 @@ fn should_not_display_type_hint(
|
||||||
match_ast! {
|
match_ast! {
|
||||||
match node {
|
match node {
|
||||||
ast::LetStmt(it) => return it.ty().is_some(),
|
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::Param(it) => return it.ty().is_some(),
|
||||||
ast::MatchArm(_) => return pat_is_enum_variant(db, bind_pat, pat_ty),
|
ast::MatchArm(_) => return pat_is_enum_variant(db, bind_pat, pat_ty),
|
||||||
ast::LetExpr(_) => 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,
|
parameter_hints: false,
|
||||||
chaining_hints: false,
|
chaining_hints: false,
|
||||||
lifetime_elision_hints: LifetimeElisionHints::Never,
|
lifetime_elision_hints: LifetimeElisionHints::Never,
|
||||||
hide_named_constructor_hints: false,
|
|
||||||
closure_return_type_hints: false,
|
closure_return_type_hints: false,
|
||||||
reborrow_hints: ReborrowHints::Always,
|
reborrow_hints: ReborrowHints::Always,
|
||||||
|
binding_mode_hints: false,
|
||||||
|
hide_named_constructor_hints: false,
|
||||||
param_names_for_lifetime_elision_hints: false,
|
param_names_for_lifetime_elision_hints: false,
|
||||||
max_length: None,
|
max_length: None,
|
||||||
};
|
};
|
||||||
|
@ -878,6 +932,7 @@ mod tests {
|
||||||
chaining_hints: true,
|
chaining_hints: true,
|
||||||
reborrow_hints: ReborrowHints::Always,
|
reborrow_hints: ReborrowHints::Always,
|
||||||
closure_return_type_hints: true,
|
closure_return_type_hints: true,
|
||||||
|
binding_mode_hints: true,
|
||||||
lifetime_elision_hints: LifetimeElisionHints::Always,
|
lifetime_elision_hints: LifetimeElisionHints::Always,
|
||||||
..DISABLED_CONFIG
|
..DISABLED_CONFIG
|
||||||
};
|
};
|
||||||
|
@ -2191,6 +2246,51 @@ fn ref_mut_id(mut_ref: &mut ()) -> &mut () {
|
||||||
fn ref_id(shared_ref: &()) -> &() {
|
fn ref_id(shared_ref: &()) -> &() {
|
||||||
shared_ref
|
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
|
||||||
|
}
|
||||||
|
}
|
||||||
"#,
|
"#,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -114,6 +114,7 @@ impl StaticIndex<'_> {
|
||||||
reborrow_hints: crate::ReborrowHints::Never,
|
reborrow_hints: crate::ReborrowHints::Never,
|
||||||
hide_named_constructor_hints: false,
|
hide_named_constructor_hints: false,
|
||||||
param_names_for_lifetime_elision_hints: false,
|
param_names_for_lifetime_elision_hints: false,
|
||||||
|
binding_mode_hints: false,
|
||||||
max_length: Some(25),
|
max_length: Some(25),
|
||||||
},
|
},
|
||||||
file_id,
|
file_id,
|
||||||
|
|
|
@ -254,6 +254,8 @@ config_data! {
|
||||||
/// The path structure for newly inserted paths to use.
|
/// The path structure for newly inserted paths to use.
|
||||||
imports_prefix: ImportPrefixDef = "\"plain\"",
|
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.
|
/// Whether to show inlay type hints for method chains.
|
||||||
inlayHints_chainingHints_enable: bool = "true",
|
inlayHints_chainingHints_enable: bool = "true",
|
||||||
/// Whether to show inlay type hints for return types of closures with blocks.
|
/// Whether to show inlay type hints for return types of closures with blocks.
|
||||||
|
@ -997,6 +999,7 @@ impl Config {
|
||||||
ReborrowHintsDef::Never => ide::ReborrowHints::Never,
|
ReborrowHintsDef::Never => ide::ReborrowHints::Never,
|
||||||
ReborrowHintsDef::Mutable => ide::ReborrowHints::MutableOnly,
|
ReborrowHintsDef::Mutable => ide::ReborrowHints::MutableOnly,
|
||||||
},
|
},
|
||||||
|
binding_mode_hints: self.data.inlayHints_bindingModeHints_enable,
|
||||||
param_names_for_lifetime_elision_hints: self
|
param_names_for_lifetime_elision_hints: self
|
||||||
.data
|
.data
|
||||||
.inlayHints_lifetimeElisionHints_useParameterNames,
|
.inlayHints_lifetimeElisionHints_useParameterNames,
|
||||||
|
|
|
@ -418,9 +418,9 @@ pub(crate) fn inlay_hint(
|
||||||
lsp_types::InlayHint {
|
lsp_types::InlayHint {
|
||||||
position: match inlay_hint.kind {
|
position: match inlay_hint.kind {
|
||||||
// before annotated thing
|
// before annotated thing
|
||||||
InlayKind::ParameterHint | InlayKind::ImplicitReborrow => {
|
InlayKind::ParameterHint
|
||||||
position(line_index, inlay_hint.range.start())
|
| InlayKind::ImplicitReborrowHint
|
||||||
}
|
| InlayKind::BindingModeHint => position(line_index, inlay_hint.range.start()),
|
||||||
// after annotated thing
|
// after annotated thing
|
||||||
InlayKind::ClosureReturnTypeHint
|
InlayKind::ClosureReturnTypeHint
|
||||||
| InlayKind::TypeHint
|
| InlayKind::TypeHint
|
||||||
|
@ -439,27 +439,30 @@ pub(crate) fn inlay_hint(
|
||||||
InlayKind::ClosureReturnTypeHint | InlayKind::TypeHint | InlayKind::ChainingHint => {
|
InlayKind::ClosureReturnTypeHint | InlayKind::TypeHint | InlayKind::ChainingHint => {
|
||||||
Some(lsp_types::InlayHintKind::TYPE)
|
Some(lsp_types::InlayHintKind::TYPE)
|
||||||
}
|
}
|
||||||
InlayKind::GenericParamListHint
|
InlayKind::BindingModeHint
|
||||||
|
| InlayKind::GenericParamListHint
|
||||||
| InlayKind::LifetimeHint
|
| InlayKind::LifetimeHint
|
||||||
| InlayKind::ImplicitReborrow => None,
|
| InlayKind::ImplicitReborrowHint => None,
|
||||||
},
|
},
|
||||||
tooltip: None,
|
tooltip: None,
|
||||||
padding_left: Some(match inlay_hint.kind {
|
padding_left: Some(match inlay_hint.kind {
|
||||||
InlayKind::TypeHint => !render_colons,
|
InlayKind::TypeHint => !render_colons,
|
||||||
InlayKind::ParameterHint | InlayKind::ClosureReturnTypeHint => false,
|
|
||||||
InlayKind::ChainingHint => true,
|
InlayKind::ChainingHint => true,
|
||||||
InlayKind::GenericParamListHint => false,
|
InlayKind::BindingModeHint
|
||||||
InlayKind::LifetimeHint => false,
|
| InlayKind::ClosureReturnTypeHint
|
||||||
InlayKind::ImplicitReborrow => false,
|
| InlayKind::GenericParamListHint
|
||||||
|
| InlayKind::ImplicitReborrowHint
|
||||||
|
| InlayKind::LifetimeHint
|
||||||
|
| InlayKind::ParameterHint => false,
|
||||||
}),
|
}),
|
||||||
padding_right: Some(match inlay_hint.kind {
|
padding_right: Some(match inlay_hint.kind {
|
||||||
InlayKind::TypeHint | InlayKind::ChainingHint | InlayKind::ClosureReturnTypeHint => {
|
InlayKind::ChainingHint
|
||||||
false
|
| InlayKind::ClosureReturnTypeHint
|
||||||
}
|
| InlayKind::GenericParamListHint
|
||||||
InlayKind::ParameterHint => true,
|
| InlayKind::ImplicitReborrowHint
|
||||||
InlayKind::LifetimeHint => true,
|
| InlayKind::TypeHint => false,
|
||||||
InlayKind::GenericParamListHint => false,
|
InlayKind::BindingModeHint => inlay_hint.label != "&",
|
||||||
InlayKind::ImplicitReborrow => false,
|
InlayKind::ParameterHint | InlayKind::LifetimeHint => true,
|
||||||
}),
|
}),
|
||||||
text_edits: None,
|
text_edits: None,
|
||||||
data: None,
|
data: None,
|
||||||
|
|
|
@ -273,7 +273,7 @@ impl ast::ArrayExpr {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_repeat(&self) -> bool {
|
fn is_repeat(&self) -> bool {
|
||||||
self.syntax().children_with_tokens().any(|it| it.kind() == T![;])
|
self.semicolon_token().is_some()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue