diff options
Diffstat (limited to 'crates/hir_ty/src/diagnostics')
-rw-r--r-- | crates/hir_ty/src/diagnostics/decl_check.rs | 174 | ||||
-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, 190 insertions, 69 deletions
diff --git a/crates/hir_ty/src/diagnostics/decl_check.rs b/crates/hir_ty/src/diagnostics/decl_check.rs index 33a0f4d7d..075dc4131 100644 --- a/crates/hir_ty/src/diagnostics/decl_check.rs +++ b/crates/hir_ty/src/diagnostics/decl_check.rs | |||
@@ -35,6 +35,8 @@ use crate::{ | |||
35 | }; | 35 | }; |
36 | 36 | ||
37 | mod allow { | 37 | mod allow { |
38 | pub(super) const BAD_STYLE: &str = "bad_style"; | ||
39 | pub(super) const NONSTANDARD_STYLE: &str = "nonstandard_style"; | ||
38 | pub(super) const NON_SNAKE_CASE: &str = "non_snake_case"; | 40 | pub(super) const NON_SNAKE_CASE: &str = "non_snake_case"; |
39 | pub(super) const NON_UPPER_CASE_GLOBAL: &str = "non_upper_case_globals"; | 41 | pub(super) const NON_UPPER_CASE_GLOBAL: &str = "non_upper_case_globals"; |
40 | pub(super) const NON_CAMEL_CASE_TYPES: &str = "non_camel_case_types"; | 42 | pub(super) const NON_CAMEL_CASE_TYPES: &str = "non_camel_case_types"; |
@@ -83,15 +85,44 @@ impl<'a, 'b> DeclValidator<'a, 'b> { | |||
83 | } | 85 | } |
84 | 86 | ||
85 | /// Checks whether not following the convention is allowed for this item. | 87 | /// Checks whether not following the convention is allowed for this item. |
86 | /// | 88 | fn allowed(&self, id: AttrDefId, allow_name: &str, recursing: bool) -> bool { |
87 | /// Currently this method doesn't check parent attributes. | 89 | let is_allowed = |def_id| { |
88 | fn allowed(&self, id: AttrDefId, allow_name: &str) -> bool { | 90 | let attrs = self.db.attrs(def_id); |
89 | self.db.attrs(id).by_key("allow").tt_values().any(|tt| tt.to_string().contains(allow_name)) | 91 | // don't bug the user about directly no_mangle annotated stuff, they can't do anything about it |
92 | (!recursing && attrs.by_key("no_mangle").exists()) | ||
93 | || attrs.by_key("allow").tt_values().any(|tt| { | ||
94 | let allows = tt.to_string(); | ||
95 | allows.contains(allow_name) | ||
96 | || allows.contains(allow::BAD_STYLE) | ||
97 | || allows.contains(allow::NONSTANDARD_STYLE) | ||
98 | }) | ||
99 | }; | ||
100 | |||
101 | is_allowed(id) | ||
102 | // go upwards one step or give up | ||
103 | || match id { | ||
104 | AttrDefId::ModuleId(m) => m.containing_module(self.db.upcast()).map(|v| v.into()), | ||
105 | AttrDefId::FunctionId(f) => Some(f.lookup(self.db.upcast()).container.into()), | ||
106 | AttrDefId::StaticId(sid) => Some(sid.lookup(self.db.upcast()).container.into()), | ||
107 | AttrDefId::ConstId(cid) => Some(cid.lookup(self.db.upcast()).container.into()), | ||
108 | AttrDefId::TraitId(tid) => Some(tid.lookup(self.db.upcast()).container.into()), | ||
109 | AttrDefId::ImplId(iid) => Some(iid.lookup(self.db.upcast()).container.into()), | ||
110 | // These warnings should not explore macro definitions at all | ||
111 | AttrDefId::MacroDefId(_) => None, | ||
112 | // Will never occur under an enum/struct/union/type alias | ||
113 | AttrDefId::AdtId(_) => None, | ||
114 | AttrDefId::FieldId(_) => None, | ||
115 | AttrDefId::EnumVariantId(_) => None, | ||
116 | AttrDefId::TypeAliasId(_) => None, | ||
117 | AttrDefId::GenericParamId(_) => None, | ||
118 | } | ||
119 | .map(|mid| self.allowed(mid, allow_name, true)) | ||
120 | .unwrap_or(false) | ||
90 | } | 121 | } |
91 | 122 | ||
92 | fn validate_func(&mut self, func: FunctionId) { | 123 | fn validate_func(&mut self, func: FunctionId) { |
93 | let data = self.db.function_data(func); | 124 | let data = self.db.function_data(func); |
94 | if data.is_in_extern_block { | 125 | if data.is_in_extern_block() { |
95 | cov_mark::hit!(extern_func_incorrect_case_ignored); | 126 | cov_mark::hit!(extern_func_incorrect_case_ignored); |
96 | return; | 127 | return; |
97 | } | 128 | } |
@@ -99,8 +130,7 @@ impl<'a, 'b> DeclValidator<'a, 'b> { | |||
99 | let body = self.db.body(func.into()); | 130 | let body = self.db.body(func.into()); |
100 | 131 | ||
101 | // Recursively validate inner scope items, such as static variables and constants. | 132 | // Recursively validate inner scope items, such as static variables and constants. |
102 | let db = self.db; | 133 | 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() { | 134 | for (_, module) in block_def_map.modules() { |
105 | for def_id in module.scope.declarations() { | 135 | for def_id in module.scope.declarations() { |
106 | let mut validator = DeclValidator::new(self.db, self.krate, self.sink); | 136 | let mut validator = DeclValidator::new(self.db, self.krate, self.sink); |
@@ -110,7 +140,7 @@ impl<'a, 'b> DeclValidator<'a, 'b> { | |||
110 | } | 140 | } |
111 | 141 | ||
112 | // Check whether non-snake case identifiers are allowed for this function. | 142 | // Check whether non-snake case identifiers are allowed for this function. |
113 | if self.allowed(func.into(), allow::NON_SNAKE_CASE) { | 143 | if self.allowed(func.into(), allow::NON_SNAKE_CASE, false) { |
114 | return; | 144 | return; |
115 | } | 145 | } |
116 | 146 | ||
@@ -329,8 +359,9 @@ impl<'a, 'b> DeclValidator<'a, 'b> { | |||
329 | fn validate_struct(&mut self, struct_id: StructId) { | 359 | fn validate_struct(&mut self, struct_id: StructId) { |
330 | let data = self.db.struct_data(struct_id); | 360 | let data = self.db.struct_data(struct_id); |
331 | 361 | ||
332 | let non_camel_case_allowed = self.allowed(struct_id.into(), allow::NON_CAMEL_CASE_TYPES); | 362 | let non_camel_case_allowed = |
333 | let non_snake_case_allowed = self.allowed(struct_id.into(), allow::NON_SNAKE_CASE); | 363 | self.allowed(struct_id.into(), allow::NON_CAMEL_CASE_TYPES, false); |
364 | let non_snake_case_allowed = self.allowed(struct_id.into(), allow::NON_SNAKE_CASE, false); | ||
334 | 365 | ||
335 | // Check the structure name. | 366 | // Check the structure name. |
336 | let struct_name = data.name.to_string(); | 367 | let struct_name = data.name.to_string(); |
@@ -462,7 +493,7 @@ impl<'a, 'b> DeclValidator<'a, 'b> { | |||
462 | let data = self.db.enum_data(enum_id); | 493 | let data = self.db.enum_data(enum_id); |
463 | 494 | ||
464 | // Check whether non-camel case names are allowed for this enum. | 495 | // Check whether non-camel case names are allowed for this enum. |
465 | if self.allowed(enum_id.into(), allow::NON_CAMEL_CASE_TYPES) { | 496 | if self.allowed(enum_id.into(), allow::NON_CAMEL_CASE_TYPES, false) { |
466 | return; | 497 | return; |
467 | } | 498 | } |
468 | 499 | ||
@@ -585,7 +616,7 @@ impl<'a, 'b> DeclValidator<'a, 'b> { | |||
585 | fn validate_const(&mut self, const_id: ConstId) { | 616 | fn validate_const(&mut self, const_id: ConstId) { |
586 | let data = self.db.const_data(const_id); | 617 | let data = self.db.const_data(const_id); |
587 | 618 | ||
588 | if self.allowed(const_id.into(), allow::NON_UPPER_CASE_GLOBAL) { | 619 | if self.allowed(const_id.into(), allow::NON_UPPER_CASE_GLOBAL, false) { |
589 | return; | 620 | return; |
590 | } | 621 | } |
591 | 622 | ||
@@ -633,7 +664,7 @@ impl<'a, 'b> DeclValidator<'a, 'b> { | |||
633 | return; | 664 | return; |
634 | } | 665 | } |
635 | 666 | ||
636 | if self.allowed(static_id.into(), allow::NON_UPPER_CASE_GLOBAL) { | 667 | if self.allowed(static_id.into(), allow::NON_UPPER_CASE_GLOBAL, false) { |
637 | return; | 668 | return; |
638 | } | 669 | } |
639 | 670 | ||
@@ -868,23 +899,116 @@ fn main() { | |||
868 | fn allow_attributes() { | 899 | fn allow_attributes() { |
869 | check_diagnostics( | 900 | check_diagnostics( |
870 | r#" | 901 | r#" |
871 | #[allow(non_snake_case)] | 902 | #[allow(non_snake_case)] |
872 | fn NonSnakeCaseName(SOME_VAR: u8) -> u8{ | 903 | fn NonSnakeCaseName(SOME_VAR: u8) -> u8{ |
873 | let OtherVar = SOME_VAR + 1; | 904 | // cov_flags generated output from elsewhere in this file |
874 | OtherVar | 905 | extern "C" { |
906 | #[no_mangle] | ||
907 | static lower_case: u8; | ||
875 | } | 908 | } |
876 | 909 | ||
877 | #[allow(non_snake_case, non_camel_case_types)] | 910 | let OtherVar = SOME_VAR + 1; |
878 | pub struct some_type { | 911 | OtherVar |
879 | SOME_FIELD: u8, | 912 | } |
880 | SomeField: u16, | 913 | |
914 | #[allow(nonstandard_style)] | ||
915 | mod CheckNonstandardStyle { | ||
916 | fn HiImABadFnName() {} | ||
917 | } | ||
918 | |||
919 | #[allow(bad_style)] | ||
920 | mod CheckBadStyle { | ||
921 | fn HiImABadFnName() {} | ||
922 | } | ||
923 | |||
924 | mod F { | ||
925 | #![allow(non_snake_case)] | ||
926 | fn CheckItWorksWithModAttr(BAD_NAME_HI: u8) {} | ||
927 | } | ||
928 | |||
929 | #[allow(non_snake_case, non_camel_case_types)] | ||
930 | pub struct some_type { | ||
931 | SOME_FIELD: u8, | ||
932 | SomeField: u16, | ||
933 | } | ||
934 | |||
935 | #[allow(non_upper_case_globals)] | ||
936 | pub const some_const: u8 = 10; | ||
937 | |||
938 | #[allow(non_upper_case_globals)] | ||
939 | pub static SomeStatic: u8 = 10; | ||
940 | "#, | ||
941 | ); | ||
881 | } | 942 | } |
882 | 943 | ||
883 | #[allow(non_upper_case_globals)] | 944 | #[test] |
884 | pub const some_const: u8 = 10; | 945 | fn allow_attributes_crate_attr() { |
946 | check_diagnostics( | ||
947 | r#" | ||
948 | #![allow(non_snake_case)] | ||
885 | 949 | ||
886 | #[allow(non_upper_case_globals)] | 950 | mod F { |
887 | pub static SomeStatic: u8 = 10; | 951 | fn CheckItWorksWithCrateAttr(BAD_NAME_HI: u8) {} |
952 | } | ||
953 | "#, | ||
954 | ); | ||
955 | } | ||
956 | |||
957 | #[test] | ||
958 | #[ignore] | ||
959 | fn bug_trait_inside_fn() { | ||
960 | // FIXME: | ||
961 | // This is broken, and in fact, should not even be looked at by this | ||
962 | // lint in the first place. There's weird stuff going on in the | ||
963 | // collection phase. | ||
964 | // It's currently being brought in by: | ||
965 | // * validate_func on `a` recursing into modules | ||
966 | // * then it finds the trait and then the function while iterating | ||
967 | // through modules | ||
968 | // * then validate_func is called on Dirty | ||
969 | // * ... which then proceeds to look at some unknown module taking no | ||
970 | // attrs from either the impl or the fn a, and then finally to the root | ||
971 | // module | ||
972 | // | ||
973 | // It should find the attribute on the trait, but it *doesn't even see | ||
974 | // the trait* as far as I can tell. | ||
975 | |||
976 | check_diagnostics( | ||
977 | r#" | ||
978 | trait T { fn a(); } | ||
979 | struct U {} | ||
980 | impl T for U { | ||
981 | fn a() { | ||
982 | // this comes out of bitflags, mostly | ||
983 | #[allow(non_snake_case)] | ||
984 | trait __BitFlags { | ||
985 | const HiImAlsoBad: u8 = 2; | ||
986 | #[inline] | ||
987 | fn Dirty(&self) -> bool { | ||
988 | false | ||
989 | } | ||
990 | } | ||
991 | |||
992 | } | ||
993 | } | ||
994 | "#, | ||
995 | ); | ||
996 | } | ||
997 | |||
998 | #[test] | ||
999 | #[ignore] | ||
1000 | fn bug_traits_arent_checked() { | ||
1001 | // FIXME: Traits and functions in traits aren't currently checked by | ||
1002 | // r-a, even though rustc will complain about them. | ||
1003 | check_diagnostics( | ||
1004 | r#" | ||
1005 | trait BAD_TRAIT { | ||
1006 | // ^^^^^^^^^ Trait `BAD_TRAIT` should have CamelCase name, e.g. `BadTrait` | ||
1007 | fn BAD_FUNCTION(); | ||
1008 | // ^^^^^^^^^^^^ Function `BAD_FUNCTION` should have snake_case name, e.g. `bad_function` | ||
1009 | fn BadFunction(); | ||
1010 | // ^^^^^^^^^^^^ Function `BadFunction` should have snake_case name, e.g. `bad_function` | ||
1011 | } | ||
888 | "#, | 1012 | "#, |
889 | ); | 1013 | ); |
890 | } | 1014 | } |
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 | } |