mirror of
https://github.com/rust-lang/rust-analyzer.git
synced 2025-09-27 12:29:21 +00:00
Auto merge of #12316 - jonas-schievink:closure-param-hints, r=jonas-schievink
feat: Show parameter inlay hints for closure invocations Fixes https://github.com/rust-lang/rust-analyzer/issues/12268
This commit is contained in:
commit
bf37fe23f3
3 changed files with 77 additions and 22 deletions
|
@ -62,9 +62,9 @@ use hir_ty::{
|
||||||
subst_prefix,
|
subst_prefix,
|
||||||
traits::FnTrait,
|
traits::FnTrait,
|
||||||
AliasEq, AliasTy, BoundVar, CallableDefId, CallableSig, Canonical, CanonicalVarKinds, Cast,
|
AliasEq, AliasTy, BoundVar, CallableDefId, CallableSig, Canonical, CanonicalVarKinds, Cast,
|
||||||
DebruijnIndex, GenericArgData, InEnvironment, Interner, ParamKind, QuantifiedWhereClause,
|
ClosureId, DebruijnIndex, GenericArgData, InEnvironment, Interner, ParamKind,
|
||||||
Scalar, Solution, Substitution, TraitEnvironment, TraitRefExt, Ty, TyBuilder, TyDefId, TyExt,
|
QuantifiedWhereClause, Scalar, Solution, Substitution, TraitEnvironment, TraitRefExt, Ty,
|
||||||
TyKind, TyVariableKind, WhereClause,
|
TyBuilder, TyDefId, TyExt, TyKind, TyVariableKind, WhereClause,
|
||||||
};
|
};
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
use nameres::diagnostics::DefDiagnosticKind;
|
use nameres::diagnostics::DefDiagnosticKind;
|
||||||
|
@ -2819,10 +2819,14 @@ impl Type {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn as_callable(&self, db: &dyn HirDatabase) -> Option<Callable> {
|
pub fn as_callable(&self, db: &dyn HirDatabase) -> Option<Callable> {
|
||||||
let def = self.ty.callable_def(db);
|
let callee = match self.ty.kind(Interner) {
|
||||||
|
TyKind::Closure(id, _) => Callee::Closure(*id),
|
||||||
|
TyKind::Function(_) => Callee::FnPtr,
|
||||||
|
_ => Callee::Def(self.ty.callable_def(db)?),
|
||||||
|
};
|
||||||
|
|
||||||
let sig = self.ty.callable_sig(db)?;
|
let sig = self.ty.callable_sig(db)?;
|
||||||
Some(Callable { ty: self.clone(), sig, def, is_bound_method: false })
|
Some(Callable { ty: self.clone(), sig, callee, is_bound_method: false })
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn is_closure(&self) -> bool {
|
pub fn is_closure(&self) -> bool {
|
||||||
|
@ -3265,34 +3269,43 @@ impl Type {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// FIXME: closures
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Callable {
|
pub struct Callable {
|
||||||
ty: Type,
|
ty: Type,
|
||||||
sig: CallableSig,
|
sig: CallableSig,
|
||||||
def: Option<CallableDefId>,
|
callee: Callee,
|
||||||
pub(crate) is_bound_method: bool,
|
pub(crate) is_bound_method: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
enum Callee {
|
||||||
|
Def(CallableDefId),
|
||||||
|
Closure(ClosureId),
|
||||||
|
FnPtr,
|
||||||
|
}
|
||||||
|
|
||||||
pub enum CallableKind {
|
pub enum CallableKind {
|
||||||
Function(Function),
|
Function(Function),
|
||||||
TupleStruct(Struct),
|
TupleStruct(Struct),
|
||||||
TupleEnumVariant(Variant),
|
TupleEnumVariant(Variant),
|
||||||
Closure,
|
Closure,
|
||||||
|
FnPtr,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Callable {
|
impl Callable {
|
||||||
pub fn kind(&self) -> CallableKind {
|
pub fn kind(&self) -> CallableKind {
|
||||||
match self.def {
|
use Callee::*;
|
||||||
Some(CallableDefId::FunctionId(it)) => CallableKind::Function(it.into()),
|
match self.callee {
|
||||||
Some(CallableDefId::StructId(it)) => CallableKind::TupleStruct(it.into()),
|
Def(CallableDefId::FunctionId(it)) => CallableKind::Function(it.into()),
|
||||||
Some(CallableDefId::EnumVariantId(it)) => CallableKind::TupleEnumVariant(it.into()),
|
Def(CallableDefId::StructId(it)) => CallableKind::TupleStruct(it.into()),
|
||||||
None => CallableKind::Closure,
|
Def(CallableDefId::EnumVariantId(it)) => CallableKind::TupleEnumVariant(it.into()),
|
||||||
|
Closure(_) => CallableKind::Closure,
|
||||||
|
FnPtr => CallableKind::FnPtr,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub fn receiver_param(&self, db: &dyn HirDatabase) -> Option<ast::SelfParam> {
|
pub fn receiver_param(&self, db: &dyn HirDatabase) -> Option<ast::SelfParam> {
|
||||||
let func = match self.def {
|
let func = match self.callee {
|
||||||
Some(CallableDefId::FunctionId(it)) if self.is_bound_method => it,
|
Callee::Def(CallableDefId::FunctionId(it)) if self.is_bound_method => it,
|
||||||
_ => return None,
|
_ => return None,
|
||||||
};
|
};
|
||||||
let src = func.lookup(db.upcast()).source(db.upcast());
|
let src = func.lookup(db.upcast()).source(db.upcast());
|
||||||
|
@ -3312,8 +3325,9 @@ impl Callable {
|
||||||
.iter()
|
.iter()
|
||||||
.skip(if self.is_bound_method { 1 } else { 0 })
|
.skip(if self.is_bound_method { 1 } else { 0 })
|
||||||
.map(|ty| self.ty.derived(ty.clone()));
|
.map(|ty| self.ty.derived(ty.clone()));
|
||||||
let patterns = match self.def {
|
let map_param = |it: ast::Param| it.pat().map(Either::Right);
|
||||||
Some(CallableDefId::FunctionId(func)) => {
|
let patterns = match self.callee {
|
||||||
|
Callee::Def(CallableDefId::FunctionId(func)) => {
|
||||||
let src = func.lookup(db.upcast()).source(db.upcast());
|
let src = func.lookup(db.upcast()).source(db.upcast());
|
||||||
src.value.param_list().map(|param_list| {
|
src.value.param_list().map(|param_list| {
|
||||||
param_list
|
param_list
|
||||||
|
@ -3321,9 +3335,20 @@ impl Callable {
|
||||||
.map(|it| Some(Either::Left(it)))
|
.map(|it| Some(Either::Left(it)))
|
||||||
.filter(|_| !self.is_bound_method)
|
.filter(|_| !self.is_bound_method)
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.chain(param_list.params().map(|it| it.pat().map(Either::Right)))
|
.chain(param_list.params().map(map_param))
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
Callee::Closure(closure_id) => match closure_source(db, closure_id) {
|
||||||
|
Some(src) => src.param_list().map(|param_list| {
|
||||||
|
param_list
|
||||||
|
.self_param()
|
||||||
|
.map(|it| Some(Either::Left(it)))
|
||||||
|
.filter(|_| !self.is_bound_method)
|
||||||
|
.into_iter()
|
||||||
|
.chain(param_list.params().map(map_param))
|
||||||
|
}),
|
||||||
|
None => None,
|
||||||
|
},
|
||||||
_ => None,
|
_ => None,
|
||||||
};
|
};
|
||||||
patterns.into_iter().flatten().chain(iter::repeat(None)).zip(types).collect()
|
patterns.into_iter().flatten().chain(iter::repeat(None)).zip(types).collect()
|
||||||
|
@ -3333,6 +3358,18 @@ impl Callable {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn closure_source(db: &dyn HirDatabase, closure: ClosureId) -> Option<ast::ClosureExpr> {
|
||||||
|
let (owner, expr_id) = db.lookup_intern_closure(closure.into());
|
||||||
|
let (_, source_map) = db.body_with_source_map(owner);
|
||||||
|
let ast = source_map.expr_syntax(expr_id).ok()?;
|
||||||
|
let root = ast.file_syntax(db.upcast());
|
||||||
|
let expr = ast.value.to_node(&root);
|
||||||
|
match expr {
|
||||||
|
ast::Expr::ClosureExpr(it) => Some(it),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
|
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
|
||||||
pub enum BindingMode {
|
pub enum BindingMode {
|
||||||
Move,
|
Move,
|
||||||
|
|
|
@ -1169,6 +1169,23 @@ fn main() {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn param_hints_on_closure() {
|
||||||
|
check_params(
|
||||||
|
r#"
|
||||||
|
fn main() {
|
||||||
|
let clo = |a: u8, b: u8| a + b;
|
||||||
|
clo(
|
||||||
|
1,
|
||||||
|
//^ a
|
||||||
|
2,
|
||||||
|
//^ b
|
||||||
|
);
|
||||||
|
}
|
||||||
|
"#,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn param_name_similar_to_fn_name_still_hints() {
|
fn param_name_similar_to_fn_name_still_hints() {
|
||||||
check_params(
|
check_params(
|
||||||
|
@ -2000,7 +2017,8 @@ fn main() {
|
||||||
|
|
||||||
;
|
;
|
||||||
|
|
||||||
let _: i32 = multiply(1, 2);
|
let _: i32 = multiply(1, 2);
|
||||||
|
//^ a ^ b
|
||||||
let multiply_ref = &multiply;
|
let multiply_ref = &multiply;
|
||||||
//^^^^^^^^^^^^ &|i32, i32| -> i32
|
//^^^^^^^^^^^^ &|i32, i32| -> i32
|
||||||
|
|
||||||
|
|
|
@ -149,7 +149,7 @@ fn signature_help_for_call(
|
||||||
variant.name(db)
|
variant.name(db)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
hir::CallableKind::Closure => (),
|
hir::CallableKind::Closure | hir::CallableKind::FnPtr => (),
|
||||||
}
|
}
|
||||||
|
|
||||||
res.signature.push('(');
|
res.signature.push('(');
|
||||||
|
@ -189,7 +189,7 @@ fn signature_help_for_call(
|
||||||
hir::CallableKind::Function(func) if callable.return_type().contains_unknown() => {
|
hir::CallableKind::Function(func) if callable.return_type().contains_unknown() => {
|
||||||
render(func.ret_type(db))
|
render(func.ret_type(db))
|
||||||
}
|
}
|
||||||
hir::CallableKind::Function(_) | hir::CallableKind::Closure => {
|
hir::CallableKind::Function(_) | hir::CallableKind::Closure | hir::CallableKind::FnPtr => {
|
||||||
render(callable.return_type())
|
render(callable.return_type())
|
||||||
}
|
}
|
||||||
hir::CallableKind::TupleStruct(_) | hir::CallableKind::TupleEnumVariant(_) => {}
|
hir::CallableKind::TupleStruct(_) | hir::CallableKind::TupleEnumVariant(_) => {}
|
||||||
|
@ -914,8 +914,8 @@ fn main() {
|
||||||
}
|
}
|
||||||
"#,
|
"#,
|
||||||
expect![[r#"
|
expect![[r#"
|
||||||
(S) -> i32
|
(s: S) -> i32
|
||||||
^
|
^^^^
|
||||||
"#]],
|
"#]],
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue