diff options
Diffstat (limited to 'crates/hir_ty/src/diagnostics/expr.rs')
-rw-r--r-- | crates/hir_ty/src/diagnostics/expr.rs | 57 |
1 files changed, 47 insertions, 10 deletions
diff --git a/crates/hir_ty/src/diagnostics/expr.rs b/crates/hir_ty/src/diagnostics/expr.rs index 849415706..107417c27 100644 --- a/crates/hir_ty/src/diagnostics/expr.rs +++ b/crates/hir_ty/src/diagnostics/expr.rs | |||
@@ -11,8 +11,8 @@ use crate::{ | |||
11 | db::HirDatabase, | 11 | db::HirDatabase, |
12 | diagnostics::{ | 12 | diagnostics::{ |
13 | match_check::{is_useful, MatchCheckCtx, Matrix, PatStack, Usefulness}, | 13 | match_check::{is_useful, MatchCheckCtx, Matrix, PatStack, Usefulness}, |
14 | MismatchedArgCount, MissingFields, MissingMatchArms, MissingOkInTailExpr, MissingPatFields, | 14 | MismatchedArgCount, MissingFields, MissingMatchArms, MissingOkOrSomeInTailExpr, |
15 | RemoveThisSemicolon, | 15 | MissingPatFields, RemoveThisSemicolon, |
16 | }, | 16 | }, |
17 | utils::variant_data, | 17 | utils::variant_data, |
18 | ApplicationTy, InferenceResult, Ty, TypeCtor, | 18 | ApplicationTy, InferenceResult, Ty, TypeCtor, |
@@ -156,7 +156,7 @@ impl<'a, 'b> ExprValidator<'a, 'b> { | |||
156 | // FIXME: Due to shortcomings in the current type system implementation, only emit this | 156 | // FIXME: Due to shortcomings in the current type system implementation, only emit this |
157 | // diagnostic if there are no type mismatches in the containing function. | 157 | // diagnostic if there are no type mismatches in the containing function. |
158 | if self.infer.type_mismatches.iter().next().is_some() { | 158 | if self.infer.type_mismatches.iter().next().is_some() { |
159 | return Some(()); | 159 | return None; |
160 | } | 160 | } |
161 | 161 | ||
162 | let is_method_call = matches!(expr, Expr::MethodCall { .. }); | 162 | let is_method_call = matches!(expr, Expr::MethodCall { .. }); |
@@ -170,6 +170,14 @@ impl<'a, 'b> ExprValidator<'a, 'b> { | |||
170 | let mut args = args.clone(); | 170 | let mut args = args.clone(); |
171 | args.insert(0, *receiver); | 171 | args.insert(0, *receiver); |
172 | 172 | ||
173 | let receiver = &self.infer.type_of_expr[*receiver]; | ||
174 | if receiver.strip_references().is_unknown() { | ||
175 | // if the receiver is of unknown type, it's very likely we | ||
176 | // don't know enough to correctly resolve the method call. | ||
177 | // This is kind of a band-aid for #6975. | ||
178 | return None; | ||
179 | } | ||
180 | |||
173 | // FIXME: note that we erase information about substs here. This | 181 | // FIXME: note that we erase information about substs here. This |
174 | // is not right, but, luckily, doesn't matter as we care only | 182 | // is not right, but, luckily, doesn't matter as we care only |
175 | // about the number of params | 183 | // about the number of params |
@@ -298,27 +306,40 @@ impl<'a, 'b> ExprValidator<'a, 'b> { | |||
298 | }; | 306 | }; |
299 | 307 | ||
300 | let core_result_path = path![core::result::Result]; | 308 | let core_result_path = path![core::result::Result]; |
309 | let core_option_path = path![core::option::Option]; | ||
301 | 310 | ||
302 | let resolver = self.owner.resolver(db.upcast()); | 311 | let resolver = self.owner.resolver(db.upcast()); |
303 | let core_result_enum = match resolver.resolve_known_enum(db.upcast(), &core_result_path) { | 312 | let core_result_enum = match resolver.resolve_known_enum(db.upcast(), &core_result_path) { |
304 | Some(it) => it, | 313 | Some(it) => it, |
305 | _ => return, | 314 | _ => return, |
306 | }; | 315 | }; |
316 | let core_option_enum = match resolver.resolve_known_enum(db.upcast(), &core_option_path) { | ||
317 | Some(it) => it, | ||
318 | _ => return, | ||
319 | }; | ||
307 | 320 | ||
308 | let core_result_ctor = TypeCtor::Adt(AdtId::EnumId(core_result_enum)); | 321 | let core_result_ctor = TypeCtor::Adt(AdtId::EnumId(core_result_enum)); |
309 | let params = match &mismatch.expected { | 322 | let core_option_ctor = TypeCtor::Adt(AdtId::EnumId(core_option_enum)); |
323 | |||
324 | let (params, required) = match &mismatch.expected { | ||
310 | Ty::Apply(ApplicationTy { ctor, parameters }) if ctor == &core_result_ctor => { | 325 | Ty::Apply(ApplicationTy { ctor, parameters }) if ctor == &core_result_ctor => { |
311 | parameters | 326 | (parameters, "Ok".to_string()) |
327 | } | ||
328 | Ty::Apply(ApplicationTy { ctor, parameters }) if ctor == &core_option_ctor => { | ||
329 | (parameters, "Some".to_string()) | ||
312 | } | 330 | } |
313 | _ => return, | 331 | _ => return, |
314 | }; | 332 | }; |
315 | 333 | ||
316 | if params.len() == 2 && params[0] == mismatch.actual { | 334 | if params.len() > 0 && params[0] == mismatch.actual { |
317 | let (_, source_map) = db.body_with_source_map(self.owner.into()); | 335 | let (_, source_map) = db.body_with_source_map(self.owner.into()); |
318 | 336 | ||
319 | if let Ok(source_ptr) = source_map.expr_syntax(id) { | 337 | if let Ok(source_ptr) = source_map.expr_syntax(id) { |
320 | self.sink | 338 | self.sink.push(MissingOkOrSomeInTailExpr { |
321 | .push(MissingOkInTailExpr { file: source_ptr.file_id, expr: source_ptr.value }); | 339 | file: source_ptr.file_id, |
340 | expr: source_ptr.value, | ||
341 | required, | ||
342 | }); | ||
322 | } | 343 | } |
323 | } | 344 | } |
324 | } | 345 | } |
@@ -358,7 +379,7 @@ pub fn record_literal_missing_fields( | |||
358 | id: ExprId, | 379 | id: ExprId, |
359 | expr: &Expr, | 380 | expr: &Expr, |
360 | ) -> Option<(VariantId, Vec<LocalFieldId>, /*exhaustive*/ bool)> { | 381 | ) -> Option<(VariantId, Vec<LocalFieldId>, /*exhaustive*/ bool)> { |
361 | let (fields, exhausitve) = match expr { | 382 | let (fields, exhaustive) = match expr { |
362 | Expr::RecordLit { path: _, fields, spread } => (fields, spread.is_none()), | 383 | Expr::RecordLit { path: _, fields, spread } => (fields, spread.is_none()), |
363 | _ => return None, | 384 | _ => return None, |
364 | }; | 385 | }; |
@@ -379,7 +400,7 @@ pub fn record_literal_missing_fields( | |||
379 | if missed_fields.is_empty() { | 400 | if missed_fields.is_empty() { |
380 | return None; | 401 | return None; |
381 | } | 402 | } |
382 | Some((variant_def, missed_fields, exhausitve)) | 403 | Some((variant_def, missed_fields, exhaustive)) |
383 | } | 404 | } |
384 | 405 | ||
385 | pub fn record_pattern_missing_fields( | 406 | pub fn record_pattern_missing_fields( |
@@ -505,6 +526,22 @@ fn f() { | |||
505 | } | 526 | } |
506 | 527 | ||
507 | #[test] | 528 | #[test] |
529 | fn method_unknown_receiver() { | ||
530 | // note: this is incorrect code, so there might be errors on this in the | ||
531 | // future, but we shouldn't emit an argument count diagnostic here | ||
532 | check_diagnostics( | ||
533 | r#" | ||
534 | trait Foo { fn method(&self, arg: usize) {} } | ||
535 | |||
536 | fn f() { | ||
537 | let x; | ||
538 | x.method(); | ||
539 | } | ||
540 | "#, | ||
541 | ); | ||
542 | } | ||
543 | |||
544 | #[test] | ||
508 | fn tuple_struct() { | 545 | fn tuple_struct() { |
509 | check_diagnostics( | 546 | check_diagnostics( |
510 | r#" | 547 | r#" |