diff options
Diffstat (limited to 'crates/hir_ty/src/diagnostics')
-rw-r--r-- | crates/hir_ty/src/diagnostics/decl_check.rs | 5 | ||||
-rw-r--r-- | crates/hir_ty/src/diagnostics/expr.rs | 24 | ||||
-rw-r--r-- | crates/hir_ty/src/diagnostics/match_check.rs | 49 | ||||
-rw-r--r-- | crates/hir_ty/src/diagnostics/unsafe_check.rs | 12 |
4 files changed, 43 insertions, 47 deletions
diff --git a/crates/hir_ty/src/diagnostics/decl_check.rs b/crates/hir_ty/src/diagnostics/decl_check.rs index 33a0f4d7d..1c9f9ede7 100644 --- a/crates/hir_ty/src/diagnostics/decl_check.rs +++ b/crates/hir_ty/src/diagnostics/decl_check.rs | |||
@@ -91,7 +91,7 @@ impl<'a, 'b> DeclValidator<'a, 'b> { | |||
91 | 91 | ||
92 | fn validate_func(&mut self, func: FunctionId) { | 92 | fn validate_func(&mut self, func: FunctionId) { |
93 | let data = self.db.function_data(func); | 93 | let data = self.db.function_data(func); |
94 | if data.is_in_extern_block { | 94 | if data.is_in_extern_block() { |
95 | cov_mark::hit!(extern_func_incorrect_case_ignored); | 95 | cov_mark::hit!(extern_func_incorrect_case_ignored); |
96 | return; | 96 | return; |
97 | } | 97 | } |
@@ -99,8 +99,7 @@ impl<'a, 'b> DeclValidator<'a, 'b> { | |||
99 | let body = self.db.body(func.into()); | 99 | let body = self.db.body(func.into()); |
100 | 100 | ||
101 | // Recursively validate inner scope items, such as static variables and constants. | 101 | // Recursively validate inner scope items, such as static variables and constants. |
102 | let db = self.db; | 102 | for (_, block_def_map) in body.blocks(self.db.upcast()) { |
103 | for block_def_map in body.block_scopes.iter().filter_map(|block| db.block_def_map(*block)) { | ||
104 | for (_, module) in block_def_map.modules() { | 103 | for (_, module) in block_def_map.modules() { |
105 | for def_id in module.scope.declarations() { | 104 | for def_id in module.scope.declarations() { |
106 | let mut validator = DeclValidator::new(self.db, self.krate, self.sink); | 105 | let mut validator = DeclValidator::new(self.db, self.krate, self.sink); |
diff --git a/crates/hir_ty/src/diagnostics/expr.rs b/crates/hir_ty/src/diagnostics/expr.rs index 3909ad354..79602c3dd 100644 --- a/crates/hir_ty/src/diagnostics/expr.rs +++ b/crates/hir_ty/src/diagnostics/expr.rs | |||
@@ -14,8 +14,7 @@ use crate::{ | |||
14 | MismatchedArgCount, MissingFields, MissingMatchArms, MissingOkOrSomeInTailExpr, | 14 | MismatchedArgCount, MissingFields, MissingMatchArms, MissingOkOrSomeInTailExpr, |
15 | MissingPatFields, RemoveThisSemicolon, | 15 | MissingPatFields, RemoveThisSemicolon, |
16 | }, | 16 | }, |
17 | utils::variant_data, | 17 | AdtId, InferenceResult, Interner, TyExt, TyKind, |
18 | AdtId, InferenceResult, Interner, Ty, TyKind, | ||
19 | }; | 18 | }; |
20 | 19 | ||
21 | pub(crate) use hir_def::{ | 20 | pub(crate) use hir_def::{ |
@@ -104,7 +103,7 @@ impl<'a, 'b> ExprValidator<'a, 'b> { | |||
104 | let root = source_ptr.file_syntax(db.upcast()); | 103 | let root = source_ptr.file_syntax(db.upcast()); |
105 | if let ast::Expr::RecordExpr(record_expr) = &source_ptr.value.to_node(&root) { | 104 | if let ast::Expr::RecordExpr(record_expr) = &source_ptr.value.to_node(&root) { |
106 | if let Some(_) = record_expr.record_expr_field_list() { | 105 | if let Some(_) = record_expr.record_expr_field_list() { |
107 | let variant_data = variant_data(db.upcast(), variant_def); | 106 | let variant_data = variant_def.variant_data(db.upcast()); |
108 | let missed_fields = missed_fields | 107 | let missed_fields = missed_fields |
109 | .into_iter() | 108 | .into_iter() |
110 | .map(|idx| variant_data.fields()[idx].name.clone()) | 109 | .map(|idx| variant_data.fields()[idx].name.clone()) |
@@ -135,7 +134,7 @@ impl<'a, 'b> ExprValidator<'a, 'b> { | |||
135 | let root = source_ptr.file_syntax(db.upcast()); | 134 | let root = source_ptr.file_syntax(db.upcast()); |
136 | if let ast::Pat::RecordPat(record_pat) = expr.to_node(&root) { | 135 | if let ast::Pat::RecordPat(record_pat) = expr.to_node(&root) { |
137 | if let Some(_) = record_pat.record_pat_field_list() { | 136 | if let Some(_) = record_pat.record_pat_field_list() { |
138 | let variant_data = variant_data(db.upcast(), variant_def); | 137 | let variant_data = variant_def.variant_data(db.upcast()); |
139 | let missed_fields = missed_fields | 138 | let missed_fields = missed_fields |
140 | .into_iter() | 139 | .into_iter() |
141 | .map(|idx| variant_data.fields()[idx].name.clone()) | 140 | .map(|idx| variant_data.fields()[idx].name.clone()) |
@@ -245,7 +244,8 @@ impl<'a, 'b> ExprValidator<'a, 'b> { | |||
245 | Some(callee) => callee, | 244 | Some(callee) => callee, |
246 | None => return, | 245 | None => return, |
247 | }; | 246 | }; |
248 | let sig = db.callable_item_signature(callee.into()).value; | 247 | let sig = |
248 | db.callable_item_signature(callee.into()).into_value_and_skipped_binders().0; | ||
249 | 249 | ||
250 | (sig, args) | 250 | (sig, args) |
251 | } | 251 | } |
@@ -314,7 +314,7 @@ impl<'a, 'b> ExprValidator<'a, 'b> { | |||
314 | if pat_ty == match_expr_ty | 314 | if pat_ty == match_expr_ty |
315 | || match_expr_ty | 315 | || match_expr_ty |
316 | .as_reference() | 316 | .as_reference() |
317 | .map(|(match_expr_ty, _)| match_expr_ty == pat_ty) | 317 | .map(|(match_expr_ty, ..)| match_expr_ty == pat_ty) |
318 | .unwrap_or(false) | 318 | .unwrap_or(false) |
319 | { | 319 | { |
320 | // If we had a NotUsefulMatchArm diagnostic, we could | 320 | // If we had a NotUsefulMatchArm diagnostic, we could |
@@ -378,7 +378,7 @@ impl<'a, 'b> ExprValidator<'a, 'b> { | |||
378 | _ => return, | 378 | _ => return, |
379 | }; | 379 | }; |
380 | 380 | ||
381 | let (params, required) = match mismatch.expected.interned(&Interner) { | 381 | let (params, required) = match mismatch.expected.kind(&Interner) { |
382 | TyKind::Adt(AdtId(hir_def::AdtId::EnumId(enum_id)), ref parameters) | 382 | TyKind::Adt(AdtId(hir_def::AdtId::EnumId(enum_id)), ref parameters) |
383 | if *enum_id == core_result_enum => | 383 | if *enum_id == core_result_enum => |
384 | { | 384 | { |
@@ -392,7 +392,9 @@ impl<'a, 'b> ExprValidator<'a, 'b> { | |||
392 | _ => return, | 392 | _ => return, |
393 | }; | 393 | }; |
394 | 394 | ||
395 | if params.len() > 0 && params[0] == mismatch.actual { | 395 | if params.len(&Interner) > 0 |
396 | && params.at(&Interner, 0).ty(&Interner) == Some(&mismatch.actual) | ||
397 | { | ||
396 | let (_, source_map) = db.body_with_source_map(self.owner); | 398 | let (_, source_map) = db.body_with_source_map(self.owner); |
397 | 399 | ||
398 | if let Ok(source_ptr) = source_map.expr_syntax(id) { | 400 | if let Ok(source_ptr) = source_map.expr_syntax(id) { |
@@ -421,7 +423,7 @@ impl<'a, 'b> ExprValidator<'a, 'b> { | |||
421 | None => return, | 423 | None => return, |
422 | }; | 424 | }; |
423 | 425 | ||
424 | if mismatch.actual != Ty::unit() || mismatch.expected != *possible_tail_ty { | 426 | if !mismatch.actual.is_unit() || mismatch.expected != *possible_tail_ty { |
425 | return; | 427 | return; |
426 | } | 428 | } |
427 | 429 | ||
@@ -450,7 +452,7 @@ pub fn record_literal_missing_fields( | |||
450 | return None; | 452 | return None; |
451 | } | 453 | } |
452 | 454 | ||
453 | let variant_data = variant_data(db.upcast(), variant_def); | 455 | let variant_data = variant_def.variant_data(db.upcast()); |
454 | 456 | ||
455 | let specified_fields: FxHashSet<_> = fields.iter().map(|f| &f.name).collect(); | 457 | let specified_fields: FxHashSet<_> = fields.iter().map(|f| &f.name).collect(); |
456 | let missed_fields: Vec<LocalFieldId> = variant_data | 458 | let missed_fields: Vec<LocalFieldId> = variant_data |
@@ -480,7 +482,7 @@ pub fn record_pattern_missing_fields( | |||
480 | return None; | 482 | return None; |
481 | } | 483 | } |
482 | 484 | ||
483 | let variant_data = variant_data(db.upcast(), variant_def); | 485 | let variant_data = variant_def.variant_data(db.upcast()); |
484 | 486 | ||
485 | let specified_fields: FxHashSet<_> = fields.iter().map(|f| &f.name).collect(); | 487 | let specified_fields: FxHashSet<_> = fields.iter().map(|f| &f.name).collect(); |
486 | let missed_fields: Vec<LocalFieldId> = variant_data | 488 | let missed_fields: Vec<LocalFieldId> = variant_data |
diff --git a/crates/hir_ty/src/diagnostics/match_check.rs b/crates/hir_ty/src/diagnostics/match_check.rs index 5a5cdcbf3..e9762622f 100644 --- a/crates/hir_ty/src/diagnostics/match_check.rs +++ b/crates/hir_ty/src/diagnostics/match_check.rs | |||
@@ -227,7 +227,7 @@ use hir_def::{ | |||
227 | use la_arena::Idx; | 227 | use la_arena::Idx; |
228 | use smallvec::{smallvec, SmallVec}; | 228 | use smallvec::{smallvec, SmallVec}; |
229 | 229 | ||
230 | use crate::{db::HirDatabase, AdtId, InferenceResult, Interner, TyKind}; | 230 | use crate::{db::HirDatabase, AdtId, InferenceResult, Interner, TyExt, TyKind}; |
231 | 231 | ||
232 | #[derive(Debug, Clone, Copy)] | 232 | #[derive(Debug, Clone, Copy)] |
233 | /// Either a pattern from the source code being analyzed, represented as | 233 | /// Either a pattern from the source code being analyzed, represented as |
@@ -539,7 +539,7 @@ impl Matrix { | |||
539 | if let Some(Pat::Or(pat_ids)) = row.get_head().map(|pat_id| pat_id.as_pat(cx)) { | 539 | if let Some(Pat::Or(pat_ids)) = row.get_head().map(|pat_id| pat_id.as_pat(cx)) { |
540 | // Or patterns are expanded here | 540 | // Or patterns are expanded here |
541 | for pat_id in pat_ids { | 541 | for pat_id in pat_ids { |
542 | self.0.push(PatStack::from_pattern(pat_id)); | 542 | self.0.push(row.replace_head_with([pat_id].iter())); |
543 | } | 543 | } |
544 | } else { | 544 | } else { |
545 | self.0.push(row); | 545 | self.0.push(row); |
@@ -626,7 +626,7 @@ pub(super) fn is_useful( | |||
626 | // - enum with no variants | 626 | // - enum with no variants |
627 | // - `!` type | 627 | // - `!` type |
628 | // In those cases, no match arm is useful. | 628 | // In those cases, no match arm is useful. |
629 | match cx.infer[cx.match_expr].strip_references().interned(&Interner) { | 629 | match cx.infer[cx.match_expr].strip_references().kind(&Interner) { |
630 | TyKind::Adt(AdtId(hir_def::AdtId::EnumId(enum_id)), ..) => { | 630 | TyKind::Adt(AdtId(hir_def::AdtId::EnumId(enum_id)), ..) => { |
631 | if cx.db.enum_data(*enum_id).variants.is_empty() { | 631 | if cx.db.enum_data(*enum_id).variants.is_empty() { |
632 | return Ok(Usefulness::NotUseful); | 632 | return Ok(Usefulness::NotUseful); |
@@ -792,7 +792,10 @@ fn pat_constructor(cx: &MatchCheckCtx, pat: PatIdOrWild) -> MatchCheckResult<Opt | |||
792 | Pat::Tuple { .. } => { | 792 | Pat::Tuple { .. } => { |
793 | let pat_id = pat.as_id().expect("we already know this pattern is not a wild"); | 793 | let pat_id = pat.as_id().expect("we already know this pattern is not a wild"); |
794 | Some(Constructor::Tuple { | 794 | Some(Constructor::Tuple { |
795 | arity: cx.infer.type_of_pat[pat_id].as_tuple().ok_or(MatchCheckErr::Unknown)?.len(), | 795 | arity: cx.infer.type_of_pat[pat_id] |
796 | .as_tuple() | ||
797 | .ok_or(MatchCheckErr::Unknown)? | ||
798 | .len(&Interner), | ||
796 | }) | 799 | }) |
797 | } | 800 | } |
798 | Pat::Lit(lit_expr) => match cx.body.exprs[lit_expr] { | 801 | Pat::Lit(lit_expr) => match cx.body.exprs[lit_expr] { |
@@ -1085,6 +1088,20 @@ fn main() { | |||
1085 | } | 1088 | } |
1086 | 1089 | ||
1087 | #[test] | 1090 | #[test] |
1091 | fn or_pattern_no_diagnostic() { | ||
1092 | check_diagnostics( | ||
1093 | r#" | ||
1094 | enum Either {A, B} | ||
1095 | |||
1096 | fn main() { | ||
1097 | match (Either::A, Either::B) { | ||
1098 | (Either::A | Either::B, _) => (), | ||
1099 | } | ||
1100 | }"#, | ||
1101 | ) | ||
1102 | } | ||
1103 | |||
1104 | #[test] | ||
1088 | fn mismatched_types() { | 1105 | fn mismatched_types() { |
1089 | // Match statements with arms that don't match the | 1106 | // Match statements with arms that don't match the |
1090 | // expression pattern do not fire this diagnostic. | 1107 | // expression pattern do not fire this diagnostic. |
@@ -1336,30 +1353,6 @@ fn bang(never: !) { | |||
1336 | } | 1353 | } |
1337 | 1354 | ||
1338 | #[test] | 1355 | #[test] |
1339 | fn or_pattern_panic() { | ||
1340 | check_diagnostics( | ||
1341 | r#" | ||
1342 | pub enum Category { Infinity, Zero } | ||
1343 | |||
1344 | fn panic(a: Category, b: Category) { | ||
1345 | match (a, b) { | ||
1346 | (Category::Zero | Category::Infinity, _) => (), | ||
1347 | (_, Category::Zero | Category::Infinity) => (), | ||
1348 | } | ||
1349 | |||
1350 | // FIXME: This is a false positive, but the code used to cause a panic in the match checker, | ||
1351 | // so this acts as a regression test for that. | ||
1352 | match (a, b) { | ||
1353 | //^^^^^^ Missing match arm | ||
1354 | (Category::Infinity, Category::Infinity) | (Category::Zero, Category::Zero) => (), | ||
1355 | (Category::Infinity | Category::Zero, _) => (), | ||
1356 | } | ||
1357 | } | ||
1358 | "#, | ||
1359 | ); | ||
1360 | } | ||
1361 | |||
1362 | #[test] | ||
1363 | fn unknown_type() { | 1356 | fn unknown_type() { |
1364 | check_diagnostics( | 1357 | check_diagnostics( |
1365 | r#" | 1358 | r#" |
diff --git a/crates/hir_ty/src/diagnostics/unsafe_check.rs b/crates/hir_ty/src/diagnostics/unsafe_check.rs index 1f49a4909..ed97dc0e3 100644 --- a/crates/hir_ty/src/diagnostics/unsafe_check.rs +++ b/crates/hir_ty/src/diagnostics/unsafe_check.rs | |||
@@ -11,7 +11,9 @@ use hir_def::{ | |||
11 | }; | 11 | }; |
12 | use hir_expand::diagnostics::DiagnosticSink; | 12 | use hir_expand::diagnostics::DiagnosticSink; |
13 | 13 | ||
14 | use crate::{db::HirDatabase, diagnostics::MissingUnsafe, InferenceResult, Interner, TyKind}; | 14 | use crate::{ |
15 | db::HirDatabase, diagnostics::MissingUnsafe, InferenceResult, Interner, TyExt, TyKind, | ||
16 | }; | ||
15 | 17 | ||
16 | pub(super) struct UnsafeValidator<'a, 'b: 'a> { | 18 | pub(super) struct UnsafeValidator<'a, 'b: 'a> { |
17 | owner: DefWithBodyId, | 19 | owner: DefWithBodyId, |
@@ -32,7 +34,7 @@ impl<'a, 'b> UnsafeValidator<'a, 'b> { | |||
32 | let def = self.owner; | 34 | let def = self.owner; |
33 | let unsafe_expressions = unsafe_expressions(db, self.infer.as_ref(), def); | 35 | let unsafe_expressions = unsafe_expressions(db, self.infer.as_ref(), def); |
34 | let is_unsafe = match self.owner { | 36 | let is_unsafe = match self.owner { |
35 | DefWithBodyId::FunctionId(it) => db.function_data(it).qualifier.is_unsafe, | 37 | DefWithBodyId::FunctionId(it) => db.function_data(it).is_unsafe(), |
36 | DefWithBodyId::StaticId(_) | DefWithBodyId::ConstId(_) => false, | 38 | DefWithBodyId::StaticId(_) | DefWithBodyId::ConstId(_) => false, |
37 | }; | 39 | }; |
38 | if is_unsafe | 40 | if is_unsafe |
@@ -86,7 +88,7 @@ fn walk_unsafe( | |||
86 | match expr { | 88 | match expr { |
87 | &Expr::Call { callee, .. } => { | 89 | &Expr::Call { callee, .. } => { |
88 | if let Some(func) = infer[callee].as_fn_def(db) { | 90 | if let Some(func) = infer[callee].as_fn_def(db) { |
89 | if db.function_data(func).qualifier.is_unsafe { | 91 | if db.function_data(func).is_unsafe() { |
90 | unsafe_exprs.push(UnsafeExpr { expr: current, inside_unsafe_block }); | 92 | unsafe_exprs.push(UnsafeExpr { expr: current, inside_unsafe_block }); |
91 | } | 93 | } |
92 | } | 94 | } |
@@ -103,14 +105,14 @@ fn walk_unsafe( | |||
103 | Expr::MethodCall { .. } => { | 105 | Expr::MethodCall { .. } => { |
104 | if infer | 106 | if infer |
105 | .method_resolution(current) | 107 | .method_resolution(current) |
106 | .map(|func| db.function_data(func).qualifier.is_unsafe) | 108 | .map(|func| db.function_data(func).is_unsafe()) |
107 | .unwrap_or(false) | 109 | .unwrap_or(false) |
108 | { | 110 | { |
109 | unsafe_exprs.push(UnsafeExpr { expr: current, inside_unsafe_block }); | 111 | unsafe_exprs.push(UnsafeExpr { expr: current, inside_unsafe_block }); |
110 | } | 112 | } |
111 | } | 113 | } |
112 | Expr::UnaryOp { expr, op: UnaryOp::Deref } => { | 114 | Expr::UnaryOp { expr, op: UnaryOp::Deref } => { |
113 | if let TyKind::Raw(..) = &infer[*expr].interned(&Interner) { | 115 | if let TyKind::Raw(..) = &infer[*expr].kind(&Interner) { |
114 | unsafe_exprs.push(UnsafeExpr { expr: current, inside_unsafe_block }); | 116 | unsafe_exprs.push(UnsafeExpr { expr: current, inside_unsafe_block }); |
115 | } | 117 | } |
116 | } | 118 | } |