diff --git a/crates/ra_hir/src/code_model.rs b/crates/ra_hir/src/code_model.rs index 0f6953158a5..859bdfb3bc1 100644 --- a/crates/ra_hir/src/code_model.rs +++ b/crates/ra_hir/src/code_model.rs @@ -1233,9 +1233,13 @@ impl Type { } pub fn as_callable(&self, db: &dyn HirDatabase) -> Option { - let (id, substs) = self.ty.value.as_callable()?; - let sig = db.callable_item_signature(id).subst(substs); - Some(Callable { ty: self.clone(), sig, id, is_bound_method: false }) + let def = match self.ty.value { + Ty::Apply(ApplicationTy { ctor: TypeCtor::FnDef(def), parameters: _ }) => Some(def), + _ => None, + }; + + let sig = self.ty.value.callable_sig(db)?; + Some(Callable { ty: self.clone(), sig, def, is_bound_method: false }) } pub fn is_closure(&self) -> bool { @@ -1525,7 +1529,7 @@ impl HirDisplay for Type { pub struct Callable { ty: Type, sig: FnSig, - id: CallableDefId, + def: Option, pub(crate) is_bound_method: bool, } @@ -1533,19 +1537,21 @@ pub enum CallableKind { Function(Function), TupleStruct(Struct), TupleEnumVariant(EnumVariant), + Closure, } impl Callable { pub fn kind(&self) -> CallableKind { - match self.id { - CallableDefId::FunctionId(it) => CallableKind::Function(it.into()), - CallableDefId::StructId(it) => CallableKind::TupleStruct(it.into()), - CallableDefId::EnumVariantId(it) => CallableKind::TupleEnumVariant(it.into()), + match self.def { + Some(CallableDefId::FunctionId(it)) => CallableKind::Function(it.into()), + Some(CallableDefId::StructId(it)) => CallableKind::TupleStruct(it.into()), + Some(CallableDefId::EnumVariantId(it)) => CallableKind::TupleEnumVariant(it.into()), + None => CallableKind::Closure, } } pub fn receiver_param(&self, db: &dyn HirDatabase) -> Option { - let func = match self.id { - CallableDefId::FunctionId(it) if self.is_bound_method => it, + let func = match self.def { + Some(CallableDefId::FunctionId(it)) if self.is_bound_method => it, _ => return None, }; let src = func.lookup(db.upcast()).source(db.upcast()); @@ -1565,8 +1571,8 @@ impl Callable { .iter() .skip(if self.is_bound_method { 1 } else { 0 }) .map(|ty| self.ty.derived(ty.clone())); - let patterns = match self.id { - CallableDefId::FunctionId(func) => { + let patterns = match self.def { + Some(CallableDefId::FunctionId(func)) => { let src = func.lookup(db.upcast()).source(db.upcast()); src.value.param_list().map(|param_list| { param_list @@ -1577,8 +1583,7 @@ impl Callable { .chain(param_list.params().map(|it| it.pat().map(Either::Right))) }) } - CallableDefId::StructId(_) => None, - CallableDefId::EnumVariantId(_) => None, + _ => None, }; patterns.into_iter().flatten().chain(iter::repeat(None)).zip(types).collect() } diff --git a/crates/ra_hir_ty/src/diagnostics/expr.rs b/crates/ra_hir_ty/src/diagnostics/expr.rs index 557d01cdc9f..fd930eab1a5 100644 --- a/crates/ra_hir_ty/src/diagnostics/expr.rs +++ b/crates/ra_hir_ty/src/diagnostics/expr.rs @@ -158,28 +158,32 @@ impl<'a, 'b> ExprValidator<'a, 'b> { } let is_method_call = matches!(expr, Expr::MethodCall { .. }); - let (callee, args) = match expr { + let (sig, args) = match expr { Expr::Call { callee, args } => { let callee = &self.infer.type_of_expr[*callee]; - let (callable, _) = callee.as_callable()?; - - (callable, args.clone()) + let sig = callee.callable_sig(db)?; + (sig, args.clone()) } Expr::MethodCall { receiver, args, .. } => { - let callee = self.infer.method_resolution(call_id)?; let mut args = args.clone(); args.insert(0, *receiver); - (callee.into(), args) + + // FIXME: note that we erase information about substs here. This + // is not right, but, luckily, doesn't matter as we care only + // about the number of params + let callee = self.infer.method_resolution(call_id)?; + let sig = db.callable_item_signature(callee.into()).value; + + (sig, args) } _ => return None, }; - let sig = db.callable_item_signature(callee); - if sig.value.is_varargs { + if sig.is_varargs { return None; } - let params = sig.value.params(); + let params = sig.params(); let mut param_count = params.len(); let mut arg_count = args.len(); @@ -542,4 +546,20 @@ fn f() { "#, ) } + + #[test] + fn arg_count_lambda() { + check_diagnostics( + r#" +fn main() { + let f = |()| (); + f(); + //^^^ Expected 1 argument, found 0 + f(()); + f((), ()); + //^^^^^^^^^ Expected 1 argument, found 2 +} +"#, + ) + } } diff --git a/crates/ra_hir_ty/src/lib.rs b/crates/ra_hir_ty/src/lib.rs index 0ef5ca78f78..7698cb0d4bb 100644 --- a/crates/ra_hir_ty/src/lib.rs +++ b/crates/ra_hir_ty/src/lib.rs @@ -767,15 +767,6 @@ impl Ty { } } - pub fn as_callable(&self) -> Option<(CallableDefId, &Substs)> { - match self { - Ty::Apply(ApplicationTy { ctor: TypeCtor::FnDef(callable_def), parameters }) => { - Some((*callable_def, parameters)) - } - _ => None, - } - } - pub fn is_never(&self) -> bool { matches!(self, Ty::Apply(ApplicationTy { ctor: TypeCtor::Never, .. })) } @@ -807,7 +798,7 @@ impl Ty { } } - fn callable_sig(&self, db: &dyn HirDatabase) -> Option { + pub fn callable_sig(&self, db: &dyn HirDatabase) -> Option { match self { Ty::Apply(a_ty) => match a_ty.ctor { TypeCtor::FnPtr { is_varargs, .. } => { diff --git a/crates/ra_ide/src/call_info.rs b/crates/ra_ide/src/call_info.rs index 35a8a0dc53f..14980afdd04 100644 --- a/crates/ra_ide/src/call_info.rs +++ b/crates/ra_ide/src/call_info.rs @@ -70,6 +70,7 @@ pub(crate) fn call_info(db: &RootDatabase, position: FilePosition) -> Option (), } res.signature.push('('); @@ -93,7 +94,7 @@ pub(crate) fn call_info(db: &RootDatabase, position: FilePosition) -> Option { + hir::CallableKind::Function(_) | hir::CallableKind::Closure => { let ret_type = callable.return_type(); if !ret_type.is_unit() { format_to!(res.signature, " -> {}", ret_type.display(db)); @@ -702,4 +703,36 @@ id! { "#]], ); } + + #[test] + fn call_info_for_lambdas() { + check( + r#" +struct S; +fn foo(s: S) -> i32 { 92 } +fn main() { + (|s| foo(s))(<|>) +} + "#, + expect![[r#" + (S) -> i32 + () + "#]], + ) + } + + #[test] + fn call_info_for_fn_ptr() { + check( + r#" +fn main(f: fn(i32, f64) -> char) { + f(0, <|>) +} + "#, + expect![[r#" + (i32, f64) -> char + (i32, ) + "#]], + ) + } } diff --git a/crates/ra_ide/src/inlay_hints.rs b/crates/ra_ide/src/inlay_hints.rs index cec3b04e86e..43a5e29b5d8 100644 --- a/crates/ra_ide/src/inlay_hints.rs +++ b/crates/ra_ide/src/inlay_hints.rs @@ -262,7 +262,9 @@ fn should_show_param_name_hint( let param_name = param_name.trim_start_matches('_'); let fn_name = match callable.kind() { hir::CallableKind::Function(it) => Some(it.name(sema.db).to_string()), - hir::CallableKind::TupleStruct(_) | hir::CallableKind::TupleEnumVariant(_) => None, + hir::CallableKind::TupleStruct(_) + | hir::CallableKind::TupleEnumVariant(_) + | hir::CallableKind::Closure => None, }; if param_name.is_empty() || Some(param_name) == fn_name.as_ref().map(|s| s.trim_start_matches('_'))