aboutsummaryrefslogtreecommitdiff
path: root/crates/hir_ty/src/diagnostics/expr.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/hir_ty/src/diagnostics/expr.rs')
-rw-r--r--crates/hir_ty/src/diagnostics/expr.rs57
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
385pub fn record_pattern_missing_fields( 406pub 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#"
534trait Foo { fn method(&self, arg: usize) {} }
535
536fn 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#"