diff options
-rw-r--r-- | crates/ra_hir/src/code_model.rs | 33 | ||||
-rw-r--r-- | crates/ra_hir_ty/src/diagnostics/expr.rs | 38 | ||||
-rw-r--r-- | crates/ra_hir_ty/src/lib.rs | 11 | ||||
-rw-r--r-- | crates/ra_ide/src/call_info.rs | 35 | ||||
-rw-r--r-- | crates/ra_ide/src/inlay_hints.rs | 4 |
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 { | |||
1525 | pub struct Callable { | 1529 | pub 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 | ||
1538 | impl Callable { | 1543 | impl 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#" | ||
554 | fn 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#" | ||
711 | struct S; | ||
712 | fn foo(s: S) -> i32 { 92 } | ||
713 | fn 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#" | ||
728 | fn 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('_')) |