Skip to content

Commit f800966

Browse files
committed
internal: move inference diagnostics to hir
1 parent 409f5fb commit f800966

File tree

6 files changed

+222
-244
lines changed

6 files changed

+222
-244
lines changed

crates/hir/src/diagnostics.rs

Lines changed: 52 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,7 @@ use syntax::{ast, AstPtr, SyntaxNodePtr, TextRange};
1414
pub use hir_ty::{
1515
diagnostics::{
1616
IncorrectCase, MismatchedArgCount, MissingFields, MissingMatchArms,
17-
MissingOkOrSomeInTailExpr, NoSuchField, RemoveThisSemicolon,
18-
ReplaceFilterMapNextWithFindMap,
17+
MissingOkOrSomeInTailExpr, RemoveThisSemicolon, ReplaceFilterMapNextWithFindMap,
1918
},
2019
diagnostics_sink::{Diagnostic, DiagnosticCode, DiagnosticSink, DiagnosticSinkBuilder},
2120
};
@@ -251,3 +250,54 @@ impl Diagnostic for UnimplementedBuiltinMacro {
251250
self
252251
}
253252
}
253+
254+
// Diagnostic: no-such-field
255+
//
256+
// This diagnostic is triggered if created structure does not have field provided in record.
257+
#[derive(Debug)]
258+
pub struct NoSuchField {
259+
pub file: HirFileId,
260+
pub field: AstPtr<ast::RecordExprField>,
261+
}
262+
263+
impl Diagnostic for NoSuchField {
264+
fn code(&self) -> DiagnosticCode {
265+
DiagnosticCode("no-such-field")
266+
}
267+
268+
fn message(&self) -> String {
269+
"no such field".to_string()
270+
}
271+
272+
fn display_source(&self) -> InFile<SyntaxNodePtr> {
273+
InFile::new(self.file, self.field.clone().into())
274+
}
275+
276+
fn as_any(&self) -> &(dyn Any + Send + 'static) {
277+
self
278+
}
279+
}
280+
281+
// Diagnostic: break-outside-of-loop
282+
//
283+
// This diagnostic is triggered if the `break` keyword is used outside of a loop.
284+
#[derive(Debug)]
285+
pub struct BreakOutsideOfLoop {
286+
pub file: HirFileId,
287+
pub expr: AstPtr<ast::Expr>,
288+
}
289+
290+
impl Diagnostic for BreakOutsideOfLoop {
291+
fn code(&self) -> DiagnosticCode {
292+
DiagnosticCode("break-outside-of-loop")
293+
}
294+
fn message(&self) -> String {
295+
"break outside of loop".to_string()
296+
}
297+
fn display_source(&self) -> InFile<SyntaxNodePtr> {
298+
InFile { file_id: self.file, value: self.expr.clone().into() }
299+
}
300+
fn as_any(&self) -> &(dyn Any + Send + 'static) {
301+
self
302+
}
303+
}

crates/hir/src/lib.rs

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,8 +36,9 @@ use std::{iter, sync::Arc};
3636
use arrayvec::ArrayVec;
3737
use base_db::{CrateDisplayName, CrateId, Edition, FileId};
3838
use diagnostics::{
39-
InactiveCode, MacroError, UnimplementedBuiltinMacro, UnresolvedExternCrate, UnresolvedImport,
40-
UnresolvedMacroCall, UnresolvedModule, UnresolvedProcMacro,
39+
BreakOutsideOfLoop, InactiveCode, MacroError, NoSuchField, UnimplementedBuiltinMacro,
40+
UnresolvedExternCrate, UnresolvedImport, UnresolvedMacroCall, UnresolvedModule,
41+
UnresolvedProcMacro,
4142
};
4243
use either::Either;
4344
use hir_def::{
@@ -1042,6 +1043,23 @@ impl Function {
10421043
}
10431044
}
10441045

1046+
let infer = db.infer(self.id.into());
1047+
let (_, source_map) = db.body_with_source_map(self.id.into());
1048+
for d in &infer.diagnostics {
1049+
match d {
1050+
hir_ty::InferenceDiagnostic::NoSuchField { expr } => {
1051+
let field = source_map.field_syntax(*expr);
1052+
sink.push(NoSuchField { file: field.file_id, field: field.value })
1053+
}
1054+
hir_ty::InferenceDiagnostic::BreakOutsideOfLoop { expr } => {
1055+
let ptr = source_map
1056+
.expr_syntax(*expr)
1057+
.expect("break outside of loop in synthetic syntax");
1058+
sink.push(BreakOutsideOfLoop { file: ptr.file_id, expr: ptr.value })
1059+
}
1060+
}
1061+
}
1062+
10451063
hir_ty::diagnostics::validate_module_item(db, krate, self.id.into(), sink);
10461064
hir_ty::diagnostics::validate_body(db, self.id.into(), sink);
10471065
}

crates/hir_ty/src/diagnostics.rs

Lines changed: 0 additions & 185 deletions
Original file line numberDiff line numberDiff line change
@@ -33,40 +33,12 @@ pub fn validate_module_item(
3333
pub fn validate_body(db: &dyn HirDatabase, owner: DefWithBodyId, sink: &mut DiagnosticSink<'_>) {
3434
let _p = profile::span("validate_body");
3535
let infer = db.infer(owner);
36-
infer.add_diagnostics(db, owner, sink);
3736
let mut validator = expr::ExprValidator::new(owner, infer.clone(), sink);
3837
validator.validate_body(db);
3938
let mut validator = unsafe_check::UnsafeValidator::new(owner, infer, sink);
4039
validator.validate_body(db);
4140
}
4241

43-
// Diagnostic: no-such-field
44-
//
45-
// This diagnostic is triggered if created structure does not have field provided in record.
46-
#[derive(Debug)]
47-
pub struct NoSuchField {
48-
pub file: HirFileId,
49-
pub field: AstPtr<ast::RecordExprField>,
50-
}
51-
52-
impl Diagnostic for NoSuchField {
53-
fn code(&self) -> DiagnosticCode {
54-
DiagnosticCode("no-such-field")
55-
}
56-
57-
fn message(&self) -> String {
58-
"no such field".to_string()
59-
}
60-
61-
fn display_source(&self) -> InFile<SyntaxNodePtr> {
62-
InFile::new(self.file, self.field.clone().into())
63-
}
64-
65-
fn as_any(&self) -> &(dyn Any + Send + 'static) {
66-
self
67-
}
68-
}
69-
7042
// Diagnostic: missing-structure-fields
7143
//
7244
// This diagnostic is triggered if record lacks some fields that exist in the corresponding structure.
@@ -247,30 +219,6 @@ impl Diagnostic for RemoveThisSemicolon {
247219
}
248220
}
249221

250-
// Diagnostic: break-outside-of-loop
251-
//
252-
// This diagnostic is triggered if the `break` keyword is used outside of a loop.
253-
#[derive(Debug)]
254-
pub struct BreakOutsideOfLoop {
255-
pub file: HirFileId,
256-
pub expr: AstPtr<ast::Expr>,
257-
}
258-
259-
impl Diagnostic for BreakOutsideOfLoop {
260-
fn code(&self) -> DiagnosticCode {
261-
DiagnosticCode("break-outside-of-loop")
262-
}
263-
fn message(&self) -> String {
264-
"break outside of loop".to_string()
265-
}
266-
fn display_source(&self) -> InFile<SyntaxNodePtr> {
267-
InFile { file_id: self.file, value: self.expr.clone().into() }
268-
}
269-
fn as_any(&self) -> &(dyn Any + Send + 'static) {
270-
self
271-
}
272-
}
273-
274222
// Diagnostic: missing-unsafe
275223
//
276224
// This diagnostic is triggered if an operation marked as `unsafe` is used outside of an `unsafe` function or block.
@@ -530,129 +478,6 @@ mod tests {
530478
assert_eq!(annotations, actual);
531479
}
532480

533-
#[test]
534-
fn no_such_field_diagnostics() {
535-
check_diagnostics(
536-
r#"
537-
struct S { foo: i32, bar: () }
538-
impl S {
539-
fn new() -> S {
540-
S {
541-
//^ Missing structure fields:
542-
//| - bar
543-
foo: 92,
544-
baz: 62,
545-
//^^^^^^^ no such field
546-
}
547-
}
548-
}
549-
"#,
550-
);
551-
}
552-
#[test]
553-
fn no_such_field_with_feature_flag_diagnostics() {
554-
check_diagnostics(
555-
r#"
556-
//- /lib.rs crate:foo cfg:feature=foo
557-
struct MyStruct {
558-
my_val: usize,
559-
#[cfg(feature = "foo")]
560-
bar: bool,
561-
}
562-
563-
impl MyStruct {
564-
#[cfg(feature = "foo")]
565-
pub(crate) fn new(my_val: usize, bar: bool) -> Self {
566-
Self { my_val, bar }
567-
}
568-
#[cfg(not(feature = "foo"))]
569-
pub(crate) fn new(my_val: usize, _bar: bool) -> Self {
570-
Self { my_val }
571-
}
572-
}
573-
"#,
574-
);
575-
}
576-
577-
#[test]
578-
fn no_such_field_enum_with_feature_flag_diagnostics() {
579-
check_diagnostics(
580-
r#"
581-
//- /lib.rs crate:foo cfg:feature=foo
582-
enum Foo {
583-
#[cfg(not(feature = "foo"))]
584-
Buz,
585-
#[cfg(feature = "foo")]
586-
Bar,
587-
Baz
588-
}
589-
590-
fn test_fn(f: Foo) {
591-
match f {
592-
Foo::Bar => {},
593-
Foo::Baz => {},
594-
}
595-
}
596-
"#,
597-
);
598-
}
599-
600-
#[test]
601-
fn no_such_field_with_feature_flag_diagnostics_on_struct_lit() {
602-
check_diagnostics(
603-
r#"
604-
//- /lib.rs crate:foo cfg:feature=foo
605-
struct S {
606-
#[cfg(feature = "foo")]
607-
foo: u32,
608-
#[cfg(not(feature = "foo"))]
609-
bar: u32,
610-
}
611-
612-
impl S {
613-
#[cfg(feature = "foo")]
614-
fn new(foo: u32) -> Self {
615-
Self { foo }
616-
}
617-
#[cfg(not(feature = "foo"))]
618-
fn new(bar: u32) -> Self {
619-
Self { bar }
620-
}
621-
fn new2(bar: u32) -> Self {
622-
#[cfg(feature = "foo")]
623-
{ Self { foo: bar } }
624-
#[cfg(not(feature = "foo"))]
625-
{ Self { bar } }
626-
}
627-
fn new2(val: u32) -> Self {
628-
Self {
629-
#[cfg(feature = "foo")]
630-
foo: val,
631-
#[cfg(not(feature = "foo"))]
632-
bar: val,
633-
}
634-
}
635-
}
636-
"#,
637-
);
638-
}
639-
640-
#[test]
641-
fn no_such_field_with_type_macro() {
642-
check_diagnostics(
643-
r#"
644-
macro_rules! Type { () => { u32 }; }
645-
struct Foo { bar: Type![] }
646-
647-
impl Foo {
648-
fn new() -> Self {
649-
Foo { bar: 0 }
650-
}
651-
}
652-
"#,
653-
);
654-
}
655-
656481
#[test]
657482
fn missing_record_pat_field_diagnostic() {
658483
check_diagnostics(
@@ -734,16 +559,6 @@ pub struct Claims {
734559
);
735560
}
736561

737-
#[test]
738-
fn break_outside_of_loop() {
739-
check_diagnostics(
740-
r#"
741-
fn foo() { break; }
742-
//^^^^^ break outside of loop
743-
"#,
744-
);
745-
}
746-
747562
#[test]
748563
fn missing_semicolon() {
749564
check_diagnostics(

0 commit comments

Comments
 (0)