diff options
author | bors[bot] <bors[bot]@users.noreply.github.com> | 2019-03-25 11:38:46 +0000 |
---|---|---|
committer | bors[bot] <bors[bot]@users.noreply.github.com> | 2019-03-25 11:38:46 +0000 |
commit | c4ead49361e4b8c0586b810399c8e96a468b891c (patch) | |
tree | 0b1ba767e34e3baef938f6b7672f95ce4572ec07 /crates/ra_hir/src/nameres.rs | |
parent | 8aedf9603df1bc68eafcd8dcf3c14e5a6a2c8638 (diff) | |
parent | 309716cffe93d065bcad0344b0f332425576c1e5 (diff) |
Merge #1034
1034: HIR diagnostics API r=matklad a=matklad
This PR introduces diagnostics API for HIR, so we can now start issuing errors and warnings! Here are requirements that this solution aims to fulfill:
* structured diagnostics: rather than immediately rendering error to string, we provide a well-typed blob of data with error-description. These data is used by IDE to provide fixes
* open set diagnostics: there's no single enum with all possible diagnostics, which hopefully should result in better modularity
The `Diagnostic` trait describes "a diagnostic", which can be downcast to a specific diagnostic kind. Diagnostics are expressed in terms of macro-expanded syntax tree: they store pointers to syntax nodes. Diagnostics are self-contained: you don't need any context, besides `db`, to fully understand the meaning of a diagnostic.
Because diagnostics are tied to the source, we can't store them in salsa. So subsystems like type-checking produce subsystem-local diagnostic (which is a closed `enum`), which is expressed in therms of subsystem IR. A separate step converts these proto-diagnostics into `Diagnostic`, by merging them with source-maps.
Note that this PR stresses type-system quite a bit: we now type-check every function in open files to compute errors!
Discussion on Zulip: https://rust-lang.zulipchat.com/#narrow/stream/185405-t-compiler.2Fwg-rls-2.2E0/topic/Diagnostics.20API
Co-authored-by: Aleksey Kladov <[email protected]>
Diffstat (limited to 'crates/ra_hir/src/nameres.rs')
-rw-r--r-- | crates/ra_hir/src/nameres.rs | 81 |
1 files changed, 59 insertions, 22 deletions
diff --git a/crates/ra_hir/src/nameres.rs b/crates/ra_hir/src/nameres.rs index d361cf9e6..56ed872d5 100644 --- a/crates/ra_hir/src/nameres.rs +++ b/crates/ra_hir/src/nameres.rs | |||
@@ -61,9 +61,11 @@ use ra_db::{FileId, Edition}; | |||
61 | use test_utils::tested_by; | 61 | use test_utils::tested_by; |
62 | 62 | ||
63 | use crate::{ | 63 | use crate::{ |
64 | ModuleDef, Name, Crate, Module, Problem, | 64 | ModuleDef, Name, Crate, Module, |
65 | DefDatabase, Path, PathKind, HirFileId, | 65 | DefDatabase, Path, PathKind, HirFileId, |
66 | ids::{SourceItemId, SourceFileItemId, MacroCallId}, | 66 | ids::{SourceItemId, SourceFileItemId, MacroCallId}, |
67 | diagnostics::DiagnosticSink, | ||
68 | nameres::diagnostics::DefDiagnostic, | ||
67 | }; | 69 | }; |
68 | 70 | ||
69 | pub(crate) use self::raw::{RawItems, ImportId, ImportSourceMap}; | 71 | pub(crate) use self::raw::{RawItems, ImportId, ImportSourceMap}; |
@@ -85,7 +87,7 @@ pub struct CrateDefMap { | |||
85 | macros: Arena<CrateMacroId, mbe::MacroRules>, | 87 | macros: Arena<CrateMacroId, mbe::MacroRules>, |
86 | public_macros: FxHashMap<Name, CrateMacroId>, | 88 | public_macros: FxHashMap<Name, CrateMacroId>, |
87 | macro_resolutions: FxHashMap<MacroCallId, (Crate, CrateMacroId)>, | 89 | macro_resolutions: FxHashMap<MacroCallId, (Crate, CrateMacroId)>, |
88 | problems: CrateDefMapProblems, | 90 | diagnostics: Vec<DefDiagnostic>, |
89 | } | 91 | } |
90 | 92 | ||
91 | impl std::ops::Index<CrateModuleId> for CrateDefMap { | 93 | impl std::ops::Index<CrateModuleId> for CrateDefMap { |
@@ -125,21 +127,6 @@ pub(crate) struct ModuleData { | |||
125 | pub(crate) definition: Option<FileId>, | 127 | pub(crate) definition: Option<FileId>, |
126 | } | 128 | } |
127 | 129 | ||
128 | #[derive(Default, Debug, PartialEq, Eq)] | ||
129 | pub(crate) struct CrateDefMapProblems { | ||
130 | problems: Vec<(SourceItemId, Problem)>, | ||
131 | } | ||
132 | |||
133 | impl CrateDefMapProblems { | ||
134 | fn add(&mut self, source_item_id: SourceItemId, problem: Problem) { | ||
135 | self.problems.push((source_item_id, problem)) | ||
136 | } | ||
137 | |||
138 | pub(crate) fn iter<'a>(&'a self) -> impl Iterator<Item = (&'a SourceItemId, &'a Problem)> + 'a { | ||
139 | self.problems.iter().map(|(s, p)| (s, p)) | ||
140 | } | ||
141 | } | ||
142 | |||
143 | #[derive(Debug, Default, PartialEq, Eq, Clone)] | 130 | #[derive(Debug, Default, PartialEq, Eq, Clone)] |
144 | pub struct ModuleScope { | 131 | pub struct ModuleScope { |
145 | items: FxHashMap<Name, Resolution>, | 132 | items: FxHashMap<Name, Resolution>, |
@@ -212,7 +199,7 @@ impl CrateDefMap { | |||
212 | macros: Arena::default(), | 199 | macros: Arena::default(), |
213 | public_macros: FxHashMap::default(), | 200 | public_macros: FxHashMap::default(), |
214 | macro_resolutions: FxHashMap::default(), | 201 | macro_resolutions: FxHashMap::default(), |
215 | problems: CrateDefMapProblems::default(), | 202 | diagnostics: Vec::new(), |
216 | } | 203 | } |
217 | }; | 204 | }; |
218 | let def_map = collector::collect_defs(db, def_map); | 205 | let def_map = collector::collect_defs(db, def_map); |
@@ -224,10 +211,6 @@ impl CrateDefMap { | |||
224 | self.root | 211 | self.root |
225 | } | 212 | } |
226 | 213 | ||
227 | pub(crate) fn problems(&self) -> &CrateDefMapProblems { | ||
228 | &self.problems | ||
229 | } | ||
230 | |||
231 | pub(crate) fn mk_module(&self, module_id: CrateModuleId) -> Module { | 214 | pub(crate) fn mk_module(&self, module_id: CrateModuleId) -> Module { |
232 | Module { krate: self.krate, module_id } | 215 | Module { krate: self.krate, module_id } |
233 | } | 216 | } |
@@ -240,6 +223,15 @@ impl CrateDefMap { | |||
240 | &self.extern_prelude | 223 | &self.extern_prelude |
241 | } | 224 | } |
242 | 225 | ||
226 | pub(crate) fn add_diagnostics( | ||
227 | &self, | ||
228 | db: &impl DefDatabase, | ||
229 | module: CrateModuleId, | ||
230 | sink: &mut DiagnosticSink, | ||
231 | ) { | ||
232 | self.diagnostics.iter().for_each(|it| it.add_to(db, module, sink)) | ||
233 | } | ||
234 | |||
243 | pub(crate) fn resolve_macro( | 235 | pub(crate) fn resolve_macro( |
244 | &self, | 236 | &self, |
245 | macro_call_id: MacroCallId, | 237 | macro_call_id: MacroCallId, |
@@ -452,3 +444,48 @@ impl CrateDefMap { | |||
452 | } | 444 | } |
453 | } | 445 | } |
454 | } | 446 | } |
447 | |||
448 | mod diagnostics { | ||
449 | use relative_path::RelativePathBuf; | ||
450 | use ra_syntax::{AstPtr, AstNode, ast}; | ||
451 | |||
452 | use crate::{ | ||
453 | SourceItemId, DefDatabase, | ||
454 | nameres::CrateModuleId, | ||
455 | diagnostics::{DiagnosticSink, UnresolvedModule}, | ||
456 | }; | ||
457 | |||
458 | #[derive(Debug, PartialEq, Eq)] | ||
459 | pub(super) enum DefDiagnostic { | ||
460 | UnresolvedModule { | ||
461 | module: CrateModuleId, | ||
462 | declaration: SourceItemId, | ||
463 | candidate: RelativePathBuf, | ||
464 | }, | ||
465 | } | ||
466 | |||
467 | impl DefDiagnostic { | ||
468 | pub(super) fn add_to( | ||
469 | &self, | ||
470 | db: &impl DefDatabase, | ||
471 | target_module: CrateModuleId, | ||
472 | sink: &mut DiagnosticSink, | ||
473 | ) { | ||
474 | match self { | ||
475 | DefDiagnostic::UnresolvedModule { module, declaration, candidate } => { | ||
476 | if *module != target_module { | ||
477 | return; | ||
478 | } | ||
479 | let syntax = db.file_item(*declaration); | ||
480 | let decl = ast::Module::cast(&syntax).unwrap(); | ||
481 | sink.push(UnresolvedModule { | ||
482 | file: declaration.file_id, | ||
483 | decl: AstPtr::new(&decl), | ||
484 | candidate: candidate.clone(), | ||
485 | }) | ||
486 | } | ||
487 | } | ||
488 | } | ||
489 | } | ||
490 | |||
491 | } | ||