diff options
Diffstat (limited to 'crates/hir/src')
-rw-r--r-- | crates/hir/src/diagnostics.rs | 263 | ||||
-rw-r--r-- | crates/hir/src/lib.rs | 175 |
2 files changed, 421 insertions, 17 deletions
diff --git a/crates/hir/src/diagnostics.rs b/crates/hir/src/diagnostics.rs index e888fc23b..26dbcd86a 100644 --- a/crates/hir/src/diagnostics.rs +++ b/crates/hir/src/diagnostics.rs | |||
@@ -7,15 +7,12 @@ use std::any::Any; | |||
7 | 7 | ||
8 | use cfg::{CfgExpr, CfgOptions, DnfExpr}; | 8 | use cfg::{CfgExpr, CfgOptions, DnfExpr}; |
9 | use hir_def::path::ModPath; | 9 | use hir_def::path::ModPath; |
10 | use hir_expand::{HirFileId, InFile}; | 10 | use hir_expand::{name::Name, HirFileId, InFile}; |
11 | use stdx::format_to; | 11 | use stdx::format_to; |
12 | use syntax::{ast, AstPtr, SyntaxNodePtr, TextRange}; | 12 | use syntax::{ast, AstPtr, SyntaxNodePtr, TextRange}; |
13 | 13 | ||
14 | pub use hir_ty::{ | 14 | pub use hir_ty::{ |
15 | diagnostics::{ | 15 | diagnostics::IncorrectCase, |
16 | IncorrectCase, MismatchedArgCount, MissingFields, MissingMatchArms, | ||
17 | MissingOkOrSomeInTailExpr, RemoveThisSemicolon, ReplaceFilterMapNextWithFindMap, | ||
18 | }, | ||
19 | diagnostics_sink::{Diagnostic, DiagnosticCode, DiagnosticSink, DiagnosticSinkBuilder}, | 16 | diagnostics_sink::{Diagnostic, DiagnosticCode, DiagnosticSink, DiagnosticSinkBuilder}, |
20 | }; | 17 | }; |
21 | 18 | ||
@@ -325,3 +322,259 @@ impl Diagnostic for MissingUnsafe { | |||
325 | self | 322 | self |
326 | } | 323 | } |
327 | } | 324 | } |
325 | |||
326 | // Diagnostic: missing-structure-fields | ||
327 | // | ||
328 | // This diagnostic is triggered if record lacks some fields that exist in the corresponding structure. | ||
329 | // | ||
330 | // Example: | ||
331 | // | ||
332 | // ```rust | ||
333 | // struct A { a: u8, b: u8 } | ||
334 | // | ||
335 | // let a = A { a: 10 }; | ||
336 | // ``` | ||
337 | #[derive(Debug)] | ||
338 | pub struct MissingFields { | ||
339 | pub file: HirFileId, | ||
340 | pub field_list_parent: AstPtr<ast::RecordExpr>, | ||
341 | pub field_list_parent_path: Option<AstPtr<ast::Path>>, | ||
342 | pub missed_fields: Vec<Name>, | ||
343 | } | ||
344 | |||
345 | impl Diagnostic for MissingFields { | ||
346 | fn code(&self) -> DiagnosticCode { | ||
347 | DiagnosticCode("missing-structure-fields") | ||
348 | } | ||
349 | fn message(&self) -> String { | ||
350 | let mut buf = String::from("Missing structure fields:\n"); | ||
351 | for field in &self.missed_fields { | ||
352 | format_to!(buf, "- {}\n", field); | ||
353 | } | ||
354 | buf | ||
355 | } | ||
356 | |||
357 | fn display_source(&self) -> InFile<SyntaxNodePtr> { | ||
358 | InFile { | ||
359 | file_id: self.file, | ||
360 | value: self | ||
361 | .field_list_parent_path | ||
362 | .clone() | ||
363 | .map(SyntaxNodePtr::from) | ||
364 | .unwrap_or_else(|| self.field_list_parent.clone().into()), | ||
365 | } | ||
366 | } | ||
367 | |||
368 | fn as_any(&self) -> &(dyn Any + Send + 'static) { | ||
369 | self | ||
370 | } | ||
371 | } | ||
372 | |||
373 | // Diagnostic: missing-pat-fields | ||
374 | // | ||
375 | // This diagnostic is triggered if pattern lacks some fields that exist in the corresponding structure. | ||
376 | // | ||
377 | // Example: | ||
378 | // | ||
379 | // ```rust | ||
380 | // struct A { a: u8, b: u8 } | ||
381 | // | ||
382 | // let a = A { a: 10, b: 20 }; | ||
383 | // | ||
384 | // if let A { a } = a { | ||
385 | // // ... | ||
386 | // } | ||
387 | // ``` | ||
388 | #[derive(Debug)] | ||
389 | pub struct MissingPatFields { | ||
390 | pub file: HirFileId, | ||
391 | pub field_list_parent: AstPtr<ast::RecordPat>, | ||
392 | pub field_list_parent_path: Option<AstPtr<ast::Path>>, | ||
393 | pub missed_fields: Vec<Name>, | ||
394 | } | ||
395 | |||
396 | impl Diagnostic for MissingPatFields { | ||
397 | fn code(&self) -> DiagnosticCode { | ||
398 | DiagnosticCode("missing-pat-fields") | ||
399 | } | ||
400 | fn message(&self) -> String { | ||
401 | let mut buf = String::from("Missing structure fields:\n"); | ||
402 | for field in &self.missed_fields { | ||
403 | format_to!(buf, "- {}\n", field); | ||
404 | } | ||
405 | buf | ||
406 | } | ||
407 | fn display_source(&self) -> InFile<SyntaxNodePtr> { | ||
408 | InFile { | ||
409 | file_id: self.file, | ||
410 | value: self | ||
411 | .field_list_parent_path | ||
412 | .clone() | ||
413 | .map(SyntaxNodePtr::from) | ||
414 | .unwrap_or_else(|| self.field_list_parent.clone().into()), | ||
415 | } | ||
416 | } | ||
417 | fn as_any(&self) -> &(dyn Any + Send + 'static) { | ||
418 | self | ||
419 | } | ||
420 | } | ||
421 | |||
422 | // Diagnostic: replace-filter-map-next-with-find-map | ||
423 | // | ||
424 | // This diagnostic is triggered when `.filter_map(..).next()` is used, rather than the more concise `.find_map(..)`. | ||
425 | #[derive(Debug)] | ||
426 | pub struct ReplaceFilterMapNextWithFindMap { | ||
427 | pub file: HirFileId, | ||
428 | /// This expression is the whole method chain up to and including `.filter_map(..).next()`. | ||
429 | pub next_expr: AstPtr<ast::Expr>, | ||
430 | } | ||
431 | |||
432 | impl Diagnostic for ReplaceFilterMapNextWithFindMap { | ||
433 | fn code(&self) -> DiagnosticCode { | ||
434 | DiagnosticCode("replace-filter-map-next-with-find-map") | ||
435 | } | ||
436 | fn message(&self) -> String { | ||
437 | "replace filter_map(..).next() with find_map(..)".to_string() | ||
438 | } | ||
439 | fn display_source(&self) -> InFile<SyntaxNodePtr> { | ||
440 | InFile { file_id: self.file, value: self.next_expr.clone().into() } | ||
441 | } | ||
442 | fn as_any(&self) -> &(dyn Any + Send + 'static) { | ||
443 | self | ||
444 | } | ||
445 | } | ||
446 | |||
447 | // Diagnostic: mismatched-arg-count | ||
448 | // | ||
449 | // This diagnostic is triggered if a function is invoked with an incorrect amount of arguments. | ||
450 | #[derive(Debug)] | ||
451 | pub struct MismatchedArgCount { | ||
452 | pub file: HirFileId, | ||
453 | pub call_expr: AstPtr<ast::Expr>, | ||
454 | pub expected: usize, | ||
455 | pub found: usize, | ||
456 | } | ||
457 | |||
458 | impl Diagnostic for MismatchedArgCount { | ||
459 | fn code(&self) -> DiagnosticCode { | ||
460 | DiagnosticCode("mismatched-arg-count") | ||
461 | } | ||
462 | fn message(&self) -> String { | ||
463 | let s = if self.expected == 1 { "" } else { "s" }; | ||
464 | format!("Expected {} argument{}, found {}", self.expected, s, self.found) | ||
465 | } | ||
466 | fn display_source(&self) -> InFile<SyntaxNodePtr> { | ||
467 | InFile { file_id: self.file, value: self.call_expr.clone().into() } | ||
468 | } | ||
469 | fn as_any(&self) -> &(dyn Any + Send + 'static) { | ||
470 | self | ||
471 | } | ||
472 | fn is_experimental(&self) -> bool { | ||
473 | true | ||
474 | } | ||
475 | } | ||
476 | |||
477 | #[derive(Debug)] | ||
478 | pub struct RemoveThisSemicolon { | ||
479 | pub file: HirFileId, | ||
480 | pub expr: AstPtr<ast::Expr>, | ||
481 | } | ||
482 | |||
483 | impl Diagnostic for RemoveThisSemicolon { | ||
484 | fn code(&self) -> DiagnosticCode { | ||
485 | DiagnosticCode("remove-this-semicolon") | ||
486 | } | ||
487 | |||
488 | fn message(&self) -> String { | ||
489 | "Remove this semicolon".to_string() | ||
490 | } | ||
491 | |||
492 | fn display_source(&self) -> InFile<SyntaxNodePtr> { | ||
493 | InFile { file_id: self.file, value: self.expr.clone().into() } | ||
494 | } | ||
495 | |||
496 | fn as_any(&self) -> &(dyn Any + Send + 'static) { | ||
497 | self | ||
498 | } | ||
499 | } | ||
500 | |||
501 | // Diagnostic: missing-ok-or-some-in-tail-expr | ||
502 | // | ||
503 | // This diagnostic is triggered if a block that should return `Result` returns a value not wrapped in `Ok`, | ||
504 | // or if a block that should return `Option` returns a value not wrapped in `Some`. | ||
505 | // | ||
506 | // Example: | ||
507 | // | ||
508 | // ```rust | ||
509 | // fn foo() -> Result<u8, ()> { | ||
510 | // 10 | ||
511 | // } | ||
512 | // ``` | ||
513 | #[derive(Debug)] | ||
514 | pub struct MissingOkOrSomeInTailExpr { | ||
515 | pub file: HirFileId, | ||
516 | pub expr: AstPtr<ast::Expr>, | ||
517 | // `Some` or `Ok` depending on whether the return type is Result or Option | ||
518 | pub required: String, | ||
519 | } | ||
520 | |||
521 | impl Diagnostic for MissingOkOrSomeInTailExpr { | ||
522 | fn code(&self) -> DiagnosticCode { | ||
523 | DiagnosticCode("missing-ok-or-some-in-tail-expr") | ||
524 | } | ||
525 | fn message(&self) -> String { | ||
526 | format!("wrap return expression in {}", self.required) | ||
527 | } | ||
528 | fn display_source(&self) -> InFile<SyntaxNodePtr> { | ||
529 | InFile { file_id: self.file, value: self.expr.clone().into() } | ||
530 | } | ||
531 | fn as_any(&self) -> &(dyn Any + Send + 'static) { | ||
532 | self | ||
533 | } | ||
534 | } | ||
535 | |||
536 | // Diagnostic: missing-match-arm | ||
537 | // | ||
538 | // This diagnostic is triggered if `match` block is missing one or more match arms. | ||
539 | #[derive(Debug)] | ||
540 | pub struct MissingMatchArms { | ||
541 | pub file: HirFileId, | ||
542 | pub match_expr: AstPtr<ast::Expr>, | ||
543 | pub arms: AstPtr<ast::MatchArmList>, | ||
544 | } | ||
545 | |||
546 | impl Diagnostic for MissingMatchArms { | ||
547 | fn code(&self) -> DiagnosticCode { | ||
548 | DiagnosticCode("missing-match-arm") | ||
549 | } | ||
550 | fn message(&self) -> String { | ||
551 | String::from("Missing match arm") | ||
552 | } | ||
553 | fn display_source(&self) -> InFile<SyntaxNodePtr> { | ||
554 | InFile { file_id: self.file, value: self.match_expr.clone().into() } | ||
555 | } | ||
556 | fn as_any(&self) -> &(dyn Any + Send + 'static) { | ||
557 | self | ||
558 | } | ||
559 | } | ||
560 | |||
561 | #[derive(Debug)] | ||
562 | pub struct InternalBailedOut { | ||
563 | pub file: HirFileId, | ||
564 | pub pat_syntax_ptr: SyntaxNodePtr, | ||
565 | } | ||
566 | |||
567 | impl Diagnostic for InternalBailedOut { | ||
568 | fn code(&self) -> DiagnosticCode { | ||
569 | DiagnosticCode("internal:match-check-bailed-out") | ||
570 | } | ||
571 | fn message(&self) -> String { | ||
572 | format!("Internal: match check bailed out") | ||
573 | } | ||
574 | fn display_source(&self) -> InFile<SyntaxNodePtr> { | ||
575 | InFile { file_id: self.file, value: self.pat_syntax_ptr.clone() } | ||
576 | } | ||
577 | fn as_any(&self) -> &(dyn Any + Send + 'static) { | ||
578 | self | ||
579 | } | ||
580 | } | ||
diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs index 8804e63c5..dd5515c2b 100644 --- a/crates/hir/src/lib.rs +++ b/crates/hir/src/lib.rs | |||
@@ -36,9 +36,11 @@ use std::{iter, sync::Arc}; | |||
36 | use arrayvec::ArrayVec; | 36 | use arrayvec::ArrayVec; |
37 | use base_db::{CrateDisplayName, CrateId, Edition, FileId}; | 37 | use base_db::{CrateDisplayName, CrateId, Edition, FileId}; |
38 | use diagnostics::{ | 38 | use diagnostics::{ |
39 | BreakOutsideOfLoop, InactiveCode, MacroError, MissingUnsafe, NoSuchField, | 39 | BreakOutsideOfLoop, InactiveCode, InternalBailedOut, MacroError, MismatchedArgCount, |
40 | UnimplementedBuiltinMacro, UnresolvedExternCrate, UnresolvedImport, UnresolvedMacroCall, | 40 | MissingFields, MissingOkOrSomeInTailExpr, MissingPatFields, MissingUnsafe, NoSuchField, |
41 | UnresolvedModule, UnresolvedProcMacro, | 41 | RemoveThisSemicolon, ReplaceFilterMapNextWithFindMap, UnimplementedBuiltinMacro, |
42 | UnresolvedExternCrate, UnresolvedImport, UnresolvedMacroCall, UnresolvedModule, | ||
43 | UnresolvedProcMacro, | ||
42 | }; | 44 | }; |
43 | use either::Either; | 45 | use either::Either; |
44 | use hir_def::{ | 46 | use hir_def::{ |
@@ -61,6 +63,7 @@ use hir_ty::{ | |||
61 | autoderef, | 63 | autoderef, |
62 | consteval::ConstExt, | 64 | consteval::ConstExt, |
63 | could_unify, | 65 | could_unify, |
66 | diagnostics::BodyValidationDiagnostic, | ||
64 | diagnostics_sink::DiagnosticSink, | 67 | diagnostics_sink::DiagnosticSink, |
65 | method_resolution::{self, def_crates, TyFingerprint}, | 68 | method_resolution::{self, def_crates, TyFingerprint}, |
66 | primitive::UintTy, | 69 | primitive::UintTy, |
@@ -82,7 +85,10 @@ use syntax::{ | |||
82 | }; | 85 | }; |
83 | use tt::{Ident, Leaf, Literal, TokenTree}; | 86 | use tt::{Ident, Leaf, Literal, TokenTree}; |
84 | 87 | ||
85 | use crate::db::{DefDatabase, HirDatabase}; | 88 | use crate::{ |
89 | db::{DefDatabase, HirDatabase}, | ||
90 | diagnostics::MissingMatchArms, | ||
91 | }; | ||
86 | 92 | ||
87 | pub use crate::{ | 93 | pub use crate::{ |
88 | attrs::{HasAttrs, Namespace}, | 94 | attrs::{HasAttrs, Namespace}, |
@@ -447,7 +453,12 @@ impl Module { | |||
447 | self.id.def_map(db.upcast())[self.id.local_id].scope.visibility_of(def.clone().into()) | 453 | self.id.def_map(db.upcast())[self.id.local_id].scope.visibility_of(def.clone().into()) |
448 | } | 454 | } |
449 | 455 | ||
450 | pub fn diagnostics(self, db: &dyn HirDatabase, sink: &mut DiagnosticSink) { | 456 | pub fn diagnostics( |
457 | self, | ||
458 | db: &dyn HirDatabase, | ||
459 | sink: &mut DiagnosticSink, | ||
460 | internal_diagnostics: bool, | ||
461 | ) { | ||
451 | let _p = profile::span("Module::diagnostics").detail(|| { | 462 | let _p = profile::span("Module::diagnostics").detail(|| { |
452 | format!("{:?}", self.name(db).map_or("<unknown>".into(), |name| name.to_string())) | 463 | format!("{:?}", self.name(db).map_or("<unknown>".into(), |name| name.to_string())) |
453 | }); | 464 | }); |
@@ -593,11 +604,11 @@ impl Module { | |||
593 | } | 604 | } |
594 | for decl in self.declarations(db) { | 605 | for decl in self.declarations(db) { |
595 | match decl { | 606 | match decl { |
596 | crate::ModuleDef::Function(f) => f.diagnostics(db, sink), | 607 | crate::ModuleDef::Function(f) => f.diagnostics(db, sink, internal_diagnostics), |
597 | crate::ModuleDef::Module(m) => { | 608 | crate::ModuleDef::Module(m) => { |
598 | // Only add diagnostics from inline modules | 609 | // Only add diagnostics from inline modules |
599 | if def_map[m.id.local_id].origin.is_inline() { | 610 | if def_map[m.id.local_id].origin.is_inline() { |
600 | m.diagnostics(db, sink) | 611 | m.diagnostics(db, sink, internal_diagnostics) |
601 | } | 612 | } |
602 | } | 613 | } |
603 | _ => { | 614 | _ => { |
@@ -609,7 +620,7 @@ impl Module { | |||
609 | for impl_def in self.impl_defs(db) { | 620 | for impl_def in self.impl_defs(db) { |
610 | for item in impl_def.items(db) { | 621 | for item in impl_def.items(db) { |
611 | if let AssocItem::Function(f) = item { | 622 | if let AssocItem::Function(f) = item { |
612 | f.diagnostics(db, sink); | 623 | f.diagnostics(db, sink, internal_diagnostics); |
613 | } | 624 | } |
614 | } | 625 | } |
615 | } | 626 | } |
@@ -1011,7 +1022,12 @@ impl Function { | |||
1011 | db.function_data(self.id).is_async() | 1022 | db.function_data(self.id).is_async() |
1012 | } | 1023 | } |
1013 | 1024 | ||
1014 | pub fn diagnostics(self, db: &dyn HirDatabase, sink: &mut DiagnosticSink) { | 1025 | pub fn diagnostics( |
1026 | self, | ||
1027 | db: &dyn HirDatabase, | ||
1028 | sink: &mut DiagnosticSink, | ||
1029 | internal_diagnostics: bool, | ||
1030 | ) { | ||
1015 | let krate = self.module(db).id.krate(); | 1031 | let krate = self.module(db).id.krate(); |
1016 | 1032 | ||
1017 | let source_map = db.body_with_source_map(self.id.into()).1; | 1033 | let source_map = db.body_with_source_map(self.id.into()).1; |
@@ -1067,14 +1083,149 @@ impl Function { | |||
1067 | sink.push(MissingUnsafe { file: in_file.file_id, expr: in_file.value }) | 1083 | sink.push(MissingUnsafe { file: in_file.file_id, expr: in_file.value }) |
1068 | } | 1084 | } |
1069 | Err(SyntheticSyntax) => { | 1085 | Err(SyntheticSyntax) => { |
1070 | // FIXME: The `expr` was desugared, report or assert that | 1086 | // FIXME: Here and eslwhere in this file, the `expr` was |
1071 | // this doesn't happen. | 1087 | // desugared, report or assert that this doesn't happen. |
1088 | } | ||
1089 | } | ||
1090 | } | ||
1091 | |||
1092 | for diagnostic in | ||
1093 | BodyValidationDiagnostic::collect(db, self.id.into(), internal_diagnostics) | ||
1094 | { | ||
1095 | match diagnostic { | ||
1096 | BodyValidationDiagnostic::RecordLiteralMissingFields { | ||
1097 | record_expr, | ||
1098 | variant, | ||
1099 | missed_fields, | ||
1100 | } => match source_map.expr_syntax(record_expr) { | ||
1101 | Ok(source_ptr) => { | ||
1102 | let root = source_ptr.file_syntax(db.upcast()); | ||
1103 | if let ast::Expr::RecordExpr(record_expr) = &source_ptr.value.to_node(&root) | ||
1104 | { | ||
1105 | if let Some(_) = record_expr.record_expr_field_list() { | ||
1106 | let variant_data = variant.variant_data(db.upcast()); | ||
1107 | let missed_fields = missed_fields | ||
1108 | .into_iter() | ||
1109 | .map(|idx| variant_data.fields()[idx].name.clone()) | ||
1110 | .collect(); | ||
1111 | sink.push(MissingFields { | ||
1112 | file: source_ptr.file_id, | ||
1113 | field_list_parent: AstPtr::new(&record_expr), | ||
1114 | field_list_parent_path: record_expr | ||
1115 | .path() | ||
1116 | .map(|path| AstPtr::new(&path)), | ||
1117 | missed_fields, | ||
1118 | }) | ||
1119 | } | ||
1120 | } | ||
1121 | } | ||
1122 | Err(SyntheticSyntax) => (), | ||
1123 | }, | ||
1124 | BodyValidationDiagnostic::RecordPatMissingFields { | ||
1125 | record_pat, | ||
1126 | variant, | ||
1127 | missed_fields, | ||
1128 | } => match source_map.pat_syntax(record_pat) { | ||
1129 | Ok(source_ptr) => { | ||
1130 | if let Some(expr) = source_ptr.value.as_ref().left() { | ||
1131 | let root = source_ptr.file_syntax(db.upcast()); | ||
1132 | if let ast::Pat::RecordPat(record_pat) = expr.to_node(&root) { | ||
1133 | if let Some(_) = record_pat.record_pat_field_list() { | ||
1134 | let variant_data = variant.variant_data(db.upcast()); | ||
1135 | let missed_fields = missed_fields | ||
1136 | .into_iter() | ||
1137 | .map(|idx| variant_data.fields()[idx].name.clone()) | ||
1138 | .collect(); | ||
1139 | sink.push(MissingPatFields { | ||
1140 | file: source_ptr.file_id, | ||
1141 | field_list_parent: AstPtr::new(&record_pat), | ||
1142 | field_list_parent_path: record_pat | ||
1143 | .path() | ||
1144 | .map(|path| AstPtr::new(&path)), | ||
1145 | missed_fields, | ||
1146 | }) | ||
1147 | } | ||
1148 | } | ||
1149 | } | ||
1150 | } | ||
1151 | Err(SyntheticSyntax) => (), | ||
1152 | }, | ||
1153 | |||
1154 | BodyValidationDiagnostic::ReplaceFilterMapNextWithFindMap { method_call_expr } => { | ||
1155 | if let Ok(next_source_ptr) = source_map.expr_syntax(method_call_expr) { | ||
1156 | sink.push(ReplaceFilterMapNextWithFindMap { | ||
1157 | file: next_source_ptr.file_id, | ||
1158 | next_expr: next_source_ptr.value, | ||
1159 | }); | ||
1160 | } | ||
1161 | } | ||
1162 | BodyValidationDiagnostic::MismatchedArgCount { call_expr, expected, found } => { | ||
1163 | match source_map.expr_syntax(call_expr) { | ||
1164 | Ok(source_ptr) => sink.push(MismatchedArgCount { | ||
1165 | file: source_ptr.file_id, | ||
1166 | call_expr: source_ptr.value, | ||
1167 | expected, | ||
1168 | found, | ||
1169 | }), | ||
1170 | Err(SyntheticSyntax) => (), | ||
1171 | } | ||
1172 | } | ||
1173 | BodyValidationDiagnostic::RemoveThisSemicolon { expr } => { | ||
1174 | match source_map.expr_syntax(expr) { | ||
1175 | Ok(source_ptr) => sink.push(RemoveThisSemicolon { | ||
1176 | file: source_ptr.file_id, | ||
1177 | expr: source_ptr.value, | ||
1178 | }), | ||
1179 | Err(SyntheticSyntax) => (), | ||
1180 | } | ||
1181 | } | ||
1182 | BodyValidationDiagnostic::MissingOkOrSomeInTailExpr { expr, required } => { | ||
1183 | match source_map.expr_syntax(expr) { | ||
1184 | Ok(source_ptr) => sink.push(MissingOkOrSomeInTailExpr { | ||
1185 | file: source_ptr.file_id, | ||
1186 | expr: source_ptr.value, | ||
1187 | required, | ||
1188 | }), | ||
1189 | Err(SyntheticSyntax) => (), | ||
1190 | } | ||
1191 | } | ||
1192 | BodyValidationDiagnostic::MissingMatchArms { match_expr } => { | ||
1193 | match source_map.expr_syntax(match_expr) { | ||
1194 | Ok(source_ptr) => { | ||
1195 | let root = source_ptr.file_syntax(db.upcast()); | ||
1196 | if let ast::Expr::MatchExpr(match_expr) = | ||
1197 | &source_ptr.value.to_node(&root) | ||
1198 | { | ||
1199 | if let (Some(match_expr), Some(arms)) = | ||
1200 | (match_expr.expr(), match_expr.match_arm_list()) | ||
1201 | { | ||
1202 | sink.push(MissingMatchArms { | ||
1203 | file: source_ptr.file_id, | ||
1204 | match_expr: AstPtr::new(&match_expr), | ||
1205 | arms: AstPtr::new(&arms), | ||
1206 | }) | ||
1207 | } | ||
1208 | } | ||
1209 | } | ||
1210 | Err(SyntheticSyntax) => (), | ||
1211 | } | ||
1212 | } | ||
1213 | BodyValidationDiagnostic::InternalBailedOut { pat } => { | ||
1214 | match source_map.pat_syntax(pat) { | ||
1215 | Ok(source_ptr) => { | ||
1216 | let pat_syntax_ptr = source_ptr.value.either(Into::into, Into::into); | ||
1217 | sink.push(InternalBailedOut { | ||
1218 | file: source_ptr.file_id, | ||
1219 | pat_syntax_ptr, | ||
1220 | }); | ||
1221 | } | ||
1222 | Err(SyntheticSyntax) => (), | ||
1223 | } | ||
1072 | } | 1224 | } |
1073 | } | 1225 | } |
1074 | } | 1226 | } |
1075 | 1227 | ||
1076 | hir_ty::diagnostics::validate_module_item(db, krate, self.id.into(), sink); | 1228 | hir_ty::diagnostics::validate_module_item(db, krate, self.id.into(), sink); |
1077 | hir_ty::diagnostics::validate_body(db, self.id.into(), sink); | ||
1078 | } | 1229 | } |
1079 | 1230 | ||
1080 | /// Whether this function declaration has a definition. | 1231 | /// Whether this function declaration has a definition. |