aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_hir/src/nameres
diff options
context:
space:
mode:
authorbors[bot] <bors[bot]@users.noreply.github.com>2019-03-25 11:38:46 +0000
committerbors[bot] <bors[bot]@users.noreply.github.com>2019-03-25 11:38:46 +0000
commitc4ead49361e4b8c0586b810399c8e96a468b891c (patch)
tree0b1ba767e34e3baef938f6b7672f95ce4572ec07 /crates/ra_hir/src/nameres
parent8aedf9603df1bc68eafcd8dcf3c14e5a6a2c8638 (diff)
parent309716cffe93d065bcad0344b0f332425576c1e5 (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')
-rw-r--r--crates/ra_hir/src/nameres/collector.rs70
-rw-r--r--crates/ra_hir/src/nameres/tests.rs19
2 files changed, 53 insertions, 36 deletions
diff --git a/crates/ra_hir/src/nameres/collector.rs b/crates/ra_hir/src/nameres/collector.rs
index c5b73cfbe..8830b4624 100644
--- a/crates/ra_hir/src/nameres/collector.rs
+++ b/crates/ra_hir/src/nameres/collector.rs
@@ -6,14 +6,17 @@ use ra_db::FileId;
6 6
7use crate::{ 7use crate::{
8 Function, Module, Struct, Enum, Const, Static, Trait, TypeAlias, 8 Function, Module, Struct, Enum, Const, Static, Trait, TypeAlias,
9 DefDatabase, HirFileId, Name, Path, Problem, Crate, 9 DefDatabase, HirFileId, Name, Path, Crate,
10 KnownName, 10 KnownName,
11 nameres::{Resolution, PerNs, ModuleDef, ReachedFixedPoint, ResolveMode, raw}, 11 nameres::{
12 Resolution, PerNs, ModuleDef, ReachedFixedPoint, ResolveMode,
13 CrateDefMap, CrateModuleId, ModuleData, CrateMacroId,
14 diagnostics::DefDiagnostic,
15 raw,
16 },
12 ids::{AstItemDef, LocationCtx, MacroCallLoc, SourceItemId, MacroCallId}, 17 ids::{AstItemDef, LocationCtx, MacroCallLoc, SourceItemId, MacroCallId},
13}; 18};
14 19
15use super::{CrateDefMap, CrateModuleId, ModuleData, CrateMacroId};
16
17pub(super) fn collect_defs(db: &impl DefDatabase, mut def_map: CrateDefMap) -> CrateDefMap { 20pub(super) fn collect_defs(db: &impl DefDatabase, mut def_map: CrateDefMap) -> CrateDefMap {
18 // populate external prelude 21 // populate external prelude
19 for dep in def_map.krate.dependencies(db) { 22 for dep in def_map.krate.dependencies(db) {
@@ -405,25 +408,27 @@ where
405 raw::ModuleData::Declaration { name, source_item_id } => { 408 raw::ModuleData::Declaration { name, source_item_id } => {
406 let source_item_id = source_item_id.with_file_id(self.file_id); 409 let source_item_id = source_item_id.with_file_id(self.file_id);
407 let is_root = self.def_collector.def_map.modules[self.module_id].parent.is_none(); 410 let is_root = self.def_collector.def_map.modules[self.module_id].parent.is_none();
408 let (file_ids, problem) = 411 match resolve_submodule(self.def_collector.db, self.file_id, name, is_root) {
409 resolve_submodule(self.def_collector.db, self.file_id, name, is_root); 412 Ok(file_id) => {
410 413 let module_id =
411 if let Some(problem) = problem { 414 self.push_child_module(name.clone(), source_item_id, Some(file_id));
412 self.def_collector.def_map.problems.add(source_item_id, problem) 415 let raw_items = self.def_collector.db.raw_items(file_id);
413 } 416 ModCollector {
414 417 def_collector: &mut *self.def_collector,
415 if let Some(&file_id) = file_ids.first() { 418 module_id,
416 let module_id = 419 file_id: file_id.into(),
417 self.push_child_module(name.clone(), source_item_id, Some(file_id)); 420 raw_items: &raw_items,
418 let raw_items = self.def_collector.db.raw_items(file_id); 421 }
419 ModCollector { 422 .collect(raw_items.items())
420 def_collector: &mut *self.def_collector,
421 module_id,
422 file_id: file_id.into(),
423 raw_items: &raw_items,
424 } 423 }
425 .collect(raw_items.items()) 424 Err(candidate) => self.def_collector.def_map.diagnostics.push(
426 } 425 DefDiagnostic::UnresolvedModule {
426 module: self.module_id,
427 declaration: source_item_id,
428 candidate,
429 },
430 ),
431 };
427 } 432 }
428 } 433 }
429 } 434 }
@@ -524,7 +529,7 @@ fn resolve_submodule(
524 file_id: HirFileId, 529 file_id: HirFileId,
525 name: &Name, 530 name: &Name,
526 is_root: bool, 531 is_root: bool,
527) -> (Vec<FileId>, Option<Problem>) { 532) -> Result<FileId, RelativePathBuf> {
528 // FIXME: handle submodules of inline modules properly 533 // FIXME: handle submodules of inline modules properly
529 let file_id = file_id.original_file(db); 534 let file_id = file_id.original_file(db);
530 let source_root_id = db.file_source_root(file_id); 535 let source_root_id = db.file_source_root(file_id);
@@ -545,17 +550,10 @@ fn resolve_submodule(
545 candidates.push(file_dir_mod.clone()); 550 candidates.push(file_dir_mod.clone());
546 }; 551 };
547 let sr = db.source_root(source_root_id); 552 let sr = db.source_root(source_root_id);
548 let points_to = candidates 553 let mut points_to = candidates.into_iter().filter_map(|path| sr.files.get(&path)).map(|&it| it);
549 .into_iter() 554 // FIXME: handle ambiguity
550 .filter_map(|path| sr.files.get(&path)) 555 match points_to.next() {
551 .map(|&it| it) 556 Some(file_id) => Ok(file_id),
552 .collect::<Vec<_>>(); 557 None => Err(if is_dir_owner { file_mod } else { file_dir_mod }),
553 let problem = if points_to.is_empty() { 558 }
554 Some(Problem::UnresolvedModule {
555 candidate: if is_dir_owner { file_mod } else { file_dir_mod },
556 })
557 } else {
558 None
559 };
560 (points_to, problem)
561} 559}
diff --git a/crates/ra_hir/src/nameres/tests.rs b/crates/ra_hir/src/nameres/tests.rs
index ac9b88520..572bd1bf7 100644
--- a/crates/ra_hir/src/nameres/tests.rs
+++ b/crates/ra_hir/src/nameres/tests.rs
@@ -552,3 +552,22 @@ foo: v
552"### 552"###
553 ); 553 );
554} 554}
555
556#[test]
557fn unresolved_module_diagnostics() {
558 let diagnostics = MockDatabase::with_files(
559 r"
560 //- /lib.rs
561 mod foo;
562 mod bar;
563 mod baz {}
564 //- /foo.rs
565 ",
566 )
567 .diagnostics();
568
569 assert_snapshot_matches!(diagnostics, @r###"
570"mod bar;": unresolved module
571"###
572 );
573}