aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--crates/ra_hir/src/code_model.rs33
-rw-r--r--crates/ra_hir_ty/src/diagnostics/expr.rs38
-rw-r--r--crates/ra_hir_ty/src/lib.rs11
-rw-r--r--crates/ra_ide/src/call_info.rs35
-rw-r--r--crates/ra_ide/src/inlay_hints.rs4
5 files changed, 86 insertions, 35 deletions
diff --git a/crates/ra_hir/src/code_model.rs b/crates/ra_hir/src/code_model.rs
index 0f6953158..859bdfb3b 100644
--- a/crates/ra_hir/src/code_model.rs
+++ b/crates/ra_hir/src/code_model.rs
@@ -1233,9 +1233,13 @@ impl Type {
1233 } 1233 }
1234 1234
1235 pub fn as_callable(&self, db: &dyn HirDatabase) -> Option<Callable> { 1235 pub fn as_callable(&self, db: &dyn HirDatabase) -> Option<Callable> {
1236 let (id, substs) = self.ty.value.as_callable()?; 1236 let def = match self.ty.value {
1237 let sig = db.callable_item_signature(id).subst(substs); 1237 Ty::Apply(ApplicationTy { ctor: TypeCtor::FnDef(def), parameters: _ }) => Some(def),
1238 Some(Callable { ty: self.clone(), sig, id, is_bound_method: false }) 1238 _ => None,
1239 };
1240
1241 let sig = self.ty.value.callable_sig(db)?;
1242 Some(Callable { ty: self.clone(), sig, def, is_bound_method: false })
1239 } 1243 }
1240 1244
1241 pub fn is_closure(&self) -> bool { 1245 pub fn is_closure(&self) -> bool {
@@ -1525,7 +1529,7 @@ impl HirDisplay for Type {
1525pub struct Callable { 1529pub struct Callable {
1526 ty: Type, 1530 ty: Type,
1527 sig: FnSig, 1531 sig: FnSig,
1528 id: CallableDefId, 1532 def: Option<CallableDefId>,
1529 pub(crate) is_bound_method: bool, 1533 pub(crate) is_bound_method: bool,
1530} 1534}
1531 1535
@@ -1533,19 +1537,21 @@ pub enum CallableKind {
1533 Function(Function), 1537 Function(Function),
1534 TupleStruct(Struct), 1538 TupleStruct(Struct),
1535 TupleEnumVariant(EnumVariant), 1539 TupleEnumVariant(EnumVariant),
1540 Closure,
1536} 1541}
1537 1542
1538impl Callable { 1543impl Callable {
1539 pub fn kind(&self) -> CallableKind { 1544 pub fn kind(&self) -> CallableKind {
1540 match self.id { 1545 match self.def {
1541 CallableDefId::FunctionId(it) => CallableKind::Function(it.into()), 1546 Some(CallableDefId::FunctionId(it)) => CallableKind::Function(it.into()),
1542 CallableDefId::StructId(it) => CallableKind::TupleStruct(it.into()), 1547 Some(CallableDefId::StructId(it)) => CallableKind::TupleStruct(it.into()),
1543 CallableDefId::EnumVariantId(it) => CallableKind::TupleEnumVariant(it.into()), 1548 Some(CallableDefId::EnumVariantId(it)) => CallableKind::TupleEnumVariant(it.into()),
1549 None => CallableKind::Closure,
1544 } 1550 }
1545 } 1551 }
1546 pub fn receiver_param(&self, db: &dyn HirDatabase) -> Option<ast::SelfParam> { 1552 pub fn receiver_param(&self, db: &dyn HirDatabase) -> Option<ast::SelfParam> {
1547 let func = match self.id { 1553 let func = match self.def {
1548 CallableDefId::FunctionId(it) if self.is_bound_method => it, 1554 Some(CallableDefId::FunctionId(it)) if self.is_bound_method => it,
1549 _ => return None, 1555 _ => return None,
1550 }; 1556 };
1551 let src = func.lookup(db.upcast()).source(db.upcast()); 1557 let src = func.lookup(db.upcast()).source(db.upcast());
@@ -1565,8 +1571,8 @@ impl Callable {
1565 .iter() 1571 .iter()
1566 .skip(if self.is_bound_method { 1 } else { 0 }) 1572 .skip(if self.is_bound_method { 1 } else { 0 })
1567 .map(|ty| self.ty.derived(ty.clone())); 1573 .map(|ty| self.ty.derived(ty.clone()));
1568 let patterns = match self.id { 1574 let patterns = match self.def {
1569 CallableDefId::FunctionId(func) => { 1575 Some(CallableDefId::FunctionId(func)) => {
1570 let src = func.lookup(db.upcast()).source(db.upcast()); 1576 let src = func.lookup(db.upcast()).source(db.upcast());
1571 src.value.param_list().map(|param_list| { 1577 src.value.param_list().map(|param_list| {
1572 param_list 1578 param_list
@@ -1577,8 +1583,7 @@ impl Callable {
1577 .chain(param_list.params().map(|it| it.pat().map(Either::Right))) 1583 .chain(param_list.params().map(|it| it.pat().map(Either::Right)))
1578 }) 1584 })
1579 } 1585 }
1580 CallableDefId::StructId(_) => None, 1586 _ => None,
1581 CallableDefId::EnumVariantId(_) => None,
1582 }; 1587 };
1583 patterns.into_iter().flatten().chain(iter::repeat(None)).zip(types).collect() 1588 patterns.into_iter().flatten().chain(iter::repeat(None)).zip(types).collect()
1584 } 1589 }
diff --git a/crates/ra_hir_ty/src/diagnostics/expr.rs b/crates/ra_hir_ty/src/diagnostics/expr.rs
index 557d01cdc..fd930eab1 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> {
158 } 158 }
159 159
160 let is_method_call = matches!(expr, Expr::MethodCall { .. }); 160 let is_method_call = matches!(expr, Expr::MethodCall { .. });
161 let (callee, args) = match expr { 161 let (sig, args) = match expr {
162 Expr::Call { callee, args } => { 162 Expr::Call { callee, args } => {
163 let callee = &self.infer.type_of_expr[*callee]; 163 let callee = &self.infer.type_of_expr[*callee];
164 let (callable, _) = callee.as_callable()?; 164 let sig = callee.callable_sig(db)?;
165 165 (sig, args.clone())
166 (callable, args.clone())
167 } 166 }
168 Expr::MethodCall { receiver, args, .. } => { 167 Expr::MethodCall { receiver, args, .. } => {
169 let callee = self.infer.method_resolution(call_id)?;
170 let mut args = args.clone(); 168 let mut args = args.clone();
171 args.insert(0, *receiver); 169 args.insert(0, *receiver);
172 (callee.into(), args) 170
171 // FIXME: note that we erase information about substs here. This
172 // is not right, but, luckily, doesn't matter as we care only
173 // about the number of params
174 let callee = self.infer.method_resolution(call_id)?;
175 let sig = db.callable_item_signature(callee.into()).value;
176
177 (sig, args)
173 } 178 }
174 _ => return None, 179 _ => return None,
175 }; 180 };
176 181
177 let sig = db.callable_item_signature(callee); 182 if sig.is_varargs {
178 if sig.value.is_varargs {
179 return None; 183 return None;
180 } 184 }
181 185
182 let params = sig.value.params(); 186 let params = sig.params();
183 187
184 let mut param_count = params.len(); 188 let mut param_count = params.len();
185 let mut arg_count = args.len(); 189 let mut arg_count = args.len();
@@ -542,4 +546,20 @@ fn f() {
542 "#, 546 "#,
543 ) 547 )
544 } 548 }
549
550 #[test]
551 fn arg_count_lambda() {
552 check_diagnostics(
553 r#"
554fn main() {
555 let f = |()| ();
556 f();
557 //^^^ Expected 1 argument, found 0
558 f(());
559 f((), ());
560 //^^^^^^^^^ Expected 1 argument, found 2
561}
562"#,
563 )
564 }
545} 565}
diff --git a/crates/ra_hir_ty/src/lib.rs b/crates/ra_hir_ty/src/lib.rs
index 0ef5ca78f..7698cb0d4 100644
--- a/crates/ra_hir_ty/src/lib.rs
+++ b/crates/ra_hir_ty/src/lib.rs
@@ -767,15 +767,6 @@ impl Ty {
767 } 767 }
768 } 768 }
769 769
770 pub fn as_callable(&self) -> Option<(CallableDefId, &Substs)> {
771 match self {
772 Ty::Apply(ApplicationTy { ctor: TypeCtor::FnDef(callable_def), parameters }) => {
773 Some((*callable_def, parameters))
774 }
775 _ => None,
776 }
777 }
778
779 pub fn is_never(&self) -> bool { 770 pub fn is_never(&self) -> bool {
780 matches!(self, Ty::Apply(ApplicationTy { ctor: TypeCtor::Never, .. })) 771 matches!(self, Ty::Apply(ApplicationTy { ctor: TypeCtor::Never, .. }))
781 } 772 }
@@ -807,7 +798,7 @@ impl Ty {
807 } 798 }
808 } 799 }
809 800
810 fn callable_sig(&self, db: &dyn HirDatabase) -> Option<FnSig> { 801 pub fn callable_sig(&self, db: &dyn HirDatabase) -> Option<FnSig> {
811 match self { 802 match self {
812 Ty::Apply(a_ty) => match a_ty.ctor { 803 Ty::Apply(a_ty) => match a_ty.ctor {
813 TypeCtor::FnPtr { is_varargs, .. } => { 804 TypeCtor::FnPtr { is_varargs, .. } => {
diff --git a/crates/ra_ide/src/call_info.rs b/crates/ra_ide/src/call_info.rs
index 35a8a0dc5..14980afdd 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<Cal
70 variant.name(db) 70 variant.name(db)
71 ); 71 );
72 } 72 }
73 hir::CallableKind::Closure => (),
73 } 74 }
74 75
75 res.signature.push('('); 76 res.signature.push('(');
@@ -93,7 +94,7 @@ pub(crate) fn call_info(db: &RootDatabase, position: FilePosition) -> Option<Cal
93 res.signature.push(')'); 94 res.signature.push(')');
94 95
95 match callable.kind() { 96 match callable.kind() {
96 hir::CallableKind::Function(_) => { 97 hir::CallableKind::Function(_) | hir::CallableKind::Closure => {
97 let ret_type = callable.return_type(); 98 let ret_type = callable.return_type();
98 if !ret_type.is_unit() { 99 if !ret_type.is_unit() {
99 format_to!(res.signature, " -> {}", ret_type.display(db)); 100 format_to!(res.signature, " -> {}", ret_type.display(db));
@@ -702,4 +703,36 @@ id! {
702 "#]], 703 "#]],
703 ); 704 );
704 } 705 }
706
707 #[test]
708 fn call_info_for_lambdas() {
709 check(
710 r#"
711struct S;
712fn foo(s: S) -> i32 { 92 }
713fn main() {
714 (|s| foo(s))(<|>)
715}
716 "#,
717 expect![[r#"
718 (S) -> i32
719 (<S>)
720 "#]],
721 )
722 }
723
724 #[test]
725 fn call_info_for_fn_ptr() {
726 check(
727 r#"
728fn main(f: fn(i32, f64) -> char) {
729 f(0, <|>)
730}
731 "#,
732 expect![[r#"
733 (i32, f64) -> char
734 (i32, <f64>)
735 "#]],
736 )
737 }
705} 738}
diff --git a/crates/ra_ide/src/inlay_hints.rs b/crates/ra_ide/src/inlay_hints.rs
index cec3b04e8..43a5e29b5 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(
262 let param_name = param_name.trim_start_matches('_'); 262 let param_name = param_name.trim_start_matches('_');
263 let fn_name = match callable.kind() { 263 let fn_name = match callable.kind() {
264 hir::CallableKind::Function(it) => Some(it.name(sema.db).to_string()), 264 hir::CallableKind::Function(it) => Some(it.name(sema.db).to_string()),
265 hir::CallableKind::TupleStruct(_) | hir::CallableKind::TupleEnumVariant(_) => None, 265 hir::CallableKind::TupleStruct(_)
266 | hir::CallableKind::TupleEnumVariant(_)
267 | hir::CallableKind::Closure => None,
266 }; 268 };
267 if param_name.is_empty() 269 if param_name.is_empty()
268 || Some(param_name) == fn_name.as_ref().map(|s| s.trim_start_matches('_')) 270 || Some(param_name) == fn_name.as_ref().map(|s| s.trim_start_matches('_'))