diff options
Diffstat (limited to 'crates')
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" | |||
10 | doctest = false | 10 | doctest = false |
11 | 11 | ||
12 | [dependencies] | 12 | [dependencies] |
13 | salsa = "0.16.0" | 13 | salsa = "0.17.0-pre.1" |
14 | rustc-hash = "1.1.0" | 14 | rustc-hash = "1.1.0" |
15 | 15 | ||
16 | syntax = { path = "../syntax", version = "0.0.0" } | 16 | syntax = { 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)] | ||
20 | pub struct Canceled { | ||
21 | _private: (), | ||
22 | } | ||
23 | |||
24 | impl 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 | |||
36 | impl 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 | |||
42 | impl std::fmt::Debug for Canceled { | ||
43 | fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { | ||
44 | write!(fmt, "Canceled") | ||
45 | } | ||
46 | } | ||
47 | |||
48 | impl 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)] |
144 | pub struct ProcMacroId(pub u32); | 148 | pub struct ProcMacroId(pub u32); |
145 | 149 | ||
146 | #[derive(Copy, Clone, Eq, PartialEq, Debug)] | 150 | #[derive(Copy, Clone, Eq, PartialEq, Debug, Hash)] |
147 | pub enum ProcMacroKind { | 151 | pub 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. |
2 | mod cancellation; | ||
3 | mod input; | 2 | mod input; |
4 | mod change; | 3 | mod change; |
5 | pub mod fixture; | 4 | pub mod fixture; |
@@ -10,14 +9,13 @@ use rustc_hash::FxHashSet; | |||
10 | use syntax::{ast, Parse, SourceFile, TextRange, TextSize}; | 9 | use syntax::{ast, Parse, SourceFile, TextRange, TextSize}; |
11 | 10 | ||
12 | pub use crate::{ | 11 | pub 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 | }; |
20 | pub use salsa; | 18 | pub use salsa::{self, Cancelled}; |
21 | pub use vfs::{file_set::FileSet, AnchoredPath, AnchoredPathBuf, FileId, VfsPath}; | 19 | pub 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 | ||
41 | pub 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 | |||
71 | impl<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)] |
81 | pub struct FilePosition { | 40 | pub 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)] |
104 | pub trait SourceDatabase: CheckCanceled + FileLoader + std::fmt::Debug { | 63 | pub 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. |
6 | pub use hir_def::diagnostics::{ | 6 | use std::any::Any; |
7 | InactiveCode, UnresolvedMacroCall, UnresolvedModule, UnresolvedProcMacro, | 7 | |
8 | }; | 8 | use cfg::{CfgExpr, CfgOptions, DnfExpr}; |
9 | pub use hir_expand::diagnostics::{ | 9 | use hir_def::path::ModPath; |
10 | Diagnostic, DiagnosticCode, DiagnosticSink, DiagnosticSinkBuilder, | 10 | use hir_expand::{HirFileId, InFile}; |
11 | }; | 11 | use stdx::format_to; |
12 | pub use hir_ty::diagnostics::{ | 12 | use syntax::{ast, AstPtr, SyntaxNodePtr, TextRange}; |
13 | IncorrectCase, MismatchedArgCount, MissingFields, MissingMatchArms, MissingOkOrSomeInTailExpr, | 13 | |
14 | NoSuchField, RemoveThisSemicolon, ReplaceFilterMapNextWithFindMap, | 14 | pub 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)] | ||
27 | pub struct UnresolvedModule { | ||
28 | pub file: HirFileId, | ||
29 | pub decl: AstPtr<ast::Module>, | ||
30 | pub candidate: String, | ||
31 | } | ||
32 | |||
33 | impl 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)] | ||
52 | pub struct UnresolvedExternCrate { | ||
53 | pub file: HirFileId, | ||
54 | pub item: AstPtr<ast::ExternCrate>, | ||
55 | } | ||
56 | |||
57 | impl 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)] | ||
73 | pub struct UnresolvedImport { | ||
74 | pub file: HirFileId, | ||
75 | pub node: AstPtr<ast::UseTree>, | ||
76 | } | ||
77 | |||
78 | impl 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)] | ||
105 | pub struct UnresolvedMacroCall { | ||
106 | pub file: HirFileId, | ||
107 | pub node: AstPtr<ast::MacroCall>, | ||
108 | pub path: ModPath, | ||
109 | } | ||
110 | |||
111 | impl 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)] | ||
133 | pub struct InactiveCode { | ||
134 | pub file: HirFileId, | ||
135 | pub node: SyntaxNodePtr, | ||
136 | pub cfg: CfgExpr, | ||
137 | pub opts: CfgOptions, | ||
138 | } | ||
139 | |||
140 | impl 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)] | ||
172 | pub 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 | |||
181 | impl 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)] | ||
206 | pub struct MacroError { | ||
207 | pub file: HirFileId, | ||
208 | pub node: SyntaxNodePtr, | ||
209 | pub message: String, | ||
210 | } | ||
211 | |||
212 | impl 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)] | ||
232 | pub struct UnimplementedBuiltinMacro { | ||
233 | pub file: HirFileId, | ||
234 | pub node: SyntaxNodePtr, | ||
235 | } | ||
236 | |||
237 | impl 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 | ||
36 | use arrayvec::ArrayVec; | 36 | use arrayvec::ArrayVec; |
37 | use base_db::{CrateDisplayName, CrateId, Edition, FileId}; | 37 | use base_db::{CrateDisplayName, CrateId, Edition, FileId}; |
38 | use diagnostics::{ | ||
39 | InactiveCode, MacroError, UnimplementedBuiltinMacro, UnresolvedExternCrate, UnresolvedImport, | ||
40 | UnresolvedMacroCall, UnresolvedModule, UnresolvedProcMacro, | ||
41 | }; | ||
38 | use either::Either; | 42 | use either::Either; |
39 | use hir_def::{ | 43 | use 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 | }; |
53 | use hir_expand::{diagnostics::DiagnosticSink, name::name, MacroDefKind}; | 59 | use hir_expand::{name::name, MacroCallKind, MacroDefKind}; |
54 | use hir_ty::{ | 60 | use 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 | }; |
67 | use itertools::Itertools; | 74 | use itertools::Itertools; |
75 | use nameres::diagnostics::DefDiagnosticKind; | ||
68 | use rustc_hash::FxHashSet; | 76 | use rustc_hash::FxHashSet; |
69 | use stdx::{format_to, impl_from}; | 77 | use stdx::{format_to, impl_from}; |
70 | use syntax::{ | 78 | use syntax::{ |
71 | ast::{self, AttrsOwner, NameOwner}, | 79 | ast::{self, AttrsOwner, NameOwner}, |
72 | AstNode, SmolStr, | 80 | AstNode, AstPtr, SmolStr, SyntaxKind, SyntaxNodePtr, |
73 | }; | 81 | }; |
74 | use tt::{Ident, Leaf, Literal, TokenTree}; | 82 | use 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)] |
1158 | pub enum MacroKind { | 1292 | pub 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 | }; |
13 | use hir_expand::{name::AsName, ExpansionInfo}; | 13 | use hir_expand::{name::AsName, ExpansionInfo}; |
14 | use hir_ty::associated_type_shorthand_candidates; | 14 | use hir_ty::{associated_type_shorthand_candidates, Interner}; |
15 | use itertools::Itertools; | 15 | use itertools::Itertools; |
16 | use rustc_hash::{FxHashMap, FxHashSet}; | 16 | use rustc_hash::{FxHashMap, FxHashSet}; |
17 | use syntax::{ | 17 | use 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 { | |||
637 | pub struct Attr { | 637 | pub 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)] |
644 | pub enum AttrInput { | 644 | pub 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 | ||
736 | impl<'a> AttrQuery<'a> { | 736 | impl<'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. |
3 | mod lower; | 3 | mod lower; |
4 | mod diagnostics; | ||
5 | #[cfg(test)] | 4 | #[cfg(test)] |
6 | mod tests; | 5 | mod tests; |
7 | pub mod scope; | 6 | pub mod scope; |
@@ -9,17 +8,16 @@ pub mod scope; | |||
9 | use std::{mem, ops::Index, sync::Arc}; | 8 | use std::{mem, ops::Index, sync::Arc}; |
10 | 9 | ||
11 | use base_db::CrateId; | 10 | use base_db::CrateId; |
12 | use cfg::CfgOptions; | 11 | use cfg::{CfgExpr, CfgOptions}; |
13 | use drop_bomb::DropBomb; | 12 | use drop_bomb::DropBomb; |
14 | use either::Either; | 13 | use either::Either; |
15 | use hir_expand::{ | 14 | use 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 | }; |
19 | use la_arena::{Arena, ArenaMap}; | 17 | use la_arena::{Arena, ArenaMap}; |
20 | use profile::Count; | 18 | use profile::Count; |
21 | use rustc_hash::FxHashMap; | 19 | use rustc_hash::FxHashMap; |
22 | use syntax::{ast, AstNode, AstPtr}; | 20 | use syntax::{ast, AstNode, AstPtr, SyntaxNodePtr}; |
23 | 21 | ||
24 | use crate::{ | 22 | use 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)] |
280 | pub struct SyntheticSyntax; | 278 | pub struct SyntheticSyntax; |
281 | 279 | ||
280 | #[derive(Debug, Eq, PartialEq)] | ||
281 | pub 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 | |||
282 | impl Body { | 288 | impl 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 | |||
3 | use hir_expand::diagnostics::DiagnosticSink; | ||
4 | |||
5 | use crate::diagnostics::{InactiveCode, MacroError, UnresolvedMacroCall, UnresolvedProcMacro}; | ||
6 | |||
7 | #[derive(Debug, Eq, PartialEq)] | ||
8 | pub(crate) enum BodyDiagnostic { | ||
9 | InactiveCode(InactiveCode), | ||
10 | MacroError(MacroError), | ||
11 | UnresolvedProcMacro(UnresolvedProcMacro), | ||
12 | UnresolvedMacroCall(UnresolvedMacroCall), | ||
13 | } | ||
14 | |||
15 | impl 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 | }; |
13 | use la_arena::Arena; | 13 | use la_arena::Arena; |
14 | use profile::Count; | 14 | use profile::Count; |
@@ -23,9 +23,9 @@ use syntax::{ | |||
23 | use crate::{ | 23 | use 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 | ||
41 | use super::{diagnostics::BodyDiagnostic, ExprSource, PatSource}; | ||
42 | |||
43 | pub struct LowerCtx<'a> { | 41 | pub 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#" |
189 | fn f() { | 189 | fn 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 | ||
118 | impl TypeAliasData { | 120 | impl 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 | ||
147 | impl TraitData { | 148 | impl 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 | |||
3 | use std::any::Any; | ||
4 | use stdx::format_to; | ||
5 | |||
6 | use cfg::{CfgExpr, CfgOptions, DnfExpr}; | ||
7 | use hir_expand::diagnostics::{Diagnostic, DiagnosticCode, DiagnosticSink}; | ||
8 | use hir_expand::{HirFileId, InFile}; | ||
9 | use syntax::{ast, AstPtr, SyntaxNodePtr, TextRange}; | ||
10 | |||
11 | use crate::{db::DefDatabase, path::ModPath, DefWithBodyId}; | ||
12 | |||
13 | pub 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)] | ||
22 | pub struct UnresolvedModule { | ||
23 | pub file: HirFileId, | ||
24 | pub decl: AstPtr<ast::Module>, | ||
25 | pub candidate: String, | ||
26 | } | ||
27 | |||
28 | impl 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)] | ||
47 | pub struct UnresolvedExternCrate { | ||
48 | pub file: HirFileId, | ||
49 | pub item: AstPtr<ast::ExternCrate>, | ||
50 | } | ||
51 | |||
52 | impl 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)] | ||
71 | pub struct UnresolvedImport { | ||
72 | pub file: HirFileId, | ||
73 | pub node: AstPtr<ast::UseTree>, | ||
74 | } | ||
75 | |||
76 | impl 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)] | ||
103 | pub struct UnresolvedMacroCall { | ||
104 | pub file: HirFileId, | ||
105 | pub node: AstPtr<ast::MacroCall>, | ||
106 | pub path: ModPath, | ||
107 | } | ||
108 | |||
109 | impl 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)] | ||
131 | pub struct InactiveCode { | ||
132 | pub file: HirFileId, | ||
133 | pub node: SyntaxNodePtr, | ||
134 | pub cfg: CfgExpr, | ||
135 | pub opts: CfgOptions, | ||
136 | } | ||
137 | |||
138 | impl 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)] | ||
170 | pub 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 | |||
179 | impl 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)] | ||
204 | pub struct MacroError { | ||
205 | pub file: HirFileId, | ||
206 | pub node: SyntaxNodePtr, | ||
207 | pub message: String, | ||
208 | } | ||
209 | |||
210 | impl 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)] |
70 | pub enum WherePredicate { | 70 | pub 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; | |||
216 | impl_internable!( | 216 | impl_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 | ||
3 | mod lower; | 33 | mod lower; |
4 | mod pretty; | 34 | mod 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)] |
498 | pub struct Import { | 527 | pub 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, | 534 | pub struct UseTree { |
535 | pub index: Idx<ast::UseTree>, | ||
536 | kind: UseTreeKind, | ||
537 | } | ||
538 | |||
539 | #[derive(Debug, Clone, Eq, PartialEq)] | ||
540 | pub 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 | ||
731 | impl 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 | |||
750 | impl 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 | |||
684 | macro_rules! impl_froms { | 822 | macro_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 @@ | |||
3 | use std::{collections::hash_map::Entry, mem, sync::Arc}; | 3 | use std::{collections::hash_map::Entry, mem, sync::Arc}; |
4 | 4 | ||
5 | use hir_expand::{ast_id_map::AstIdMap, hygiene::Hygiene, name::known, HirFileId}; | 5 | use hir_expand::{ast_id_map::AstIdMap, hygiene::Hygiene, name::known, HirFileId}; |
6 | use smallvec::SmallVec; | ||
7 | use syntax::{ | 6 | use 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 | ||
23 | struct ModItems(SmallVec<[ModItem; 1]>); | ||
24 | |||
25 | impl<T> From<T> for ModItems | ||
26 | where | ||
27 | T: Into<ModItem>, | ||
28 | { | ||
29 | fn from(t: T) -> Self { | ||
30 | ModItems(SmallVec::from_buf([t.into(); 1])) | ||
31 | } | ||
32 | } | ||
33 | |||
34 | pub(super) struct Ctx<'a> { | 22 | pub(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 | |||
842 | struct UseTreeLowering<'a> { | ||
843 | db: &'a dyn DefDatabase, | ||
844 | hygiene: &'a Hygiene, | ||
845 | mapping: Arena<ast::UseTree>, | ||
846 | } | ||
847 | |||
848 | impl 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 | |||
910 | pub(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 |
28 | use crate::{A, B}; | 28 | use crate::{A, B}; |
29 | |||
30 | use 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; | |||
19 | pub mod type_ref; | 19 | pub mod type_ref; |
20 | pub mod builtin_type; | 20 | pub mod builtin_type; |
21 | pub mod builtin_attr; | 21 | pub mod builtin_attr; |
22 | pub mod diagnostics; | ||
23 | pub mod per_ns; | 22 | pub mod per_ns; |
24 | pub mod item_scope; | 23 | pub mod item_scope; |
25 | 24 | ||
@@ -56,7 +55,6 @@ use std::{ | |||
56 | sync::Arc, | 55 | sync::Arc, |
57 | }; | 56 | }; |
58 | 57 | ||
59 | use adt::VariantData; | ||
60 | use base_db::{impl_intern_key, salsa, CrateId}; | 58 | use base_db::{impl_intern_key, salsa, CrateId}; |
61 | use hir_expand::{ | 59 | use hir_expand::{ |
62 | ast_id_map::FileAstId, | 60 | ast_id_map::FileAstId, |
@@ -67,15 +65,18 @@ use hir_expand::{ | |||
67 | use la_arena::Idx; | 65 | use la_arena::Idx; |
68 | use nameres::DefMap; | 66 | use nameres::DefMap; |
69 | use path::ModPath; | 67 | use path::ModPath; |
68 | use stdx::impl_from; | ||
70 | use syntax::ast; | 69 | use syntax::ast; |
71 | 70 | ||
72 | use crate::attr::AttrId; | 71 | use crate::{ |
73 | use crate::builtin_type::BuiltinType; | 72 | adt::VariantData, |
74 | use 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 | }; |
78 | use stdx::impl_from; | ||
79 | 80 | ||
80 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | 81 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] |
81 | pub struct ModuleId { | 82 | pub 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 | ||
490 | trait Intern { | 499 | trait 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 | ||
50 | pub mod diagnostics; | ||
50 | mod collector; | 51 | mod collector; |
51 | mod mod_resolution; | 52 | mod mod_resolution; |
52 | mod path_resolution; | 53 | mod path_resolution; |
54 | mod proc_macro; | ||
53 | 55 | ||
54 | #[cfg(test)] | 56 | #[cfg(test)] |
55 | mod tests; | 57 | mod tests; |
56 | mod proc_macro; | ||
57 | 58 | ||
58 | use std::sync::Arc; | 59 | use std::sync::Arc; |
59 | 60 | ||
60 | use base_db::{CrateId, Edition, FileId}; | 61 | use base_db::{CrateId, Edition, FileId}; |
61 | use hir_expand::{diagnostics::DiagnosticSink, name::Name, InFile, MacroDefId}; | 62 | use hir_expand::{name::Name, InFile, MacroDefId}; |
62 | use la_arena::Arena; | 63 | use la_arena::Arena; |
63 | use profile::Count; | 64 | use profile::Count; |
64 | use rustc_hash::FxHashMap; | 65 | use 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 | ||
453 | impl ModuleData { | 450 | impl 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 | |||
475 | mod 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 | }; |
18 | use hir_expand::{InFile, MacroCallLoc}; | 18 | use hir_expand::{InFile, MacroCallLoc}; |
19 | use itertools::Itertools; | 19 | use itertools::Itertools; |
20 | use la_arena::Idx; | ||
20 | use rustc_hash::{FxHashMap, FxHashSet}; | 21 | use rustc_hash::{FxHashMap, FxHashSet}; |
21 | use syntax::ast; | 22 | use 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, |