diff options
author | Jonas Schievink <[email protected]> | 2020-07-08 18:58:45 +0100 |
---|---|---|
committer | Jonas Schievink <[email protected]> | 2020-07-09 11:16:29 +0100 |
commit | 63ce2c7b5fd96e6688796f2ddd1cd7316df8d11d (patch) | |
tree | 8e3ce783592c9c136efac6bbf78ffff177c077cc /crates/ra_hir_ty/src/expr.rs | |
parent | 91005ecc27427f46529b9372f91e5072dfe5e179 (diff) |
Add argument count mismatch diagnostic
Diffstat (limited to 'crates/ra_hir_ty/src/expr.rs')
-rw-r--r-- | crates/ra_hir_ty/src/expr.rs | 68 |
1 files changed, 63 insertions, 5 deletions
diff --git a/crates/ra_hir_ty/src/expr.rs b/crates/ra_hir_ty/src/expr.rs index 7db928dde..7c3cd7952 100644 --- a/crates/ra_hir_ty/src/expr.rs +++ b/crates/ra_hir_ty/src/expr.rs | |||
@@ -9,9 +9,11 @@ use rustc_hash::FxHashSet; | |||
9 | 9 | ||
10 | use crate::{ | 10 | use crate::{ |
11 | db::HirDatabase, | 11 | db::HirDatabase, |
12 | diagnostics::{MissingFields, MissingMatchArms, MissingOkInTailExpr, MissingPatFields}, | 12 | diagnostics::{ |
13 | MismatchedArgCount, MissingFields, MissingMatchArms, MissingOkInTailExpr, MissingPatFields, | ||
14 | }, | ||
13 | utils::variant_data, | 15 | utils::variant_data, |
14 | ApplicationTy, InferenceResult, Ty, TypeCtor, | 16 | ApplicationTy, CallableDef, InferenceResult, Ty, TypeCtor, |
15 | _match::{is_useful, MatchCheckCtx, Matrix, PatStack, Usefulness}, | 17 | _match::{is_useful, MatchCheckCtx, Matrix, PatStack, Usefulness}, |
16 | }; | 18 | }; |
17 | 19 | ||
@@ -24,7 +26,8 @@ pub use hir_def::{ | |||
24 | ArithOp, Array, BinaryOp, BindingAnnotation, CmpOp, Expr, ExprId, Literal, LogicOp, | 26 | ArithOp, Array, BinaryOp, BindingAnnotation, CmpOp, Expr, ExprId, Literal, LogicOp, |
25 | MatchArm, Ordering, Pat, PatId, RecordFieldPat, RecordLitField, Statement, UnaryOp, | 27 | MatchArm, Ordering, Pat, PatId, RecordFieldPat, RecordLitField, Statement, UnaryOp, |
26 | }, | 28 | }, |
27 | LocalFieldId, VariantId, | 29 | src::HasSource, |
30 | LocalFieldId, Lookup, VariantId, | ||
28 | }; | 31 | }; |
29 | 32 | ||
30 | pub struct ExprValidator<'a, 'b: 'a> { | 33 | pub struct ExprValidator<'a, 'b: 'a> { |
@@ -56,8 +59,15 @@ impl<'a, 'b> ExprValidator<'a, 'b> { | |||
56 | missed_fields, | 59 | missed_fields, |
57 | ); | 60 | ); |
58 | } | 61 | } |
59 | if let Expr::Match { expr, arms } = expr { | 62 | |
60 | self.validate_match(id, *expr, arms, db, self.infer.clone()); | 63 | match expr { |
64 | Expr::Match { expr, arms } => { | ||
65 | self.validate_match(id, *expr, arms, db, self.infer.clone()); | ||
66 | } | ||
67 | Expr::Call { .. } | Expr::MethodCall { .. } => { | ||
68 | self.validate_call(db, id, expr); | ||
69 | } | ||
70 | _ => {} | ||
61 | } | 71 | } |
62 | } | 72 | } |
63 | for (id, pat) in body.pats.iter() { | 73 | for (id, pat) in body.pats.iter() { |
@@ -138,6 +148,54 @@ impl<'a, 'b> ExprValidator<'a, 'b> { | |||
138 | } | 148 | } |
139 | } | 149 | } |
140 | 150 | ||
151 | fn validate_call(&mut self, db: &dyn HirDatabase, call_id: ExprId, expr: &Expr) -> Option<()> { | ||
152 | // Check that the number of arguments matches the number of parameters. | ||
153 | let (callee, args) = match expr { | ||
154 | Expr::Call { callee, args } => { | ||
155 | let callee = &self.infer.type_of_expr[*callee]; | ||
156 | let (callable, _) = callee.as_callable()?; | ||
157 | let callee = match callable { | ||
158 | CallableDef::FunctionId(func) => func, | ||
159 | _ => return None, | ||
160 | }; | ||
161 | |||
162 | (callee, args.clone()) | ||
163 | } | ||
164 | Expr::MethodCall { receiver, args, .. } => { | ||
165 | let callee = self.infer.method_resolution(call_id)?; | ||
166 | let mut args = args.clone(); | ||
167 | args.insert(0, *receiver); | ||
168 | (callee, args) | ||
169 | } | ||
170 | _ => return None, | ||
171 | }; | ||
172 | |||
173 | let loc = callee.lookup(db.upcast()); | ||
174 | let ast = loc.source(db.upcast()); | ||
175 | let params = ast.value.param_list()?; | ||
176 | |||
177 | let mut param_count = params.params().count(); | ||
178 | if params.self_param().is_some() { | ||
179 | param_count += 1; | ||
180 | } | ||
181 | let arg_count = args.len(); | ||
182 | |||
183 | if arg_count != param_count { | ||
184 | let (_, source_map): (Arc<Body>, Arc<BodySourceMap>) = | ||
185 | db.body_with_source_map(self.func.into()); | ||
186 | if let Ok(source_ptr) = source_map.expr_syntax(call_id) { | ||
187 | self.sink.push(MismatchedArgCount { | ||
188 | file: source_ptr.file_id, | ||
189 | call_expr: source_ptr.value, | ||
190 | expected: param_count, | ||
191 | found: arg_count, | ||
192 | }); | ||
193 | } | ||
194 | } | ||
195 | |||
196 | None | ||
197 | } | ||
198 | |||
141 | fn validate_match( | 199 | fn validate_match( |
142 | &mut self, | 200 | &mut self, |
143 | id: ExprId, | 201 | id: ExprId, |