aboutsummaryrefslogtreecommitdiff
path: root/crates
diff options
context:
space:
mode:
Diffstat (limited to 'crates')
-rw-r--r--crates/base_db/Cargo.toml2
-rw-r--r--crates/base_db/src/cancellation.rs48
-rw-r--r--crates/base_db/src/fixture.rs10
-rw-r--r--crates/base_db/src/input.rs16
-rw-r--r--crates/base_db/src/lib.rs45
-rw-r--r--crates/hir/src/diagnostics.rs256
-rw-r--r--crates/hir/src/display.rs6
-rw-r--r--crates/hir/src/lib.rs226
-rw-r--r--crates/hir/src/semantics.rs29
-rw-r--r--crates/hir/src/source_analyzer.rs15
-rw-r--r--crates/hir_def/src/attr.rs24
-rw-r--r--crates/hir_def/src/body.rs25
-rw-r--r--crates/hir_def/src/body/diagnostics.rs32
-rw-r--r--crates/hir_def/src/body/lower.rs45
-rw-r--r--crates/hir_def/src/body/tests.rs16
-rw-r--r--crates/hir_def/src/data.rs8
-rw-r--r--crates/hir_def/src/diagnostics.rs227
-rw-r--r--crates/hir_def/src/generics.rs20
-rw-r--r--crates/hir_def/src/intern.rs3
-rw-r--r--crates/hir_def/src/item_tree.rs164
-rw-r--r--crates/hir_def/src/item_tree/lower.rs207
-rw-r--r--crates/hir_def/src/item_tree/pretty.rs53
-rw-r--r--crates/hir_def/src/item_tree/tests.rs21
-rw-r--r--crates/hir_def/src/lib.rs25
-rw-r--r--crates/hir_def/src/nameres.rs252
-rw-r--r--crates/hir_def/src/nameres/collector.rs136
-rw-r--r--crates/hir_def/src/nameres/diagnostics.rs105
-rw-r--r--crates/hir_def/src/nameres/proc_macro.rs10
-rw-r--r--crates/hir_def/src/nameres/tests/diagnostics.rs57
-rw-r--r--crates/hir_def/src/nameres/tests/incremental.rs74
-rw-r--r--crates/hir_def/src/path.rs29
-rw-r--r--crates/hir_def/src/path/lower.rs44
-rw-r--r--crates/hir_def/src/path/lower/lower_use.rs78
-rw-r--r--crates/hir_def/src/resolver.rs38
-rw-r--r--crates/hir_def/src/test_db.rs92
-rw-r--r--crates/hir_def/src/type_ref.rs14
-rw-r--r--crates/hir_expand/src/builtin_macro.rs37
-rw-r--r--crates/hir_expand/src/db.rs18
-rw-r--r--crates/hir_expand/src/eager.rs5
-rw-r--r--crates/hir_expand/src/hygiene.rs2
-rw-r--r--crates/hir_expand/src/lib.rs16
-rw-r--r--crates/hir_ty/Cargo.toml6
-rw-r--r--crates/hir_ty/src/chalk_db.rs8
-rw-r--r--crates/hir_ty/src/diagnostics.rs12
-rw-r--r--crates/hir_ty/src/diagnostics/decl_check.rs6
-rw-r--r--crates/hir_ty/src/diagnostics/expr.rs15
-rw-r--r--crates/hir_ty/src/diagnostics/unsafe_check.rs6
-rw-r--r--crates/hir_ty/src/diagnostics_sink.rs (renamed from crates/hir_expand/src/diagnostics.rs)3
-rw-r--r--crates/hir_ty/src/display.rs13
-rw-r--r--crates/hir_ty/src/infer.rs45
-rw-r--r--crates/hir_ty/src/infer/coerce.rs12
-rw-r--r--crates/hir_ty/src/infer/expr.rs49
-rw-r--r--crates/hir_ty/src/infer/pat.rs9
-rw-r--r--crates/hir_ty/src/infer/unify.rs7
-rw-r--r--crates/hir_ty/src/lib.rs1
-rw-r--r--crates/hir_ty/src/lower.rs5
-rw-r--r--crates/hir_ty/src/tests.rs45
-rw-r--r--crates/hir_ty/src/tests/coercion.rs101
-rw-r--r--crates/hir_ty/src/tests/incremental.rs51
-rw-r--r--crates/hir_ty/src/tests/macros.rs18
-rw-r--r--crates/hir_ty/src/tests/traits.rs157
-rw-r--r--crates/hir_ty/src/traits.rs2
-rw-r--r--crates/ide/src/annotations.rs100
-rw-r--r--crates/ide/src/diagnostics.rs72
-rw-r--r--crates/ide/src/doc_links.rs6
-rw-r--r--crates/ide/src/fixture.rs17
-rwxr-xr-xcrates/ide/src/folding_ranges.rs17
-rw-r--r--crates/ide/src/goto_implementation.rs70
-rw-r--r--crates/ide/src/goto_type_definition.rs32
-rw-r--r--crates/ide/src/inlay_hints.rs2
-rw-r--r--crates/ide/src/lib.rs128
-rw-r--r--crates/ide/src/runnables.rs2
-rw-r--r--crates/ide/src/syntax_highlighting.rs101
-rw-r--r--crates/ide/src/syntax_highlighting/highlight.rs107
-rw-r--r--crates/ide/src/syntax_highlighting/tags.rs6
-rw-r--r--crates/ide/src/syntax_highlighting/test_data/highlighting.html18
-rw-r--r--crates/ide/src/syntax_highlighting/tests.rs44
-rw-r--r--crates/ide_assists/src/handlers/expand_glob_import.rs2
-rw-r--r--crates/ide_assists/src/handlers/fill_match_arms.rs148
-rw-r--r--crates/ide_assists/src/handlers/fix_visibility.rs2
-rw-r--r--crates/ide_assists/src/handlers/generate_getter.rs292
-rw-r--r--crates/ide_assists/src/handlers/generate_getter_mut.rs195
-rw-r--r--crates/ide_assists/src/lib.rs3
-rw-r--r--crates/ide_assists/src/tests.rs2
-rw-r--r--crates/ide_assists/src/tests/generated.rs10
-rw-r--r--crates/ide_completion/Cargo.toml1
-rw-r--r--crates/ide_completion/src/completions.rs42
-rw-r--r--crates/ide_completion/src/completions/attribute.rs939
-rw-r--r--crates/ide_completion/src/completions/attribute/derive.rs147
-rw-r--r--crates/ide_completion/src/completions/attribute/lint.rs187
-rw-r--r--crates/ide_completion/src/completions/dot.rs84
-rw-r--r--crates/ide_completion/src/completions/flyimport.rs8
-rw-r--r--crates/ide_completion/src/completions/fn_param.rs15
-rw-r--r--crates/ide_completion/src/completions/keyword.rs249
-rw-r--r--crates/ide_completion/src/completions/lifetime.rs12
-rw-r--r--crates/ide_completion/src/completions/macro_in_item_position.rs19
-rw-r--r--crates/ide_completion/src/completions/mod_.rs6
-rw-r--r--crates/ide_completion/src/completions/pattern.rs49
-rw-r--r--crates/ide_completion/src/completions/qualified_path.rs92
-rw-r--r--crates/ide_completion/src/completions/record.rs43
-rw-r--r--crates/ide_completion/src/completions/snippet.rs8
-rw-r--r--crates/ide_completion/src/completions/unqualified_path.rs94
-rw-r--r--crates/ide_completion/src/config.rs1
-rw-r--r--crates/ide_completion/src/context.rs495
-rw-r--r--crates/ide_completion/src/lib.rs4
-rw-r--r--crates/ide_completion/src/patterns.rs478
-rw-r--r--crates/ide_completion/src/render.rs161
-rw-r--r--crates/ide_completion/src/render/enum_variant.rs55
-rw-r--r--crates/ide_completion/src/render/function.rs50
-rw-r--r--crates/ide_completion/src/render/macro_.rs15
-rw-r--r--crates/ide_completion/src/test_utils.rs19
-rw-r--r--crates/ide_db/src/call_info/tests.rs24
-rw-r--r--crates/ide_db/src/defs.rs2
-rw-r--r--crates/ide_db/src/helpers/import_assets.rs19
-rw-r--r--crates/ide_db/src/lib.rs20
-rw-r--r--crates/ide_db/src/symbol_index.rs2
-rw-r--r--crates/ide_db/src/traits/tests.rs6
-rw-r--r--crates/ide_db/src/ty_filter.rs6
-rw-r--r--crates/mbe/src/expander/matcher.rs2
-rw-r--r--crates/mbe/src/lib.rs10
-rw-r--r--crates/mbe/src/syntax_bridge.rs83
-rw-r--r--crates/mbe/src/tests/expand.rs5
-rw-r--r--crates/mbe/src/token_map.rs85
-rw-r--r--crates/proc_macro_api/Cargo.toml2
-rw-r--r--crates/proc_macro_srv/Cargo.toml7
-rw-r--r--crates/proc_macro_srv/src/dylib.rs2
-rw-r--r--crates/proc_macro_srv/src/tests/fixtures/test_serialize_proc_macro.txt181
-rw-r--r--crates/proc_macro_srv/src/tests/mod.rs92
-rw-r--r--crates/proc_macro_srv/src/tests/utils.rs41
-rw-r--r--crates/proc_macro_test/src/lib.rs38
-rw-r--r--crates/project_model/src/build_data.rs6
-rw-r--r--crates/project_model/src/cargo_workspace.rs43
-rw-r--r--crates/project_model/src/sysroot.rs4
-rw-r--r--crates/project_model/src/workspace.rs89
-rw-r--r--crates/rust-analyzer/src/bin/main.rs85
-rw-r--r--crates/rust-analyzer/src/caps.rs22
-rw-r--r--crates/rust-analyzer/src/cli/analysis_stats.rs87
-rw-r--r--crates/rust-analyzer/src/config.rs48
-rw-r--r--crates/rust-analyzer/src/diagnostics/test_data/clippy_pass_by_ref.txt11
-rw-r--r--crates/rust-analyzer/src/diagnostics/test_data/handles_macro_location.txt2
-rw-r--r--crates/rust-analyzer/src/diagnostics/test_data/macro_compiler_error.txt7
-rw-r--r--crates/rust-analyzer/src/diagnostics/test_data/rustc_incompatible_type_for_trait.txt2
-rw-r--r--crates/rust-analyzer/src/diagnostics/test_data/rustc_mismatched_type.txt2
-rw-r--r--crates/rust-analyzer/src/diagnostics/test_data/rustc_unused_variable.txt5
-rw-r--r--crates/rust-analyzer/src/diagnostics/test_data/rustc_unused_variable_as_hint.txt5
-rw-r--r--crates/rust-analyzer/src/diagnostics/test_data/rustc_unused_variable_as_info.txt5
-rw-r--r--crates/rust-analyzer/src/diagnostics/test_data/rustc_wrong_number_of_parameters.txt6
-rw-r--r--crates/rust-analyzer/src/diagnostics/test_data/snap_multi_line_fix.txt11
-rw-r--r--crates/rust-analyzer/src/dispatch.rs4
-rw-r--r--crates/rust-analyzer/src/global_state.rs5
-rw-r--r--crates/rust-analyzer/src/handlers.rs274
-rw-r--r--crates/rust-analyzer/src/integrated_benchmarks.rs2
-rw-r--r--crates/rust-analyzer/src/lsp_utils.rs6
-rw-r--r--crates/rust-analyzer/src/main_loop.rs6
-rw-r--r--crates/rust-analyzer/src/reload.rs15
-rw-r--r--crates/rust-analyzer/src/semantic_tokens.rs3
-rw-r--r--crates/rust-analyzer/src/to_proto.rs13
-rw-r--r--crates/syntax/Cargo.toml2
-rw-r--r--crates/syntax/src/ast/edit_in_place.rs21
-rw-r--r--crates/syntax/src/ast/node_ext.rs7
-rw-r--r--crates/test_utils/src/lib.rs15
161 files changed, 5674 insertions, 3516 deletions
diff --git a/crates/base_db/Cargo.toml b/crates/base_db/Cargo.toml
index 1724d2f85..69173ad1f 100644
--- a/crates/base_db/Cargo.toml
+++ b/crates/base_db/Cargo.toml
@@ -10,7 +10,7 @@ edition = "2018"
10doctest = false 10doctest = false
11 11
12[dependencies] 12[dependencies]
13salsa = "0.16.0" 13salsa = "0.17.0-pre.1"
14rustc-hash = "1.1.0" 14rustc-hash = "1.1.0"
15 15
16syntax = { path = "../syntax", version = "0.0.0" } 16syntax = { path = "../syntax", version = "0.0.0" }
diff --git a/crates/base_db/src/cancellation.rs b/crates/base_db/src/cancellation.rs
deleted file mode 100644
index 7420a1976..000000000
--- a/crates/base_db/src/cancellation.rs
+++ /dev/null
@@ -1,48 +0,0 @@
1//! Utility types to support cancellation.
2//!
3//! In a typical IDE use-case, requests and modification happen concurrently, as
4//! in the following scenario:
5//!
6//! * user types a character,
7//! * a syntax highlighting process is started
8//! * user types next character, while syntax highlighting *is still in
9//! progress*.
10//!
11//! In this situation, we want to react to modification as quickly as possible.
12//! At the same time, in-progress results are not very interesting, because they
13//! are invalidated by the edit anyway. So, we first cancel all in-flight
14//! requests, and then apply modification knowing that it won't interfere with
15//! any background processing (this bit is handled by salsa, see the
16//! `BaseDatabase::check_canceled` method).
17
18/// An "error" signifying that the operation was canceled.
19#[derive(Clone, PartialEq, Eq, Hash)]
20pub struct Canceled {
21 _private: (),
22}
23
24impl Canceled {
25 pub(crate) fn new() -> Canceled {
26 Canceled { _private: () }
27 }
28
29 pub fn throw() -> ! {
30 // We use resume and not panic here to avoid running the panic
31 // hook (that is, to avoid collecting and printing backtrace).
32 std::panic::resume_unwind(Box::new(Canceled::new()))
33 }
34}
35
36impl std::fmt::Display for Canceled {
37 fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
38 fmt.write_str("canceled")
39 }
40}
41
42impl std::fmt::Debug for Canceled {
43 fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
44 write!(fmt, "Canceled")
45 }
46}
47
48impl std::error::Error for Canceled {}
diff --git a/crates/base_db/src/fixture.rs b/crates/base_db/src/fixture.rs
index 0132565e4..69ceba735 100644
--- a/crates/base_db/src/fixture.rs
+++ b/crates/base_db/src/fixture.rs
@@ -34,19 +34,13 @@ pub trait WithFixture: Default + SourceDatabaseExt + 'static {
34 34
35 fn with_position(ra_fixture: &str) -> (Self, FilePosition) { 35 fn with_position(ra_fixture: &str) -> (Self, FilePosition) {
36 let (db, file_id, range_or_offset) = Self::with_range_or_offset(ra_fixture); 36 let (db, file_id, range_or_offset) = Self::with_range_or_offset(ra_fixture);
37 let offset = match range_or_offset { 37 let offset = range_or_offset.expect_offset();
38 RangeOrOffset::Range(_) => panic!("Expected a cursor position, got a range instead"),
39 RangeOrOffset::Offset(it) => it,
40 };
41 (db, FilePosition { file_id, offset }) 38 (db, FilePosition { file_id, offset })
42 } 39 }
43 40
44 fn with_range(ra_fixture: &str) -> (Self, FileRange) { 41 fn with_range(ra_fixture: &str) -> (Self, FileRange) {
45 let (db, file_id, range_or_offset) = Self::with_range_or_offset(ra_fixture); 42 let (db, file_id, range_or_offset) = Self::with_range_or_offset(ra_fixture);
46 let range = match range_or_offset { 43 let range = range_or_offset.expect_range();
47 RangeOrOffset::Range(it) => it,
48 RangeOrOffset::Offset(_) => panic!("Expected a cursor range, got a position instead"),
49 };
50 (db, FileRange { file_id, range }) 44 (db, FileRange { file_id, range })
51 } 45 }
52 46
diff --git a/crates/base_db/src/input.rs b/crates/base_db/src/input.rs
index 0ef77ef5d..23cb0c839 100644
--- a/crates/base_db/src/input.rs
+++ b/crates/base_db/src/input.rs
@@ -53,11 +53,15 @@ impl SourceRoot {
53} 53}
54 54
55/// `CrateGraph` is a bit of information which turns a set of text files into a 55/// `CrateGraph` is a bit of information which turns a set of text files into a
56/// number of Rust crates. Each crate is defined by the `FileId` of its root module, 56/// number of Rust crates.
57/// the set of cfg flags (not yet implemented) and the set of dependencies. Note 57///
58/// that, due to cfg's, there might be several crates for a single `FileId`! As 58/// Each crate is defined by the `FileId` of its root module, the set of enabled
59/// in the rust-lang proper, a crate does not have a name. Instead, names are 59/// `cfg` flags and the set of dependencies.
60/// specified on dependency edges. That is, a crate might be known under 60///
61/// Note that, due to cfg's, there might be several crates for a single `FileId`!
62///
63/// For the purposes of analysis, a crate does not have a name. Instead, names
64/// are specified on dependency edges. That is, a crate might be known under
61/// different names in different dependent crates. 65/// different names in different dependent crates.
62/// 66///
63/// Note that `CrateGraph` is build-system agnostic: it's a concept of the Rust 67/// Note that `CrateGraph` is build-system agnostic: it's a concept of the Rust
@@ -143,7 +147,7 @@ impl CrateDisplayName {
143#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] 147#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
144pub struct ProcMacroId(pub u32); 148pub struct ProcMacroId(pub u32);
145 149
146#[derive(Copy, Clone, Eq, PartialEq, Debug)] 150#[derive(Copy, Clone, Eq, PartialEq, Debug, Hash)]
147pub enum ProcMacroKind { 151pub enum ProcMacroKind {
148 CustomDerive, 152 CustomDerive,
149 FuncLike, 153 FuncLike,
diff --git a/crates/base_db/src/lib.rs b/crates/base_db/src/lib.rs
index 980a0ed98..62bf2a4b2 100644
--- a/crates/base_db/src/lib.rs
+++ b/crates/base_db/src/lib.rs
@@ -1,5 +1,4 @@
1//! base_db defines basic database traits. The concrete DB is defined by ide. 1//! base_db defines basic database traits. The concrete DB is defined by ide.
2mod cancellation;
3mod input; 2mod input;
4mod change; 3mod change;
5pub mod fixture; 4pub mod fixture;
@@ -10,14 +9,13 @@ use rustc_hash::FxHashSet;
10use syntax::{ast, Parse, SourceFile, TextRange, TextSize}; 9use syntax::{ast, Parse, SourceFile, TextRange, TextSize};
11 10
12pub use crate::{ 11pub use crate::{
13 cancellation::Canceled,
14 change::Change, 12 change::Change,
15 input::{ 13 input::{
16 CrateData, CrateDisplayName, CrateGraph, CrateId, CrateName, Dependency, Edition, Env, 14 CrateData, CrateDisplayName, CrateGraph, CrateId, CrateName, Dependency, Edition, Env,
17 ProcMacro, ProcMacroExpander, ProcMacroId, ProcMacroKind, SourceRoot, SourceRootId, 15 ProcMacro, ProcMacroExpander, ProcMacroId, ProcMacroKind, SourceRoot, SourceRootId,
18 }, 16 },
19}; 17};
20pub use salsa; 18pub use salsa::{self, Cancelled};
21pub use vfs::{file_set::FileSet, AnchoredPath, AnchoredPathBuf, FileId, VfsPath}; 19pub use vfs::{file_set::FileSet, AnchoredPath, AnchoredPathBuf, FileId, VfsPath};
22 20
23#[macro_export] 21#[macro_export]
@@ -38,45 +36,6 @@ pub trait Upcast<T: ?Sized> {
38 fn upcast(&self) -> &T; 36 fn upcast(&self) -> &T;
39} 37}
40 38
41pub trait CheckCanceled {
42 /// Aborts current query if there are pending changes.
43 ///
44 /// rust-analyzer needs to be able to answer semantic questions about the
45 /// code while the code is being modified. A common problem is that a
46 /// long-running query is being calculated when a new change arrives.
47 ///
48 /// We can't just apply the change immediately: this will cause the pending
49 /// query to see inconsistent state (it will observe an absence of
50 /// repeatable read). So what we do is we **cancel** all pending queries
51 /// before applying the change.
52 ///
53 /// We implement cancellation by panicking with a special value and catching
54 /// it on the API boundary. Salsa explicitly supports this use-case.
55 fn check_canceled(&self);
56
57 fn catch_canceled<F, T>(&self, f: F) -> Result<T, Canceled>
58 where
59 Self: Sized + panic::RefUnwindSafe,
60 F: FnOnce(&Self) -> T + panic::UnwindSafe,
61 {
62 // Uncomment to debug missing cancellations.
63 // let _span = profile::heartbeat_span();
64 panic::catch_unwind(|| f(self)).map_err(|err| match err.downcast::<Canceled>() {
65 Ok(canceled) => *canceled,
66 Err(payload) => panic::resume_unwind(payload),
67 })
68 }
69}
70
71impl<T: salsa::Database> CheckCanceled for T {
72 fn check_canceled(&self) {
73 // profile::heartbeat();
74 if self.salsa_runtime().is_current_revision_canceled() {
75 Canceled::throw()
76 }
77 }
78}
79
80#[derive(Clone, Copy, Debug)] 39#[derive(Clone, Copy, Debug)]
81pub struct FilePosition { 40pub struct FilePosition {
82 pub file_id: FileId, 41 pub file_id: FileId,
@@ -101,7 +60,7 @@ pub trait FileLoader {
101/// Database which stores all significant input facts: source code and project 60/// Database which stores all significant input facts: source code and project
102/// model. Everything else in rust-analyzer is derived from these queries. 61/// model. Everything else in rust-analyzer is derived from these queries.
103#[salsa::query_group(SourceDatabaseStorage)] 62#[salsa::query_group(SourceDatabaseStorage)]
104pub trait SourceDatabase: CheckCanceled + FileLoader + std::fmt::Debug { 63pub trait SourceDatabase: FileLoader + std::fmt::Debug {
105 // Parses the file into the syntax tree. 64 // Parses the file into the syntax tree.
106 #[salsa::invoke(parse_query)] 65 #[salsa::invoke(parse_query)]
107 fn parse(&self, file_id: FileId) -> Parse<ast::SourceFile>; 66 fn parse(&self, file_id: FileId) -> Parse<ast::SourceFile>;
diff --git a/crates/hir/src/diagnostics.rs b/crates/hir/src/diagnostics.rs
index 414c3f35e..2cdbd172a 100644
--- a/crates/hir/src/diagnostics.rs
+++ b/crates/hir/src/diagnostics.rs
@@ -3,13 +3,251 @@
3//! 3//!
4//! This probably isn't the best way to do this -- ideally, diagnistics should 4//! This probably isn't the best way to do this -- ideally, diagnistics should
5//! be expressed in terms of hir types themselves. 5//! be expressed in terms of hir types themselves.
6pub use hir_def::diagnostics::{ 6use std::any::Any;
7 InactiveCode, UnresolvedMacroCall, UnresolvedModule, UnresolvedProcMacro, 7
8}; 8use cfg::{CfgExpr, CfgOptions, DnfExpr};
9pub use hir_expand::diagnostics::{ 9use hir_def::path::ModPath;
10 Diagnostic, DiagnosticCode, DiagnosticSink, DiagnosticSinkBuilder, 10use hir_expand::{HirFileId, InFile};
11}; 11use stdx::format_to;
12pub use hir_ty::diagnostics::{ 12use syntax::{ast, AstPtr, SyntaxNodePtr, TextRange};
13 IncorrectCase, MismatchedArgCount, MissingFields, MissingMatchArms, MissingOkOrSomeInTailExpr, 13
14 NoSuchField, RemoveThisSemicolon, ReplaceFilterMapNextWithFindMap, 14pub use hir_ty::{
15 diagnostics::{
16 IncorrectCase, MismatchedArgCount, MissingFields, MissingMatchArms,
17 MissingOkOrSomeInTailExpr, NoSuchField, RemoveThisSemicolon,
18 ReplaceFilterMapNextWithFindMap,
19 },
20 diagnostics_sink::{Diagnostic, DiagnosticCode, DiagnosticSink, DiagnosticSinkBuilder},
15}; 21};
22
23// Diagnostic: unresolved-module
24//
25// This diagnostic is triggered if rust-analyzer is unable to discover referred module.
26#[derive(Debug)]
27pub struct UnresolvedModule {
28 pub file: HirFileId,
29 pub decl: AstPtr<ast::Module>,
30 pub candidate: String,
31}
32
33impl Diagnostic for UnresolvedModule {
34 fn code(&self) -> DiagnosticCode {
35 DiagnosticCode("unresolved-module")
36 }
37 fn message(&self) -> String {
38 "unresolved module".to_string()
39 }
40 fn display_source(&self) -> InFile<SyntaxNodePtr> {
41 InFile::new(self.file, self.decl.clone().into())
42 }
43 fn as_any(&self) -> &(dyn Any + Send + 'static) {
44 self
45 }
46}
47
48// Diagnostic: unresolved-extern-crate
49//
50// This diagnostic is triggered if rust-analyzer is unable to discover referred extern crate.
51#[derive(Debug)]
52pub struct UnresolvedExternCrate {
53 pub file: HirFileId,
54 pub item: AstPtr<ast::ExternCrate>,
55}
56
57impl Diagnostic for UnresolvedExternCrate {
58 fn code(&self) -> DiagnosticCode {
59 DiagnosticCode("unresolved-extern-crate")
60 }
61 fn message(&self) -> String {
62 "unresolved extern crate".to_string()
63 }
64 fn display_source(&self) -> InFile<SyntaxNodePtr> {
65 InFile::new(self.file, self.item.clone().into())
66 }
67 fn as_any(&self) -> &(dyn Any + Send + 'static) {
68 self
69 }
70}
71
72#[derive(Debug)]
73pub struct UnresolvedImport {
74 pub file: HirFileId,
75 pub node: AstPtr<ast::UseTree>,
76}
77
78impl Diagnostic for UnresolvedImport {
79 fn code(&self) -> DiagnosticCode {
80 DiagnosticCode("unresolved-import")
81 }
82 fn message(&self) -> String {
83 "unresolved import".to_string()
84 }
85 fn display_source(&self) -> InFile<SyntaxNodePtr> {
86 InFile::new(self.file, self.node.clone().into())
87 }
88 fn as_any(&self) -> &(dyn Any + Send + 'static) {
89 self
90 }
91 fn is_experimental(&self) -> bool {
92 // This currently results in false positives in the following cases:
93 // - `cfg_if!`-generated code in libstd (we don't load the sysroot correctly)
94 // - `core::arch` (we don't handle `#[path = "../<path>"]` correctly)
95 // - proc macros and/or proc macro generated code
96 true
97 }
98}
99
100// Diagnostic: unresolved-macro-call
101//
102// This diagnostic is triggered if rust-analyzer is unable to resolve the path to a
103// macro in a macro invocation.
104#[derive(Debug, Clone, Eq, PartialEq)]
105pub struct UnresolvedMacroCall {
106 pub file: HirFileId,
107 pub node: AstPtr<ast::MacroCall>,
108 pub path: ModPath,
109}
110
111impl Diagnostic for UnresolvedMacroCall {
112 fn code(&self) -> DiagnosticCode {
113 DiagnosticCode("unresolved-macro-call")
114 }
115 fn message(&self) -> String {
116 format!("unresolved macro `{}!`", self.path)
117 }
118 fn display_source(&self) -> InFile<SyntaxNodePtr> {
119 InFile::new(self.file, self.node.clone().into())
120 }
121 fn as_any(&self) -> &(dyn Any + Send + 'static) {
122 self
123 }
124 fn is_experimental(&self) -> bool {
125 true
126 }
127}
128
129// Diagnostic: inactive-code
130//
131// This diagnostic is shown for code with inactive `#[cfg]` attributes.
132#[derive(Debug, Clone, Eq, PartialEq)]
133pub struct InactiveCode {
134 pub file: HirFileId,
135 pub node: SyntaxNodePtr,
136 pub cfg: CfgExpr,
137 pub opts: CfgOptions,
138}
139
140impl Diagnostic for InactiveCode {
141 fn code(&self) -> DiagnosticCode {
142 DiagnosticCode("inactive-code")
143 }
144 fn message(&self) -> String {
145 let inactive = DnfExpr::new(self.cfg.clone()).why_inactive(&self.opts);
146 let mut buf = "code is inactive due to #[cfg] directives".to_string();
147
148 if let Some(inactive) = inactive {
149 format_to!(buf, ": {}", inactive);
150 }
151
152 buf
153 }
154 fn display_source(&self) -> InFile<SyntaxNodePtr> {
155 InFile::new(self.file, self.node.clone())
156 }
157 fn as_any(&self) -> &(dyn Any + Send + 'static) {
158 self
159 }
160}
161
162// Diagnostic: unresolved-proc-macro
163//
164// This diagnostic is shown when a procedural macro can not be found. This usually means that
165// procedural macro support is simply disabled (and hence is only a weak hint instead of an error),
166// but can also indicate project setup problems.
167//
168// If you are seeing a lot of "proc macro not expanded" warnings, you can add this option to the
169// `rust-analyzer.diagnostics.disabled` list to prevent them from showing. Alternatively you can
170// enable support for procedural macros (see `rust-analyzer.procMacro.enable`).
171#[derive(Debug, Clone, Eq, PartialEq)]
172pub struct UnresolvedProcMacro {
173 pub file: HirFileId,
174 pub node: SyntaxNodePtr,
175 /// If the diagnostic can be pinpointed more accurately than via `node`, this is the `TextRange`
176 /// to use instead.
177 pub precise_location: Option<TextRange>,
178 pub macro_name: Option<String>,
179}
180
181impl Diagnostic for UnresolvedProcMacro {
182 fn code(&self) -> DiagnosticCode {
183 DiagnosticCode("unresolved-proc-macro")
184 }
185
186 fn message(&self) -> String {
187 match &self.macro_name {
188 Some(name) => format!("proc macro `{}` not expanded", name),
189 None => "proc macro not expanded".to_string(),
190 }
191 }
192
193 fn display_source(&self) -> InFile<SyntaxNodePtr> {
194 InFile::new(self.file, self.node.clone())
195 }
196
197 fn as_any(&self) -> &(dyn Any + Send + 'static) {
198 self
199 }
200}
201
202// Diagnostic: macro-error
203//
204// This diagnostic is shown for macro expansion errors.
205#[derive(Debug, Clone, Eq, PartialEq)]
206pub struct MacroError {
207 pub file: HirFileId,
208 pub node: SyntaxNodePtr,
209 pub message: String,
210}
211
212impl Diagnostic for MacroError {
213 fn code(&self) -> DiagnosticCode {
214 DiagnosticCode("macro-error")
215 }
216 fn message(&self) -> String {
217 self.message.clone()
218 }
219 fn display_source(&self) -> InFile<SyntaxNodePtr> {
220 InFile::new(self.file, self.node.clone())
221 }
222 fn as_any(&self) -> &(dyn Any + Send + 'static) {
223 self
224 }
225 fn is_experimental(&self) -> bool {
226 // Newly added and not very well-tested, might contain false positives.
227 true
228 }
229}
230
231#[derive(Debug)]
232pub struct UnimplementedBuiltinMacro {
233 pub file: HirFileId,
234 pub node: SyntaxNodePtr,
235}
236
237impl Diagnostic for UnimplementedBuiltinMacro {
238 fn code(&self) -> DiagnosticCode {
239 DiagnosticCode("unimplemented-builtin-macro")
240 }
241
242 fn message(&self) -> String {
243 "unimplemented built-in macro".to_string()
244 }
245
246 fn display_source(&self) -> InFile<SyntaxNodePtr> {
247 InFile::new(self.file, self.node.clone())
248 }
249
250 fn as_any(&self) -> &(dyn Any + Send + 'static) {
251 self
252 }
253}
diff --git a/crates/hir/src/display.rs b/crates/hir/src/display.rs
index 508ac37c2..72f0d9b5f 100644
--- a/crates/hir/src/display.rs
+++ b/crates/hir/src/display.rs
@@ -92,7 +92,7 @@ impl HirDisplay for Function {
92 &data.ret_type 92 &data.ret_type
93 } else { 93 } else {
94 match &*data.ret_type { 94 match &*data.ret_type {
95 TypeRef::ImplTrait(bounds) => match &bounds[0] { 95 TypeRef::ImplTrait(bounds) => match bounds[0].as_ref() {
96 TypeBound::Path(path) => { 96 TypeBound::Path(path) => {
97 path.segments().iter().last().unwrap().args_and_bindings.unwrap().bindings 97 path.segments().iter().last().unwrap().args_and_bindings.unwrap().bindings
98 [0] 98 [0]
@@ -427,10 +427,6 @@ impl HirDisplay for Trait {
427 write!(f, "trait {}", data.name)?; 427 write!(f, "trait {}", data.name)?;
428 let def_id = GenericDefId::TraitId(self.id); 428 let def_id = GenericDefId::TraitId(self.id);
429 write_generic_params(def_id, f)?; 429 write_generic_params(def_id, f)?;
430 if !data.bounds.is_empty() {
431 write!(f, ": ")?;
432 f.write_joined(&*data.bounds, " + ")?;
433 }
434 write_where_clause(def_id, f)?; 430 write_where_clause(def_id, f)?;
435 Ok(()) 431 Ok(())
436 } 432 }
diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs
index a7c42ca1e..d3ef29db4 100644
--- a/crates/hir/src/lib.rs
+++ b/crates/hir/src/lib.rs
@@ -35,12 +35,18 @@ use std::{iter, sync::Arc};
35 35
36use arrayvec::ArrayVec; 36use arrayvec::ArrayVec;
37use base_db::{CrateDisplayName, CrateId, Edition, FileId}; 37use base_db::{CrateDisplayName, CrateId, Edition, FileId};
38use diagnostics::{
39 InactiveCode, MacroError, UnimplementedBuiltinMacro, UnresolvedExternCrate, UnresolvedImport,
40 UnresolvedMacroCall, UnresolvedModule, UnresolvedProcMacro,
41};
38use either::Either; 42use either::Either;
39use hir_def::{ 43use hir_def::{
40 adt::{ReprKind, VariantData}, 44 adt::{ReprKind, VariantData},
45 body::BodyDiagnostic,
41 expr::{BindingAnnotation, LabelId, Pat, PatId}, 46 expr::{BindingAnnotation, LabelId, Pat, PatId},
42 item_tree::ItemTreeNode, 47 item_tree::ItemTreeNode,
43 lang_item::LangItemTarget, 48 lang_item::LangItemTarget,
49 nameres,
44 per_ns::PerNs, 50 per_ns::PerNs,
45 resolver::{HasResolver, Resolver}, 51 resolver::{HasResolver, Resolver},
46 src::HasSource as _, 52 src::HasSource as _,
@@ -50,11 +56,12 @@ use hir_def::{
50 LocalEnumVariantId, LocalFieldId, Lookup, ModuleId, StaticId, StructId, TraitId, TypeAliasId, 56 LocalEnumVariantId, LocalFieldId, Lookup, ModuleId, StaticId, StructId, TraitId, TypeAliasId,
51 TypeParamId, UnionId, 57 TypeParamId, UnionId,
52}; 58};
53use hir_expand::{diagnostics::DiagnosticSink, name::name, MacroDefKind}; 59use hir_expand::{name::name, MacroCallKind, MacroDefKind};
54use hir_ty::{ 60use hir_ty::{
55 autoderef, 61 autoderef,
56 consteval::ConstExt, 62 consteval::ConstExt,
57 could_unify, 63 could_unify,
64 diagnostics_sink::DiagnosticSink,
58 method_resolution::{self, def_crates, TyFingerprint}, 65 method_resolution::{self, def_crates, TyFingerprint},
59 primitive::UintTy, 66 primitive::UintTy,
60 subst_prefix, 67 subst_prefix,
@@ -65,11 +72,12 @@ use hir_ty::{
65 WhereClause, 72 WhereClause,
66}; 73};
67use itertools::Itertools; 74use itertools::Itertools;
75use nameres::diagnostics::DefDiagnosticKind;
68use rustc_hash::FxHashSet; 76use rustc_hash::FxHashSet;
69use stdx::{format_to, impl_from}; 77use stdx::{format_to, impl_from};
70use syntax::{ 78use syntax::{
71 ast::{self, AttrsOwner, NameOwner}, 79 ast::{self, AttrsOwner, NameOwner},
72 AstNode, SmolStr, 80 AstNode, AstPtr, SmolStr, SyntaxKind, SyntaxNodePtr,
73}; 81};
74use tt::{Ident, Leaf, Literal, TokenTree}; 82use tt::{Ident, Leaf, Literal, TokenTree};
75 83
@@ -442,7 +450,131 @@ impl Module {
442 format!("{:?}", self.name(db).map_or("<unknown>".into(), |name| name.to_string())) 450 format!("{:?}", self.name(db).map_or("<unknown>".into(), |name| name.to_string()))
443 }); 451 });
444 let def_map = self.id.def_map(db.upcast()); 452 let def_map = self.id.def_map(db.upcast());
445 def_map.add_diagnostics(db.upcast(), self.id.local_id, sink); 453 for diag in def_map.diagnostics() {
454 if diag.in_module != self.id.local_id {
455 // FIXME: This is accidentally quadratic.
456 continue;
457 }
458 match &diag.kind {
459 DefDiagnosticKind::UnresolvedModule { ast: declaration, candidate } => {
460 let decl = declaration.to_node(db.upcast());
461 sink.push(UnresolvedModule {
462 file: declaration.file_id,
463 decl: AstPtr::new(&decl),
464 candidate: candidate.clone(),
465 })
466 }
467 DefDiagnosticKind::UnresolvedExternCrate { ast } => {
468 let item = ast.to_node(db.upcast());
469 sink.push(UnresolvedExternCrate {
470 file: ast.file_id,
471 item: AstPtr::new(&item),
472 });
473 }
474
475 DefDiagnosticKind::UnresolvedImport { id, index } => {
476 let file_id = id.file_id();
477 let item_tree = id.item_tree(db.upcast());
478 let import = &item_tree[id.value];
479
480 let use_tree = import.use_tree_to_ast(db.upcast(), file_id, *index);
481 sink.push(UnresolvedImport { file: file_id, node: AstPtr::new(&use_tree) });
482 }
483
484 DefDiagnosticKind::UnconfiguredCode { ast, cfg, opts } => {
485 let item = ast.to_node(db.upcast());
486 sink.push(InactiveCode {
487 file: ast.file_id,
488 node: AstPtr::new(&item).into(),
489 cfg: cfg.clone(),
490 opts: opts.clone(),
491 });
492 }
493
494 DefDiagnosticKind::UnresolvedProcMacro { ast } => {
495 let mut precise_location = None;
496 let (file, ast, name) = match ast {
497 MacroCallKind::FnLike { ast_id, .. } => {
498 let node = ast_id.to_node(db.upcast());
499 (ast_id.file_id, SyntaxNodePtr::from(AstPtr::new(&node)), None)
500 }
501 MacroCallKind::Derive { ast_id, derive_name, .. } => {
502 let node = ast_id.to_node(db.upcast());
503
504 // Compute the precise location of the macro name's token in the derive
505 // list.
506 // FIXME: This does not handle paths to the macro, but neither does the
507 // rest of r-a.
508 let derive_attrs =
509 node.attrs().filter_map(|attr| match attr.as_simple_call() {
510 Some((name, args)) if name == "derive" => Some(args),
511 _ => None,
512 });
513 'outer: for attr in derive_attrs {
514 let tokens =
515 attr.syntax().children_with_tokens().filter_map(|elem| {
516 match elem {
517 syntax::NodeOrToken::Node(_) => None,
518 syntax::NodeOrToken::Token(tok) => Some(tok),
519 }
520 });
521 for token in tokens {
522 if token.kind() == SyntaxKind::IDENT
523 && token.text() == derive_name.as_str()
524 {
525 precise_location = Some(token.text_range());
526 break 'outer;
527 }
528 }
529 }
530
531 (
532 ast_id.file_id,
533 SyntaxNodePtr::from(AstPtr::new(&node)),
534 Some(derive_name.clone()),
535 )
536 }
537 };
538 sink.push(UnresolvedProcMacro {
539 file,
540 node: ast,
541 precise_location,
542 macro_name: name,
543 });
544 }
545
546 DefDiagnosticKind::UnresolvedMacroCall { ast, path } => {
547 let node = ast.to_node(db.upcast());
548 sink.push(UnresolvedMacroCall {
549 file: ast.file_id,
550 node: AstPtr::new(&node),
551 path: path.clone(),
552 });
553 }
554
555 DefDiagnosticKind::MacroError { ast, message } => {
556 let (file, ast) = match ast {
557 MacroCallKind::FnLike { ast_id, .. } => {
558 let node = ast_id.to_node(db.upcast());
559 (ast_id.file_id, SyntaxNodePtr::from(AstPtr::new(&node)))
560 }
561 MacroCallKind::Derive { ast_id, .. } => {
562 let node = ast_id.to_node(db.upcast());
563 (ast_id.file_id, SyntaxNodePtr::from(AstPtr::new(&node)))
564 }
565 };
566 sink.push(MacroError { file, node: ast, message: message.clone() });
567 }
568
569 DefDiagnosticKind::UnimplementedBuiltinMacro { ast } => {
570 let node = ast.to_node(db.upcast());
571 // Must have a name, otherwise we wouldn't emit it.
572 let name = node.name().expect("unimplemented builtin macro with no name");
573 let ptr = SyntaxNodePtr::from(AstPtr::new(&name));
574 sink.push(UnimplementedBuiltinMacro { file: ast.file_id, node: ptr });
575 }
576 }
577 }
446 for decl in self.declarations(db) { 578 for decl in self.declarations(db) {
447 match decl { 579 match decl {
448 crate::ModuleDef::Function(f) => f.diagnostics(db, sink), 580 crate::ModuleDef::Function(f) => f.diagnostics(db, sink),
@@ -513,9 +645,8 @@ impl Field {
513 } 645 }
514 646
515 /// Returns the type as in the signature of the struct (i.e., with 647 /// Returns the type as in the signature of the struct (i.e., with
516 /// placeholder types for type parameters). This is good for showing 648 /// placeholder types for type parameters). Only use this in the context of
517 /// signature help, but not so good to actually get the type of the field 649 /// the field definition.
518 /// when you actually have a variable of the struct.
519 pub fn ty(&self, db: &dyn HirDatabase) -> Type { 650 pub fn ty(&self, db: &dyn HirDatabase) -> Type {
520 let var_id = self.parent.into(); 651 let var_id = self.parent.into();
521 let generic_def_id: GenericDefId = match self.parent { 652 let generic_def_id: GenericDefId = match self.parent {
@@ -552,10 +683,6 @@ impl Struct {
552 Module { id: self.id.lookup(db.upcast()).container } 683 Module { id: self.id.lookup(db.upcast()).container }
553 } 684 }
554 685
555 pub fn krate(self, db: &dyn HirDatabase) -> Option<Crate> {
556 Some(self.module(db).krate())
557 }
558
559 pub fn name(self, db: &dyn HirDatabase) -> Name { 686 pub fn name(self, db: &dyn HirDatabase) -> Name {
560 db.struct_data(self.id).name.clone() 687 db.struct_data(self.id).name.clone()
561 } 688 }
@@ -640,10 +767,6 @@ impl Enum {
640 Module { id: self.id.lookup(db.upcast()).container } 767 Module { id: self.id.lookup(db.upcast()).container }
641 } 768 }
642 769
643 pub fn krate(self, db: &dyn HirDatabase) -> Option<Crate> {
644 Some(self.module(db).krate())
645 }
646
647 pub fn name(self, db: &dyn HirDatabase) -> Name { 770 pub fn name(self, db: &dyn HirDatabase) -> Name {
648 db.enum_data(self.id).name.clone() 771 db.enum_data(self.id).name.clone()
649 } 772 }
@@ -673,6 +796,7 @@ impl Variant {
673 pub fn module(self, db: &dyn HirDatabase) -> Module { 796 pub fn module(self, db: &dyn HirDatabase) -> Module {
674 self.parent.module(db) 797 self.parent.module(db)
675 } 798 }
799
676 pub fn parent_enum(self, _db: &dyn HirDatabase) -> Enum { 800 pub fn parent_enum(self, _db: &dyn HirDatabase) -> Enum {
677 self.parent 801 self.parent
678 } 802 }
@@ -729,10 +853,6 @@ impl Adt {
729 } 853 }
730 } 854 }
731 855
732 pub fn krate(self, db: &dyn HirDatabase) -> Crate {
733 self.module(db).krate()
734 }
735
736 pub fn name(self, db: &dyn HirDatabase) -> Name { 856 pub fn name(self, db: &dyn HirDatabase) -> Name {
737 match self { 857 match self {
738 Adt::Struct(s) => s.name(db), 858 Adt::Struct(s) => s.name(db),
@@ -821,10 +941,6 @@ impl Function {
821 self.id.lookup(db.upcast()).module(db.upcast()).into() 941 self.id.lookup(db.upcast()).module(db.upcast()).into()
822 } 942 }
823 943
824 pub fn krate(self, db: &dyn HirDatabase) -> Option<Crate> {
825 Some(self.module(db).krate())
826 }
827
828 pub fn name(self, db: &dyn HirDatabase) -> Name { 944 pub fn name(self, db: &dyn HirDatabase) -> Name {
829 db.function_data(self.id).name.clone() 945 db.function_data(self.id).name.clone()
830 } 946 }
@@ -881,7 +997,37 @@ impl Function {
881 997
882 pub fn diagnostics(self, db: &dyn HirDatabase, sink: &mut DiagnosticSink) { 998 pub fn diagnostics(self, db: &dyn HirDatabase, sink: &mut DiagnosticSink) {
883 let krate = self.module(db).id.krate(); 999 let krate = self.module(db).id.krate();
884 hir_def::diagnostics::validate_body(db.upcast(), self.id.into(), sink); 1000
1001 let source_map = db.body_with_source_map(self.id.into()).1;
1002 for diag in source_map.diagnostics() {
1003 match diag {
1004 BodyDiagnostic::InactiveCode { node, cfg, opts } => sink.push(InactiveCode {
1005 file: node.file_id,
1006 node: node.value.clone(),
1007 cfg: cfg.clone(),
1008 opts: opts.clone(),
1009 }),
1010 BodyDiagnostic::MacroError { node, message } => sink.push(MacroError {
1011 file: node.file_id,
1012 node: node.value.clone().into(),
1013 message: message.to_string(),
1014 }),
1015 BodyDiagnostic::UnresolvedProcMacro { node } => sink.push(UnresolvedProcMacro {
1016 file: node.file_id,
1017 node: node.value.clone().into(),
1018 precise_location: None,
1019 macro_name: None,
1020 }),
1021 BodyDiagnostic::UnresolvedMacroCall { node, path } => {
1022 sink.push(UnresolvedMacroCall {
1023 file: node.file_id,
1024 node: node.value.clone(),
1025 path: path.clone(),
1026 })
1027 }
1028 }
1029 }
1030
885 hir_ty::diagnostics::validate_module_item(db, krate, self.id.into(), sink); 1031 hir_ty::diagnostics::validate_module_item(db, krate, self.id.into(), sink);
886 hir_ty::diagnostics::validate_body(db, self.id.into(), sink); 1032 hir_ty::diagnostics::validate_body(db, self.id.into(), sink);
887 } 1033 }
@@ -1014,10 +1160,6 @@ impl Const {
1014 Module { id: self.id.lookup(db.upcast()).module(db.upcast()) } 1160 Module { id: self.id.lookup(db.upcast()).module(db.upcast()) }
1015 } 1161 }
1016 1162
1017 pub fn krate(self, db: &dyn HirDatabase) -> Option<Crate> {
1018 Some(self.module(db).krate())
1019 }
1020
1021 pub fn name(self, db: &dyn HirDatabase) -> Option<Name> { 1163 pub fn name(self, db: &dyn HirDatabase) -> Option<Name> {
1022 db.const_data(self.id).name.clone() 1164 db.const_data(self.id).name.clone()
1023 } 1165 }
@@ -1045,10 +1187,6 @@ impl Static {
1045 Module { id: self.id.lookup(db.upcast()).module(db.upcast()) } 1187 Module { id: self.id.lookup(db.upcast()).module(db.upcast()) }
1046 } 1188 }
1047 1189
1048 pub fn krate(self, db: &dyn HirDatabase) -> Option<Crate> {
1049 Some(self.module(db).krate())
1050 }
1051
1052 pub fn name(self, db: &dyn HirDatabase) -> Option<Name> { 1190 pub fn name(self, db: &dyn HirDatabase) -> Option<Name> {
1053 db.static_data(self.id).name.clone() 1191 db.static_data(self.id).name.clone()
1054 } 1192 }
@@ -1112,10 +1250,6 @@ impl TypeAlias {
1112 Module { id: self.id.lookup(db.upcast()).module(db.upcast()) } 1250 Module { id: self.id.lookup(db.upcast()).module(db.upcast()) }
1113 } 1251 }
1114 1252
1115 pub fn krate(self, db: &dyn HirDatabase) -> Crate {
1116 self.module(db).krate()
1117 }
1118
1119 pub fn type_ref(self, db: &dyn HirDatabase) -> Option<TypeRef> { 1253 pub fn type_ref(self, db: &dyn HirDatabase) -> Option<TypeRef> {
1120 db.type_alias_data(self.id).type_ref.as_deref().cloned() 1254 db.type_alias_data(self.id).type_ref.as_deref().cloned()
1121 } 1255 }
@@ -1156,10 +1290,16 @@ impl BuiltinType {
1156 1290
1157#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] 1291#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
1158pub enum MacroKind { 1292pub enum MacroKind {
1293 /// `macro_rules!` or Macros 2.0 macro.
1159 Declarative, 1294 Declarative,
1160 ProcMacro, 1295 /// A built-in or custom derive.
1161 Derive, 1296 Derive,
1297 /// A built-in function-like macro.
1162 BuiltIn, 1298 BuiltIn,
1299 /// A procedural attribute macro.
1300 Attr,
1301 /// A function-like procedural macro.
1302 ProcMacro,
1163} 1303}
1164 1304
1165#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] 1305#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
@@ -1189,11 +1329,13 @@ impl MacroDef {
1189 pub fn kind(&self) -> MacroKind { 1329 pub fn kind(&self) -> MacroKind {
1190 match self.id.kind { 1330 match self.id.kind {
1191 MacroDefKind::Declarative(_) => MacroKind::Declarative, 1331 MacroDefKind::Declarative(_) => MacroKind::Declarative,
1192 MacroDefKind::BuiltIn(_, _) => MacroKind::BuiltIn, 1332 MacroDefKind::BuiltIn(_, _) | MacroDefKind::BuiltInEager(_, _) => MacroKind::BuiltIn,
1193 MacroDefKind::BuiltInDerive(_, _) => MacroKind::Derive, 1333 MacroDefKind::BuiltInDerive(_, _) => MacroKind::Derive,
1194 MacroDefKind::BuiltInEager(_, _) => MacroKind::BuiltIn, 1334 MacroDefKind::ProcMacro(_, base_db::ProcMacroKind::CustomDerive, _) => {
1195 // FIXME might be a derive 1335 MacroKind::Derive
1196 MacroDefKind::ProcMacro(_, _) => MacroKind::ProcMacro, 1336 }
1337 MacroDefKind::ProcMacro(_, base_db::ProcMacroKind::Attr, _) => MacroKind::Attr,
1338 MacroDefKind::ProcMacro(_, base_db::ProcMacroKind::FuncLike, _) => MacroKind::ProcMacro,
1197 } 1339 }
1198 } 1340 }
1199} 1341}
@@ -1667,10 +1809,6 @@ impl Impl {
1667 self.id.lookup(db.upcast()).container.into() 1809 self.id.lookup(db.upcast()).container.into()
1668 } 1810 }
1669 1811
1670 pub fn krate(self, db: &dyn HirDatabase) -> Crate {
1671 Crate { id: self.module(db).id.krate() }
1672 }
1673
1674 pub fn is_builtin_derive(self, db: &dyn HirDatabase) -> Option<InFile<ast::Attr>> { 1812 pub fn is_builtin_derive(self, db: &dyn HirDatabase) -> Option<InFile<ast::Attr>> {
1675 let src = self.source(db)?; 1813 let src = self.source(db)?;
1676 let item = src.file_id.is_builtin_derive(db.upcast())?; 1814 let item = src.file_id.is_builtin_derive(db.upcast())?;
diff --git a/crates/hir/src/semantics.rs b/crates/hir/src/semantics.rs
index 1b5064b5a..c7f2c02e4 100644
--- a/crates/hir/src/semantics.rs
+++ b/crates/hir/src/semantics.rs
@@ -11,7 +11,7 @@ use hir_def::{
11 AsMacroCall, FunctionId, TraitId, VariantId, 11 AsMacroCall, FunctionId, TraitId, VariantId,
12}; 12};
13use hir_expand::{name::AsName, ExpansionInfo}; 13use hir_expand::{name::AsName, ExpansionInfo};
14use hir_ty::associated_type_shorthand_candidates; 14use hir_ty::{associated_type_shorthand_candidates, Interner};
15use itertools::Itertools; 15use itertools::Itertools;
16use rustc_hash::{FxHashMap, FxHashSet}; 16use rustc_hash::{FxHashMap, FxHashSet};
17use syntax::{ 17use syntax::{
@@ -120,10 +120,10 @@ impl<'db, DB: HirDatabase> Semantics<'db, DB> {
120 pub fn speculative_expand( 120 pub fn speculative_expand(
121 &self, 121 &self,
122 actual_macro_call: &ast::MacroCall, 122 actual_macro_call: &ast::MacroCall,
123 hypothetical_args: &ast::TokenTree, 123 speculative_args: &ast::TokenTree,
124 token_to_map: SyntaxToken, 124 token_to_map: SyntaxToken,
125 ) -> Option<(SyntaxNode, SyntaxToken)> { 125 ) -> Option<(SyntaxNode, SyntaxToken)> {
126 self.imp.speculative_expand(actual_macro_call, hypothetical_args, token_to_map) 126 self.imp.speculative_expand(actual_macro_call, speculative_args, token_to_map)
127 } 127 }
128 128
129 pub fn descend_into_macros(&self, token: SyntaxToken) -> SyntaxToken { 129 pub fn descend_into_macros(&self, token: SyntaxToken) -> SyntaxToken {
@@ -227,7 +227,7 @@ impl<'db, DB: HirDatabase> Semantics<'db, DB> {
227 pub fn resolve_record_field( 227 pub fn resolve_record_field(
228 &self, 228 &self,
229 field: &ast::RecordExprField, 229 field: &ast::RecordExprField,
230 ) -> Option<(Field, Option<Local>)> { 230 ) -> Option<(Field, Option<Local>, Type)> {
231 self.imp.resolve_record_field(field) 231 self.imp.resolve_record_field(field)
232 } 232 }
233 233
@@ -335,7 +335,7 @@ impl<'db> SemanticsImpl<'db> {
335 fn speculative_expand( 335 fn speculative_expand(
336 &self, 336 &self,
337 actual_macro_call: &ast::MacroCall, 337 actual_macro_call: &ast::MacroCall,
338 hypothetical_args: &ast::TokenTree, 338 speculative_args: &ast::TokenTree,
339 token_to_map: SyntaxToken, 339 token_to_map: SyntaxToken,
340 ) -> Option<(SyntaxNode, SyntaxToken)> { 340 ) -> Option<(SyntaxNode, SyntaxToken)> {
341 let sa = self.analyze(actual_macro_call.syntax()); 341 let sa = self.analyze(actual_macro_call.syntax());
@@ -344,10 +344,10 @@ impl<'db> SemanticsImpl<'db> {
344 let macro_call_id = macro_call.as_call_id(self.db.upcast(), krate, |path| { 344 let macro_call_id = macro_call.as_call_id(self.db.upcast(), krate, |path| {
345 sa.resolver.resolve_path_as_macro(self.db.upcast(), &path) 345 sa.resolver.resolve_path_as_macro(self.db.upcast(), &path)
346 })?; 346 })?;
347 hir_expand::db::expand_hypothetical( 347 hir_expand::db::expand_speculative(
348 self.db.upcast(), 348 self.db.upcast(),
349 macro_call_id, 349 macro_call_id,
350 hypothetical_args, 350 speculative_args,
351 token_to_map, 351 token_to_map,
352 ) 352 )
353 } 353 }
@@ -361,7 +361,7 @@ impl<'db> SemanticsImpl<'db> {
361 let sa = self.analyze(&parent); 361 let sa = self.analyze(&parent);
362 362
363 let token = successors(Some(InFile::new(sa.file_id, token)), |token| { 363 let token = successors(Some(InFile::new(sa.file_id, token)), |token| {
364 self.db.check_canceled(); 364 self.db.unwind_if_cancelled();
365 let macro_call = token.value.ancestors().find_map(ast::MacroCall::cast)?; 365 let macro_call = token.value.ancestors().find_map(ast::MacroCall::cast)?;
366 let tt = macro_call.token_tree()?; 366 let tt = macro_call.token_tree()?;
367 if !tt.syntax().text_range().contains_range(token.value.text_range()) { 367 if !tt.syntax().text_range().contains_range(token.value.text_range()) {
@@ -501,14 +501,12 @@ impl<'db> SemanticsImpl<'db> {
501 } 501 }
502 502
503 fn resolve_method_call(&self, call: &ast::MethodCallExpr) -> Option<FunctionId> { 503 fn resolve_method_call(&self, call: &ast::MethodCallExpr) -> Option<FunctionId> {
504 self.analyze(call.syntax()).resolve_method_call(self.db, call) 504 self.analyze(call.syntax()).resolve_method_call(self.db, call).map(|(id, _)| id)
505 } 505 }
506 506
507 fn resolve_method_call_as_callable(&self, call: &ast::MethodCallExpr) -> Option<Callable> { 507 fn resolve_method_call_as_callable(&self, call: &ast::MethodCallExpr) -> Option<Callable> {
508 // FIXME: this erases Substs, we should instead record the correct 508 let (func, subst) = self.analyze(call.syntax()).resolve_method_call(self.db, call)?;
509 // substitution during inference and use that 509 let ty = self.db.value_ty(func.into()).substitute(&Interner, &subst);
510 let func = self.resolve_method_call(call)?;
511 let ty = hir_ty::TyBuilder::value_ty(self.db, func.into()).fill_with_unknown().build();
512 let resolver = self.analyze(call.syntax()).resolver; 510 let resolver = self.analyze(call.syntax()).resolver;
513 let ty = Type::new_with_resolver(self.db, &resolver, ty)?; 511 let ty = Type::new_with_resolver(self.db, &resolver, ty)?;
514 let mut res = ty.as_callable(self.db)?; 512 let mut res = ty.as_callable(self.db)?;
@@ -520,7 +518,10 @@ impl<'db> SemanticsImpl<'db> {
520 self.analyze(field.syntax()).resolve_field(self.db, field) 518 self.analyze(field.syntax()).resolve_field(self.db, field)
521 } 519 }
522 520
523 fn resolve_record_field(&self, field: &ast::RecordExprField) -> Option<(Field, Option<Local>)> { 521 fn resolve_record_field(
522 &self,
523 field: &ast::RecordExprField,
524 ) -> Option<(Field, Option<Local>, Type)> {
524 self.analyze(field.syntax()).resolve_record_field(self.db, field) 525 self.analyze(field.syntax()).resolve_record_field(self.db, field)
525 } 526 }
526 527
diff --git a/crates/hir/src/source_analyzer.rs b/crates/hir/src/source_analyzer.rs
index 20753314d..37a050415 100644
--- a/crates/hir/src/source_analyzer.rs
+++ b/crates/hir/src/source_analyzer.rs
@@ -143,7 +143,7 @@ impl SourceAnalyzer {
143 &self, 143 &self,
144 db: &dyn HirDatabase, 144 db: &dyn HirDatabase,
145 call: &ast::MethodCallExpr, 145 call: &ast::MethodCallExpr,
146 ) -> Option<FunctionId> { 146 ) -> Option<(FunctionId, Substitution)> {
147 let expr_id = self.expr_id(db, &call.clone().into())?; 147 let expr_id = self.expr_id(db, &call.clone().into())?;
148 self.infer.as_ref()?.method_resolution(expr_id) 148 self.infer.as_ref()?.method_resolution(expr_id)
149 } 149 }
@@ -161,7 +161,7 @@ impl SourceAnalyzer {
161 &self, 161 &self,
162 db: &dyn HirDatabase, 162 db: &dyn HirDatabase,
163 field: &ast::RecordExprField, 163 field: &ast::RecordExprField,
164 ) -> Option<(Field, Option<Local>)> { 164 ) -> Option<(Field, Option<Local>, Type)> {
165 let record_expr = ast::RecordExpr::cast(field.syntax().parent().and_then(|p| p.parent())?)?; 165 let record_expr = ast::RecordExpr::cast(field.syntax().parent().and_then(|p| p.parent())?)?;
166 let expr = ast::Expr::from(record_expr); 166 let expr = ast::Expr::from(record_expr);
167 let expr_id = self.body_source_map.as_ref()?.node_expr(InFile::new(self.file_id, &expr))?; 167 let expr_id = self.body_source_map.as_ref()?.node_expr(InFile::new(self.file_id, &expr))?;
@@ -178,10 +178,13 @@ impl SourceAnalyzer {
178 _ => None, 178 _ => None,
179 } 179 }
180 }; 180 };
181 let (_, subst) = self.infer.as_ref()?.type_of_expr.get(expr_id)?.as_adt()?;
181 let variant = self.infer.as_ref()?.variant_resolution_for_expr(expr_id)?; 182 let variant = self.infer.as_ref()?.variant_resolution_for_expr(expr_id)?;
182 let variant_data = variant.variant_data(db.upcast()); 183 let variant_data = variant.variant_data(db.upcast());
183 let field = FieldId { parent: variant, local_id: variant_data.field(&local_name)? }; 184 let field = FieldId { parent: variant, local_id: variant_data.field(&local_name)? };
184 Some((field.into(), local)) 185 let field_ty =
186 db.field_types(variant).get(field.local_id)?.clone().substitute(&Interner, subst);
187 Some((field.into(), local, Type::new_with_resolver(db, &self.resolver, field_ty)?))
185 } 188 }
186 189
187 pub(crate) fn resolve_record_pat_field( 190 pub(crate) fn resolve_record_pat_field(
@@ -305,7 +308,11 @@ impl SourceAnalyzer {
305 } 308 }
306 } 309 }
307 310
308 resolve_hir_path_(db, &self.resolver, &hir_path, prefer_value_ns) 311 if parent().map_or(false, |it| ast::Visibility::can_cast(it.kind())) {
312 resolve_hir_path_qualifier(db, &self.resolver, &hir_path)
313 } else {
314 resolve_hir_path_(db, &self.resolver, &hir_path, prefer_value_ns)
315 }
309 } 316 }
310 317
311 pub(crate) fn record_literal_missing_fields( 318 pub(crate) fn record_literal_missing_fields(
diff --git a/crates/hir_def/src/attr.rs b/crates/hir_def/src/attr.rs
index 89a1ea770..385ba8c80 100644
--- a/crates/hir_def/src/attr.rs
+++ b/crates/hir_def/src/attr.rs
@@ -105,7 +105,7 @@ impl RawAttrs {
105 Either::Left(attr) => Attr::from_src(db, attr, hygiene, id), 105 Either::Left(attr) => Attr::from_src(db, attr, hygiene, id),
106 Either::Right(comment) => comment.doc_comment().map(|doc| Attr { 106 Either::Right(comment) => comment.doc_comment().map(|doc| Attr {
107 id, 107 id,
108 input: Some(AttrInput::Literal(SmolStr::new(doc))), 108 input: Some(Interned::new(AttrInput::Literal(SmolStr::new(doc)))),
109 path: Interned::new(ModPath::from(hir_expand::name!(doc))), 109 path: Interned::new(ModPath::from(hir_expand::name!(doc))),
110 }), 110 }),
111 }) 111 })
@@ -151,7 +151,7 @@ impl RawAttrs {
151 return smallvec![attr.clone()]; 151 return smallvec![attr.clone()];
152 } 152 }
153 153
154 let subtree = match &attr.input { 154 let subtree = match attr.input.as_deref() {
155 Some(AttrInput::TokenTree(it)) => it, 155 Some(AttrInput::TokenTree(it)) => it,
156 _ => return smallvec![attr.clone()], 156 _ => return smallvec![attr.clone()],
157 }; 157 };
@@ -251,7 +251,7 @@ impl Attrs {
251 } 251 }
252 252
253 pub fn docs(&self) -> Option<Documentation> { 253 pub fn docs(&self) -> Option<Documentation> {
254 let docs = self.by_key("doc").attrs().flat_map(|attr| match attr.input.as_ref()? { 254 let docs = self.by_key("doc").attrs().flat_map(|attr| match attr.input.as_deref()? {
255 AttrInput::Literal(s) => Some(s), 255 AttrInput::Literal(s) => Some(s),
256 AttrInput::TokenTree(_) => None, 256 AttrInput::TokenTree(_) => None,
257 }); 257 });
@@ -454,7 +454,7 @@ impl AttrsWithOwner {
454 db: &dyn DefDatabase, 454 db: &dyn DefDatabase,
455 ) -> Option<(Documentation, DocsRangeMap)> { 455 ) -> Option<(Documentation, DocsRangeMap)> {
456 // FIXME: code duplication in `docs` above 456 // FIXME: code duplication in `docs` above
457 let docs = self.by_key("doc").attrs().flat_map(|attr| match attr.input.as_ref()? { 457 let docs = self.by_key("doc").attrs().flat_map(|attr| match attr.input.as_deref()? {
458 AttrInput::Literal(s) => Some((s, attr.id)), 458 AttrInput::Literal(s) => Some((s, attr.id)),
459 AttrInput::TokenTree(_) => None, 459 AttrInput::TokenTree(_) => None,
460 }); 460 });
@@ -637,10 +637,10 @@ pub(crate) struct AttrId {
637pub struct Attr { 637pub struct Attr {
638 pub(crate) id: AttrId, 638 pub(crate) id: AttrId,
639 pub(crate) path: Interned<ModPath>, 639 pub(crate) path: Interned<ModPath>,
640 pub(crate) input: Option<AttrInput>, 640 pub(crate) input: Option<Interned<AttrInput>>,
641} 641}
642 642
643#[derive(Debug, Clone, PartialEq, Eq)] 643#[derive(Debug, Clone, PartialEq, Eq, Hash)]
644pub enum AttrInput { 644pub enum AttrInput {
645 /// `#[attr = "string"]` 645 /// `#[attr = "string"]`
646 Literal(SmolStr), 646 Literal(SmolStr),
@@ -670,9 +670,9 @@ impl Attr {
670 ast::LiteralKind::String(string) => string.value()?.into(), 670 ast::LiteralKind::String(string) => string.value()?.into(),
671 _ => lit.syntax().first_token()?.text().trim_matches('"').into(), 671 _ => lit.syntax().first_token()?.text().trim_matches('"').into(),
672 }; 672 };
673 Some(AttrInput::Literal(value)) 673 Some(Interned::new(AttrInput::Literal(value)))
674 } else if let Some(tt) = ast.token_tree() { 674 } else if let Some(tt) = ast.token_tree() {
675 Some(AttrInput::TokenTree(ast_to_token_tree(&tt).0)) 675 Some(Interned::new(AttrInput::TokenTree(ast_to_token_tree(&tt).0)))
676 } else { 676 } else {
677 None 677 None
678 }; 678 };
@@ -688,7 +688,7 @@ impl Attr {
688 return None; 688 return None;
689 } 689 }
690 690
691 match &self.input { 691 match self.input.as_deref() {
692 Some(AttrInput::TokenTree(args)) => { 692 Some(AttrInput::TokenTree(args)) => {
693 let mut counter = 0; 693 let mut counter = 0;
694 let paths = args 694 let paths = args
@@ -720,7 +720,7 @@ impl Attr {
720 } 720 }
721 721
722 pub fn string_value(&self) -> Option<&SmolStr> { 722 pub fn string_value(&self) -> Option<&SmolStr> {
723 match self.input.as_ref()? { 723 match self.input.as_deref()? {
724 AttrInput::Literal(it) => Some(it), 724 AttrInput::Literal(it) => Some(it),
725 _ => None, 725 _ => None,
726 } 726 }
@@ -735,14 +735,14 @@ pub struct AttrQuery<'a> {
735 735
736impl<'a> AttrQuery<'a> { 736impl<'a> AttrQuery<'a> {
737 pub fn tt_values(self) -> impl Iterator<Item = &'a Subtree> { 737 pub fn tt_values(self) -> impl Iterator<Item = &'a Subtree> {
738 self.attrs().filter_map(|attr| match attr.input.as_ref()? { 738 self.attrs().filter_map(|attr| match attr.input.as_deref()? {
739 AttrInput::TokenTree(it) => Some(it), 739 AttrInput::TokenTree(it) => Some(it),
740 _ => None, 740 _ => None,
741 }) 741 })
742 } 742 }
743 743
744 pub fn string_value(self) -> Option<&'a SmolStr> { 744 pub fn string_value(self) -> Option<&'a SmolStr> {
745 self.attrs().find_map(|attr| match attr.input.as_ref()? { 745 self.attrs().find_map(|attr| match attr.input.as_deref()? {
746 AttrInput::Literal(it) => Some(it), 746 AttrInput::Literal(it) => Some(it),
747 _ => None, 747 _ => None,
748 }) 748 })
diff --git a/crates/hir_def/src/body.rs b/crates/hir_def/src/body.rs
index 98b485b60..c521879c8 100644
--- a/crates/hir_def/src/body.rs
+++ b/crates/hir_def/src/body.rs
@@ -1,7 +1,6 @@
1//! Defines `Body`: a lowered representation of bodies of functions, statics and 1//! Defines `Body`: a lowered representation of bodies of functions, statics and
2//! consts. 2//! consts.
3mod lower; 3mod lower;
4mod diagnostics;
5#[cfg(test)] 4#[cfg(test)]
6mod tests; 5mod tests;
7pub mod scope; 6pub mod scope;
@@ -9,17 +8,16 @@ pub mod scope;
9use std::{mem, ops::Index, sync::Arc}; 8use std::{mem, ops::Index, sync::Arc};
10 9
11use base_db::CrateId; 10use base_db::CrateId;
12use cfg::CfgOptions; 11use cfg::{CfgExpr, CfgOptions};
13use drop_bomb::DropBomb; 12use drop_bomb::DropBomb;
14use either::Either; 13use either::Either;
15use hir_expand::{ 14use hir_expand::{
16 ast_id_map::AstIdMap, diagnostics::DiagnosticSink, hygiene::Hygiene, AstId, ExpandResult, 15 ast_id_map::AstIdMap, hygiene::Hygiene, AstId, ExpandResult, HirFileId, InFile, MacroDefId,
17 HirFileId, InFile, MacroDefId,
18}; 16};
19use la_arena::{Arena, ArenaMap}; 17use la_arena::{Arena, ArenaMap};
20use profile::Count; 18use profile::Count;
21use rustc_hash::FxHashMap; 19use rustc_hash::FxHashMap;
22use syntax::{ast, AstNode, AstPtr}; 20use syntax::{ast, AstNode, AstPtr, SyntaxNodePtr};
23 21
24use crate::{ 22use crate::{
25 attr::{Attrs, RawAttrs}, 23 attr::{Attrs, RawAttrs},
@@ -273,12 +271,20 @@ pub struct BodySourceMap {
273 271
274 /// Diagnostics accumulated during body lowering. These contain `AstPtr`s and so are stored in 272 /// Diagnostics accumulated during body lowering. These contain `AstPtr`s and so are stored in
275 /// the source map (since they're just as volatile). 273 /// the source map (since they're just as volatile).
276 diagnostics: Vec<diagnostics::BodyDiagnostic>, 274 diagnostics: Vec<BodyDiagnostic>,
277} 275}
278 276
279#[derive(Default, Debug, Eq, PartialEq, Clone, Copy)] 277#[derive(Default, Debug, Eq, PartialEq, Clone, Copy)]
280pub struct SyntheticSyntax; 278pub struct SyntheticSyntax;
281 279
280#[derive(Debug, Eq, PartialEq)]
281pub enum BodyDiagnostic {
282 InactiveCode { node: InFile<SyntaxNodePtr>, cfg: CfgExpr, opts: CfgOptions },
283 MacroError { node: InFile<AstPtr<ast::MacroCall>>, message: String },
284 UnresolvedProcMacro { node: InFile<AstPtr<ast::MacroCall>> },
285 UnresolvedMacroCall { node: InFile<AstPtr<ast::MacroCall>>, path: ModPath },
286}
287
282impl Body { 288impl Body {
283 pub(crate) fn body_with_source_map_query( 289 pub(crate) fn body_with_source_map_query(
284 db: &dyn DefDatabase, 290 db: &dyn DefDatabase,
@@ -416,9 +422,8 @@ impl BodySourceMap {
416 self.field_map.get(&src).cloned() 422 self.field_map.get(&src).cloned()
417 } 423 }
418 424
419 pub(crate) fn add_diagnostics(&self, _db: &dyn DefDatabase, sink: &mut DiagnosticSink<'_>) { 425 /// Get a reference to the body source map's diagnostics.
420 for diag in &self.diagnostics { 426 pub fn diagnostics(&self) -> &[BodyDiagnostic] {
421 diag.add_to(sink); 427 &self.diagnostics
422 }
423 } 428 }
424} 429}
diff --git a/crates/hir_def/src/body/diagnostics.rs b/crates/hir_def/src/body/diagnostics.rs
deleted file mode 100644
index f6992c9a8..000000000
--- a/crates/hir_def/src/body/diagnostics.rs
+++ /dev/null
@@ -1,32 +0,0 @@
1//! Diagnostics emitted during body lowering.
2
3use hir_expand::diagnostics::DiagnosticSink;
4
5use crate::diagnostics::{InactiveCode, MacroError, UnresolvedMacroCall, UnresolvedProcMacro};
6
7#[derive(Debug, Eq, PartialEq)]
8pub(crate) enum BodyDiagnostic {
9 InactiveCode(InactiveCode),
10 MacroError(MacroError),
11 UnresolvedProcMacro(UnresolvedProcMacro),
12 UnresolvedMacroCall(UnresolvedMacroCall),
13}
14
15impl BodyDiagnostic {
16 pub(crate) fn add_to(&self, sink: &mut DiagnosticSink<'_>) {
17 match self {
18 BodyDiagnostic::InactiveCode(diag) => {
19 sink.push(diag.clone());
20 }
21 BodyDiagnostic::MacroError(diag) => {
22 sink.push(diag.clone());
23 }
24 BodyDiagnostic::UnresolvedProcMacro(diag) => {
25 sink.push(diag.clone());
26 }
27 BodyDiagnostic::UnresolvedMacroCall(diag) => {
28 sink.push(diag.clone());
29 }
30 }
31 }
32}
diff --git a/crates/hir_def/src/body/lower.rs b/crates/hir_def/src/body/lower.rs
index 2a7e0205f..da1fdac33 100644
--- a/crates/hir_def/src/body/lower.rs
+++ b/crates/hir_def/src/body/lower.rs
@@ -8,7 +8,7 @@ use hir_expand::{
8 ast_id_map::{AstIdMap, FileAstId}, 8 ast_id_map::{AstIdMap, FileAstId},
9 hygiene::Hygiene, 9 hygiene::Hygiene,
10 name::{name, AsName, Name}, 10 name::{name, AsName, Name},
11 ExpandError, HirFileId, 11 ExpandError, HirFileId, InFile,
12}; 12};
13use la_arena::Arena; 13use la_arena::Arena;
14use profile::Count; 14use profile::Count;
@@ -23,9 +23,9 @@ use syntax::{
23use crate::{ 23use crate::{
24 adt::StructKind, 24 adt::StructKind,
25 body::{Body, BodySourceMap, Expander, LabelSource, PatPtr, SyntheticSyntax}, 25 body::{Body, BodySourceMap, Expander, LabelSource, PatPtr, SyntheticSyntax},
26 body::{BodyDiagnostic, ExprSource, PatSource},
26 builtin_type::{BuiltinFloat, BuiltinInt, BuiltinUint}, 27 builtin_type::{BuiltinFloat, BuiltinInt, BuiltinUint},
27 db::DefDatabase, 28 db::DefDatabase,
28 diagnostics::{InactiveCode, MacroError, UnresolvedMacroCall, UnresolvedProcMacro},
29 expr::{ 29 expr::{
30 dummy_expr_id, ArithOp, Array, BinaryOp, BindingAnnotation, CmpOp, Expr, ExprId, Label, 30 dummy_expr_id, ArithOp, Array, BinaryOp, BindingAnnotation, CmpOp, Expr, ExprId, Label,
31 LabelId, Literal, LogicOp, MatchArm, Ordering, Pat, PatId, RecordFieldPat, RecordLitField, 31 LabelId, Literal, LogicOp, MatchArm, Ordering, Pat, PatId, RecordFieldPat, RecordLitField,
@@ -38,8 +38,6 @@ use crate::{
38 AdtId, BlockLoc, ModuleDefId, UnresolvedMacro, 38 AdtId, BlockLoc, ModuleDefId, UnresolvedMacro,
39}; 39};
40 40
41use super::{diagnostics::BodyDiagnostic, ExprSource, PatSource};
42
43pub struct LowerCtx<'a> { 41pub struct LowerCtx<'a> {
44 pub db: &'a dyn DefDatabase, 42 pub db: &'a dyn DefDatabase,
45 hygiene: Hygiene, 43 hygiene: Hygiene,
@@ -592,13 +590,10 @@ impl ExprCollector<'_> {
592 let res = match res { 590 let res = match res {
593 Ok(res) => res, 591 Ok(res) => res,
594 Err(UnresolvedMacro { path }) => { 592 Err(UnresolvedMacro { path }) => {
595 self.source_map.diagnostics.push(BodyDiagnostic::UnresolvedMacroCall( 593 self.source_map.diagnostics.push(BodyDiagnostic::UnresolvedMacroCall {
596 UnresolvedMacroCall { 594 node: InFile::new(outer_file, syntax_ptr),
597 file: outer_file, 595 path,
598 node: syntax_ptr.cast().unwrap(), 596 });
599 path,
600 },
601 ));
602 collector(self, None); 597 collector(self, None);
603 return; 598 return;
604 } 599 }
@@ -606,21 +601,15 @@ impl ExprCollector<'_> {
606 601
607 match &res.err { 602 match &res.err {
608 Some(ExpandError::UnresolvedProcMacro) => { 603 Some(ExpandError::UnresolvedProcMacro) => {
609 self.source_map.diagnostics.push(BodyDiagnostic::UnresolvedProcMacro( 604 self.source_map.diagnostics.push(BodyDiagnostic::UnresolvedProcMacro {
610 UnresolvedProcMacro { 605 node: InFile::new(outer_file, syntax_ptr),
611 file: outer_file, 606 });
612 node: syntax_ptr.into(),
613 precise_location: None,
614 macro_name: None,
615 },
616 ));
617 } 607 }
618 Some(err) => { 608 Some(err) => {
619 self.source_map.diagnostics.push(BodyDiagnostic::MacroError(MacroError { 609 self.source_map.diagnostics.push(BodyDiagnostic::MacroError {
620 file: outer_file, 610 node: InFile::new(outer_file, syntax_ptr),
621 node: syntax_ptr.into(),
622 message: err.to_string(), 611 message: err.to_string(),
623 })); 612 });
624 } 613 }
625 None => {} 614 None => {}
626 } 615 }
@@ -945,12 +934,14 @@ impl ExprCollector<'_> {
945 return Some(()); 934 return Some(());
946 } 935 }
947 936
948 self.source_map.diagnostics.push(BodyDiagnostic::InactiveCode(InactiveCode { 937 self.source_map.diagnostics.push(BodyDiagnostic::InactiveCode {
949 file: self.expander.current_file_id, 938 node: InFile::new(
950 node: SyntaxNodePtr::new(owner.syntax()), 939 self.expander.current_file_id,
940 SyntaxNodePtr::new(owner.syntax()),
941 ),
951 cfg, 942 cfg,
952 opts: self.expander.cfg_options().clone(), 943 opts: self.expander.cfg_options().clone(),
953 })); 944 });
954 945
955 None 946 None
956 } 947 }
diff --git a/crates/hir_def/src/body/tests.rs b/crates/hir_def/src/body/tests.rs
index 3e8f16306..d4fae05a6 100644
--- a/crates/hir_def/src/body/tests.rs
+++ b/crates/hir_def/src/body/tests.rs
@@ -96,26 +96,26 @@ fn f() {
96 // The three g̶e̶n̶d̶e̶r̶s̶ statements: 96 // The three g̶e̶n̶d̶e̶r̶s̶ statements:
97 97
98 #[cfg(a)] fn f() {} // Item statement 98 #[cfg(a)] fn f() {} // Item statement
99 //^^^^^^^^^^^^^^^^^^^ code is inactive due to #[cfg] directives: a is disabled 99 //^^^^^^^^^^^^^^^^^^^ InactiveCode
100 #[cfg(a)] {} // Expression statement 100 #[cfg(a)] {} // Expression statement
101 //^^^^^^^^^^^^ code is inactive due to #[cfg] directives: a is disabled 101 //^^^^^^^^^^^^ InactiveCode
102 #[cfg(a)] let x = 0; // let statement 102 #[cfg(a)] let x = 0; // let statement
103 //^^^^^^^^^^^^^^^^^^^^ code is inactive due to #[cfg] directives: a is disabled 103 //^^^^^^^^^^^^^^^^^^^^ InactiveCode
104 104
105 abc(#[cfg(a)] 0); 105 abc(#[cfg(a)] 0);
106 //^^^^^^^^^^^ code is inactive due to #[cfg] directives: a is disabled 106 //^^^^^^^^^^^ InactiveCode
107 let x = Struct { 107 let x = Struct {
108 #[cfg(a)] f: 0, 108 #[cfg(a)] f: 0,
109 //^^^^^^^^^^^^^^ code is inactive due to #[cfg] directives: a is disabled 109 //^^^^^^^^^^^^^^ InactiveCode
110 }; 110 };
111 match () { 111 match () {
112 () => (), 112 () => (),
113 #[cfg(a)] () => (), 113 #[cfg(a)] () => (),
114 //^^^^^^^^^^^^^^^^^^ code is inactive due to #[cfg] directives: a is disabled 114 //^^^^^^^^^^^^^^^^^^ InactiveCode
115 } 115 }
116 116
117 #[cfg(a)] 0 // Trailing expression of block 117 #[cfg(a)] 0 // Trailing expression of block
118 //^^^^^^^^^^^ code is inactive due to #[cfg] directives: a is disabled 118 //^^^^^^^^^^^ InactiveCode
119} 119}
120 ", 120 ",
121 ); 121 );
@@ -188,7 +188,7 @@ fn unresolved_macro_diag() {
188 r#" 188 r#"
189fn f() { 189fn f() {
190 m!(); 190 m!();
191 //^^^^ unresolved macro `m!` 191 //^^^^ UnresolvedMacroCall
192} 192}
193 "#, 193 "#,
194 ); 194 );
diff --git a/crates/hir_def/src/data.rs b/crates/hir_def/src/data.rs
index 135a6698e..d2bb381be 100644
--- a/crates/hir_def/src/data.rs
+++ b/crates/hir_def/src/data.rs
@@ -22,6 +22,7 @@ pub struct FunctionData {
22 pub name: Name, 22 pub name: Name,
23 pub params: Vec<Interned<TypeRef>>, 23 pub params: Vec<Interned<TypeRef>>,
24 pub ret_type: Interned<TypeRef>, 24 pub ret_type: Interned<TypeRef>,
25 pub async_ret_type: Option<Interned<TypeRef>>,
25 pub attrs: Attrs, 26 pub attrs: Attrs,
26 pub visibility: RawVisibility, 27 pub visibility: RawVisibility,
27 pub abi: Option<Interned<str>>, 28 pub abi: Option<Interned<str>>,
@@ -63,6 +64,7 @@ impl FunctionData {
63 }) 64 })
64 .collect(), 65 .collect(),
65 ret_type: func.ret_type.clone(), 66 ret_type: func.ret_type.clone(),
67 async_ret_type: func.async_ret_type.clone(),
66 attrs: item_tree.attrs(db, krate, ModItem::from(loc.id.value).into()), 68 attrs: item_tree.attrs(db, krate, ModItem::from(loc.id.value).into()),
67 visibility: item_tree[func.visibility].clone(), 69 visibility: item_tree[func.visibility].clone(),
68 abi: func.abi.clone(), 70 abi: func.abi.clone(),
@@ -112,7 +114,7 @@ pub struct TypeAliasData {
112 pub visibility: RawVisibility, 114 pub visibility: RawVisibility,
113 pub is_extern: bool, 115 pub is_extern: bool,
114 /// Bounds restricting the type alias itself (eg. `type Ty: Bound;` in a trait or impl). 116 /// Bounds restricting the type alias itself (eg. `type Ty: Bound;` in a trait or impl).
115 pub bounds: Vec<TypeBound>, 117 pub bounds: Vec<Interned<TypeBound>>,
116} 118}
117 119
118impl TypeAliasData { 120impl TypeAliasData {
@@ -141,7 +143,6 @@ pub struct TraitData {
141 pub is_auto: bool, 143 pub is_auto: bool,
142 pub is_unsafe: bool, 144 pub is_unsafe: bool,
143 pub visibility: RawVisibility, 145 pub visibility: RawVisibility,
144 pub bounds: Box<[TypeBound]>,
145} 146}
146 147
147impl TraitData { 148impl TraitData {
@@ -155,7 +156,6 @@ impl TraitData {
155 let module_id = tr_loc.container; 156 let module_id = tr_loc.container;
156 let container = AssocContainerId::TraitId(tr); 157 let container = AssocContainerId::TraitId(tr);
157 let visibility = item_tree[tr_def.visibility].clone(); 158 let visibility = item_tree[tr_def.visibility].clone();
158 let bounds = tr_def.bounds.clone();
159 let mut expander = Expander::new(db, tr_loc.id.file_id(), module_id); 159 let mut expander = Expander::new(db, tr_loc.id.file_id(), module_id);
160 160
161 let items = collect_items( 161 let items = collect_items(
@@ -168,7 +168,7 @@ impl TraitData {
168 100, 168 100,
169 ); 169 );
170 170
171 Arc::new(TraitData { name, items, is_auto, is_unsafe, visibility, bounds }) 171 Arc::new(TraitData { name, items, is_auto, is_unsafe, visibility })
172 } 172 }
173 173
174 pub fn associated_types(&self) -> impl Iterator<Item = TypeAliasId> + '_ { 174 pub fn associated_types(&self) -> impl Iterator<Item = TypeAliasId> + '_ {
diff --git a/crates/hir_def/src/diagnostics.rs b/crates/hir_def/src/diagnostics.rs
deleted file mode 100644
index a71ae2668..000000000
--- a/crates/hir_def/src/diagnostics.rs
+++ /dev/null
@@ -1,227 +0,0 @@
1//! Diagnostics produced by `hir_def`.
2
3use std::any::Any;
4use stdx::format_to;
5
6use cfg::{CfgExpr, CfgOptions, DnfExpr};
7use hir_expand::diagnostics::{Diagnostic, DiagnosticCode, DiagnosticSink};
8use hir_expand::{HirFileId, InFile};
9use syntax::{ast, AstPtr, SyntaxNodePtr, TextRange};
10
11use crate::{db::DefDatabase, path::ModPath, DefWithBodyId};
12
13pub fn validate_body(db: &dyn DefDatabase, owner: DefWithBodyId, sink: &mut DiagnosticSink<'_>) {
14 let source_map = db.body_with_source_map(owner).1;
15 source_map.add_diagnostics(db, sink);
16}
17
18// Diagnostic: unresolved-module
19//
20// This diagnostic is triggered if rust-analyzer is unable to discover referred module.
21#[derive(Debug)]
22pub struct UnresolvedModule {
23 pub file: HirFileId,
24 pub decl: AstPtr<ast::Module>,
25 pub candidate: String,
26}
27
28impl Diagnostic for UnresolvedModule {
29 fn code(&self) -> DiagnosticCode {
30 DiagnosticCode("unresolved-module")
31 }
32 fn message(&self) -> String {
33 "unresolved module".to_string()
34 }
35 fn display_source(&self) -> InFile<SyntaxNodePtr> {
36 InFile::new(self.file, self.decl.clone().into())
37 }
38 fn as_any(&self) -> &(dyn Any + Send + 'static) {
39 self
40 }
41}
42
43// Diagnostic: unresolved-extern-crate
44//
45// This diagnostic is triggered if rust-analyzer is unable to discover referred extern crate.
46#[derive(Debug)]
47pub struct UnresolvedExternCrate {
48 pub file: HirFileId,
49 pub item: AstPtr<ast::ExternCrate>,
50}
51
52impl Diagnostic for UnresolvedExternCrate {
53 fn code(&self) -> DiagnosticCode {
54 DiagnosticCode("unresolved-extern-crate")
55 }
56 fn message(&self) -> String {
57 "unresolved extern crate".to_string()
58 }
59 fn display_source(&self) -> InFile<SyntaxNodePtr> {
60 InFile::new(self.file, self.item.clone().into())
61 }
62 fn as_any(&self) -> &(dyn Any + Send + 'static) {
63 self
64 }
65}
66
67// Diagnostic: unresolved-import
68//
69// This diagnostic is triggered if rust-analyzer is unable to discover imported module.
70#[derive(Debug)]
71pub struct UnresolvedImport {
72 pub file: HirFileId,
73 pub node: AstPtr<ast::UseTree>,
74}
75
76impl Diagnostic for UnresolvedImport {
77 fn code(&self) -> DiagnosticCode {
78 DiagnosticCode("unresolved-import")
79 }
80 fn message(&self) -> String {
81 "unresolved import".to_string()
82 }
83 fn display_source(&self) -> InFile<SyntaxNodePtr> {
84 InFile::new(self.file, self.node.clone().into())
85 }
86 fn as_any(&self) -> &(dyn Any + Send + 'static) {
87 self
88 }
89 fn is_experimental(&self) -> bool {
90 // This currently results in false positives in the following cases:
91 // - `cfg_if!`-generated code in libstd (we don't load the sysroot correctly)
92 // - `core::arch` (we don't handle `#[path = "../<path>"]` correctly)
93 // - proc macros and/or proc macro generated code
94 true
95 }
96}
97
98// Diagnostic: unresolved-macro-call
99//
100// This diagnostic is triggered if rust-analyzer is unable to resolve the path to a
101// macro in a macro invocation.
102#[derive(Debug, Clone, Eq, PartialEq)]
103pub struct UnresolvedMacroCall {
104 pub file: HirFileId,
105 pub node: AstPtr<ast::MacroCall>,
106 pub path: ModPath,
107}
108
109impl Diagnostic for UnresolvedMacroCall {
110 fn code(&self) -> DiagnosticCode {
111 DiagnosticCode("unresolved-macro-call")
112 }
113 fn message(&self) -> String {
114 format!("unresolved macro `{}!`", self.path)
115 }
116 fn display_source(&self) -> InFile<SyntaxNodePtr> {
117 InFile::new(self.file, self.node.clone().into())
118 }
119 fn as_any(&self) -> &(dyn Any + Send + 'static) {
120 self
121 }
122 fn is_experimental(&self) -> bool {
123 true
124 }
125}
126
127// Diagnostic: inactive-code
128//
129// This diagnostic is shown for code with inactive `#[cfg]` attributes.
130#[derive(Debug, Clone, Eq, PartialEq)]
131pub struct InactiveCode {
132 pub file: HirFileId,
133 pub node: SyntaxNodePtr,
134 pub cfg: CfgExpr,
135 pub opts: CfgOptions,
136}
137
138impl Diagnostic for InactiveCode {
139 fn code(&self) -> DiagnosticCode {
140 DiagnosticCode("inactive-code")
141 }
142 fn message(&self) -> String {
143 let inactive = DnfExpr::new(self.cfg.clone()).why_inactive(&self.opts);
144 let mut buf = "code is inactive due to #[cfg] directives".to_string();
145
146 if let Some(inactive) = inactive {
147 format_to!(buf, ": {}", inactive);
148 }
149
150 buf
151 }
152 fn display_source(&self) -> InFile<SyntaxNodePtr> {
153 InFile::new(self.file, self.node.clone())
154 }
155 fn as_any(&self) -> &(dyn Any + Send + 'static) {
156 self
157 }
158}
159
160// Diagnostic: unresolved-proc-macro
161//
162// This diagnostic is shown when a procedural macro can not be found. This usually means that
163// procedural macro support is simply disabled (and hence is only a weak hint instead of an error),
164// but can also indicate project setup problems.
165//
166// If you are seeing a lot of "proc macro not expanded" warnings, you can add this option to the
167// `rust-analyzer.diagnostics.disabled` list to prevent them from showing. Alternatively you can
168// enable support for procedural macros (see `rust-analyzer.procMacro.enable`).
169#[derive(Debug, Clone, Eq, PartialEq)]
170pub struct UnresolvedProcMacro {
171 pub file: HirFileId,
172 pub node: SyntaxNodePtr,
173 /// If the diagnostic can be pinpointed more accurately than via `node`, this is the `TextRange`
174 /// to use instead.
175 pub precise_location: Option<TextRange>,
176 pub macro_name: Option<String>,
177}
178
179impl Diagnostic for UnresolvedProcMacro {
180 fn code(&self) -> DiagnosticCode {
181 DiagnosticCode("unresolved-proc-macro")
182 }
183
184 fn message(&self) -> String {
185 match &self.macro_name {
186 Some(name) => format!("proc macro `{}` not expanded", name),
187 None => "proc macro not expanded".to_string(),
188 }
189 }
190
191 fn display_source(&self) -> InFile<SyntaxNodePtr> {
192 InFile::new(self.file, self.node.clone())
193 }
194
195 fn as_any(&self) -> &(dyn Any + Send + 'static) {
196 self
197 }
198}
199
200// Diagnostic: macro-error
201//
202// This diagnostic is shown for macro expansion errors.
203#[derive(Debug, Clone, Eq, PartialEq)]
204pub struct MacroError {
205 pub file: HirFileId,
206 pub node: SyntaxNodePtr,
207 pub message: String,
208}
209
210impl Diagnostic for MacroError {
211 fn code(&self) -> DiagnosticCode {
212 DiagnosticCode("macro-error")
213 }
214 fn message(&self) -> String {
215 self.message.clone()
216 }
217 fn display_source(&self) -> InFile<SyntaxNodePtr> {
218 InFile::new(self.file, self.node.clone())
219 }
220 fn as_any(&self) -> &(dyn Any + Send + 'static) {
221 self
222 }
223 fn is_experimental(&self) -> bool {
224 // Newly added and not very well-tested, might contain false positives.
225 true
226 }
227}
diff --git a/crates/hir_def/src/generics.rs b/crates/hir_def/src/generics.rs
index de5acced8..44d22b918 100644
--- a/crates/hir_def/src/generics.rs
+++ b/crates/hir_def/src/generics.rs
@@ -68,9 +68,19 @@ pub struct GenericParams {
68/// associated type bindings like `Iterator<Item = u32>`. 68/// associated type bindings like `Iterator<Item = u32>`.
69#[derive(Clone, PartialEq, Eq, Debug, Hash)] 69#[derive(Clone, PartialEq, Eq, Debug, Hash)]
70pub enum WherePredicate { 70pub enum WherePredicate {
71 TypeBound { target: WherePredicateTypeTarget, bound: TypeBound }, 71 TypeBound {
72 Lifetime { target: LifetimeRef, bound: LifetimeRef }, 72 target: WherePredicateTypeTarget,
73 ForLifetime { lifetimes: Box<[Name]>, target: WherePredicateTypeTarget, bound: TypeBound }, 73 bound: Interned<TypeBound>,
74 },
75 Lifetime {
76 target: LifetimeRef,
77 bound: LifetimeRef,
78 },
79 ForLifetime {
80 lifetimes: Box<[Name]>,
81 target: WherePredicateTypeTarget,
82 bound: Interned<TypeBound>,
83 },
74} 84}
75 85
76#[derive(Clone, PartialEq, Eq, Debug, Hash)] 86#[derive(Clone, PartialEq, Eq, Debug, Hash)]
@@ -339,11 +349,11 @@ impl GenericParams {
339 Some(hrtb_lifetimes) => WherePredicate::ForLifetime { 349 Some(hrtb_lifetimes) => WherePredicate::ForLifetime {
340 lifetimes: hrtb_lifetimes.clone(), 350 lifetimes: hrtb_lifetimes.clone(),
341 target: WherePredicateTypeTarget::TypeRef(Interned::new(type_ref)), 351 target: WherePredicateTypeTarget::TypeRef(Interned::new(type_ref)),
342 bound, 352 bound: Interned::new(bound),
343 }, 353 },
344 None => WherePredicate::TypeBound { 354 None => WherePredicate::TypeBound {
345 target: WherePredicateTypeTarget::TypeRef(Interned::new(type_ref)), 355 target: WherePredicateTypeTarget::TypeRef(Interned::new(type_ref)),
346 bound, 356 bound: Interned::new(bound),
347 }, 357 },
348 }, 358 },
349 (Either::Right(lifetime), TypeBound::Lifetime(bound)) => { 359 (Either::Right(lifetime), TypeBound::Lifetime(bound)) => {
diff --git a/crates/hir_def/src/intern.rs b/crates/hir_def/src/intern.rs
index 5cc7f2df6..79ba970e7 100644
--- a/crates/hir_def/src/intern.rs
+++ b/crates/hir_def/src/intern.rs
@@ -216,7 +216,10 @@ pub use crate::_impl_internable as impl_internable;
216impl_internable!( 216impl_internable!(
217 crate::type_ref::TypeRef, 217 crate::type_ref::TypeRef,
218 crate::type_ref::TraitRef, 218 crate::type_ref::TraitRef,
219 crate::type_ref::TypeBound,
219 crate::path::ModPath, 220 crate::path::ModPath,
221 crate::path::GenericArgs,
222 crate::attr::AttrInput,
220 GenericParams, 223 GenericParams,
221 str, 224 str,
222); 225);
diff --git a/crates/hir_def/src/item_tree.rs b/crates/hir_def/src/item_tree.rs
index 528270d49..227337a8d 100644
--- a/crates/hir_def/src/item_tree.rs
+++ b/crates/hir_def/src/item_tree.rs
@@ -1,4 +1,34 @@
1//! A simplified AST that only contains items. 1//! A simplified AST that only contains items.
2//!
3//! This is the primary IR used throughout `hir_def`. It is the input to the name resolution
4//! algorithm, as well as to the queries defined in `adt.rs`, `data.rs`, and most things in
5//! `attr.rs`.
6//!
7//! `ItemTree`s are built per `HirFileId`, from the syntax tree of the parsed file. This means that
8//! they are crate-independent: they don't know which `#[cfg]`s are active or which module they
9//! belong to, since those concepts don't exist at this level (a single `ItemTree` might be part of
10//! multiple crates, or might be included into the same crate twice via `#[path]`).
11//!
12//! One important purpose of this layer is to provide an "invalidation barrier" for incremental
13//! computations: when typing inside an item body, the `ItemTree` of the modified file is typically
14//! unaffected, so we don't have to recompute name resolution results or item data (see `data.rs`).
15//!
16//! The `ItemTree` for the currently open file can be displayed by using the VS Code command
17//! "Rust Analyzer: Debug ItemTree".
18//!
19//! Compared to rustc's architecture, `ItemTree` has properties from both rustc's AST and HIR: many
20//! syntax-level Rust features are already desugared to simpler forms in the `ItemTree`, but name
21//! resolution has not yet been performed. `ItemTree`s are per-file, while rustc's AST and HIR are
22//! per-crate, because we are interested in incrementally computing it.
23//!
24//! The representation of items in the `ItemTree` should generally mirror the surface syntax: it is
25//! usually a bad idea to desugar a syntax-level construct to something that is structurally
26//! different here. Name resolution needs to be able to process attributes and expand macros
27//! (including attribute macros), and having a 1-to-1 mapping between syntax and the `ItemTree`
28//! avoids introducing subtle bugs.
29//!
30//! In general, any item in the `ItemTree` stores its `AstId`, which allows mapping it back to its
31//! surface syntax.
2 32
3mod lower; 33mod lower;
4mod pretty; 34mod pretty;
@@ -493,21 +523,38 @@ impl<N: ItemTreeNode> Index<FileItemTreeId<N>> for ItemTree {
493 } 523 }
494} 524}
495 525
496/// A desugared `use` import.
497#[derive(Debug, Clone, Eq, PartialEq)] 526#[derive(Debug, Clone, Eq, PartialEq)]
498pub struct Import { 527pub struct Import {
499 pub path: Interned<ModPath>,
500 pub alias: Option<ImportAlias>,
501 pub visibility: RawVisibilityId, 528 pub visibility: RawVisibilityId,
502 pub is_glob: bool,
503 /// AST ID of the `use` or `extern crate` item this import was derived from. Note that many
504 /// `Import`s can map to the same `use` item.
505 pub ast_id: FileAstId<ast::Use>, 529 pub ast_id: FileAstId<ast::Use>,
506 /// Index of this `Import` when the containing `Use` is visited via `ModPath::expand_use_item`. 530 pub use_tree: UseTree,
507 /// 531}
508 /// This can be used to get the `UseTree` this `Import` corresponds to and allows emitting 532
509 /// precise diagnostics. 533#[derive(Debug, Clone, Eq, PartialEq)]
510 pub index: usize, 534pub struct UseTree {
535 pub index: Idx<ast::UseTree>,
536 kind: UseTreeKind,
537}
538
539#[derive(Debug, Clone, Eq, PartialEq)]
540pub enum UseTreeKind {
541 /// ```
542 /// use path::to::Item;
543 /// use path::to::Item as Renamed;
544 /// use path::to::Trait as _;
545 /// ```
546 Single { path: Interned<ModPath>, alias: Option<ImportAlias> },
547
548 /// ```
549 /// use *; // (invalid, but can occur in nested tree)
550 /// use path::*;
551 /// ```
552 Glob { path: Option<Interned<ModPath>> },
553
554 /// ```
555 /// use prefix::{self, Item, ...};
556 /// ```
557 Prefixed { prefix: Option<Interned<ModPath>>, list: Box<[UseTree]> },
511} 558}
512 559
513#[derive(Debug, Clone, Eq, PartialEq)] 560#[derive(Debug, Clone, Eq, PartialEq)]
@@ -533,6 +580,7 @@ pub struct Function {
533 pub abi: Option<Interned<str>>, 580 pub abi: Option<Interned<str>>,
534 pub params: IdRange<Param>, 581 pub params: IdRange<Param>,
535 pub ret_type: Interned<TypeRef>, 582 pub ret_type: Interned<TypeRef>,
583 pub async_ret_type: Option<Interned<TypeRef>>,
536 pub ast_id: FileAstId<ast::Fn>, 584 pub ast_id: FileAstId<ast::Fn>,
537 pub(crate) flags: FnFlags, 585 pub(crate) flags: FnFlags,
538} 586}
@@ -614,7 +662,6 @@ pub struct Trait {
614 pub generic_params: Interned<GenericParams>, 662 pub generic_params: Interned<GenericParams>,
615 pub is_auto: bool, 663 pub is_auto: bool,
616 pub is_unsafe: bool, 664 pub is_unsafe: bool,
617 pub bounds: Box<[TypeBound]>,
618 pub items: Box<[AssocItem]>, 665 pub items: Box<[AssocItem]>,
619 pub ast_id: FileAstId<ast::Trait>, 666 pub ast_id: FileAstId<ast::Trait>,
620} 667}
@@ -634,7 +681,7 @@ pub struct TypeAlias {
634 pub name: Name, 681 pub name: Name,
635 pub visibility: RawVisibilityId, 682 pub visibility: RawVisibilityId,
636 /// Bounds on the type alias itself. Only valid in trait declarations, eg. `type Assoc: Copy;`. 683 /// Bounds on the type alias itself. Only valid in trait declarations, eg. `type Assoc: Copy;`.
637 pub bounds: Box<[TypeBound]>, 684 pub bounds: Box<[Interned<TypeBound>]>,
638 pub generic_params: Interned<GenericParams>, 685 pub generic_params: Interned<GenericParams>,
639 pub type_ref: Option<Interned<TypeRef>>, 686 pub type_ref: Option<Interned<TypeRef>>,
640 pub is_extern: bool, 687 pub is_extern: bool,
@@ -681,6 +728,97 @@ pub struct MacroDef {
681 pub ast_id: FileAstId<ast::MacroDef>, 728 pub ast_id: FileAstId<ast::MacroDef>,
682} 729}
683 730
731impl Import {
732 /// Maps a `UseTree` contained in this import back to its AST node.
733 pub fn use_tree_to_ast(
734 &self,
735 db: &dyn DefDatabase,
736 file_id: HirFileId,
737 index: Idx<ast::UseTree>,
738 ) -> ast::UseTree {
739 // Re-lower the AST item and get the source map.
740 // Note: The AST unwraps are fine, since if they fail we should have never obtained `index`.
741 let ast = InFile::new(file_id, self.ast_id).to_node(db.upcast());
742 let ast_use_tree = ast.use_tree().expect("missing `use_tree`");
743 let hygiene = Hygiene::new(db.upcast(), file_id);
744 let (_, source_map) =
745 lower::lower_use_tree(db, &hygiene, ast_use_tree).expect("failed to lower use tree");
746 source_map[index].clone()
747 }
748}
749
750impl UseTree {
751 /// Expands the `UseTree` into individually imported `ModPath`s.
752 pub fn expand(
753 &self,
754 mut cb: impl FnMut(Idx<ast::UseTree>, ModPath, /* is_glob */ bool, Option<ImportAlias>),
755 ) {
756 self.expand_impl(None, &mut cb)
757 }
758
759 fn expand_impl(
760 &self,
761 prefix: Option<ModPath>,
762 cb: &mut dyn FnMut(
763 Idx<ast::UseTree>,
764 ModPath,
765 /* is_glob */ bool,
766 Option<ImportAlias>,
767 ),
768 ) {
769 fn concat_mod_paths(prefix: Option<ModPath>, path: &ModPath) -> Option<ModPath> {
770 match (prefix, &path.kind) {
771 (None, _) => Some(path.clone()),
772 (Some(mut prefix), PathKind::Plain) => {
773 for segment in path.segments() {
774 prefix.push_segment(segment.clone());
775 }
776 Some(prefix)
777 }
778 (Some(prefix), PathKind::Super(0)) => {
779 // `some::path::self` == `some::path`
780 if path.segments().is_empty() {
781 Some(prefix)
782 } else {
783 None
784 }
785 }
786 (Some(_), _) => None,
787 }
788 }
789
790 match &self.kind {
791 UseTreeKind::Single { path, alias } => {
792 if let Some(path) = concat_mod_paths(prefix, path) {
793 cb(self.index, path, false, alias.clone());
794 }
795 }
796 UseTreeKind::Glob { path: Some(path) } => {
797 if let Some(path) = concat_mod_paths(prefix, path) {
798 cb(self.index, path, true, None);
799 }
800 }
801 UseTreeKind::Glob { path: None } => {
802 if let Some(prefix) = prefix {
803 cb(self.index, prefix, true, None);
804 }
805 }
806 UseTreeKind::Prefixed { prefix: additional_prefix, list } => {
807 let prefix = match additional_prefix {
808 Some(path) => match concat_mod_paths(prefix, path) {
809 Some(path) => Some(path),
810 None => return,
811 },
812 None => prefix,
813 };
814 for tree in &**list {
815 tree.expand_impl(prefix.clone(), cb);
816 }
817 }
818 }
819 }
820}
821
684macro_rules! impl_froms { 822macro_rules! impl_froms {
685 ($e:ident { $($v:ident ($t:ty)),* $(,)? }) => { 823 ($e:ident { $($v:ident ($t:ty)),* $(,)? }) => {
686 $( 824 $(
diff --git a/crates/hir_def/src/item_tree/lower.rs b/crates/hir_def/src/item_tree/lower.rs
index 91cf75371..6208facd5 100644
--- a/crates/hir_def/src/item_tree/lower.rs
+++ b/crates/hir_def/src/item_tree/lower.rs
@@ -3,7 +3,6 @@
3use std::{collections::hash_map::Entry, mem, sync::Arc}; 3use std::{collections::hash_map::Entry, mem, sync::Arc};
4 4
5use hir_expand::{ast_id_map::AstIdMap, hygiene::Hygiene, name::known, HirFileId}; 5use hir_expand::{ast_id_map::AstIdMap, hygiene::Hygiene, name::known, HirFileId};
6use smallvec::SmallVec;
7use syntax::{ 6use syntax::{
8 ast::{self, ModuleItemOwner}, 7 ast::{self, ModuleItemOwner},
9 SyntaxNode, WalkEvent, 8 SyntaxNode, WalkEvent,
@@ -20,22 +19,10 @@ fn id<N: ItemTreeNode>(index: Idx<N>) -> FileItemTreeId<N> {
20 FileItemTreeId { index, _p: PhantomData } 19 FileItemTreeId { index, _p: PhantomData }
21} 20}
22 21
23struct ModItems(SmallVec<[ModItem; 1]>);
24
25impl<T> From<T> for ModItems
26where
27 T: Into<ModItem>,
28{
29 fn from(t: T) -> Self {
30 ModItems(SmallVec::from_buf([t.into(); 1]))
31 }
32}
33
34pub(super) struct Ctx<'a> { 22pub(super) struct Ctx<'a> {
35 db: &'a dyn DefDatabase, 23 db: &'a dyn DefDatabase,
36 tree: ItemTree, 24 tree: ItemTree,
37 hygiene: Hygiene, 25 hygiene: Hygiene,
38 file: HirFileId,
39 source_ast_id_map: Arc<AstIdMap>, 26 source_ast_id_map: Arc<AstIdMap>,
40 body_ctx: crate::body::LowerCtx<'a>, 27 body_ctx: crate::body::LowerCtx<'a>,
41 forced_visibility: Option<RawVisibilityId>, 28 forced_visibility: Option<RawVisibilityId>,
@@ -47,7 +34,6 @@ impl<'a> Ctx<'a> {
47 db, 34 db,
48 tree: ItemTree::default(), 35 tree: ItemTree::default(),
49 hygiene, 36 hygiene,
50 file,
51 source_ast_id_map: db.ast_id_map(file), 37 source_ast_id_map: db.ast_id_map(file),
52 body_ctx: crate::body::LowerCtx::new(db, file), 38 body_ctx: crate::body::LowerCtx::new(db, file),
53 forced_visibility: None, 39 forced_visibility: None,
@@ -55,11 +41,8 @@ impl<'a> Ctx<'a> {
55 } 41 }
56 42
57 pub(super) fn lower_module_items(mut self, item_owner: &dyn ModuleItemOwner) -> ItemTree { 43 pub(super) fn lower_module_items(mut self, item_owner: &dyn ModuleItemOwner) -> ItemTree {
58 self.tree.top_level = item_owner 44 self.tree.top_level =
59 .items() 45 item_owner.items().flat_map(|item| self.lower_mod_item(&item, false)).collect();
60 .flat_map(|item| self.lower_mod_item(&item, false))
61 .flat_map(|items| items.0)
62 .collect();
63 self.tree 46 self.tree
64 } 47 }
65 48
@@ -71,7 +54,6 @@ impl<'a> Ctx<'a> {
71 _ => None, 54 _ => None,
72 }) 55 })
73 .flat_map(|item| self.lower_mod_item(&item, false)) 56 .flat_map(|item| self.lower_mod_item(&item, false))
74 .flat_map(|items| items.0)
75 .collect(); 57 .collect();
76 58
77 // Non-items need to have their inner items collected. 59 // Non-items need to have their inner items collected.
@@ -98,7 +80,7 @@ impl<'a> Ctx<'a> {
98 self.tree.data_mut() 80 self.tree.data_mut()
99 } 81 }
100 82
101 fn lower_mod_item(&mut self, item: &ast::Item, inner: bool) -> Option<ModItems> { 83 fn lower_mod_item(&mut self, item: &ast::Item, inner: bool) -> Option<ModItem> {
102 // Collect inner items for 1-to-1-lowered items. 84 // Collect inner items for 1-to-1-lowered items.
103 match item { 85 match item {
104 ast::Item::Struct(_) 86 ast::Item::Struct(_)
@@ -129,34 +111,28 @@ impl<'a> Ctx<'a> {
129 }; 111 };
130 112
131 let attrs = RawAttrs::new(self.db, item, &self.hygiene); 113 let attrs = RawAttrs::new(self.db, item, &self.hygiene);
132 let items = match item { 114 let item: ModItem = match item {
133 ast::Item::Struct(ast) => self.lower_struct(ast).map(Into::into), 115 ast::Item::Struct(ast) => self.lower_struct(ast)?.into(),
134 ast::Item::Union(ast) => self.lower_union(ast).map(Into::into), 116 ast::Item::Union(ast) => self.lower_union(ast)?.into(),
135 ast::Item::Enum(ast) => self.lower_enum(ast).map(Into::into), 117 ast::Item::Enum(ast) => self.lower_enum(ast)?.into(),
136 ast::Item::Fn(ast) => self.lower_function(ast).map(Into::into), 118 ast::Item::Fn(ast) => self.lower_function(ast)?.into(),
137 ast::Item::TypeAlias(ast) => self.lower_type_alias(ast).map(Into::into), 119 ast::Item::TypeAlias(ast) => self.lower_type_alias(ast)?.into(),
138 ast::Item::Static(ast) => self.lower_static(ast).map(Into::into), 120 ast::Item::Static(ast) => self.lower_static(ast)?.into(),
139 ast::Item::Const(ast) => Some(self.lower_const(ast).into()), 121 ast::Item::Const(ast) => self.lower_const(ast).into(),
140 ast::Item::Module(ast) => self.lower_module(ast).map(Into::into), 122 ast::Item::Module(ast) => self.lower_module(ast)?.into(),
141 ast::Item::Trait(ast) => self.lower_trait(ast).map(Into::into), 123 ast::Item::Trait(ast) => self.lower_trait(ast)?.into(),
142 ast::Item::Impl(ast) => self.lower_impl(ast).map(Into::into), 124 ast::Item::Impl(ast) => self.lower_impl(ast)?.into(),
143 ast::Item::Use(ast) => Some(ModItems( 125 ast::Item::Use(ast) => self.lower_use(ast)?.into(),
144 self.lower_use(ast).into_iter().map(Into::into).collect::<SmallVec<_>>(), 126 ast::Item::ExternCrate(ast) => self.lower_extern_crate(ast)?.into(),
145 )), 127 ast::Item::MacroCall(ast) => self.lower_macro_call(ast)?.into(),
146 ast::Item::ExternCrate(ast) => self.lower_extern_crate(ast).map(Into::into), 128 ast::Item::MacroRules(ast) => self.lower_macro_rules(ast)?.into(),
147 ast::Item::MacroCall(ast) => self.lower_macro_call(ast).map(Into::into), 129 ast::Item::MacroDef(ast) => self.lower_macro_def(ast)?.into(),
148 ast::Item::MacroRules(ast) => self.lower_macro_rules(ast).map(Into::into), 130 ast::Item::ExternBlock(ast) => self.lower_extern_block(ast).into(),
149 ast::Item::MacroDef(ast) => self.lower_macro_def(ast).map(Into::into),
150 ast::Item::ExternBlock(ast) => Some(self.lower_extern_block(ast).into()),
151 }; 131 };
152 132
153 if !attrs.is_empty() { 133 self.add_attrs(item.into(), attrs.clone());
154 for item in items.iter().flat_map(|items| &items.0) {
155 self.add_attrs((*item).into(), attrs.clone());
156 }
157 }
158 134
159 items 135 Some(item)
160 } 136 }
161 137
162 fn add_attrs(&mut self, item: AttrOwner, attrs: RawAttrs) { 138 fn add_attrs(&mut self, item: AttrOwner, attrs: RawAttrs) {
@@ -190,12 +166,10 @@ impl<'a> Ctx<'a> {
190 }, 166 },
191 ast::Item(item) => { 167 ast::Item(item) => {
192 // FIXME: This triggers for macro calls in expression/pattern/type position 168 // FIXME: This triggers for macro calls in expression/pattern/type position
193 let mod_items = self.lower_mod_item(&item, true); 169 let mod_item = self.lower_mod_item(&item, true);
194 let current_block = block_stack.last(); 170 let current_block = block_stack.last();
195 if let (Some(mod_items), Some(block)) = (mod_items, current_block) { 171 if let (Some(mod_item), Some(block)) = (mod_item, current_block) {
196 if !mod_items.0.is_empty() { 172 self.data().inner_items.entry(*block).or_default().push(mod_item);
197 self.data().inner_items.entry(*block).or_default().extend(mod_items.0.iter().copied());
198 }
199 } 173 }
200 }, 174 },
201 _ => {} 175 _ => {}
@@ -382,12 +356,13 @@ impl<'a> Ctx<'a> {
382 _ => TypeRef::unit(), 356 _ => TypeRef::unit(),
383 }; 357 };
384 358
385 let ret_type = if func.async_token().is_some() { 359 let (ret_type, async_ret_type) = if func.async_token().is_some() {
360 let async_ret_type = ret_type.clone();
386 let future_impl = desugar_future_path(ret_type); 361 let future_impl = desugar_future_path(ret_type);
387 let ty_bound = TypeBound::Path(future_impl); 362 let ty_bound = Interned::new(TypeBound::Path(future_impl));
388 TypeRef::ImplTrait(vec![ty_bound]) 363 (TypeRef::ImplTrait(vec![ty_bound]), Some(async_ret_type))
389 } else { 364 } else {
390 ret_type 365 (ret_type, None)
391 }; 366 };
392 367
393 let abi = func.abi().map(lower_abi); 368 let abi = func.abi().map(lower_abi);
@@ -421,6 +396,7 @@ impl<'a> Ctx<'a> {
421 abi, 396 abi,
422 params, 397 params,
423 ret_type: Interned::new(ret_type), 398 ret_type: Interned::new(ret_type),
399 async_ret_type: async_ret_type.map(Interned::new),
424 ast_id, 400 ast_id,
425 flags, 401 flags,
426 }; 402 };
@@ -480,10 +456,7 @@ impl<'a> Ctx<'a> {
480 items: module 456 items: module
481 .item_list() 457 .item_list()
482 .map(|list| { 458 .map(|list| {
483 list.items() 459 list.items().flat_map(|item| self.lower_mod_item(&item, false)).collect()
484 .flat_map(|item| self.lower_mod_item(&item, false))
485 .flat_map(|items| items.0)
486 .collect()
487 }) 460 })
488 .unwrap_or_else(|| { 461 .unwrap_or_else(|| {
489 cov_mark::hit!(name_res_works_for_broken_modules); 462 cov_mark::hit!(name_res_works_for_broken_modules);
@@ -503,7 +476,6 @@ impl<'a> Ctx<'a> {
503 self.lower_generic_params_and_inner_items(GenericsOwner::Trait(trait_def), trait_def); 476 self.lower_generic_params_and_inner_items(GenericsOwner::Trait(trait_def), trait_def);
504 let is_auto = trait_def.auto_token().is_some(); 477 let is_auto = trait_def.auto_token().is_some();
505 let is_unsafe = trait_def.unsafe_token().is_some(); 478 let is_unsafe = trait_def.unsafe_token().is_some();
506 let bounds = self.lower_type_bounds(trait_def);
507 let items = trait_def.assoc_item_list().map(|list| { 479 let items = trait_def.assoc_item_list().map(|list| {
508 let db = self.db; 480 let db = self.db;
509 self.with_inherited_visibility(visibility, |this| { 481 self.with_inherited_visibility(visibility, |this| {
@@ -526,7 +498,6 @@ impl<'a> Ctx<'a> {
526 generic_params, 498 generic_params,
527 is_auto, 499 is_auto,
528 is_unsafe, 500 is_unsafe,
529 bounds: bounds.into(),
530 items: items.unwrap_or_default(), 501 items: items.unwrap_or_default(),
531 ast_id, 502 ast_id,
532 }; 503 };
@@ -561,30 +532,13 @@ impl<'a> Ctx<'a> {
561 Some(id(self.data().impls.alloc(res))) 532 Some(id(self.data().impls.alloc(res)))
562 } 533 }
563 534
564 fn lower_use(&mut self, use_item: &ast::Use) -> Vec<FileItemTreeId<Import>> { 535 fn lower_use(&mut self, use_item: &ast::Use) -> Option<FileItemTreeId<Import>> {
565 let visibility = self.lower_visibility(use_item); 536 let visibility = self.lower_visibility(use_item);
566 let ast_id = self.source_ast_id_map.ast_id(use_item); 537 let ast_id = self.source_ast_id_map.ast_id(use_item);
538 let (use_tree, _) = lower_use_tree(self.db, &self.hygiene, use_item.use_tree()?)?;
567 539
568 // Every use item can expand to many `Import`s. 540 let res = Import { visibility, ast_id, use_tree };
569 let mut imports = Vec::new(); 541 Some(id(self.data().imports.alloc(res)))
570 let tree = self.tree.data_mut();
571 ModPath::expand_use_item(
572 self.db,
573 InFile::new(self.file, use_item.clone()),
574 &self.hygiene,
575 |path, _use_tree, is_glob, alias| {
576 imports.push(id(tree.imports.alloc(Import {
577 path: Interned::new(path),
578 alias,
579 visibility,
580 is_glob,
581 ast_id,
582 index: imports.len(),
583 })));
584 },
585 );
586
587 imports
588 } 542 }
589 543
590 fn lower_extern_crate( 544 fn lower_extern_crate(
@@ -738,11 +692,12 @@ impl<'a> Ctx<'a> {
738 Interned::new(generics) 692 Interned::new(generics)
739 } 693 }
740 694
741 fn lower_type_bounds(&mut self, node: &impl ast::TypeBoundsOwner) -> Vec<TypeBound> { 695 fn lower_type_bounds(&mut self, node: &impl ast::TypeBoundsOwner) -> Vec<Interned<TypeBound>> {
742 match node.type_bound_list() { 696 match node.type_bound_list() {
743 Some(bound_list) => { 697 Some(bound_list) => bound_list
744 bound_list.bounds().map(|it| TypeBound::from_ast(&self.body_ctx, it)).collect() 698 .bounds()
745 } 699 .map(|it| Interned::new(TypeBound::from_ast(&self.body_ctx, it)))
700 .collect(),
746 None => Vec::new(), 701 None => Vec::new(),
747 } 702 }
748 } 703 }
@@ -810,7 +765,7 @@ fn desugar_future_path(orig: TypeRef) -> Path {
810 let binding = 765 let binding =
811 AssociatedTypeBinding { name: name![Output], type_ref: Some(orig), bounds: Vec::new() }; 766 AssociatedTypeBinding { name: name![Output], type_ref: Some(orig), bounds: Vec::new() };
812 last.bindings.push(binding); 767 last.bindings.push(binding);
813 generic_args.push(Some(Arc::new(last))); 768 generic_args.push(Some(Interned::new(last)));
814 769
815 Path::from_known_path(path, generic_args) 770 Path::from_known_path(path, generic_args)
816} 771}
@@ -883,3 +838,81 @@ fn lower_abi(abi: ast::Abi) -> Interned<str> {
883 } 838 }
884 } 839 }
885} 840}
841
842struct UseTreeLowering<'a> {
843 db: &'a dyn DefDatabase,
844 hygiene: &'a Hygiene,
845 mapping: Arena<ast::UseTree>,
846}
847
848impl UseTreeLowering<'_> {
849 fn lower_use_tree(&mut self, tree: ast::UseTree) -> Option<UseTree> {
850 if let Some(use_tree_list) = tree.use_tree_list() {
851 let prefix = match tree.path() {
852 // E.g. use something::{{{inner}}};
853 None => None,
854 // E.g. `use something::{inner}` (prefix is `None`, path is `something`)
855 // or `use something::{path::{inner::{innerer}}}` (prefix is `something::path`, path is `inner`)
856 Some(path) => {
857 match ModPath::from_src(self.db, path, &self.hygiene) {
858 Some(it) => Some(it),
859 None => return None, // FIXME: report errors somewhere
860 }
861 }
862 };
863
864 let list =
865 use_tree_list.use_trees().filter_map(|tree| self.lower_use_tree(tree)).collect();
866
867 Some(
868 self.use_tree(
869 UseTreeKind::Prefixed { prefix: prefix.map(Interned::new), list },
870 tree,
871 ),
872 )
873 } else {
874 let is_glob = tree.star_token().is_some();
875 let path = match tree.path() {
876 Some(path) => Some(ModPath::from_src(self.db, path, &self.hygiene)?),
877 None => None,
878 };
879 let alias = tree.rename().map(|a| {
880 a.name().map(|it| it.as_name()).map_or(ImportAlias::Underscore, ImportAlias::Alias)
881 });
882 if alias.is_some() && is_glob {
883 return None;
884 }
885
886 match (path, alias, is_glob) {
887 (path, None, true) => {
888 if path.is_none() {
889 cov_mark::hit!(glob_enum_group);
890 }
891 Some(self.use_tree(UseTreeKind::Glob { path: path.map(Interned::new) }, tree))
892 }
893 // Globs can't be renamed
894 (_, Some(_), true) | (None, None, false) => None,
895 // `bla::{ as Name}` is invalid
896 (None, Some(_), false) => None,
897 (Some(path), alias, false) => Some(
898 self.use_tree(UseTreeKind::Single { path: Interned::new(path), alias }, tree),
899 ),
900 }
901 }
902 }
903
904 fn use_tree(&mut self, kind: UseTreeKind, ast: ast::UseTree) -> UseTree {
905 let index = self.mapping.alloc(ast);
906 UseTree { index, kind }
907 }
908}
909
910pub(super) fn lower_use_tree(
911 db: &dyn DefDatabase,
912 hygiene: &Hygiene,
913 tree: ast::UseTree,
914) -> Option<(UseTree, Arena<ast::UseTree>)> {
915 let mut lowering = UseTreeLowering { db, hygiene, mapping: Arena::new() };
916 let tree = lowering.lower_use_tree(tree)?;
917 Some((tree, lowering.mapping))
918}
diff --git a/crates/hir_def/src/item_tree/pretty.rs b/crates/hir_def/src/item_tree/pretty.rs
index 4bc87a0e2..cc9944a22 100644
--- a/crates/hir_def/src/item_tree/pretty.rs
+++ b/crates/hir_def/src/item_tree/pretty.rs
@@ -163,21 +163,46 @@ impl<'a> Printer<'a> {
163 } 163 }
164 } 164 }
165 165
166 fn print_use_tree(&mut self, use_tree: &UseTree) {
167 match &use_tree.kind {
168 UseTreeKind::Single { path, alias } => {
169 w!(self, "{}", path);
170 if let Some(alias) = alias {
171 w!(self, " as {}", alias);
172 }
173 }
174 UseTreeKind::Glob { path } => {
175 if let Some(path) = path {
176 w!(self, "{}::", path);
177 }
178 w!(self, "*");
179 }
180 UseTreeKind::Prefixed { prefix, list } => {
181 if let Some(prefix) = prefix {
182 w!(self, "{}::", prefix);
183 }
184 w!(self, "{{");
185 for (i, tree) in list.iter().enumerate() {
186 if i != 0 {
187 w!(self, ", ");
188 }
189 self.print_use_tree(tree);
190 }
191 w!(self, "}}");
192 }
193 }
194 }
195
166 fn print_mod_item(&mut self, item: ModItem) { 196 fn print_mod_item(&mut self, item: ModItem) {
167 self.print_attrs_of(item); 197 self.print_attrs_of(item);
168 198
169 match item { 199 match item {
170 ModItem::Import(it) => { 200 ModItem::Import(it) => {
171 let Import { visibility, path, is_glob, alias, ast_id: _, index } = &self.tree[it]; 201 let Import { visibility, use_tree, ast_id: _ } = &self.tree[it];
172 self.print_visibility(*visibility); 202 self.print_visibility(*visibility);
173 w!(self, "use {}", path); 203 w!(self, "use ");
174 if *is_glob { 204 self.print_use_tree(use_tree);
175 w!(self, "::*"); 205 wln!(self, ";");
176 }
177 if let Some(alias) = alias {
178 w!(self, " as {}", alias);
179 }
180 wln!(self, "; // {}", index);
181 } 206 }
182 ModItem::ExternCrate(it) => { 207 ModItem::ExternCrate(it) => {
183 let ExternCrate { name, alias, visibility, ast_id: _ } = &self.tree[it]; 208 let ExternCrate { name, alias, visibility, ast_id: _ } = &self.tree[it];
@@ -210,6 +235,7 @@ impl<'a> Printer<'a> {
210 abi, 235 abi,
211 params, 236 params,
212 ret_type, 237 ret_type,
238 async_ret_type: _,
213 ast_id: _, 239 ast_id: _,
214 flags, 240 flags,
215 } = &self.tree[it]; 241 } = &self.tree[it];
@@ -320,7 +346,6 @@ impl<'a> Printer<'a> {
320 visibility, 346 visibility,
321 is_auto, 347 is_auto,
322 is_unsafe, 348 is_unsafe,
323 bounds,
324 items, 349 items,
325 generic_params, 350 generic_params,
326 ast_id: _, 351 ast_id: _,
@@ -334,10 +359,6 @@ impl<'a> Printer<'a> {
334 } 359 }
335 w!(self, "trait {}", name); 360 w!(self, "trait {}", name);
336 self.print_generic_params(generic_params); 361 self.print_generic_params(generic_params);
337 if !bounds.is_empty() {
338 w!(self, ": ");
339 self.print_type_bounds(bounds);
340 }
341 self.print_where_clause_and_opening_brace(generic_params); 362 self.print_where_clause_and_opening_brace(generic_params);
342 self.indented(|this| { 363 self.indented(|this| {
343 for item in &**items { 364 for item in &**items {
@@ -513,13 +534,13 @@ impl<'a> Printer<'a> {
513 } 534 }
514 } 535 }
515 536
516 fn print_type_bounds(&mut self, bounds: &[TypeBound]) { 537 fn print_type_bounds(&mut self, bounds: &[Interned<TypeBound>]) {
517 for (i, bound) in bounds.iter().enumerate() { 538 for (i, bound) in bounds.iter().enumerate() {
518 if i != 0 { 539 if i != 0 {
519 w!(self, " + "); 540 w!(self, " + ");
520 } 541 }
521 542
522 match bound { 543 match bound.as_ref() {
523 TypeBound::Path(path) => self.print_path(path), 544 TypeBound::Path(path) => self.print_path(path),
524 TypeBound::Lifetime(lt) => w!(self, "{}", lt.name), 545 TypeBound::Lifetime(lt) => w!(self, "{}", lt.name),
525 TypeBound::Error => w!(self, "{{unknown}}"), 546 TypeBound::Error => w!(self, "{{unknown}}"),
diff --git a/crates/hir_def/src/item_tree/tests.rs b/crates/hir_def/src/item_tree/tests.rs
index 6407871b5..b362add5c 100644
--- a/crates/hir_def/src/item_tree/tests.rs
+++ b/crates/hir_def/src/item_tree/tests.rs
@@ -26,6 +26,8 @@ use globs::*;
26 26
27/// docs on import 27/// docs on import
28use crate::{A, B}; 28use crate::{A, B};
29
30use a::{c, d::{e}};
29 "#, 31 "#,
30 expect![[r##" 32 expect![[r##"
31 #![doc = " file comment"] // AttrId { is_doc_comment: true, ast_index: 0 } 33 #![doc = " file comment"] // AttrId { is_doc_comment: true, ast_index: 0 }
@@ -36,19 +38,14 @@ use crate::{A, B};
36 38
37 pub(super) extern crate bli; 39 pub(super) extern crate bli;
38 40
39 pub use crate::path::nested; // 0 41 pub use crate::path::{nested, items as renamed, Trait as _};
40
41 pub use crate::path::items as renamed; // 1
42 42
43 pub use crate::path::Trait as _; // 2 43 pub(self) use globs::*;
44
45 pub(self) use globs::*; // 0
46 44
47 #[doc = " docs on import"] // AttrId { is_doc_comment: true, ast_index: 0 } 45 #[doc = " docs on import"] // AttrId { is_doc_comment: true, ast_index: 0 }
48 pub(self) use crate::A; // 0 46 pub(self) use crate::{A, B};
49 47
50 #[doc = " docs on import"] // AttrId { is_doc_comment: true, ast_index: 0 } 48 pub(self) use a::{c, d::{e}};
51 pub(self) use crate::B; // 1
52 "##]], 49 "##]],
53 ); 50 );
54} 51}
@@ -183,7 +180,7 @@ trait Tr: SuperTrait + 'lifetime {
183 _: (), 180 _: (),
184 ) -> (); 181 ) -> ();
185 182
186 pub(self) trait Tr<Self>: SuperTrait + 'lifetime 183 pub(self) trait Tr<Self>
187 where 184 where
188 Self: SuperTrait, 185 Self: SuperTrait,
189 Self: 'lifetime 186 Self: 'lifetime
@@ -218,7 +215,7 @@ mod outline;
218 #[doc = " outer"] // AttrId { is_doc_comment: true, ast_index: 0 } 215 #[doc = " outer"] // AttrId { is_doc_comment: true, ast_index: 0 }
219 #[doc = " inner"] // AttrId { is_doc_comment: true, ast_index: 1 } 216 #[doc = " inner"] // AttrId { is_doc_comment: true, ast_index: 1 }
220 pub(self) mod inline { 217 pub(self) mod inline {
221 pub(self) use super::*; // 0 218 pub(self) use super::*;
222 219
223 // flags = 0x2 220 // flags = 0x2
224 pub(self) fn fn_in_module() -> (); 221 pub(self) fn fn_in_module() -> ();
@@ -353,7 +350,7 @@ trait Tr<'a, T: 'a>: Super {}
353 pub(self) union Union<'a, T, const U: u8> { 350 pub(self) union Union<'a, T, const U: u8> {
354 } 351 }
355 352
356 pub(self) trait Tr<'a, Self, T>: Super 353 pub(self) trait Tr<'a, Self, T>
357 where 354 where
358 Self: Super, 355 Self: Super,
359 T: 'a 356 T: 'a
diff --git a/crates/hir_def/src/lib.rs b/crates/hir_def/src/lib.rs
index a82ea5957..9aa95720a 100644
--- a/crates/hir_def/src/lib.rs
+++ b/crates/hir_def/src/lib.rs
@@ -19,7 +19,6 @@ pub mod path;
19pub mod type_ref; 19pub mod type_ref;
20pub mod builtin_type; 20pub mod builtin_type;
21pub mod builtin_attr; 21pub mod builtin_attr;
22pub mod diagnostics;
23pub mod per_ns; 22pub mod per_ns;
24pub mod item_scope; 23pub mod item_scope;
25 24
@@ -56,7 +55,6 @@ use std::{
56 sync::Arc, 55 sync::Arc,
57}; 56};
58 57
59use adt::VariantData;
60use base_db::{impl_intern_key, salsa, CrateId}; 58use base_db::{impl_intern_key, salsa, CrateId};
61use hir_expand::{ 59use hir_expand::{
62 ast_id_map::FileAstId, 60 ast_id_map::FileAstId,
@@ -67,15 +65,18 @@ use hir_expand::{
67use la_arena::Idx; 65use la_arena::Idx;
68use nameres::DefMap; 66use nameres::DefMap;
69use path::ModPath; 67use path::ModPath;
68use stdx::impl_from;
70use syntax::ast; 69use syntax::ast;
71 70
72use crate::attr::AttrId; 71use crate::{
73use crate::builtin_type::BuiltinType; 72 adt::VariantData,
74use item_tree::{ 73 attr::AttrId,
75 Const, Enum, Function, Impl, ItemTreeId, ItemTreeNode, ModItem, Static, Struct, Trait, 74 builtin_type::BuiltinType,
76 TypeAlias, Union, 75 item_tree::{
76 Const, Enum, Function, Impl, ItemTreeId, ItemTreeNode, ModItem, Static, Struct, Trait,
77 TypeAlias, Union,
78 },
77}; 79};
78use stdx::impl_from;
79 80
80#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] 81#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
81pub struct ModuleId { 82pub struct ModuleId {
@@ -485,6 +486,14 @@ impl VariantId {
485 VariantId::UnionId(it) => it.lookup(db).id.file_id(), 486 VariantId::UnionId(it) => it.lookup(db).id.file_id(),
486 } 487 }
487 } 488 }
489
490 pub fn adt_id(self) -> AdtId {
491 match self {
492 VariantId::EnumVariantId(it) => it.parent.into(),
493 VariantId::StructId(it) => it.into(),
494 VariantId::UnionId(it) => it.into(),
495 }
496 }
488} 497}
489 498
490trait Intern { 499trait Intern {
diff --git a/crates/hir_def/src/nameres.rs b/crates/hir_def/src/nameres.rs
index 249af6fc8..ebfcc26c4 100644
--- a/crates/hir_def/src/nameres.rs
+++ b/crates/hir_def/src/nameres.rs
@@ -47,18 +47,19 @@
47//! path and, upon success, we run macro expansion and "collect module" phase on 47//! path and, upon success, we run macro expansion and "collect module" phase on
48//! the result 48//! the result
49 49
50pub mod diagnostics;
50mod collector; 51mod collector;
51mod mod_resolution; 52mod mod_resolution;
52mod path_resolution; 53mod path_resolution;
54mod proc_macro;
53 55
54#[cfg(test)] 56#[cfg(test)]
55mod tests; 57mod tests;
56mod proc_macro;
57 58
58use std::sync::Arc; 59use std::sync::Arc;
59 60
60use base_db::{CrateId, Edition, FileId}; 61use base_db::{CrateId, Edition, FileId};
61use hir_expand::{diagnostics::DiagnosticSink, name::Name, InFile, MacroDefId}; 62use hir_expand::{name::Name, InFile, MacroDefId};
62use la_arena::Arena; 63use la_arena::Arena;
63use profile::Count; 64use profile::Count;
64use rustc_hash::FxHashMap; 65use rustc_hash::FxHashMap;
@@ -254,15 +255,6 @@ impl DefMap {
254 } 255 }
255 } 256 }
256 257
257 pub fn add_diagnostics(
258 &self,
259 db: &dyn DefDatabase,
260 module: LocalModuleId,
261 sink: &mut DiagnosticSink,
262 ) {
263 self.diagnostics.iter().for_each(|it| it.add_to(db, module, sink))
264 }
265
266 pub fn modules_for_file(&self, file_id: FileId) -> impl Iterator<Item = LocalModuleId> + '_ { 258 pub fn modules_for_file(&self, file_id: FileId) -> impl Iterator<Item = LocalModuleId> + '_ {
267 self.modules 259 self.modules
268 .iter() 260 .iter()
@@ -448,6 +440,11 @@ impl DefMap {
448 module.scope.shrink_to_fit(); 440 module.scope.shrink_to_fit();
449 } 441 }
450 } 442 }
443
444 /// Get a reference to the def map's diagnostics.
445 pub fn diagnostics(&self) -> &[DefDiagnostic] {
446 self.diagnostics.as_slice()
447 }
451} 448}
452 449
453impl ModuleData { 450impl ModuleData {
@@ -471,236 +468,3 @@ pub enum ModuleSource {
471 Module(ast::Module), 468 Module(ast::Module),
472 BlockExpr(ast::BlockExpr), 469 BlockExpr(ast::BlockExpr),
473} 470}
474
475mod diagnostics {
476 use cfg::{CfgExpr, CfgOptions};
477 use hir_expand::diagnostics::DiagnosticSink;
478 use hir_expand::hygiene::Hygiene;
479 use hir_expand::{InFile, MacroCallKind};
480 use syntax::ast::AttrsOwner;
481 use syntax::{ast, AstNode, AstPtr, SyntaxKind, SyntaxNodePtr};
482
483 use crate::path::ModPath;
484 use crate::{db::DefDatabase, diagnostics::*, nameres::LocalModuleId, AstId};
485
486 #[derive(Debug, PartialEq, Eq)]
487 enum DiagnosticKind {
488 UnresolvedModule { declaration: AstId<ast::Module>, candidate: String },
489
490 UnresolvedExternCrate { ast: AstId<ast::ExternCrate> },
491
492 UnresolvedImport { ast: AstId<ast::Use>, index: usize },
493
494 UnconfiguredCode { ast: AstId<ast::Item>, cfg: CfgExpr, opts: CfgOptions },
495
496 UnresolvedProcMacro { ast: MacroCallKind },
497
498 UnresolvedMacroCall { ast: AstId<ast::MacroCall>, path: ModPath },
499
500 MacroError { ast: MacroCallKind, message: String },
501 }
502
503 #[derive(Debug, PartialEq, Eq)]
504 pub(super) struct DefDiagnostic {
505 in_module: LocalModuleId,
506 kind: DiagnosticKind,
507 }
508
509 impl DefDiagnostic {
510 pub(super) fn unresolved_module(
511 container: LocalModuleId,
512 declaration: AstId<ast::Module>,
513 candidate: String,
514 ) -> Self {
515 Self {
516 in_module: container,
517 kind: DiagnosticKind::UnresolvedModule { declaration, candidate },
518 }
519 }
520
521 pub(super) fn unresolved_extern_crate(
522 container: LocalModuleId,
523 declaration: AstId<ast::ExternCrate>,
524 ) -> Self {
525 Self {
526 in_module: container,
527 kind: DiagnosticKind::UnresolvedExternCrate { ast: declaration },
528 }
529 }
530
531 pub(super) fn unresolved_import(
532 container: LocalModuleId,
533 ast: AstId<ast::Use>,
534 index: usize,
535 ) -> Self {
536 Self { in_module: container, kind: DiagnosticKind::UnresolvedImport { ast, index } }
537 }
538
539 pub(super) fn unconfigured_code(
540 container: LocalModuleId,
541 ast: AstId<ast::Item>,
542 cfg: CfgExpr,
543 opts: CfgOptions,
544 ) -> Self {
545 Self { in_module: container, kind: DiagnosticKind::UnconfiguredCode { ast, cfg, opts } }
546 }
547
548 pub(super) fn unresolved_proc_macro(container: LocalModuleId, ast: MacroCallKind) -> Self {
549 Self { in_module: container, kind: DiagnosticKind::UnresolvedProcMacro { ast } }
550 }
551
552 pub(super) fn macro_error(
553 container: LocalModuleId,
554 ast: MacroCallKind,
555 message: String,
556 ) -> Self {
557 Self { in_module: container, kind: DiagnosticKind::MacroError { ast, message } }
558 }
559
560 pub(super) fn unresolved_macro_call(
561 container: LocalModuleId,
562 ast: AstId<ast::MacroCall>,
563 path: ModPath,
564 ) -> Self {
565 Self { in_module: container, kind: DiagnosticKind::UnresolvedMacroCall { ast, path } }
566 }
567
568 pub(super) fn add_to(
569 &self,
570 db: &dyn DefDatabase,
571 target_module: LocalModuleId,
572 sink: &mut DiagnosticSink,
573 ) {
574 if self.in_module != target_module {
575 return;
576 }
577
578 match &self.kind {
579 DiagnosticKind::UnresolvedModule { declaration, candidate } => {
580 let decl = declaration.to_node(db.upcast());
581 sink.push(UnresolvedModule {
582 file: declaration.file_id,
583 decl: AstPtr::new(&decl),
584 candidate: candidate.clone(),
585 })
586 }
587
588 DiagnosticKind::UnresolvedExternCrate { ast } => {
589 let item = ast.to_node(db.upcast());
590 sink.push(UnresolvedExternCrate {
591 file: ast.file_id,
592 item: AstPtr::new(&item),
593 });
594 }
595
596 DiagnosticKind::UnresolvedImport { ast, index } => {
597 let use_item = ast.to_node(db.upcast());
598 let hygiene = Hygiene::new(db.upcast(), ast.file_id);
599 let mut cur = 0;
600 let mut tree = None;
601 ModPath::expand_use_item(
602 db,
603 InFile::new(ast.file_id, use_item),
604 &hygiene,
605 |_mod_path, use_tree, _is_glob, _alias| {
606 if cur == *index {
607 tree = Some(use_tree.clone());
608 }
609
610 cur += 1;
611 },
612 );
613
614 if let Some(tree) = tree {
615 sink.push(UnresolvedImport { file: ast.file_id, node: AstPtr::new(&tree) });
616 }
617 }
618
619 DiagnosticKind::UnconfiguredCode { ast, cfg, opts } => {
620 let item = ast.to_node(db.upcast());
621 sink.push(InactiveCode {
622 file: ast.file_id,
623 node: AstPtr::new(&item).into(),
624 cfg: cfg.clone(),
625 opts: opts.clone(),
626 });
627 }
628
629 DiagnosticKind::UnresolvedProcMacro { ast } => {
630 let mut precise_location = None;
631 let (file, ast, name) = match ast {
632 MacroCallKind::FnLike { ast_id, .. } => {
633 let node = ast_id.to_node(db.upcast());
634 (ast_id.file_id, SyntaxNodePtr::from(AstPtr::new(&node)), None)
635 }
636 MacroCallKind::Derive { ast_id, derive_name, .. } => {
637 let node = ast_id.to_node(db.upcast());
638
639 // Compute the precise location of the macro name's token in the derive
640 // list.
641 // FIXME: This does not handle paths to the macro, but neither does the
642 // rest of r-a.
643 let derive_attrs =
644 node.attrs().filter_map(|attr| match attr.as_simple_call() {
645 Some((name, args)) if name == "derive" => Some(args),
646 _ => None,
647 });
648 'outer: for attr in derive_attrs {
649 let tokens =
650 attr.syntax().children_with_tokens().filter_map(|elem| {
651 match elem {
652 syntax::NodeOrToken::Node(_) => None,
653 syntax::NodeOrToken::Token(tok) => Some(tok),
654 }
655 });
656 for token in tokens {
657 if token.kind() == SyntaxKind::IDENT
658 && token.text() == derive_name.as_str()
659 {
660 precise_location = Some(token.text_range());
661 break 'outer;
662 }
663 }
664 }
665
666 (
667 ast_id.file_id,
668 SyntaxNodePtr::from(AstPtr::new(&node)),
669 Some(derive_name.clone()),
670 )
671 }
672 };
673 sink.push(UnresolvedProcMacro {
674 file,
675 node: ast,
676 precise_location,
677 macro_name: name,
678 });
679 }
680
681 DiagnosticKind::UnresolvedMacroCall { ast, path } => {
682 let node = ast.to_node(db.upcast());
683 sink.push(UnresolvedMacroCall {
684 file: ast.file_id,
685 node: AstPtr::new(&node),
686 path: path.clone(),
687 });
688 }
689
690 DiagnosticKind::MacroError { ast, message } => {
691 let (file, ast) = match ast {
692 MacroCallKind::FnLike { ast_id, .. } => {
693 let node = ast_id.to_node(db.upcast());
694 (ast_id.file_id, SyntaxNodePtr::from(AstPtr::new(&node)))
695 }
696 MacroCallKind::Derive { ast_id, .. } => {
697 let node = ast_id.to_node(db.upcast());
698 (ast_id.file_id, SyntaxNodePtr::from(AstPtr::new(&node)))
699 }
700 };
701 sink.push(MacroError { file, node: ast, message: message.clone() });
702 }
703 }
704 }
705 }
706}
diff --git a/crates/hir_def/src/nameres/collector.rs b/crates/hir_def/src/nameres/collector.rs
index 014ea4de4..7f9fdb379 100644
--- a/crates/hir_def/src/nameres/collector.rs
+++ b/crates/hir_def/src/nameres/collector.rs
@@ -17,6 +17,7 @@ use hir_expand::{
17}; 17};
18use hir_expand::{InFile, MacroCallLoc}; 18use hir_expand::{InFile, MacroCallLoc};
19use itertools::Itertools; 19use itertools::Itertools;
20use la_arena::Idx;
20use rustc_hash::{FxHashMap, FxHashSet}; 21use rustc_hash::{FxHashMap, FxHashSet};
21use syntax::ast; 22use syntax::ast;
22 23
@@ -33,7 +34,10 @@ use crate::{
33 }, 34 },
34 macro_call_as_call_id, 35 macro_call_as_call_id,
35 nameres::{ 36 nameres::{
36 diagnostics::DefDiagnostic, mod_resolution::ModDir, path_resolution::ReachedFixedPoint, 37 diagnostics::DefDiagnostic,
38 mod_resolution::ModDir,
39 path_resolution::ReachedFixedPoint,
40 proc_macro::{ProcMacroDef, ProcMacroKind},
37 BuiltinShadowMode, DefMap, ModuleData, ModuleOrigin, ResolveMode, 41 BuiltinShadowMode, DefMap, ModuleData, ModuleOrigin, ResolveMode,
38 }, 42 },
39 path::{ImportAlias, ModPath, PathKind}, 43 path::{ImportAlias, ModPath, PathKind},
@@ -44,8 +48,6 @@ use crate::{
44 UnresolvedMacro, 48 UnresolvedMacro,