diff options
330 files changed, 14039 insertions, 11266 deletions
diff --git a/Cargo.lock b/Cargo.lock index 505263c64..e47b87964 100644 --- a/Cargo.lock +++ b/Cargo.lock | |||
@@ -245,9 +245,9 @@ dependencies = [ | |||
245 | 245 | ||
246 | [[package]] | 246 | [[package]] |
247 | name = "cov-mark" | 247 | name = "cov-mark" |
248 | version = "1.1.0" | 248 | version = "2.0.0-pre.1" |
249 | source = "registry+https://github.com/rust-lang/crates.io-index" | 249 | source = "registry+https://github.com/rust-lang/crates.io-index" |
250 | checksum = "9ffa3d3e0138386cd4361f63537765cac7ee40698028844635a54495a92f67f3" | 250 | checksum = "0d48d8f76bd9331f19fe2aaf3821a9f9fb32c3963e1e3d6ce82a8c09cef7444a" |
251 | 251 | ||
252 | [[package]] | 252 | [[package]] |
253 | name = "crc32fast" | 253 | name = "crc32fast" |
@@ -482,6 +482,7 @@ dependencies = [ | |||
482 | "hir_ty", | 482 | "hir_ty", |
483 | "itertools", | 483 | "itertools", |
484 | "log", | 484 | "log", |
485 | "once_cell", | ||
485 | "profile", | 486 | "profile", |
486 | "rustc-hash", | 487 | "rustc-hash", |
487 | "smallvec", | 488 | "smallvec", |
@@ -765,9 +766,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" | |||
765 | 766 | ||
766 | [[package]] | 767 | [[package]] |
767 | name = "libc" | 768 | name = "libc" |
768 | version = "0.2.95" | 769 | version = "0.2.97" |
769 | source = "registry+https://github.com/rust-lang/crates.io-index" | 770 | source = "registry+https://github.com/rust-lang/crates.io-index" |
770 | checksum = "789da6d93f1b866ffe175afc5322a4d76c038605a1c3319bb57b06967ca98a36" | 771 | checksum = "12b8adadd720df158f4d70dfe7ccc6adb0472d7c55ca83445f6a5ab3e36f8fb6" |
771 | 772 | ||
772 | [[package]] | 773 | [[package]] |
773 | name = "libloading" | 774 | name = "libloading" |
@@ -1158,6 +1159,15 @@ dependencies = [ | |||
1158 | [[package]] | 1159 | [[package]] |
1159 | name = "proc_macro_test" | 1160 | name = "proc_macro_test" |
1160 | version = "0.0.0" | 1161 | version = "0.0.0" |
1162 | dependencies = [ | ||
1163 | "cargo_metadata", | ||
1164 | "proc_macro_test_impl", | ||
1165 | "toolchain", | ||
1166 | ] | ||
1167 | |||
1168 | [[package]] | ||
1169 | name = "proc_macro_test_impl" | ||
1170 | version = "0.0.0" | ||
1161 | 1171 | ||
1162 | [[package]] | 1172 | [[package]] |
1163 | name = "profile" | 1173 | name = "profile" |
@@ -1170,6 +1180,7 @@ dependencies = [ | |||
1170 | "once_cell", | 1180 | "once_cell", |
1171 | "perf-event", | 1181 | "perf-event", |
1172 | "tikv-jemalloc-ctl", | 1182 | "tikv-jemalloc-ctl", |
1183 | "winapi", | ||
1173 | ] | 1184 | ] |
1174 | 1185 | ||
1175 | [[package]] | 1186 | [[package]] |
@@ -1792,9 +1803,9 @@ checksum = "56dee185309b50d1f11bfedef0fe6d036842e3fb77413abef29f8f8d1c5d4c1c" | |||
1792 | 1803 | ||
1793 | [[package]] | 1804 | [[package]] |
1794 | name = "ungrammar" | 1805 | name = "ungrammar" |
1795 | version = "1.13.0" | 1806 | version = "1.14.0" |
1796 | source = "registry+https://github.com/rust-lang/crates.io-index" | 1807 | source = "registry+https://github.com/rust-lang/crates.io-index" |
1797 | checksum = "76760314176cc2b94047af2f921b92c39f11a34dc05c43a3c2b0fc91cb22959f" | 1808 | checksum = "50ef6d7335c77ec3e4a7c4be74c2b9e4642569e94a4004c836f8cca71fede3a7" |
1798 | 1809 | ||
1799 | [[package]] | 1810 | [[package]] |
1800 | name = "unicase" | 1811 | name = "unicase" |
diff --git a/Cargo.toml b/Cargo.toml index 32ba3923b..4d6908fa9 100644 --- a/Cargo.toml +++ b/Cargo.toml | |||
@@ -1,6 +1,7 @@ | |||
1 | [workspace] | 1 | [workspace] |
2 | resolver = "2" | 2 | resolver = "2" |
3 | members = ["xtask/", "lib/*", "crates/*"] | 3 | members = ["xtask/", "lib/*", "crates/*"] |
4 | exclude = ["crates/proc_macro_test/imp"] | ||
4 | 5 | ||
5 | [profile.dev] | 6 | [profile.dev] |
6 | # Disabling debug info speeds up builds a bunch, | 7 | # Disabling debug info speeds up builds a bunch, |
diff --git a/crates/base_db/src/fixture.rs b/crates/base_db/src/fixture.rs index 69ceba735..da4afb5eb 100644 --- a/crates/base_db/src/fixture.rs +++ b/crates/base_db/src/fixture.rs | |||
@@ -190,7 +190,7 @@ impl From<Fixture> for FileMeta { | |||
190 | edition: f | 190 | edition: f |
191 | .edition | 191 | .edition |
192 | .as_ref() | 192 | .as_ref() |
193 | .map_or(Edition::Edition2018, |v| Edition::from_str(&v).unwrap()), | 193 | .map_or(Edition::Edition2018, |v| Edition::from_str(v).unwrap()), |
194 | env: f.env.into_iter().collect(), | 194 | env: f.env.into_iter().collect(), |
195 | introduce_new_source_root: f.introduce_new_source_root, | 195 | introduce_new_source_root: f.introduce_new_source_root, |
196 | } | 196 | } |
diff --git a/crates/base_db/src/lib.rs b/crates/base_db/src/lib.rs index 62bf2a4b2..d26f8f180 100644 --- a/crates/base_db/src/lib.rs +++ b/crates/base_db/src/lib.rs | |||
@@ -42,7 +42,7 @@ pub struct FilePosition { | |||
42 | pub offset: TextSize, | 42 | pub offset: TextSize, |
43 | } | 43 | } |
44 | 44 | ||
45 | #[derive(Clone, Copy, Debug, Eq, PartialEq)] | 45 | #[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)] |
46 | pub struct FileRange { | 46 | pub struct FileRange { |
47 | pub file_id: FileId, | 47 | pub file_id: FileId, |
48 | pub range: TextRange, | 48 | pub range: TextRange, |
@@ -120,6 +120,7 @@ impl<T: SourceDatabaseExt> FileLoader for FileLoaderDelegate<&'_ T> { | |||
120 | } | 120 | } |
121 | 121 | ||
122 | fn relevant_crates(&self, file_id: FileId) -> Arc<FxHashSet<CrateId>> { | 122 | fn relevant_crates(&self, file_id: FileId) -> Arc<FxHashSet<CrateId>> { |
123 | let _p = profile::span("relevant_crates"); | ||
123 | let source_root = self.0.file_source_root(file_id); | 124 | let source_root = self.0.file_source_root(file_id); |
124 | self.0.source_root_crates(source_root) | 125 | self.0.source_root_crates(source_root) |
125 | } | 126 | } |
diff --git a/crates/cfg/src/cfg_expr.rs b/crates/cfg/src/cfg_expr.rs index 069fc01d0..8a1a51e6e 100644 --- a/crates/cfg/src/cfg_expr.rs +++ b/crates/cfg/src/cfg_expr.rs | |||
@@ -1,6 +1,6 @@ | |||
1 | //! The condition expression used in `#[cfg(..)]` attributes. | 1 | //! The condition expression used in `#[cfg(..)]` attributes. |
2 | //! | 2 | //! |
3 | //! See: https://doc.rust-lang.org/reference/conditional-compilation.html#conditional-compilation | 3 | //! See: <https://doc.rust-lang.org/reference/conditional-compilation.html#conditional-compilation> |
4 | 4 | ||
5 | use std::{fmt, slice::Iter as SliceIter}; | 5 | use std::{fmt, slice::Iter as SliceIter}; |
6 | 6 | ||
diff --git a/crates/cfg/src/lib.rs b/crates/cfg/src/lib.rs index 59fd38880..03b8dd767 100644 --- a/crates/cfg/src/lib.rs +++ b/crates/cfg/src/lib.rs | |||
@@ -22,7 +22,7 @@ pub use dnf::DnfExpr; | |||
22 | /// `foo` and `bar` are both enabled. And here, we store key-value options as a set of tuple | 22 | /// `foo` and `bar` are both enabled. And here, we store key-value options as a set of tuple |
23 | /// of key and value in `key_values`. | 23 | /// of key and value in `key_values`. |
24 | /// | 24 | /// |
25 | /// See: https://doc.rust-lang.org/reference/conditional-compilation.html#set-configuration-options | 25 | /// See: <https://doc.rust-lang.org/reference/conditional-compilation.html#set-configuration-options> |
26 | #[derive(Debug, Clone, PartialEq, Eq, Default)] | 26 | #[derive(Debug, Clone, PartialEq, Eq, Default)] |
27 | pub struct CfgOptions { | 27 | pub struct CfgOptions { |
28 | enabled: FxHashSet<CfgAtom>, | 28 | enabled: FxHashSet<CfgAtom>, |
diff --git a/crates/hir/Cargo.toml b/crates/hir/Cargo.toml index 560b15238..7c148fd40 100644 --- a/crates/hir/Cargo.toml +++ b/crates/hir/Cargo.toml | |||
@@ -16,6 +16,7 @@ either = "1.5.3" | |||
16 | arrayvec = "0.7" | 16 | arrayvec = "0.7" |
17 | itertools = "0.10.0" | 17 | itertools = "0.10.0" |
18 | smallvec = "1.4.0" | 18 | smallvec = "1.4.0" |
19 | once_cell = "1" | ||
19 | 20 | ||
20 | stdx = { path = "../stdx", version = "0.0.0" } | 21 | stdx = { path = "../stdx", version = "0.0.0" } |
21 | syntax = { path = "../syntax", version = "0.0.0" } | 22 | syntax = { path = "../syntax", version = "0.0.0" } |
diff --git a/crates/hir/src/diagnostics.rs b/crates/hir/src/diagnostics.rs index 2cdbd172a..b4c505898 100644 --- a/crates/hir/src/diagnostics.rs +++ b/crates/hir/src/diagnostics.rs | |||
@@ -3,251 +3,152 @@ | |||
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 | use std::any::Any; | 6 | use cfg::{CfgExpr, CfgOptions}; |
7 | 7 | use either::Either; | |
8 | use cfg::{CfgExpr, CfgOptions, DnfExpr}; | ||
9 | use hir_def::path::ModPath; | 8 | use hir_def::path::ModPath; |
10 | use hir_expand::{HirFileId, InFile}; | 9 | use hir_expand::{name::Name, HirFileId, InFile}; |
11 | use stdx::format_to; | ||
12 | use syntax::{ast, AstPtr, SyntaxNodePtr, TextRange}; | 10 | use syntax::{ast, AstPtr, SyntaxNodePtr, TextRange}; |
13 | 11 | ||
14 | pub use hir_ty::{ | 12 | macro_rules! diagnostics { |
15 | diagnostics::{ | 13 | ($($diag:ident,)*) => { |
16 | IncorrectCase, MismatchedArgCount, MissingFields, MissingMatchArms, | 14 | pub enum AnyDiagnostic {$( |
17 | MissingOkOrSomeInTailExpr, NoSuchField, RemoveThisSemicolon, | 15 | $diag(Box<$diag>), |
18 | ReplaceFilterMapNextWithFindMap, | 16 | )*} |
19 | }, | 17 | |
20 | diagnostics_sink::{Diagnostic, DiagnosticCode, DiagnosticSink, DiagnosticSinkBuilder}, | 18 | $( |
21 | }; | 19 | impl From<$diag> for AnyDiagnostic { |
22 | 20 | fn from(d: $diag) -> AnyDiagnostic { | |
23 | // Diagnostic: unresolved-module | 21 | AnyDiagnostic::$diag(Box::new(d)) |
24 | // | 22 | } |
25 | // This diagnostic is triggered if rust-analyzer is unable to discover referred module. | 23 | } |
24 | )* | ||
25 | }; | ||
26 | } | ||
27 | |||
28 | diagnostics![ | ||
29 | BreakOutsideOfLoop, | ||
30 | InactiveCode, | ||
31 | IncorrectCase, | ||
32 | MacroError, | ||
33 | MismatchedArgCount, | ||
34 | MissingFields, | ||
35 | MissingMatchArms, | ||
36 | MissingOkOrSomeInTailExpr, | ||
37 | MissingUnsafe, | ||
38 | NoSuchField, | ||
39 | RemoveThisSemicolon, | ||
40 | ReplaceFilterMapNextWithFindMap, | ||
41 | UnimplementedBuiltinMacro, | ||
42 | UnresolvedExternCrate, | ||
43 | UnresolvedImport, | ||
44 | UnresolvedMacroCall, | ||
45 | UnresolvedModule, | ||
46 | UnresolvedProcMacro, | ||
47 | ]; | ||
48 | |||
26 | #[derive(Debug)] | 49 | #[derive(Debug)] |
27 | pub struct UnresolvedModule { | 50 | pub struct UnresolvedModule { |
28 | pub file: HirFileId, | 51 | pub decl: InFile<AstPtr<ast::Module>>, |
29 | pub decl: AstPtr<ast::Module>, | ||
30 | pub candidate: String, | 52 | pub candidate: String, |
31 | } | 53 | } |
32 | 54 | ||
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)] | 55 | #[derive(Debug)] |
52 | pub struct UnresolvedExternCrate { | 56 | pub struct UnresolvedExternCrate { |
53 | pub file: HirFileId, | 57 | pub decl: InFile<AstPtr<ast::ExternCrate>>, |
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 | } | 58 | } |
71 | 59 | ||
72 | #[derive(Debug)] | 60 | #[derive(Debug)] |
73 | pub struct UnresolvedImport { | 61 | pub struct UnresolvedImport { |
74 | pub file: HirFileId, | 62 | pub decl: InFile<AstPtr<ast::UseTree>>, |
75 | pub node: AstPtr<ast::UseTree>, | 63 | } |
76 | } | 64 | |
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)] | 65 | #[derive(Debug, Clone, Eq, PartialEq)] |
105 | pub struct UnresolvedMacroCall { | 66 | pub struct UnresolvedMacroCall { |
106 | pub file: HirFileId, | 67 | pub macro_call: InFile<AstPtr<ast::MacroCall>>, |
107 | pub node: AstPtr<ast::MacroCall>, | ||
108 | pub path: ModPath, | 68 | pub path: ModPath, |
109 | } | 69 | } |
110 | 70 | ||
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)] | 71 | #[derive(Debug, Clone, Eq, PartialEq)] |
133 | pub struct InactiveCode { | 72 | pub struct InactiveCode { |
134 | pub file: HirFileId, | 73 | pub node: InFile<SyntaxNodePtr>, |
135 | pub node: SyntaxNodePtr, | ||
136 | pub cfg: CfgExpr, | 74 | pub cfg: CfgExpr, |
137 | pub opts: CfgOptions, | 75 | pub opts: CfgOptions, |
138 | } | 76 | } |
139 | 77 | ||
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)] | 78 | #[derive(Debug, Clone, Eq, PartialEq)] |
172 | pub struct UnresolvedProcMacro { | 79 | pub struct UnresolvedProcMacro { |
173 | pub file: HirFileId, | 80 | pub node: InFile<SyntaxNodePtr>, |
174 | pub node: SyntaxNodePtr, | ||
175 | /// If the diagnostic can be pinpointed more accurately than via `node`, this is the `TextRange` | 81 | /// If the diagnostic can be pinpointed more accurately than via `node`, this is the `TextRange` |
176 | /// to use instead. | 82 | /// to use instead. |
177 | pub precise_location: Option<TextRange>, | 83 | pub precise_location: Option<TextRange>, |
178 | pub macro_name: Option<String>, | 84 | pub macro_name: Option<String>, |
179 | } | 85 | } |
180 | 86 | ||
181 | impl Diagnostic for UnresolvedProcMacro { | 87 | #[derive(Debug, Clone, Eq, PartialEq)] |
182 | fn code(&self) -> DiagnosticCode { | 88 | pub struct MacroError { |
183 | DiagnosticCode("unresolved-proc-macro") | 89 | pub node: InFile<SyntaxNodePtr>, |
184 | } | 90 | pub message: String, |
91 | } | ||
185 | 92 | ||
186 | fn message(&self) -> String { | 93 | #[derive(Debug)] |
187 | match &self.macro_name { | 94 | pub struct UnimplementedBuiltinMacro { |
188 | Some(name) => format!("proc macro `{}` not expanded", name), | 95 | pub node: InFile<SyntaxNodePtr>, |
189 | None => "proc macro not expanded".to_string(), | 96 | } |
190 | } | ||
191 | } | ||
192 | 97 | ||
193 | fn display_source(&self) -> InFile<SyntaxNodePtr> { | 98 | #[derive(Debug)] |
194 | InFile::new(self.file, self.node.clone()) | 99 | pub struct NoSuchField { |
195 | } | 100 | pub field: InFile<AstPtr<ast::RecordExprField>>, |
101 | } | ||
196 | 102 | ||
197 | fn as_any(&self) -> &(dyn Any + Send + 'static) { | 103 | #[derive(Debug)] |
198 | self | 104 | pub struct BreakOutsideOfLoop { |
199 | } | 105 | pub expr: InFile<AstPtr<ast::Expr>>, |
200 | } | 106 | } |
201 | 107 | ||
202 | // Diagnostic: macro-error | 108 | #[derive(Debug)] |
203 | // | 109 | pub struct MissingUnsafe { |
204 | // This diagnostic is shown for macro expansion errors. | 110 | pub expr: InFile<AstPtr<ast::Expr>>, |
205 | #[derive(Debug, Clone, Eq, PartialEq)] | ||
206 | pub struct MacroError { | ||
207 | pub file: HirFileId, | ||
208 | pub node: SyntaxNodePtr, | ||
209 | pub message: String, | ||
210 | } | 111 | } |
211 | 112 | ||
212 | impl Diagnostic for MacroError { | 113 | #[derive(Debug)] |
213 | fn code(&self) -> DiagnosticCode { | 114 | pub struct MissingFields { |
214 | DiagnosticCode("macro-error") | 115 | pub file: HirFileId, |
215 | } | 116 | pub field_list_parent: Either<AstPtr<ast::RecordExpr>, AstPtr<ast::RecordPat>>, |
216 | fn message(&self) -> String { | 117 | pub field_list_parent_path: Option<AstPtr<ast::Path>>, |
217 | self.message.clone() | 118 | pub missed_fields: Vec<Name>, |
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 | } | 119 | } |
230 | 120 | ||
231 | #[derive(Debug)] | 121 | #[derive(Debug)] |
232 | pub struct UnimplementedBuiltinMacro { | 122 | pub struct ReplaceFilterMapNextWithFindMap { |
233 | pub file: HirFileId, | 123 | pub file: HirFileId, |
234 | pub node: SyntaxNodePtr, | 124 | /// This expression is the whole method chain up to and including `.filter_map(..).next()`. |
125 | pub next_expr: AstPtr<ast::Expr>, | ||
235 | } | 126 | } |
236 | 127 | ||
237 | impl Diagnostic for UnimplementedBuiltinMacro { | 128 | #[derive(Debug)] |
238 | fn code(&self) -> DiagnosticCode { | 129 | pub struct MismatchedArgCount { |
239 | DiagnosticCode("unimplemented-builtin-macro") | 130 | pub call_expr: InFile<AstPtr<ast::Expr>>, |
240 | } | 131 | pub expected: usize, |
132 | pub found: usize, | ||
133 | } | ||
241 | 134 | ||
242 | fn message(&self) -> String { | 135 | #[derive(Debug)] |
243 | "unimplemented built-in macro".to_string() | 136 | pub struct RemoveThisSemicolon { |
244 | } | 137 | pub expr: InFile<AstPtr<ast::Expr>>, |
138 | } | ||
245 | 139 | ||
246 | fn display_source(&self) -> InFile<SyntaxNodePtr> { | 140 | #[derive(Debug)] |
247 | InFile::new(self.file, self.node.clone()) | 141 | pub struct MissingOkOrSomeInTailExpr { |
248 | } | 142 | pub expr: InFile<AstPtr<ast::Expr>>, |
143 | // `Some` or `Ok` depending on whether the return type is Result or Option | ||
144 | pub required: String, | ||
145 | } | ||
249 | 146 | ||
250 | fn as_any(&self) -> &(dyn Any + Send + 'static) { | 147 | #[derive(Debug)] |
251 | self | 148 | pub struct MissingMatchArms { |
252 | } | 149 | pub file: HirFileId, |
150 | pub match_expr: AstPtr<ast::Expr>, | ||
151 | pub arms: AstPtr<ast::MatchArmList>, | ||
253 | } | 152 | } |
153 | |||
154 | pub use hir_ty::diagnostics::IncorrectCase; | ||
diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs index d3ef29db4..5bc0b2338 100644 --- a/crates/hir/src/lib.rs +++ b/crates/hir/src/lib.rs | |||
@@ -15,7 +15,7 @@ | |||
15 | //! | 15 | //! |
16 | //! `hir` is what insulates the "we don't know how to actually write an incremental compiler" | 16 | //! `hir` is what insulates the "we don't know how to actually write an incremental compiler" |
17 | //! from the ide with completions, hovers, etc. It is a (soft, internal) boundary: | 17 | //! from the ide with completions, hovers, etc. It is a (soft, internal) boundary: |
18 | //! https://www.tedinski.com/2018/02/06/system-boundaries.html. | 18 | //! <https://www.tedinski.com/2018/02/06/system-boundaries.html>. |
19 | 19 | ||
20 | #![recursion_limit = "512"] | 20 | #![recursion_limit = "512"] |
21 | 21 | ||
@@ -35,14 +35,10 @@ 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 | }; | ||
42 | use either::Either; | 38 | use either::Either; |
43 | use hir_def::{ | 39 | use hir_def::{ |
44 | adt::{ReprKind, VariantData}, | 40 | adt::{ReprKind, VariantData}, |
45 | body::BodyDiagnostic, | 41 | body::{BodyDiagnostic, SyntheticSyntax}, |
46 | expr::{BindingAnnotation, LabelId, Pat, PatId}, | 42 | expr::{BindingAnnotation, LabelId, Pat, PatId}, |
47 | item_tree::ItemTreeNode, | 43 | item_tree::ItemTreeNode, |
48 | lang_item::LangItemTarget, | 44 | lang_item::LangItemTarget, |
@@ -50,7 +46,6 @@ use hir_def::{ | |||
50 | per_ns::PerNs, | 46 | per_ns::PerNs, |
51 | resolver::{HasResolver, Resolver}, | 47 | resolver::{HasResolver, Resolver}, |
52 | src::HasSource as _, | 48 | src::HasSource as _, |
53 | type_ref::TraitRef, | ||
54 | AdtId, AssocContainerId, AssocItemId, AssocItemLoc, AttrDefId, ConstId, ConstParamId, | 49 | AdtId, AssocContainerId, AssocItemId, AssocItemLoc, AttrDefId, ConstId, ConstParamId, |
55 | DefWithBodyId, EnumId, FunctionId, GenericDefId, HasModule, ImplId, LifetimeParamId, | 50 | DefWithBodyId, EnumId, FunctionId, GenericDefId, HasModule, ImplId, LifetimeParamId, |
56 | LocalEnumVariantId, LocalFieldId, Lookup, ModuleId, StaticId, StructId, TraitId, TypeAliasId, | 51 | LocalEnumVariantId, LocalFieldId, Lookup, ModuleId, StaticId, StructId, TraitId, TypeAliasId, |
@@ -61,8 +56,8 @@ use hir_ty::{ | |||
61 | autoderef, | 56 | autoderef, |
62 | consteval::ConstExt, | 57 | consteval::ConstExt, |
63 | could_unify, | 58 | could_unify, |
64 | diagnostics_sink::DiagnosticSink, | 59 | diagnostics::BodyValidationDiagnostic, |
65 | method_resolution::{self, def_crates, TyFingerprint}, | 60 | method_resolution::{self, TyFingerprint}, |
66 | primitive::UintTy, | 61 | primitive::UintTy, |
67 | subst_prefix, | 62 | subst_prefix, |
68 | traits::FnTrait, | 63 | traits::FnTrait, |
@@ -73,6 +68,7 @@ use hir_ty::{ | |||
73 | }; | 68 | }; |
74 | use itertools::Itertools; | 69 | use itertools::Itertools; |
75 | use nameres::diagnostics::DefDiagnosticKind; | 70 | use nameres::diagnostics::DefDiagnosticKind; |
71 | use once_cell::unsync::Lazy; | ||
76 | use rustc_hash::FxHashSet; | 72 | use rustc_hash::FxHashSet; |
77 | use stdx::{format_to, impl_from}; | 73 | use stdx::{format_to, impl_from}; |
78 | use syntax::{ | 74 | use syntax::{ |
@@ -85,6 +81,13 @@ use crate::db::{DefDatabase, HirDatabase}; | |||
85 | 81 | ||
86 | pub use crate::{ | 82 | pub use crate::{ |
87 | attrs::{HasAttrs, Namespace}, | 83 | attrs::{HasAttrs, Namespace}, |
84 | diagnostics::{ | ||
85 | AnyDiagnostic, BreakOutsideOfLoop, InactiveCode, IncorrectCase, MacroError, | ||
86 | MismatchedArgCount, MissingFields, MissingMatchArms, MissingOkOrSomeInTailExpr, | ||
87 | MissingUnsafe, NoSuchField, RemoveThisSemicolon, ReplaceFilterMapNextWithFindMap, | ||
88 | UnimplementedBuiltinMacro, UnresolvedExternCrate, UnresolvedImport, UnresolvedMacroCall, | ||
89 | UnresolvedModule, UnresolvedProcMacro, | ||
90 | }, | ||
88 | has_source::HasSource, | 91 | has_source::HasSource, |
89 | semantics::{PathResolution, Semantics, SemanticsScope}, | 92 | semantics::{PathResolution, Semantics, SemanticsScope}, |
90 | }; | 93 | }; |
@@ -192,6 +195,7 @@ impl Crate { | |||
192 | db: &dyn DefDatabase, | 195 | db: &dyn DefDatabase, |
193 | query: import_map::Query, | 196 | query: import_map::Query, |
194 | ) -> impl Iterator<Item = Either<ModuleDef, MacroDef>> { | 197 | ) -> impl Iterator<Item = Either<ModuleDef, MacroDef>> { |
198 | let _p = profile::span("query_external_importables"); | ||
195 | import_map::search_dependencies(db, self.into(), query).into_iter().map(|item| match item { | 199 | import_map::search_dependencies(db, self.into(), query).into_iter().map(|item| match item { |
196 | ItemInNs::Types(mod_id) | ItemInNs::Values(mod_id) => Either::Left(mod_id.into()), | 200 | ItemInNs::Types(mod_id) | ItemInNs::Values(mod_id) => Either::Left(mod_id.into()), |
197 | ItemInNs::Macros(mac_id) => Either::Right(mac_id.into()), | 201 | ItemInNs::Macros(mac_id) => Either::Right(mac_id.into()), |
@@ -332,7 +336,7 @@ impl ModuleDef { | |||
332 | } | 336 | } |
333 | } | 337 | } |
334 | 338 | ||
335 | pub fn diagnostics(self, db: &dyn HirDatabase, sink: &mut DiagnosticSink) { | 339 | pub fn diagnostics(self, db: &dyn HirDatabase) -> Vec<AnyDiagnostic> { |
336 | let id = match self { | 340 | let id = match self { |
337 | ModuleDef::Adt(it) => match it { | 341 | ModuleDef::Adt(it) => match it { |
338 | Adt::Struct(it) => it.id.into(), | 342 | Adt::Struct(it) => it.id.into(), |
@@ -345,15 +349,19 @@ impl ModuleDef { | |||
345 | ModuleDef::Module(it) => it.id.into(), | 349 | ModuleDef::Module(it) => it.id.into(), |
346 | ModuleDef::Const(it) => it.id.into(), | 350 | ModuleDef::Const(it) => it.id.into(), |
347 | ModuleDef::Static(it) => it.id.into(), | 351 | ModuleDef::Static(it) => it.id.into(), |
348 | _ => return, | 352 | _ => return Vec::new(), |
349 | }; | 353 | }; |
350 | 354 | ||
351 | let module = match self.module(db) { | 355 | let module = match self.module(db) { |
352 | Some(it) => it, | 356 | Some(it) => it, |
353 | None => return, | 357 | None => return Vec::new(), |
354 | }; | 358 | }; |
355 | 359 | ||
356 | hir_ty::diagnostics::validate_module_item(db, module.id.krate(), id, sink) | 360 | let mut acc = Vec::new(); |
361 | for diag in hir_ty::diagnostics::validate_module_item(db, module.id.krate(), id) { | ||
362 | acc.push(diag.into()) | ||
363 | } | ||
364 | acc | ||
357 | } | 365 | } |
358 | } | 366 | } |
359 | 367 | ||
@@ -442,10 +450,10 @@ impl Module { | |||
442 | } | 450 | } |
443 | 451 | ||
444 | pub fn visibility_of(self, db: &dyn HirDatabase, def: &ModuleDef) -> Option<Visibility> { | 452 | pub fn visibility_of(self, db: &dyn HirDatabase, def: &ModuleDef) -> Option<Visibility> { |
445 | self.id.def_map(db.upcast())[self.id.local_id].scope.visibility_of(def.clone().into()) | 453 | self.id.def_map(db.upcast())[self.id.local_id].scope.visibility_of((*def).into()) |
446 | } | 454 | } |
447 | 455 | ||
448 | pub fn diagnostics(self, db: &dyn HirDatabase, sink: &mut DiagnosticSink) { | 456 | pub fn diagnostics(self, db: &dyn HirDatabase, acc: &mut Vec<AnyDiagnostic>) { |
449 | let _p = profile::span("Module::diagnostics").detail(|| { | 457 | let _p = profile::span("Module::diagnostics").detail(|| { |
450 | format!("{:?}", self.name(db).map_or("<unknown>".into(), |name| name.to_string())) | 458 | format!("{:?}", self.name(db).map_or("<unknown>".into(), |name| name.to_string())) |
451 | }); | 459 | }); |
@@ -458,18 +466,22 @@ impl Module { | |||
458 | match &diag.kind { | 466 | match &diag.kind { |
459 | DefDiagnosticKind::UnresolvedModule { ast: declaration, candidate } => { | 467 | DefDiagnosticKind::UnresolvedModule { ast: declaration, candidate } => { |
460 | let decl = declaration.to_node(db.upcast()); | 468 | let decl = declaration.to_node(db.upcast()); |
461 | sink.push(UnresolvedModule { | 469 | acc.push( |
462 | file: declaration.file_id, | 470 | UnresolvedModule { |
463 | decl: AstPtr::new(&decl), | 471 | decl: InFile::new(declaration.file_id, AstPtr::new(&decl)), |
464 | candidate: candidate.clone(), | 472 | candidate: candidate.clone(), |
465 | }) | 473 | } |
474 | .into(), | ||
475 | ) | ||
466 | } | 476 | } |
467 | DefDiagnosticKind::UnresolvedExternCrate { ast } => { | 477 | DefDiagnosticKind::UnresolvedExternCrate { ast } => { |
468 | let item = ast.to_node(db.upcast()); | 478 | let item = ast.to_node(db.upcast()); |
469 | sink.push(UnresolvedExternCrate { | 479 | acc.push( |
470 | file: ast.file_id, | 480 | UnresolvedExternCrate { |
471 | item: AstPtr::new(&item), | 481 | decl: InFile::new(ast.file_id, AstPtr::new(&item)), |
472 | }); | 482 | } |
483 | .into(), | ||
484 | ); | ||
473 | } | 485 | } |
474 | 486 | ||
475 | DefDiagnosticKind::UnresolvedImport { id, index } => { | 487 | DefDiagnosticKind::UnresolvedImport { id, index } => { |
@@ -478,25 +490,30 @@ impl Module { | |||
478 | let import = &item_tree[id.value]; | 490 | let import = &item_tree[id.value]; |
479 | 491 | ||
480 | let use_tree = import.use_tree_to_ast(db.upcast(), file_id, *index); | 492 | 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) }); | 493 | acc.push( |
494 | UnresolvedImport { decl: InFile::new(file_id, AstPtr::new(&use_tree)) } | ||
495 | .into(), | ||
496 | ); | ||
482 | } | 497 | } |
483 | 498 | ||
484 | DefDiagnosticKind::UnconfiguredCode { ast, cfg, opts } => { | 499 | DefDiagnosticKind::UnconfiguredCode { ast, cfg, opts } => { |
485 | let item = ast.to_node(db.upcast()); | 500 | let item = ast.to_node(db.upcast()); |
486 | sink.push(InactiveCode { | 501 | acc.push( |
487 | file: ast.file_id, | 502 | InactiveCode { |
488 | node: AstPtr::new(&item).into(), | 503 | node: ast.with_value(AstPtr::new(&item).into()), |
489 | cfg: cfg.clone(), | 504 | cfg: cfg.clone(), |
490 | opts: opts.clone(), | 505 | opts: opts.clone(), |
491 | }); | 506 | } |
507 | .into(), | ||
508 | ); | ||
492 | } | 509 | } |
493 | 510 | ||
494 | DefDiagnosticKind::UnresolvedProcMacro { ast } => { | 511 | DefDiagnosticKind::UnresolvedProcMacro { ast } => { |
495 | let mut precise_location = None; | 512 | let mut precise_location = None; |
496 | let (file, ast, name) = match ast { | 513 | let (node, name) = match ast { |
497 | MacroCallKind::FnLike { ast_id, .. } => { | 514 | MacroCallKind::FnLike { ast_id, .. } => { |
498 | let node = ast_id.to_node(db.upcast()); | 515 | let node = ast_id.to_node(db.upcast()); |
499 | (ast_id.file_id, SyntaxNodePtr::from(AstPtr::new(&node)), None) | 516 | (ast_id.with_value(SyntaxNodePtr::from(AstPtr::new(&node))), None) |
500 | } | 517 | } |
501 | MacroCallKind::Derive { ast_id, derive_name, .. } => { | 518 | MacroCallKind::Derive { ast_id, derive_name, .. } => { |
502 | let node = ast_id.to_node(db.upcast()); | 519 | let node = ast_id.to_node(db.upcast()); |
@@ -529,71 +546,84 @@ impl Module { | |||
529 | } | 546 | } |
530 | 547 | ||
531 | ( | 548 | ( |
532 | ast_id.file_id, | 549 | ast_id.with_value(SyntaxNodePtr::from(AstPtr::new(&node))), |
533 | SyntaxNodePtr::from(AstPtr::new(&node)), | ||
534 | Some(derive_name.clone()), | 550 | Some(derive_name.clone()), |
535 | ) | 551 | ) |
536 | } | 552 | } |
553 | MacroCallKind::Attr { ast_id, invoc_attr_index, attr_name, .. } => { | ||
554 | let node = ast_id.to_node(db.upcast()); | ||
555 | let attr = | ||
556 | node.attrs().nth((*invoc_attr_index) as usize).unwrap_or_else( | ||
557 | || panic!("cannot find attribute #{}", invoc_attr_index), | ||
558 | ); | ||
559 | ( | ||
560 | ast_id.with_value(SyntaxNodePtr::from(AstPtr::new(&attr))), | ||
561 | Some(attr_name.clone()), | ||
562 | ) | ||
563 | } | ||
537 | }; | 564 | }; |
538 | sink.push(UnresolvedProcMacro { | 565 | acc.push( |
539 | file, | 566 | UnresolvedProcMacro { node, precise_location, macro_name: name }.into(), |
540 | node: ast, | 567 | ); |
541 | precise_location, | ||
542 | macro_name: name, | ||
543 | }); | ||
544 | } | 568 | } |
545 | 569 | ||
546 | DefDiagnosticKind::UnresolvedMacroCall { ast, path } => { | 570 | DefDiagnosticKind::UnresolvedMacroCall { ast, path } => { |
547 | let node = ast.to_node(db.upcast()); | 571 | let node = ast.to_node(db.upcast()); |
548 | sink.push(UnresolvedMacroCall { | 572 | acc.push( |
549 | file: ast.file_id, | 573 | UnresolvedMacroCall { |
550 | node: AstPtr::new(&node), | 574 | macro_call: InFile::new(ast.file_id, AstPtr::new(&node)), |
551 | path: path.clone(), | 575 | path: path.clone(), |
552 | }); | 576 | } |
577 | .into(), | ||
578 | ); | ||
553 | } | 579 | } |
554 | 580 | ||
555 | DefDiagnosticKind::MacroError { ast, message } => { | 581 | DefDiagnosticKind::MacroError { ast, message } => { |
556 | let (file, ast) = match ast { | 582 | let node = match ast { |
557 | MacroCallKind::FnLike { ast_id, .. } => { | 583 | MacroCallKind::FnLike { ast_id, .. } => { |
558 | let node = ast_id.to_node(db.upcast()); | 584 | let node = ast_id.to_node(db.upcast()); |
559 | (ast_id.file_id, SyntaxNodePtr::from(AstPtr::new(&node))) | 585 | ast_id.with_value(SyntaxNodePtr::from(AstPtr::new(&node))) |
560 | } | 586 | } |
561 | MacroCallKind::Derive { ast_id, .. } => { | 587 | MacroCallKind::Derive { ast_id, .. } |
588 | | MacroCallKind::Attr { ast_id, .. } => { | ||
589 | // FIXME: point to the attribute instead, this creates very large diagnostics | ||
562 | let node = ast_id.to_node(db.upcast()); | 590 | let node = ast_id.to_node(db.upcast()); |
563 | (ast_id.file_id, SyntaxNodePtr::from(AstPtr::new(&node))) | 591 | ast_id.with_value(SyntaxNodePtr::from(AstPtr::new(&node))) |
564 | } | 592 | } |
565 | }; | 593 | }; |
566 | sink.push(MacroError { file, node: ast, message: message.clone() }); | 594 | acc.push(MacroError { node, message: message.clone() }.into()); |
567 | } | 595 | } |
568 | 596 | ||
569 | DefDiagnosticKind::UnimplementedBuiltinMacro { ast } => { | 597 | DefDiagnosticKind::UnimplementedBuiltinMacro { ast } => { |
570 | let node = ast.to_node(db.upcast()); | 598 | let node = ast.to_node(db.upcast()); |
571 | // Must have a name, otherwise we wouldn't emit it. | 599 | // Must have a name, otherwise we wouldn't emit it. |
572 | let name = node.name().expect("unimplemented builtin macro with no name"); | 600 | let name = node.name().expect("unimplemented builtin macro with no name"); |
573 | let ptr = SyntaxNodePtr::from(AstPtr::new(&name)); | 601 | acc.push( |
574 | sink.push(UnimplementedBuiltinMacro { file: ast.file_id, node: ptr }); | 602 | UnimplementedBuiltinMacro { |
603 | node: ast.with_value(SyntaxNodePtr::from(AstPtr::new(&name))), | ||
604 | } | ||
605 | .into(), | ||
606 | ); | ||
575 | } | 607 | } |
576 | } | 608 | } |
577 | } | 609 | } |
578 | for decl in self.declarations(db) { | 610 | for decl in self.declarations(db) { |
579 | match decl { | 611 | match decl { |
580 | crate::ModuleDef::Function(f) => f.diagnostics(db, sink), | 612 | ModuleDef::Function(f) => f.diagnostics(db, acc), |
581 | crate::ModuleDef::Module(m) => { | 613 | ModuleDef::Module(m) => { |
582 | // Only add diagnostics from inline modules | 614 | // Only add diagnostics from inline modules |
583 | if def_map[m.id.local_id].origin.is_inline() { | 615 | if def_map[m.id.local_id].origin.is_inline() { |
584 | m.diagnostics(db, sink) | 616 | m.diagnostics(db, acc) |
585 | } | 617 | } |
586 | } | 618 | } |
587 | _ => { | 619 | _ => acc.extend(decl.diagnostics(db)), |
588 | decl.diagnostics(db, sink); | ||
589 | } | ||
590 | } | 620 | } |
591 | } | 621 | } |
592 | 622 | ||
593 | for impl_def in self.impl_defs(db) { | 623 | for impl_def in self.impl_defs(db) { |
594 | for item in impl_def.items(db) { | 624 | for item in impl_def.items(db) { |
595 | if let AssocItem::Function(f) = item { | 625 | if let AssocItem::Function(f) = item { |
596 | f.diagnostics(db, sink); | 626 | f.diagnostics(db, acc); |
597 | } | 627 | } |
598 | } | 628 | } |
599 | } | 629 | } |
@@ -995,41 +1025,191 @@ impl Function { | |||
995 | db.function_data(self.id).is_async() | 1025 | db.function_data(self.id).is_async() |
996 | } | 1026 | } |
997 | 1027 | ||
998 | pub fn diagnostics(self, db: &dyn HirDatabase, sink: &mut DiagnosticSink) { | 1028 | pub fn diagnostics(self, db: &dyn HirDatabase, acc: &mut Vec<AnyDiagnostic>) { |
999 | let krate = self.module(db).id.krate(); | 1029 | let krate = self.module(db).id.krate(); |
1000 | 1030 | ||
1001 | let source_map = db.body_with_source_map(self.id.into()).1; | 1031 | let source_map = db.body_with_source_map(self.id.into()).1; |
1002 | for diag in source_map.diagnostics() { | 1032 | for diag in source_map.diagnostics() { |
1003 | match diag { | 1033 | match diag { |
1004 | BodyDiagnostic::InactiveCode { node, cfg, opts } => sink.push(InactiveCode { | 1034 | BodyDiagnostic::InactiveCode { node, cfg, opts } => acc.push( |
1005 | file: node.file_id, | 1035 | InactiveCode { node: node.clone(), cfg: cfg.clone(), opts: opts.clone() } |
1006 | node: node.value.clone(), | 1036 | .into(), |
1007 | cfg: cfg.clone(), | 1037 | ), |
1008 | opts: opts.clone(), | 1038 | BodyDiagnostic::MacroError { node, message } => acc.push( |
1009 | }), | 1039 | MacroError { |
1010 | BodyDiagnostic::MacroError { node, message } => sink.push(MacroError { | 1040 | node: node.clone().map(|it| it.into()), |
1011 | file: node.file_id, | 1041 | message: message.to_string(), |
1012 | node: node.value.clone().into(), | 1042 | } |
1013 | message: message.to_string(), | 1043 | .into(), |
1014 | }), | 1044 | ), |
1015 | BodyDiagnostic::UnresolvedProcMacro { node } => sink.push(UnresolvedProcMacro { | 1045 | BodyDiagnostic::UnresolvedProcMacro { node } => acc.push( |
1016 | file: node.file_id, | 1046 | UnresolvedProcMacro { |
1017 | node: node.value.clone().into(), | 1047 | node: node.clone().map(|it| it.into()), |
1018 | precise_location: None, | 1048 | precise_location: None, |
1019 | macro_name: None, | 1049 | macro_name: None, |
1020 | }), | 1050 | } |
1021 | BodyDiagnostic::UnresolvedMacroCall { node, path } => { | 1051 | .into(), |
1022 | sink.push(UnresolvedMacroCall { | 1052 | ), |
1023 | file: node.file_id, | 1053 | BodyDiagnostic::UnresolvedMacroCall { node, path } => acc.push( |
1024 | node: node.value.clone(), | 1054 | UnresolvedMacroCall { macro_call: node.clone(), path: path.clone() }.into(), |
1025 | path: path.clone(), | 1055 | ), |
1026 | }) | 1056 | } |
1057 | } | ||
1058 | |||
1059 | let infer = db.infer(self.id.into()); | ||
1060 | let source_map = Lazy::new(|| db.body_with_source_map(self.id.into()).1); | ||
1061 | for d in &infer.diagnostics { | ||
1062 | match d { | ||
1063 | hir_ty::InferenceDiagnostic::NoSuchField { expr } => { | ||
1064 | let field = source_map.field_syntax(*expr); | ||
1065 | acc.push(NoSuchField { field }.into()) | ||
1066 | } | ||
1067 | hir_ty::InferenceDiagnostic::BreakOutsideOfLoop { expr } => { | ||
1068 | let expr = source_map | ||
1069 | .expr_syntax(*expr) | ||
1070 | .expect("break outside of loop in synthetic syntax"); | ||
1071 | acc.push(BreakOutsideOfLoop { expr }.into()) | ||
1072 | } | ||
1073 | } | ||
1074 | } | ||
1075 | |||
1076 | for expr in hir_ty::diagnostics::missing_unsafe(db, self.id.into()) { | ||
1077 | match source_map.expr_syntax(expr) { | ||
1078 | Ok(expr) => acc.push(MissingUnsafe { expr }.into()), | ||
1079 | Err(SyntheticSyntax) => { | ||
1080 | // FIXME: Here and eslwhere in this file, the `expr` was | ||
1081 | // desugared, report or assert that this doesn't happen. | ||
1082 | } | ||
1083 | } | ||
1084 | } | ||
1085 | |||
1086 | for diagnostic in BodyValidationDiagnostic::collect(db, self.id.into()) { | ||
1087 | match diagnostic { | ||
1088 | BodyValidationDiagnostic::RecordMissingFields { | ||
1089 | record, | ||
1090 | variant, | ||
1091 | missed_fields, | ||
1092 | } => { | ||
1093 | let variant_data = variant.variant_data(db.upcast()); | ||
1094 | let missed_fields = missed_fields | ||
1095 | .into_iter() | ||
1096 | .map(|idx| variant_data.fields()[idx].name.clone()) | ||
1097 | .collect(); | ||
1098 | |||
1099 | match record { | ||
1100 | Either::Left(record_expr) => match source_map.expr_syntax(record_expr) { | ||
1101 | Ok(source_ptr) => { | ||
1102 | let root = source_ptr.file_syntax(db.upcast()); | ||
1103 | if let ast::Expr::RecordExpr(record_expr) = | ||
1104 | &source_ptr.value.to_node(&root) | ||
1105 | { | ||
1106 | if let Some(_) = record_expr.record_expr_field_list() { | ||
1107 | acc.push( | ||
1108 | MissingFields { | ||
1109 | file: source_ptr.file_id, | ||
1110 | field_list_parent: Either::Left(AstPtr::new( | ||
1111 | record_expr, | ||
1112 | )), | ||
1113 | field_list_parent_path: record_expr | ||
1114 | .path() | ||
1115 | .map(|path| AstPtr::new(&path)), | ||
1116 | missed_fields, | ||
1117 | } | ||
1118 | .into(), | ||
1119 | ) | ||
1120 | } | ||
1121 | } | ||
1122 | } | ||
1123 | Err(SyntheticSyntax) => (), | ||
1124 | }, | ||
1125 | Either::Right(record_pat) => match source_map.pat_syntax(record_pat) { | ||
1126 | Ok(source_ptr) => { | ||
1127 | if let Some(expr) = source_ptr.value.as_ref().left() { | ||
1128 | let root = source_ptr.file_syntax(db.upcast()); | ||
1129 | if let ast::Pat::RecordPat(record_pat) = expr.to_node(&root) { | ||
1130 | if let Some(_) = record_pat.record_pat_field_list() { | ||
1131 | acc.push( | ||
1132 | MissingFields { | ||
1133 | file: source_ptr.file_id, | ||
1134 | field_list_parent: Either::Right(AstPtr::new( | ||
1135 | &record_pat, | ||
1136 | )), | ||
1137 | field_list_parent_path: record_pat | ||
1138 | .path() | ||
1139 | .map(|path| AstPtr::new(&path)), | ||
1140 | missed_fields, | ||
1141 | } | ||
1142 | .into(), | ||
1143 | ) | ||
1144 | } | ||
1145 | } | ||
1146 | } | ||
1147 | } | ||
1148 | Err(SyntheticSyntax) => (), | ||
1149 | }, | ||
1150 | } | ||
1151 | } | ||
1152 | BodyValidationDiagnostic::ReplaceFilterMapNextWithFindMap { method_call_expr } => { | ||
1153 | if let Ok(next_source_ptr) = source_map.expr_syntax(method_call_expr) { | ||
1154 | acc.push( | ||
1155 | ReplaceFilterMapNextWithFindMap { | ||
1156 | file: next_source_ptr.file_id, | ||
1157 | next_expr: next_source_ptr.value, | ||
1158 | } | ||
1159 | .into(), | ||
1160 | ); | ||
1161 | } | ||
1162 | } | ||
1163 | BodyValidationDiagnostic::MismatchedArgCount { call_expr, expected, found } => { | ||
1164 | match source_map.expr_syntax(call_expr) { | ||
1165 | Ok(source_ptr) => acc.push( | ||
1166 | MismatchedArgCount { call_expr: source_ptr, expected, found }.into(), | ||
1167 | ), | ||
1168 | Err(SyntheticSyntax) => (), | ||
1169 | } | ||
1170 | } | ||
1171 | BodyValidationDiagnostic::RemoveThisSemicolon { expr } => { | ||
1172 | match source_map.expr_syntax(expr) { | ||
1173 | Ok(expr) => acc.push(RemoveThisSemicolon { expr }.into()), | ||
1174 | Err(SyntheticSyntax) => (), | ||
1175 | } | ||
1176 | } | ||
1177 | BodyValidationDiagnostic::MissingOkOrSomeInTailExpr { expr, required } => { | ||
1178 | match source_map.expr_syntax(expr) { | ||
1179 | Ok(expr) => acc.push(MissingOkOrSomeInTailExpr { expr, required }.into()), | ||
1180 | Err(SyntheticSyntax) => (), | ||
1181 | } | ||
1182 | } | ||
1183 | BodyValidationDiagnostic::MissingMatchArms { match_expr } => { | ||
1184 | match source_map.expr_syntax(match_expr) { | ||
1185 | Ok(source_ptr) => { | ||
1186 | let root = source_ptr.file_syntax(db.upcast()); | ||
1187 | if let ast::Expr::MatchExpr(match_expr) = | ||
1188 | &source_ptr.value.to_node(&root) | ||
1189 | { | ||
1190 | if let (Some(match_expr), Some(arms)) = | ||
1191 | (match_expr.expr(), match_expr.match_arm_list()) | ||
1192 | { | ||
1193 | acc.push( | ||
1194 | MissingMatchArms { | ||
1195 | file: source_ptr.file_id, | ||
1196 | match_expr: AstPtr::new(&match_expr), | ||
1197 | arms: AstPtr::new(&arms), | ||
1198 | } | ||
1199 | .into(), | ||
1200 | ) | ||
1201 | } | ||
1202 | } | ||
1203 | } | ||
1204 | Err(SyntheticSyntax) => (), | ||
1205 | } | ||
1027 | } | 1206 | } |
1028 | } | 1207 | } |
1029 | } | 1208 | } |
1030 | 1209 | ||
1031 | hir_ty::diagnostics::validate_module_item(db, krate, self.id.into(), sink); | 1210 | for diag in hir_ty::diagnostics::validate_module_item(db, krate, self.id.into()) { |
1032 | hir_ty::diagnostics::validate_body(db, self.id.into(), sink); | 1211 | acc.push(diag.into()) |
1212 | } | ||
1033 | } | 1213 | } |
1034 | 1214 | ||
1035 | /// Whether this function declaration has a definition. | 1215 | /// Whether this function declaration has a definition. |
@@ -1331,6 +1511,7 @@ impl MacroDef { | |||
1331 | MacroDefKind::Declarative(_) => MacroKind::Declarative, | 1511 | MacroDefKind::Declarative(_) => MacroKind::Declarative, |
1332 | MacroDefKind::BuiltIn(_, _) | MacroDefKind::BuiltInEager(_, _) => MacroKind::BuiltIn, | 1512 | MacroDefKind::BuiltIn(_, _) | MacroDefKind::BuiltInEager(_, _) => MacroKind::BuiltIn, |
1333 | MacroDefKind::BuiltInDerive(_, _) => MacroKind::Derive, | 1513 | MacroDefKind::BuiltInDerive(_, _) => MacroKind::Derive, |
1514 | MacroDefKind::BuiltInAttr(_, _) => MacroKind::Attr, | ||
1334 | MacroDefKind::ProcMacro(_, base_db::ProcMacroKind::CustomDerive, _) => { | 1515 | MacroDefKind::ProcMacro(_, base_db::ProcMacroKind::CustomDerive, _) => { |
1335 | MacroKind::Derive | 1516 | MacroKind::Derive |
1336 | } | 1517 | } |
@@ -1338,6 +1519,13 @@ impl MacroDef { | |||
1338 | MacroDefKind::ProcMacro(_, base_db::ProcMacroKind::FuncLike, _) => MacroKind::ProcMacro, | 1519 | MacroDefKind::ProcMacro(_, base_db::ProcMacroKind::FuncLike, _) => MacroKind::ProcMacro, |
1339 | } | 1520 | } |
1340 | } | 1521 | } |
1522 | |||
1523 | pub fn is_fn_like(&self) -> bool { | ||
1524 | match self.kind() { | ||
1525 | MacroKind::Declarative | MacroKind::BuiltIn | MacroKind::ProcMacro => true, | ||
1526 | MacroKind::Attr | MacroKind::Derive => false, | ||
1527 | } | ||
1528 | } | ||
1341 | } | 1529 | } |
1342 | 1530 | ||
1343 | /// Invariant: `inner.as_assoc_item(db).is_some()` | 1531 | /// Invariant: `inner.as_assoc_item(db).is_some()` |
@@ -1429,6 +1617,20 @@ impl AssocItem { | |||
1429 | _ => None, | 1617 | _ => None, |
1430 | } | 1618 | } |
1431 | } | 1619 | } |
1620 | |||
1621 | pub fn containing_trait_impl(self, db: &dyn HirDatabase) -> Option<Trait> { | ||
1622 | match self.container(db) { | ||
1623 | AssocItemContainer::Impl(i) => i.trait_(db), | ||
1624 | _ => None, | ||
1625 | } | ||
1626 | } | ||
1627 | |||
1628 | pub fn containing_trait_or_trait_impl(self, db: &dyn HirDatabase) -> Option<Trait> { | ||
1629 | match self.container(db) { | ||
1630 | AssocItemContainer::Trait(t) => Some(t), | ||
1631 | AssocItemContainer::Impl(i) => i.trait_(db), | ||
1632 | } | ||
1633 | } | ||
1432 | } | 1634 | } |
1433 | 1635 | ||
1434 | impl HasVisibility for AssocItem { | 1636 | impl HasVisibility for AssocItem { |
@@ -1726,7 +1928,7 @@ impl Impl { | |||
1726 | } | 1928 | } |
1727 | 1929 | ||
1728 | pub fn all_for_type(db: &dyn HirDatabase, Type { krate, ty, .. }: Type) -> Vec<Impl> { | 1930 | pub fn all_for_type(db: &dyn HirDatabase, Type { krate, ty, .. }: Type) -> Vec<Impl> { |
1729 | let def_crates = match def_crates(db, &ty, krate) { | 1931 | let def_crates = match method_resolution::def_crates(db, &ty, krate) { |
1730 | Some(def_crates) => def_crates, | 1932 | Some(def_crates) => def_crates, |
1731 | None => return Vec::new(), | 1933 | None => return Vec::new(), |
1732 | }; | 1934 | }; |
@@ -1783,9 +1985,11 @@ impl Impl { | |||
1783 | } | 1985 | } |
1784 | 1986 | ||
1785 | // FIXME: the return type is wrong. This should be a hir version of | 1987 | // FIXME: the return type is wrong. This should be a hir version of |
1786 | // `TraitRef` (ie, resolved `TypeRef`). | 1988 | // `TraitRef` (to account for parameters and qualifiers) |
1787 | pub fn trait_(self, db: &dyn HirDatabase) -> Option<TraitRef> { | 1989 | pub fn trait_(self, db: &dyn HirDatabase) -> Option<Trait> { |
1788 | db.impl_data(self.id).target_trait.as_deref().cloned() | 1990 | let trait_ref = db.impl_trait(self.id)?.skip_binders().clone(); |
1991 | let id = hir_ty::from_chalk_trait_id(trait_ref.trait_id); | ||
1992 | Some(Trait { id }) | ||
1789 | } | 1993 | } |
1790 | 1994 | ||
1791 | pub fn self_ty(self, db: &dyn HirDatabase) -> Type { | 1995 | pub fn self_ty(self, db: &dyn HirDatabase) -> Type { |
@@ -2130,7 +2334,7 @@ impl Type { | |||
2130 | krate: Crate, | 2334 | krate: Crate, |
2131 | mut callback: impl FnMut(AssocItem) -> Option<T>, | 2335 | mut callback: impl FnMut(AssocItem) -> Option<T>, |
2132 | ) -> Option<T> { | 2336 | ) -> Option<T> { |
2133 | for krate in def_crates(db, &self.ty, krate.id)? { | 2337 | for krate in method_resolution::def_crates(db, &self.ty, krate.id)? { |
2134 | let impls = db.inherent_impls_in_crate(krate); | 2338 | let impls = db.inherent_impls_in_crate(krate); |
2135 | 2339 | ||
2136 | for impl_def in impls.for_self_ty(&self.ty) { | 2340 | for impl_def in impls.for_self_ty(&self.ty) { |
@@ -2162,6 +2366,7 @@ impl Type { | |||
2162 | name: Option<&Name>, | 2366 | name: Option<&Name>, |
2163 | mut callback: impl FnMut(&Ty, Function) -> Option<T>, | 2367 | mut callback: impl FnMut(&Ty, Function) -> Option<T>, |
2164 | ) -> Option<T> { | 2368 | ) -> Option<T> { |
2369 | let _p = profile::span("iterate_method_candidates"); | ||
2165 | // There should be no inference vars in types passed here | 2370 | // There should be no inference vars in types passed here |
2166 | // FIXME check that? | 2371 | // FIXME check that? |
2167 | // FIXME replace Unknown by bound vars here | 2372 | // FIXME replace Unknown by bound vars here |
@@ -2195,6 +2400,7 @@ impl Type { | |||
2195 | name: Option<&Name>, | 2400 | name: Option<&Name>, |
2196 | mut callback: impl FnMut(&Ty, AssocItem) -> Option<T>, | 2401 | mut callback: impl FnMut(&Ty, AssocItem) -> Option<T>, |
2197 | ) -> Option<T> { | 2402 | ) -> Option<T> { |
2403 | let _p = profile::span("iterate_path_candidates"); | ||
2198 | let canonical = hir_ty::replace_errors_with_variables(&self.ty); | 2404 | let canonical = hir_ty::replace_errors_with_variables(&self.ty); |
2199 | 2405 | ||
2200 | let env = self.env.clone(); | 2406 | let env = self.env.clone(); |
@@ -2232,6 +2438,7 @@ impl Type { | |||
2232 | &'a self, | 2438 | &'a self, |
2233 | db: &'a dyn HirDatabase, | 2439 | db: &'a dyn HirDatabase, |
2234 | ) -> impl Iterator<Item = Trait> + 'a { | 2440 | ) -> impl Iterator<Item = Trait> + 'a { |
2441 | let _p = profile::span("applicable_inherent_traits"); | ||
2235 | self.autoderef(db) | 2442 | self.autoderef(db) |
2236 | .filter_map(|derefed_type| derefed_type.ty.dyn_trait()) | 2443 | .filter_map(|derefed_type| derefed_type.ty.dyn_trait()) |
2237 | .flat_map(move |dyn_trait_id| hir_ty::all_super_traits(db.upcast(), dyn_trait_id)) | 2444 | .flat_map(move |dyn_trait_id| hir_ty::all_super_traits(db.upcast(), dyn_trait_id)) |
@@ -2304,13 +2511,13 @@ impl Type { | |||
2304 | match ty.kind(&Interner) { | 2511 | match ty.kind(&Interner) { |
2305 | TyKind::Adt(_, substs) => { | 2512 | TyKind::Adt(_, substs) => { |
2306 | cb(type_.derived(ty.clone())); | 2513 | cb(type_.derived(ty.clone())); |
2307 | walk_substs(db, type_, &substs, cb); | 2514 | walk_substs(db, type_, substs, cb); |
2308 | } | 2515 | } |
2309 | TyKind::AssociatedType(_, substs) => { | 2516 | TyKind::AssociatedType(_, substs) => { |
2310 | if let Some(_) = ty.associated_type_parent_trait(db) { | 2517 | if let Some(_) = ty.associated_type_parent_trait(db) { |
2311 | cb(type_.derived(ty.clone())); | 2518 | cb(type_.derived(ty.clone())); |
2312 | } | 2519 | } |
2313 | walk_substs(db, type_, &substs, cb); | 2520 | walk_substs(db, type_, substs, cb); |
2314 | } | 2521 | } |
2315 | TyKind::OpaqueType(_, subst) => { | 2522 | TyKind::OpaqueType(_, subst) => { |
2316 | if let Some(bounds) = ty.impl_trait_bounds(db) { | 2523 | if let Some(bounds) = ty.impl_trait_bounds(db) { |
@@ -2350,7 +2557,7 @@ impl Type { | |||
2350 | TyKind::FnDef(_, substs) | 2557 | TyKind::FnDef(_, substs) |
2351 | | TyKind::Tuple(_, substs) | 2558 | | TyKind::Tuple(_, substs) |
2352 | | TyKind::Closure(.., substs) => { | 2559 | | TyKind::Closure(.., substs) => { |
2353 | walk_substs(db, type_, &substs, cb); | 2560 | walk_substs(db, type_, substs, cb); |
2354 | } | 2561 | } |
2355 | TyKind::Function(hir_ty::FnPointer { substitution, .. }) => { | 2562 | TyKind::Function(hir_ty::FnPointer { substitution, .. }) => { |
2356 | walk_substs(db, type_, &substitution.0, cb); | 2563 | walk_substs(db, type_, &substitution.0, cb); |
@@ -2481,6 +2688,18 @@ impl ScopeDef { | |||
2481 | 2688 | ||
2482 | items | 2689 | items |
2483 | } | 2690 | } |
2691 | |||
2692 | pub fn is_value_def(&self) -> bool { | ||
2693 | matches!( | ||
2694 | self, | ||
2695 | ScopeDef::ModuleDef(ModuleDef::Function(_)) | ||
2696 | | ScopeDef::ModuleDef(ModuleDef::Variant(_)) | ||
2697 | | ScopeDef::ModuleDef(ModuleDef::Const(_)) | ||
2698 | | ScopeDef::ModuleDef(ModuleDef::Static(_)) | ||
2699 | | ScopeDef::GenericParam(GenericParam::ConstParam(_)) | ||
2700 | | ScopeDef::Local(_) | ||
2701 | ) | ||
2702 | } | ||
2484 | } | 2703 | } |
2485 | 2704 | ||
2486 | impl From<ItemInNs> for ScopeDef { | 2705 | impl From<ItemInNs> for ScopeDef { |
diff --git a/crates/hir/src/semantics.rs b/crates/hir/src/semantics.rs index c7f2c02e4..613266e07 100644 --- a/crates/hir/src/semantics.rs +++ b/crates/hir/src/semantics.rs | |||
@@ -17,7 +17,7 @@ use rustc_hash::{FxHashMap, FxHashSet}; | |||
17 | use syntax::{ | 17 | use syntax::{ |
18 | algo::find_node_at_offset, | 18 | algo::find_node_at_offset, |
19 | ast::{self, GenericParamsOwner, LoopBodyOwner}, | 19 | ast::{self, GenericParamsOwner, LoopBodyOwner}, |
20 | match_ast, AstNode, SyntaxNode, SyntaxNodePtr, SyntaxToken, TextSize, | 20 | match_ast, AstNode, SyntaxNode, SyntaxNodePtr, SyntaxToken, TextRange, TextSize, |
21 | }; | 21 | }; |
22 | 22 | ||
23 | use crate::{ | 23 | use crate::{ |
@@ -35,8 +35,9 @@ pub enum PathResolution { | |||
35 | Def(ModuleDef), | 35 | Def(ModuleDef), |
36 | /// A local binding (only value namespace) | 36 | /// A local binding (only value namespace) |
37 | Local(Local), | 37 | Local(Local), |
38 | /// A generic parameter | 38 | /// A type parameter |
39 | TypeParam(TypeParam), | 39 | TypeParam(TypeParam), |
40 | /// A const parameter | ||
40 | ConstParam(ConstParam), | 41 | ConstParam(ConstParam), |
41 | SelfType(Impl), | 42 | SelfType(Impl), |
42 | Macro(MacroDef), | 43 | Macro(MacroDef), |
@@ -117,6 +118,16 @@ impl<'db, DB: HirDatabase> Semantics<'db, DB> { | |||
117 | pub fn expand(&self, macro_call: &ast::MacroCall) -> Option<SyntaxNode> { | 118 | pub fn expand(&self, macro_call: &ast::MacroCall) -> Option<SyntaxNode> { |
118 | self.imp.expand(macro_call) | 119 | self.imp.expand(macro_call) |
119 | } | 120 | } |
121 | |||
122 | /// If `item` has an attribute macro attached to it, expands it. | ||
123 | pub fn expand_attr_macro(&self, item: &ast::Item) -> Option<SyntaxNode> { | ||
124 | self.imp.expand_attr_macro(item) | ||
125 | } | ||
126 | |||
127 | pub fn is_attr_macro_call(&self, item: &ast::Item) -> bool { | ||
128 | self.imp.is_attr_macro_call(item) | ||
129 | } | ||
130 | |||
120 | pub fn speculative_expand( | 131 | pub fn speculative_expand( |
121 | &self, | 132 | &self, |
122 | actual_macro_call: &ast::MacroCall, | 133 | actual_macro_call: &ast::MacroCall, |
@@ -181,7 +192,7 @@ impl<'db, DB: HirDatabase> Semantics<'db, DB> { | |||
181 | node: &SyntaxNode, | 192 | node: &SyntaxNode, |
182 | offset: TextSize, | 193 | offset: TextSize, |
183 | ) -> Option<N> { | 194 | ) -> Option<N> { |
184 | if let Some(it) = find_node_at_offset(&node, offset) { | 195 | if let Some(it) = find_node_at_offset(node, offset) { |
185 | return Some(it); | 196 | return Some(it); |
186 | } | 197 | } |
187 | 198 | ||
@@ -332,6 +343,22 @@ impl<'db> SemanticsImpl<'db> { | |||
332 | Some(node) | 343 | Some(node) |
333 | } | 344 | } |
334 | 345 | ||
346 | fn expand_attr_macro(&self, item: &ast::Item) -> Option<SyntaxNode> { | ||
347 | let sa = self.analyze(item.syntax()); | ||
348 | let src = InFile::new(sa.file_id, item.clone()); | ||
349 | let macro_call_id = self.with_ctx(|ctx| ctx.item_to_macro_call(src))?; | ||
350 | let file_id = macro_call_id.as_file(); | ||
351 | let node = self.db.parse_or_expand(file_id)?; | ||
352 | self.cache(node.clone(), file_id); | ||
353 | Some(node) | ||
354 | } | ||
355 | |||
356 | fn is_attr_macro_call(&self, item: &ast::Item) -> bool { | ||
357 | let sa = self.analyze(item.syntax()); | ||
358 | let src = InFile::new(sa.file_id, item.clone()); | ||
359 | self.with_ctx(|ctx| ctx.item_to_macro_call(src).is_some()) | ||
360 | } | ||
361 | |||
335 | fn speculative_expand( | 362 | fn speculative_expand( |
336 | &self, | 363 | &self, |
337 | actual_macro_call: &ast::MacroCall, | 364 | actual_macro_call: &ast::MacroCall, |
@@ -362,25 +389,65 @@ impl<'db> SemanticsImpl<'db> { | |||
362 | 389 | ||
363 | let token = successors(Some(InFile::new(sa.file_id, token)), |token| { | 390 | let token = successors(Some(InFile::new(sa.file_id, token)), |token| { |
364 | self.db.unwind_if_cancelled(); | 391 | self.db.unwind_if_cancelled(); |
365 | let macro_call = token.value.ancestors().find_map(ast::MacroCall::cast)?; | 392 | |
366 | let tt = macro_call.token_tree()?; | 393 | for node in token.value.ancestors() { |
367 | if !tt.syntax().text_range().contains_range(token.value.text_range()) { | 394 | match_ast! { |
368 | return None; | 395 | match node { |
369 | } | 396 | ast::MacroCall(macro_call) => { |
370 | let file_id = sa.expand(self.db, token.with_value(¯o_call))?; | 397 | let tt = macro_call.token_tree()?; |
371 | let token = self | 398 | let l_delim = match tt.left_delimiter_token() { |
372 | .expansion_info_cache | 399 | Some(it) => it.text_range().end(), |
373 | .borrow_mut() | 400 | None => tt.syntax().text_range().start() |
374 | .entry(file_id) | 401 | }; |
375 | .or_insert_with(|| file_id.expansion_info(self.db.upcast())) | 402 | let r_delim = match tt.right_delimiter_token() { |
376 | .as_ref()? | 403 | Some(it) => it.text_range().start(), |
377 | .map_token_down(token.as_ref())?; | 404 | None => tt.syntax().text_range().end() |
378 | 405 | }; | |
379 | if let Some(parent) = token.value.parent() { | 406 | if !TextRange::new(l_delim, r_delim).contains_range(token.value.text_range()) { |
380 | self.cache(find_root(&parent), token.file_id); | 407 | return None; |
408 | } | ||
409 | let file_id = sa.expand(self.db, token.with_value(¯o_call))?; | ||
410 | let token = self | ||
411 | .expansion_info_cache | ||
412 | .borrow_mut() | ||
413 | .entry(file_id) | ||
414 | .or_insert_with(|| file_id.expansion_info(self.db.upcast())) | ||
415 | .as_ref()? | ||
416 | .map_token_down(token.as_ref())?; | ||
417 | |||
418 | if let Some(parent) = token.value.parent() { | ||
419 | self.cache(find_root(&parent), token.file_id); | ||
420 | } | ||
421 | |||
422 | return Some(token); | ||
423 | }, | ||
424 | ast::Item(item) => { | ||
425 | match self.with_ctx(|ctx| ctx.item_to_macro_call(token.with_value(item))) { | ||
426 | Some(call_id) => { | ||
427 | let file_id = call_id.as_file(); | ||
428 | let token = self | ||
429 | .expansion_info_cache | ||
430 | .borrow_mut() | ||
431 | .entry(file_id) | ||
432 | .or_insert_with(|| file_id.expansion_info(self.db.upcast())) | ||
433 | .as_ref()? | ||
434 | .map_token_down(token.as_ref())?; | ||
435 | |||
436 | if let Some(parent) = token.value.parent() { | ||
437 | self.cache(find_root(&parent), token.file_id); | ||
438 | } | ||
439 | |||
440 | return Some(token); | ||
441 | } | ||
442 | None => {} | ||
443 | } | ||
444 | }, | ||
445 | _ => {} | ||
446 | } | ||
447 | } | ||
381 | } | 448 | } |
382 | 449 | ||
383 | Some(token) | 450 | None |
384 | }) | 451 | }) |
385 | .last() | 452 | .last() |
386 | .unwrap(); | 453 | .unwrap(); |
@@ -677,7 +744,7 @@ impl<'db> SemanticsImpl<'db> { | |||
677 | return None; | 744 | return None; |
678 | } | 745 | } |
679 | 746 | ||
680 | let func = self.resolve_method_call(&method_call_expr).map(Function::from)?; | 747 | let func = self.resolve_method_call(method_call_expr).map(Function::from)?; |
681 | let res = match func.self_param(self.db)?.access(self.db) { | 748 | let res = match func.self_param(self.db)?.access(self.db) { |
682 | Access::Shared | Access::Exclusive => true, | 749 | Access::Shared | Access::Exclusive => true, |
683 | Access::Owned => false, | 750 | Access::Owned => false, |
diff --git a/crates/hir/src/semantics/source_to_def.rs b/crates/hir/src/semantics/source_to_def.rs index 9a5a2255f..e8c2ed48e 100644 --- a/crates/hir/src/semantics/source_to_def.rs +++ b/crates/hir/src/semantics/source_to_def.rs | |||
@@ -10,7 +10,7 @@ use hir_def::{ | |||
10 | ImplId, LifetimeParamId, ModuleId, StaticId, StructId, TraitId, TypeAliasId, TypeParamId, | 10 | ImplId, LifetimeParamId, ModuleId, StaticId, StructId, TraitId, TypeAliasId, TypeParamId, |
11 | UnionId, VariantId, | 11 | UnionId, VariantId, |
12 | }; | 12 | }; |
13 | use hir_expand::{name::AsName, AstId, MacroDefKind}; | 13 | use hir_expand::{name::AsName, AstId, MacroCallId, MacroDefKind}; |
14 | use rustc_hash::FxHashMap; | 14 | use rustc_hash::FxHashMap; |
15 | use smallvec::SmallVec; | 15 | use smallvec::SmallVec; |
16 | use stdx::impl_from; | 16 | use stdx::impl_from; |
@@ -145,16 +145,25 @@ impl SourceToDefCtx<'_, '_> { | |||
145 | Some((container, label_id)) | 145 | Some((container, label_id)) |
146 | } | 146 | } |
147 | 147 | ||
148 | pub(super) fn item_to_macro_call(&mut self, src: InFile<ast::Item>) -> Option<MacroCallId> { | ||
149 | let map = self.dyn_map(src.as_ref())?; | ||
150 | map[keys::ATTR_MACRO].get(&src).copied() | ||
151 | } | ||
152 | |||
148 | fn to_def<Ast: AstNode + 'static, ID: Copy + 'static>( | 153 | fn to_def<Ast: AstNode + 'static, ID: Copy + 'static>( |
149 | &mut self, | 154 | &mut self, |
150 | src: InFile<Ast>, | 155 | src: InFile<Ast>, |
151 | key: Key<Ast, ID>, | 156 | key: Key<Ast, ID>, |
152 | ) -> Option<ID> { | 157 | ) -> Option<ID> { |
153 | let container = self.find_container(src.as_ref().map(|it| it.syntax()))?; | 158 | self.dyn_map(src.as_ref())?[key].get(&src).copied() |
159 | } | ||
160 | |||
161 | fn dyn_map<Ast: AstNode + 'static>(&mut self, src: InFile<&Ast>) -> Option<&DynMap> { | ||
162 | let container = self.find_container(src.map(|it| it.syntax()))?; | ||
154 | let db = self.db; | 163 | let db = self.db; |
155 | let dyn_map = | 164 | let dyn_map = |
156 | &*self.cache.entry(container).or_insert_with(|| container.child_by_source(db)); | 165 | &*self.cache.entry(container).or_insert_with(|| container.child_by_source(db)); |
157 | dyn_map[key].get(&src).copied() | 166 | Some(dyn_map) |
158 | } | 167 | } |
159 | 168 | ||
160 | pub(super) fn type_param_to_def(&mut self, src: InFile<ast::TypeParam>) -> Option<TypeParamId> { | 169 | pub(super) fn type_param_to_def(&mut self, src: InFile<ast::TypeParam>) -> Option<TypeParamId> { |
@@ -202,62 +211,68 @@ impl SourceToDefCtx<'_, '_> { | |||
202 | 211 | ||
203 | pub(super) fn find_container(&mut self, src: InFile<&SyntaxNode>) -> Option<ChildContainer> { | 212 | pub(super) fn find_container(&mut self, src: InFile<&SyntaxNode>) -> Option<ChildContainer> { |
204 | for container in src.cloned().ancestors_with_macros(self.db.upcast()).skip(1) { | 213 | for container in src.cloned().ancestors_with_macros(self.db.upcast()).skip(1) { |
205 | let res: ChildContainer = match_ast! { | 214 | if let Some(res) = self.container_to_def(container) { |
206 | match (container.value) { | 215 | return Some(res); |
207 | ast::Module(it) => { | 216 | } |
208 | let def = self.module_to_def(container.with_value(it))?; | ||
209 | def.into() | ||
210 | }, | ||
211 | ast::Trait(it) => { | ||
212 | let def = self.trait_to_def(container.with_value(it))?; | ||
213 | def.into() | ||
214 | }, | ||
215 | ast::Impl(it) => { | ||
216 | let def = self.impl_to_def(container.with_value(it))?; | ||
217 | def.into() | ||
218 | }, | ||
219 | ast::Fn(it) => { | ||
220 | let def = self.fn_to_def(container.with_value(it))?; | ||
221 | DefWithBodyId::from(def).into() | ||
222 | }, | ||
223 | ast::Struct(it) => { | ||
224 | let def = self.struct_to_def(container.with_value(it))?; | ||
225 | VariantId::from(def).into() | ||
226 | }, | ||
227 | ast::Enum(it) => { | ||
228 | let def = self.enum_to_def(container.with_value(it))?; | ||
229 | def.into() | ||
230 | }, | ||
231 | ast::Union(it) => { | ||
232 | let def = self.union_to_def(container.with_value(it))?; | ||
233 | VariantId::from(def).into() | ||
234 | }, | ||
235 | ast::Static(it) => { | ||
236 | let def = self.static_to_def(container.with_value(it))?; | ||
237 | DefWithBodyId::from(def).into() | ||
238 | }, | ||
239 | ast::Const(it) => { | ||
240 | let def = self.const_to_def(container.with_value(it))?; | ||
241 | DefWithBodyId::from(def).into() | ||
242 | }, | ||
243 | ast::TypeAlias(it) => { | ||
244 | let def = self.type_alias_to_def(container.with_value(it))?; | ||
245 | def.into() | ||
246 | }, | ||
247 | ast::Variant(it) => { | ||
248 | let def = self.enum_variant_to_def(container.with_value(it))?; | ||
249 | VariantId::from(def).into() | ||
250 | }, | ||
251 | _ => continue, | ||
252 | } | ||
253 | }; | ||
254 | return Some(res); | ||
255 | } | 217 | } |
256 | 218 | ||
257 | let def = self.file_to_def(src.file_id.original_file(self.db.upcast())).get(0).copied()?; | 219 | let def = self.file_to_def(src.file_id.original_file(self.db.upcast())).get(0).copied()?; |
258 | Some(def.into()) | 220 | Some(def.into()) |
259 | } | 221 | } |
260 | 222 | ||
223 | fn container_to_def(&mut self, container: InFile<SyntaxNode>) -> Option<ChildContainer> { | ||
224 | let cont = match_ast! { | ||
225 | match (container.value) { | ||
226 | ast::Module(it) => { | ||
227 | let def = self.module_to_def(container.with_value(it))?; | ||
228 | def.into() | ||
229 | }, | ||
230 | ast::Trait(it) => { | ||
231 | let def = self.trait_to_def(container.with_value(it))?; | ||
232 | def.into() | ||
233 | }, | ||
234 | ast::Impl(it) => { | ||
235 | let def = self.impl_to_def(container.with_value(it))?; | ||
236 | def.into() | ||
237 | }, | ||
238 | ast::Fn(it) => { | ||
239 | let def = self.fn_to_def(container.with_value(it))?; | ||
240 | DefWithBodyId::from(def).into() | ||
241 | }, | ||
242 | ast::Struct(it) => { | ||
243 | let def = self.struct_to_def(container.with_value(it))?; | ||
244 | VariantId::from(def).into() | ||
245 | }, | ||
246 | ast::Enum(it) => { | ||
247 | let def = self.enum_to_def(container.with_value(it))?; | ||
248 | def.into() | ||
249 | }, | ||
250 | ast::Union(it) => { | ||
251 | let def = self.union_to_def(container.with_value(it))?; | ||
252 | VariantId::from(def).into() | ||
253 | }, | ||
254 | ast::Static(it) => { | ||
255 | let def = self.static_to_def(container.with_value(it))?; | ||
256 | DefWithBodyId::from(def).into() | ||
257 | }, | ||
258 | ast::Const(it) => { | ||
259 | let def = self.const_to_def(container.with_value(it))?; | ||
260 | DefWithBodyId::from(def).into() | ||
261 | }, | ||
262 | ast::TypeAlias(it) => { | ||
263 | let def = self.type_alias_to_def(container.with_value(it))?; | ||
264 | def.into() | ||
265 | }, | ||
266 | ast::Variant(it) => { | ||
267 | let def = self.enum_variant_to_def(container.with_value(it))?; | ||
268 | VariantId::from(def).into() | ||
269 | }, | ||
270 | _ => return None, | ||
271 | } | ||
272 | }; | ||
273 | Some(cont) | ||
274 | } | ||
275 | |||
261 | fn find_generic_param_container(&mut self, src: InFile<&SyntaxNode>) -> Option<GenericDefId> { | 276 | fn find_generic_param_container(&mut self, src: InFile<&SyntaxNode>) -> Option<GenericDefId> { |
262 | for container in src.cloned().ancestors_with_macros(self.db.upcast()).skip(1) { | 277 | for container in src.cloned().ancestors_with_macros(self.db.upcast()).skip(1) { |
263 | let res: GenericDefId = match_ast! { | 278 | let res: GenericDefId = match_ast! { |
diff --git a/crates/hir/src/source_analyzer.rs b/crates/hir/src/source_analyzer.rs index 37a050415..c9744d81d 100644 --- a/crates/hir/src/source_analyzer.rs +++ b/crates/hir/src/source_analyzer.rs | |||
@@ -222,7 +222,7 @@ impl SourceAnalyzer { | |||
222 | Pat::Path(path) => path, | 222 | Pat::Path(path) => path, |
223 | _ => return None, | 223 | _ => return None, |
224 | }; | 224 | }; |
225 | let res = resolve_hir_path(db, &self.resolver, &path)?; | 225 | let res = resolve_hir_path(db, &self.resolver, path)?; |
226 | match res { | 226 | match res { |
227 | PathResolution::Def(def) => Some(def), | 227 | PathResolution::Def(def) => Some(def), |
228 | _ => None, | 228 | _ => None, |
@@ -329,7 +329,7 @@ impl SourceAnalyzer { | |||
329 | 329 | ||
330 | let (variant, missing_fields, _exhaustive) = | 330 | let (variant, missing_fields, _exhaustive) = |
331 | record_literal_missing_fields(db, infer, expr_id, &body[expr_id])?; | 331 | record_literal_missing_fields(db, infer, expr_id, &body[expr_id])?; |
332 | let res = self.missing_fields(db, krate, &substs, variant, missing_fields); | 332 | let res = self.missing_fields(db, krate, substs, variant, missing_fields); |
333 | Some(res) | 333 | Some(res) |
334 | } | 334 | } |
335 | 335 | ||
@@ -347,7 +347,7 @@ impl SourceAnalyzer { | |||
347 | 347 | ||
348 | let (variant, missing_fields, _exhaustive) = | 348 | let (variant, missing_fields, _exhaustive) = |
349 | record_pattern_missing_fields(db, infer, pat_id, &body[pat_id])?; | 349 | record_pattern_missing_fields(db, infer, pat_id, &body[pat_id])?; |
350 | let res = self.missing_fields(db, krate, &substs, variant, missing_fields); | 350 | let res = self.missing_fields(db, krate, substs, variant, missing_fields); |
351 | Some(res) | 351 | Some(res) |
352 | } | 352 | } |
353 | 353 | ||
diff --git a/crates/hir_def/Cargo.toml b/crates/hir_def/Cargo.toml index 43324d8d9..bb86f6a73 100644 --- a/crates/hir_def/Cargo.toml +++ b/crates/hir_def/Cargo.toml | |||
@@ -10,7 +10,7 @@ edition = "2018" | |||
10 | doctest = false | 10 | doctest = false |
11 | 11 | ||
12 | [dependencies] | 12 | [dependencies] |
13 | cov-mark = { version = "1.1", features = ["thread-local"] } | 13 | cov-mark = "2.0.0-pre.1" |
14 | dashmap = { version = "4.0.2", features = ["raw-api"] } | 14 | dashmap = { version = "4.0.2", features = ["raw-api"] } |
15 | log = "0.4.8" | 15 | log = "0.4.8" |
16 | once_cell = "1.3.1" | 16 | once_cell = "1.3.1" |
diff --git a/crates/hir_def/src/attr.rs b/crates/hir_def/src/attr.rs index 385ba8c80..d07adb084 100644 --- a/crates/hir_def/src/attr.rs +++ b/crates/hir_def/src/attr.rs | |||
@@ -36,6 +36,10 @@ use crate::{ | |||
36 | pub struct Documentation(String); | 36 | pub struct Documentation(String); |
37 | 37 | ||
38 | impl Documentation { | 38 | impl Documentation { |
39 | pub fn new(s: String) -> Self { | ||
40 | Documentation(s) | ||
41 | } | ||
42 | |||
39 | pub fn as_str(&self) -> &str { | 43 | pub fn as_str(&self) -> &str { |
40 | &self.0 | 44 | &self.0 |
41 | } | 45 | } |
@@ -102,7 +106,9 @@ impl RawAttrs { | |||
102 | ) -> Self { | 106 | ) -> Self { |
103 | let entries = collect_attrs(owner) | 107 | let entries = collect_attrs(owner) |
104 | .flat_map(|(id, attr)| match attr { | 108 | .flat_map(|(id, attr)| match attr { |
105 | Either::Left(attr) => Attr::from_src(db, attr, hygiene, id), | 109 | Either::Left(attr) => { |
110 | attr.meta().and_then(|meta| Attr::from_src(db, meta, hygiene, id)) | ||
111 | } | ||
106 | Either::Right(comment) => comment.doc_comment().map(|doc| Attr { | 112 | Either::Right(comment) => comment.doc_comment().map(|doc| Attr { |
107 | id, | 113 | id, |
108 | input: Some(Interned::new(AttrInput::Literal(SmolStr::new(doc)))), | 114 | input: Some(Interned::new(AttrInput::Literal(SmolStr::new(doc)))), |
@@ -168,10 +174,9 @@ impl RawAttrs { | |||
168 | let index = attr.id; | 174 | let index = attr.id; |
169 | let attrs = parts.filter(|a| !a.is_empty()).filter_map(|attr| { | 175 | let attrs = parts.filter(|a| !a.is_empty()).filter_map(|attr| { |
170 | let tree = Subtree { delimiter: None, token_trees: attr.to_vec() }; | 176 | let tree = Subtree { delimiter: None, token_trees: attr.to_vec() }; |
171 | let attr = ast::Attr::parse(&format!("#[{}]", tree)).ok()?; | ||
172 | // FIXME hygiene | 177 | // FIXME hygiene |
173 | let hygiene = Hygiene::new_unhygienic(); | 178 | let hygiene = Hygiene::new_unhygienic(); |
174 | Attr::from_src(db, attr, &hygiene, index) | 179 | Attr::from_tt(db, &tree, &hygiene, index) |
175 | }); | 180 | }); |
176 | 181 | ||
177 | let cfg_options = &crate_graph[krate].cfg_options; | 182 | let cfg_options = &crate_graph[krate].cfg_options; |
@@ -578,13 +583,13 @@ impl AttrSourceMap { | |||
578 | .get(id.ast_index as usize) | 583 | .get(id.ast_index as usize) |
579 | .unwrap_or_else(|| panic!("cannot find doc comment at index {:?}", id)) | 584 | .unwrap_or_else(|| panic!("cannot find doc comment at index {:?}", id)) |
580 | .clone() | 585 | .clone() |
581 | .map(|attr| Either::Right(attr)) | 586 | .map(Either::Right) |
582 | } else { | 587 | } else { |
583 | self.attrs | 588 | self.attrs |
584 | .get(id.ast_index as usize) | 589 | .get(id.ast_index as usize) |
585 | .unwrap_or_else(|| panic!("cannot find `Attr` at index {:?}", id)) | 590 | .unwrap_or_else(|| panic!("cannot find `Attr` at index {:?}", id)) |
586 | .clone() | 591 | .clone() |
587 | .map(|attr| Either::Left(attr)) | 592 | .map(Either::Left) |
588 | } | 593 | } |
589 | } | 594 | } |
590 | } | 595 | } |
@@ -601,7 +606,7 @@ pub struct DocsRangeMap { | |||
601 | impl DocsRangeMap { | 606 | impl DocsRangeMap { |
602 | pub fn map(&self, range: TextRange) -> Option<InFile<TextRange>> { | 607 | pub fn map(&self, range: TextRange) -> Option<InFile<TextRange>> { |
603 | let found = self.mapping.binary_search_by(|(probe, ..)| probe.ordering(range)).ok()?; | 608 | let found = self.mapping.binary_search_by(|(probe, ..)| probe.ordering(range)).ok()?; |
604 | let (line_docs_range, idx, original_line_src_range) = self.mapping[found].clone(); | 609 | let (line_docs_range, idx, original_line_src_range) = self.mapping[found]; |
605 | if !line_docs_range.contains_range(range) { | 610 | if !line_docs_range.contains_range(range) { |
606 | return None; | 611 | return None; |
607 | } | 612 | } |
@@ -660,7 +665,7 @@ impl fmt::Display for AttrInput { | |||
660 | impl Attr { | 665 | impl Attr { |
661 | fn from_src( | 666 | fn from_src( |
662 | db: &dyn DefDatabase, | 667 | db: &dyn DefDatabase, |
663 | ast: ast::Attr, | 668 | ast: ast::Meta, |
664 | hygiene: &Hygiene, | 669 | hygiene: &Hygiene, |
665 | id: AttrId, | 670 | id: AttrId, |
666 | ) -> Option<Attr> { | 671 | ) -> Option<Attr> { |
@@ -679,6 +684,19 @@ impl Attr { | |||
679 | Some(Attr { id, path, input }) | 684 | Some(Attr { id, path, input }) |
680 | } | 685 | } |
681 | 686 | ||
687 | fn from_tt( | ||
688 | db: &dyn DefDatabase, | ||
689 | tt: &tt::Subtree, | ||
690 | hygiene: &Hygiene, | ||
691 | id: AttrId, | ||
692 | ) -> Option<Attr> { | ||
693 | let (parse, _) = | ||
694 | mbe::token_tree_to_syntax_node(tt, hir_expand::FragmentKind::MetaItem).ok()?; | ||
695 | let ast = ast::Meta::cast(parse.syntax_node())?; | ||
696 | |||
697 | Self::from_src(db, ast, hygiene, id) | ||
698 | } | ||
699 | |||
682 | /// Parses this attribute as a `#[derive]`, returns an iterator that yields all contained paths | 700 | /// Parses this attribute as a `#[derive]`, returns an iterator that yields all contained paths |
683 | /// to derive macros. | 701 | /// to derive macros. |
684 | /// | 702 | /// |
diff --git a/crates/hir_def/src/body/lower.rs b/crates/hir_def/src/body/lower.rs index da1fdac33..bed4c4994 100644 --- a/crates/hir_def/src/body/lower.rs +++ b/crates/hir_def/src/body/lower.rs | |||
@@ -1000,18 +1000,18 @@ impl From<ast::LiteralKind> for Literal { | |||
1000 | // FIXME: these should have actual values filled in, but unsure on perf impact | 1000 | // FIXME: these should have actual values filled in, but unsure on perf impact |
1001 | LiteralKind::IntNumber(lit) => { | 1001 | LiteralKind::IntNumber(lit) => { |
1002 | if let builtin @ Some(_) = lit.suffix().and_then(BuiltinFloat::from_suffix) { | 1002 | if let builtin @ Some(_) = lit.suffix().and_then(BuiltinFloat::from_suffix) { |
1003 | return Literal::Float(Default::default(), builtin); | 1003 | Literal::Float(Default::default(), builtin) |
1004 | } else if let builtin @ Some(_) = | 1004 | } else if let builtin @ Some(_) = |
1005 | lit.suffix().and_then(|it| BuiltinInt::from_suffix(&it)) | 1005 | lit.suffix().and_then(|it| BuiltinInt::from_suffix(it)) |
1006 | { | 1006 | { |
1007 | Literal::Int(lit.value().unwrap_or(0) as i128, builtin) | 1007 | Literal::Int(lit.value().unwrap_or(0) as i128, builtin) |
1008 | } else { | 1008 | } else { |
1009 | let builtin = lit.suffix().and_then(|it| BuiltinUint::from_suffix(&it)); | 1009 | let builtin = lit.suffix().and_then(|it| BuiltinUint::from_suffix(it)); |
1010 | Literal::Uint(lit.value().unwrap_or(0), builtin) | 1010 | Literal::Uint(lit.value().unwrap_or(0), builtin) |
1011 | } | 1011 | } |
1012 | } | 1012 | } |
1013 | LiteralKind::FloatNumber(lit) => { | 1013 | LiteralKind::FloatNumber(lit) => { |
1014 | let ty = lit.suffix().and_then(|it| BuiltinFloat::from_suffix(&it)); | 1014 | let ty = lit.suffix().and_then(|it| BuiltinFloat::from_suffix(it)); |
1015 | Literal::Float(Default::default(), ty) | 1015 | Literal::Float(Default::default(), ty) |
1016 | } | 1016 | } |
1017 | LiteralKind::ByteString(bs) => { | 1017 | LiteralKind::ByteString(bs) => { |
diff --git a/crates/hir_def/src/body/scope.rs b/crates/hir_def/src/body/scope.rs index 6764de3a7..58a1fc81c 100644 --- a/crates/hir_def/src/body/scope.rs +++ b/crates/hir_def/src/body/scope.rs | |||
@@ -198,7 +198,7 @@ fn compute_expr_scopes(expr: ExprId, body: &Body, scopes: &mut ExprScopes, scope | |||
198 | } | 198 | } |
199 | Expr::Lambda { args, body: body_expr, .. } => { | 199 | Expr::Lambda { args, body: body_expr, .. } => { |
200 | let scope = scopes.new_scope(scope); | 200 | let scope = scopes.new_scope(scope); |
201 | scopes.add_params_bindings(body, scope, &args); | 201 | scopes.add_params_bindings(body, scope, args); |
202 | compute_expr_scopes(*body_expr, body, scopes, scope); | 202 | compute_expr_scopes(*body_expr, body, scopes, scope); |
203 | } | 203 | } |
204 | Expr::Match { expr, arms } => { | 204 | Expr::Match { expr, arms } => { |
diff --git a/crates/hir_def/src/body/tests.rs b/crates/hir_def/src/body/tests.rs index d4fae05a6..27d837d47 100644 --- a/crates/hir_def/src/body/tests.rs +++ b/crates/hir_def/src/body/tests.rs | |||
@@ -3,7 +3,7 @@ mod block; | |||
3 | use base_db::{fixture::WithFixture, SourceDatabase}; | 3 | use base_db::{fixture::WithFixture, SourceDatabase}; |
4 | use expect_test::Expect; | 4 | use expect_test::Expect; |
5 | 5 | ||
6 | use crate::{test_db::TestDB, ModuleDefId}; | 6 | use crate::ModuleDefId; |
7 | 7 | ||
8 | use super::*; | 8 | use super::*; |
9 | 9 | ||
@@ -28,11 +28,6 @@ fn lower(ra_fixture: &str) -> Arc<Body> { | |||
28 | db.body(fn_def.unwrap().into()) | 28 | db.body(fn_def.unwrap().into()) |
29 | } | 29 | } |
30 | 30 | ||
31 | fn check_diagnostics(ra_fixture: &str) { | ||
32 | let db: TestDB = TestDB::with_files(ra_fixture); | ||
33 | db.check_diagnostics(); | ||
34 | } | ||
35 | |||
36 | fn block_def_map_at(ra_fixture: &str) -> String { | 31 | fn block_def_map_at(ra_fixture: &str) -> String { |
37 | let (db, position) = crate::test_db::TestDB::with_position(ra_fixture); | 32 | let (db, position) = crate::test_db::TestDB::with_position(ra_fixture); |
38 | 33 | ||
@@ -57,7 +52,7 @@ fn check_at(ra_fixture: &str, expect: Expect) { | |||
57 | fn your_stack_belongs_to_me() { | 52 | fn your_stack_belongs_to_me() { |
58 | cov_mark::check!(your_stack_belongs_to_me); | 53 | cov_mark::check!(your_stack_belongs_to_me); |
59 | lower( | 54 | lower( |
60 | " | 55 | r#" |
61 | macro_rules! n_nuple { | 56 | macro_rules! n_nuple { |
62 | ($e:tt) => (); | 57 | ($e:tt) => (); |
63 | ($($rest:tt)*) => {{ | 58 | ($($rest:tt)*) => {{ |
@@ -65,7 +60,7 @@ macro_rules! n_nuple { | |||
65 | }}; | 60 | }}; |
66 | } | 61 | } |
67 | fn main() { n_nuple!(1,2,3); } | 62 | fn main() { n_nuple!(1,2,3); } |
68 | ", | 63 | "#, |
69 | ); | 64 | ); |
70 | } | 65 | } |
71 | 66 | ||
@@ -73,7 +68,7 @@ fn main() { n_nuple!(1,2,3); } | |||
73 | fn macro_resolve() { | 68 | fn macro_resolve() { |
74 | // Regression test for a path resolution bug introduced with inner item handling. | 69 | // Regression test for a path resolution bug introduced with inner item handling. |
75 | lower( | 70 | lower( |
76 | r" | 71 | r#" |
77 | macro_rules! vec { | 72 | macro_rules! vec { |
78 | () => { () }; | 73 | () => { () }; |
79 | ($elem:expr; $n:expr) => { () }; | 74 | ($elem:expr; $n:expr) => { () }; |
@@ -84,140 +79,6 @@ mod m { | |||
84 | let _ = vec![FileSet::default(); self.len()]; | 79 | let _ = vec![FileSet::default(); self.len()]; |
85 | } | 80 | } |
86 | } | 81 | } |
87 | ", | 82 | "#, |
88 | ); | ||
89 | } | ||
90 | |||
91 | #[test] | ||
92 | fn cfg_diagnostics() { | ||
93 | check_diagnostics( | ||
94 | r" | ||
95 | fn f() { | ||
96 | // The three g̶e̶n̶d̶e̶r̶s̶ statements: | ||
97 | |||
98 | #[cfg(a)] fn f() {} // Item statement | ||
99 | //^^^^^^^^^^^^^^^^^^^ InactiveCode | ||
100 | #[cfg(a)] {} // Expression statement | ||
101 | //^^^^^^^^^^^^ InactiveCode | ||
102 | #[cfg(a)] let x = 0; // let statement | ||
103 | //^^^^^^^^^^^^^^^^^^^^ InactiveCode | ||
104 | |||
105 | abc(#[cfg(a)] 0); | ||
106 | //^^^^^^^^^^^ InactiveCode | ||
107 | let x = Struct { | ||
108 | #[cfg(a)] f: 0, | ||
109 | //^^^^^^^^^^^^^^ InactiveCode | ||
110 | }; | ||
111 | match () { | ||
112 | () => (), | ||
113 | #[cfg(a)] () => (), | ||
114 | //^^^^^^^^^^^^^^^^^^ InactiveCode | ||
115 | } | ||
116 | |||
117 | #[cfg(a)] 0 // Trailing expression of block | ||
118 | //^^^^^^^^^^^ InactiveCode | ||
119 | } | ||
120 | ", | ||
121 | ); | ||
122 | } | ||
123 | |||
124 | #[test] | ||
125 | fn macro_diag_builtin() { | ||
126 | check_diagnostics( | ||
127 | r#" | ||
128 | #[rustc_builtin_macro] | ||
129 | macro_rules! env {} | ||
130 | |||
131 | #[rustc_builtin_macro] | ||
132 | macro_rules! include {} | ||
133 | |||
134 | #[rustc_builtin_macro] | ||
135 | macro_rules! compile_error {} | ||
136 | |||
137 | #[rustc_builtin_macro] | ||
138 | macro_rules! format_args { | ||
139 | () => {} | ||
140 | } | ||
141 | |||
142 | fn f() { | ||
143 | // Test a handful of built-in (eager) macros: | ||
144 | |||
145 | include!(invalid); | ||
146 | //^^^^^^^^^^^^^^^^^ could not convert tokens | ||
147 | include!("does not exist"); | ||
148 | //^^^^^^^^^^^^^^^^^^^^^^^^^^ failed to load file `does not exist` | ||
149 | |||
150 | env!(invalid); | ||
151 | //^^^^^^^^^^^^^ could not convert tokens | ||
152 | |||
153 | env!("OUT_DIR"); | ||
154 | //^^^^^^^^^^^^^^^ `OUT_DIR` not set, enable "run build scripts" to fix | ||
155 | |||
156 | compile_error!("compile_error works"); | ||
157 | //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ compile_error works | ||
158 | |||
159 | // Lazy: | ||
160 | |||
161 | format_args!(); | ||
162 | //^^^^^^^^^^^^^^ no rule matches input tokens | ||
163 | } | ||
164 | "#, | ||
165 | ); | ||
166 | } | ||
167 | |||
168 | #[test] | ||
169 | fn macro_rules_diag() { | ||
170 | check_diagnostics( | ||
171 | r#" | ||
172 | macro_rules! m { | ||
173 | () => {}; | ||
174 | } | ||
175 | fn f() { | ||
176 | m!(); | ||
177 | |||
178 | m!(hi); | ||
179 | //^^^^^^ leftover tokens | ||
180 | } | ||
181 | "#, | ||
182 | ); | 83 | ); |
183 | } | 84 | } |
184 | |||
185 | #[test] | ||
186 | fn unresolved_macro_diag() { | ||
187 | check_diagnostics( | ||
188 | r#" | ||
189 | fn f() { | ||
190 | m!(); | ||
191 | //^^^^ UnresolvedMacroCall | ||
192 | } | ||
193 | "#, | ||
194 | ); | ||
195 | } | ||
196 | |||
197 | #[test] | ||
198 | fn dollar_crate_in_builtin_macro() { | ||
199 | check_diagnostics( | ||
200 | r#" | ||
201 | #[macro_export] | ||
202 | #[rustc_builtin_macro] | ||
203 | macro_rules! format_args {} | ||
204 | |||
205 | #[macro_export] | ||
206 | macro_rules! arg { | ||
207 | () => {} | ||
208 | } | ||
209 | |||
210 | #[macro_export] | ||
211 | macro_rules! outer { | ||
212 | () => { | ||
213 | $crate::format_args!( "", $crate::arg!(1) ) | ||
214 | }; | ||
215 | } | ||
216 | |||
217 | fn f() { | ||
218 | outer!(); | ||
219 | //^^^^^^^^ leftover tokens | ||
220 | } | ||
221 | "#, | ||
222 | ) | ||
223 | } | ||
diff --git a/crates/hir_def/src/body/tests/block.rs b/crates/hir_def/src/body/tests/block.rs index bc3d0f138..15c10d053 100644 --- a/crates/hir_def/src/body/tests/block.rs +++ b/crates/hir_def/src/body/tests/block.rs | |||
@@ -163,14 +163,14 @@ fn legacy_macro_items() { | |||
163 | // correctly. | 163 | // correctly. |
164 | check_at( | 164 | check_at( |
165 | r#" | 165 | r#" |
166 | macro_rules! hit { | 166 | macro_rules! mark { |
167 | () => { | 167 | () => { |
168 | struct Hit {} | 168 | struct Hit {} |
169 | } | 169 | } |
170 | } | 170 | } |
171 | 171 | ||
172 | fn f() { | 172 | fn f() { |
173 | hit!(); | 173 | mark!(); |
174 | $0 | 174 | $0 |
175 | } | 175 | } |
176 | "#, | 176 | "#, |
@@ -193,20 +193,20 @@ use core::cov_mark; | |||
193 | 193 | ||
194 | fn f() { | 194 | fn f() { |
195 | fn nested() { | 195 | fn nested() { |
196 | cov_mark::hit!(Hit); | 196 | cov_mark::mark!(Hit); |
197 | $0 | 197 | $0 |
198 | } | 198 | } |
199 | } | 199 | } |
200 | //- /core.rs crate:core | 200 | //- /core.rs crate:core |
201 | pub mod cov_mark { | 201 | pub mod cov_mark { |
202 | #[macro_export] | 202 | #[macro_export] |
203 | macro_rules! _hit { | 203 | macro_rules! _mark { |
204 | ($name:ident) => { | 204 | ($name:ident) => { |
205 | struct $name {} | 205 | struct $name {} |
206 | } | 206 | } |
207 | } | 207 | } |
208 | 208 | ||
209 | pub use crate::_hit as hit; | 209 | pub use crate::_mark as mark; |
210 | } | 210 | } |
211 | "#, | 211 | "#, |
212 | expect![[r#" | 212 | expect![[r#" |
diff --git a/crates/hir_def/src/builtin_attr.rs b/crates/hir_def/src/builtin_attr.rs index d5d7f0f47..39c7f84f7 100644 --- a/crates/hir_def/src/builtin_attr.rs +++ b/crates/hir_def/src/builtin_attr.rs | |||
@@ -2,7 +2,7 @@ | |||
2 | //! | 2 | //! |
3 | //! The actual definitions were copied from rustc's `compiler/rustc_feature/src/builtin_attrs.rs`. | 3 | //! The actual definitions were copied from rustc's `compiler/rustc_feature/src/builtin_attrs.rs`. |
4 | //! | 4 | //! |
5 | //! It was last synchronized with upstream commit 2225ee1b62ff089917434aefd9b2bf509cfa087f. | 5 | //! It was last synchronized with upstream commit 835150e70288535bc57bb624792229b9dc94991d. |
6 | //! | 6 | //! |
7 | //! The macros were adjusted to only expand to the attribute name, since that is all we need to do | 7 | //! The macros were adjusted to only expand to the attribute name, since that is all we need to do |
8 | //! name resolution, and `BUILTIN_ATTRIBUTES` is almost entirely unchanged from the original, to | 8 | //! name resolution, and `BUILTIN_ATTRIBUTES` is almost entirely unchanged from the original, to |
@@ -58,7 +58,6 @@ pub const INERT_ATTRIBUTES: &[BuiltinAttribute] = &[ | |||
58 | ungated!(reexport_test_harness_main, Normal, template!(NameValueStr: "name")), | 58 | ungated!(reexport_test_harness_main, Normal, template!(NameValueStr: "name")), |
59 | 59 | ||
60 | // Macros: | 60 | // Macros: |
61 | ungated!(derive, Normal, template!(List: "Trait1, Trait2, ...")), | ||
62 | ungated!(automatically_derived, Normal, template!(Word)), | 61 | ungated!(automatically_derived, Normal, template!(Word)), |
63 | // FIXME(#14407) | 62 | // FIXME(#14407) |
64 | ungated!(macro_use, Normal, template!(Word, List: "name1, name2, ...")), | 63 | ungated!(macro_use, Normal, template!(Word, List: "name1, name2, ...")), |
@@ -98,8 +97,8 @@ pub const INERT_ATTRIBUTES: &[BuiltinAttribute] = &[ | |||
98 | template!(List: r#"name = "...", /*opt*/ kind = "dylib|static|...", /*opt*/ wasm_import_module = "...""#), | 97 | template!(List: r#"name = "...", /*opt*/ kind = "dylib|static|...", /*opt*/ wasm_import_module = "...""#), |
99 | ), | 98 | ), |
100 | ungated!(link_name, AssumedUsed, template!(NameValueStr: "name")), | 99 | ungated!(link_name, AssumedUsed, template!(NameValueStr: "name")), |
101 | ungated!(no_link, Normal, template!(Word)), | 100 | ungated!(no_link, AssumedUsed, template!(Word)), |
102 | ungated!(repr, Normal, template!(List: "C")), | 101 | ungated!(repr, AssumedUsed, template!(List: "C")), |
103 | ungated!(export_name, AssumedUsed, template!(NameValueStr: "name")), | 102 | ungated!(export_name, AssumedUsed, template!(NameValueStr: "name")), |
104 | ungated!(link_section, AssumedUsed, template!(NameValueStr: "name")), | 103 | ungated!(link_section, AssumedUsed, template!(NameValueStr: "name")), |
105 | ungated!(no_mangle, AssumedUsed, template!(Word)), | 104 | ungated!(no_mangle, AssumedUsed, template!(Word)), |
@@ -112,6 +111,10 @@ pub const INERT_ATTRIBUTES: &[BuiltinAttribute] = &[ | |||
112 | const_eval_limit, CrateLevel, template!(NameValueStr: "N"), const_eval_limit, | 111 | const_eval_limit, CrateLevel, template!(NameValueStr: "N"), const_eval_limit, |
113 | experimental!(const_eval_limit) | 112 | experimental!(const_eval_limit) |
114 | ), | 113 | ), |
114 | gated!( | ||
115 | move_size_limit, CrateLevel, template!(NameValueStr: "N"), large_assignments, | ||
116 | experimental!(move_size_limit) | ||
117 | ), | ||
115 | 118 | ||
116 | // Entry point: | 119 | // Entry point: |
117 | ungated!(main, Normal, template!(Word)), | 120 | ungated!(main, Normal, template!(Word)), |
@@ -140,6 +143,7 @@ pub const INERT_ATTRIBUTES: &[BuiltinAttribute] = &[ | |||
140 | template!(List: "address, memory, thread"), | 143 | template!(List: "address, memory, thread"), |
141 | experimental!(no_sanitize) | 144 | experimental!(no_sanitize) |
142 | ), | 145 | ), |
146 | gated!(no_coverage, AssumedUsed, template!(Word), experimental!(no_coverage)), | ||
143 | 147 | ||
144 | // FIXME: #14408 assume docs are used since rustdoc looks at them. | 148 | // FIXME: #14408 assume docs are used since rustdoc looks at them. |
145 | ungated!(doc, AssumedUsed, template!(List: "hidden|inline|...", NameValueStr: "string")), | 149 | ungated!(doc, AssumedUsed, template!(List: "hidden|inline|...", NameValueStr: "string")), |
@@ -151,11 +155,6 @@ pub const INERT_ATTRIBUTES: &[BuiltinAttribute] = &[ | |||
151 | // Linking: | 155 | // Linking: |
152 | gated!(naked, AssumedUsed, template!(Word), naked_functions, experimental!(naked)), | 156 | gated!(naked, AssumedUsed, template!(Word), naked_functions, experimental!(naked)), |
153 | gated!( | 157 | gated!( |
154 | link_args, Normal, template!(NameValueStr: "args"), | ||
155 | "the `link_args` attribute is experimental and not portable across platforms, \ | ||
156 | it is recommended to use `#[link(name = \"foo\")] instead", | ||
157 | ), | ||
158 | gated!( | ||
159 | link_ordinal, AssumedUsed, template!(List: "ordinal"), raw_dylib, | 158 | link_ordinal, AssumedUsed, template!(List: "ordinal"), raw_dylib, |
160 | experimental!(link_ordinal) | 159 | experimental!(link_ordinal) |
161 | ), | 160 | ), |
@@ -172,7 +171,7 @@ pub const INERT_ATTRIBUTES: &[BuiltinAttribute] = &[ | |||
172 | "custom test frameworks are an unstable feature", | 171 | "custom test frameworks are an unstable feature", |
173 | ), | 172 | ), |
174 | // RFC #1268 | 173 | // RFC #1268 |
175 | gated!(marker, Normal, template!(Word), marker_trait_attr, experimental!(marker)), | 174 | gated!(marker, AssumedUsed, template!(Word), marker_trait_attr, experimental!(marker)), |
176 | gated!( | 175 | gated!( |
177 | thread_local, AssumedUsed, template!(Word), | 176 | thread_local, AssumedUsed, template!(Word), |
178 | "`#[thread_local]` is an experimental feature, and does not currently handle destructors", | 177 | "`#[thread_local]` is an experimental feature, and does not currently handle destructors", |
@@ -291,7 +290,7 @@ pub const INERT_ATTRIBUTES: &[BuiltinAttribute] = &[ | |||
291 | // Internal attributes, Macro related: | 290 | // Internal attributes, Macro related: |
292 | // ========================================================================== | 291 | // ========================================================================== |
293 | 292 | ||
294 | rustc_attr!(rustc_builtin_macro, AssumedUsed, template!(Word), IMPL_DETAIL), | 293 | rustc_attr!(rustc_builtin_macro, AssumedUsed, template!(Word, NameValueStr: "name"), IMPL_DETAIL), |
295 | rustc_attr!(rustc_proc_macro_decls, Normal, template!(Word), INTERNAL_UNSTABLE), | 294 | rustc_attr!(rustc_proc_macro_decls, Normal, template!(Word), INTERNAL_UNSTABLE), |
296 | rustc_attr!( | 295 | rustc_attr!( |
297 | rustc_macro_transparency, AssumedUsed, | 296 | rustc_macro_transparency, AssumedUsed, |
@@ -319,7 +318,7 @@ pub const INERT_ATTRIBUTES: &[BuiltinAttribute] = &[ | |||
319 | // ========================================================================== | 318 | // ========================================================================== |
320 | 319 | ||
321 | rustc_attr!(rustc_promotable, AssumedUsed, template!(Word), IMPL_DETAIL), | 320 | rustc_attr!(rustc_promotable, AssumedUsed, template!(Word), IMPL_DETAIL), |
322 | rustc_attr!(rustc_args_required_const, AssumedUsed, template!(List: "N"), INTERNAL_UNSTABLE), | 321 | rustc_attr!(rustc_legacy_const_generics, AssumedUsed, template!(List: "N"), INTERNAL_UNSTABLE), |
323 | 322 | ||
324 | // ========================================================================== | 323 | // ========================================================================== |
325 | // Internal attributes, Layout related: | 324 | // Internal attributes, Layout related: |
@@ -380,6 +379,15 @@ pub const INERT_ATTRIBUTES: &[BuiltinAttribute] = &[ | |||
380 | rustc_specialization_trait, Normal, template!(Word), | 379 | rustc_specialization_trait, Normal, template!(Word), |
381 | "the `#[rustc_specialization_trait]` attribute is used to check specializations" | 380 | "the `#[rustc_specialization_trait]` attribute is used to check specializations" |
382 | ), | 381 | ), |
382 | rustc_attr!( | ||
383 | rustc_main, Normal, template!(Word), | ||
384 | "the `#[rustc_main]` attribute is used internally to specify test entry point function", | ||
385 | ), | ||
386 | rustc_attr!( | ||
387 | rustc_skip_array_during_method_dispatch, Normal, template!(Word), | ||
388 | "the `#[rustc_skip_array_during_method_dispatch]` attribute is used to exclude a trait \ | ||
389 | from method dispatch when the receiver is an array, for compatibility in editions < 2021." | ||
390 | ), | ||
383 | 391 | ||
384 | // ========================================================================== | 392 | // ========================================================================== |
385 | // Internal attributes, Testing: | 393 | // Internal attributes, Testing: |
@@ -387,6 +395,7 @@ pub const INERT_ATTRIBUTES: &[BuiltinAttribute] = &[ | |||
387 | 395 | ||
388 | rustc_attr!(TEST, rustc_outlives, Normal, template!(Word)), | 396 | rustc_attr!(TEST, rustc_outlives, Normal, template!(Word)), |
389 | rustc_attr!(TEST, rustc_capture_analysis, Normal, template!(Word)), | 397 | rustc_attr!(TEST, rustc_capture_analysis, Normal, template!(Word)), |
398 | rustc_attr!(TEST, rustc_insignificant_dtor, Normal, template!(Word)), | ||
390 | rustc_attr!(TEST, rustc_variance, Normal, template!(Word)), | 399 | rustc_attr!(TEST, rustc_variance, Normal, template!(Word)), |
391 | rustc_attr!(TEST, rustc_layout, Normal, template!(List: "field1, field2, ...")), | 400 | rustc_attr!(TEST, rustc_layout, Normal, template!(List: "field1, field2, ...")), |
392 | rustc_attr!(TEST, rustc_regions, Normal, template!(Word)), | 401 | rustc_attr!(TEST, rustc_regions, Normal, template!(Word)), |
@@ -395,13 +404,10 @@ pub const INERT_ATTRIBUTES: &[BuiltinAttribute] = &[ | |||
395 | template!(Word, List: "delay_span_bug_from_inside_query") | 404 | template!(Word, List: "delay_span_bug_from_inside_query") |
396 | ), | 405 | ), |
397 | rustc_attr!(TEST, rustc_dump_user_substs, AssumedUsed, template!(Word)), | 406 | rustc_attr!(TEST, rustc_dump_user_substs, AssumedUsed, template!(Word)), |
407 | rustc_attr!(TEST, rustc_evaluate_where_clauses, AssumedUsed, template!(Word)), | ||
398 | rustc_attr!(TEST, rustc_if_this_changed, AssumedUsed, template!(Word, List: "DepNode")), | 408 | rustc_attr!(TEST, rustc_if_this_changed, AssumedUsed, template!(Word, List: "DepNode")), |
399 | rustc_attr!(TEST, rustc_then_this_would_need, AssumedUsed, template!(List: "DepNode")), | 409 | rustc_attr!(TEST, rustc_then_this_would_need, AssumedUsed, template!(List: "DepNode")), |
400 | rustc_attr!( | 410 | rustc_attr!( |
401 | TEST, rustc_dirty, AssumedUsed, | ||
402 | template!(List: r#"cfg = "...", /*opt*/ label = "...", /*opt*/ except = "...""#), | ||
403 | ), | ||
404 | rustc_attr!( | ||
405 | TEST, rustc_clean, AssumedUsed, | 411 | TEST, rustc_clean, AssumedUsed, |
406 | template!(List: r#"cfg = "...", /*opt*/ label = "...", /*opt*/ except = "...""#), | 412 | template!(List: r#"cfg = "...", /*opt*/ label = "...", /*opt*/ except = "...""#), |
407 | ), | 413 | ), |
diff --git a/crates/hir_def/src/child_by_source.rs b/crates/hir_def/src/child_by_source.rs index f2e809ca9..f22383e22 100644 --- a/crates/hir_def/src/child_by_source.rs +++ b/crates/hir_def/src/child_by_source.rs | |||
@@ -85,6 +85,10 @@ impl ChildBySource for ItemScope { | |||
85 | res[keys::CONST].insert(src, konst); | 85 | res[keys::CONST].insert(src, konst); |
86 | }); | 86 | }); |
87 | self.impls().for_each(|imp| add_impl(db, res, imp)); | 87 | self.impls().for_each(|imp| add_impl(db, res, imp)); |
88 | self.attr_macro_invocs().for_each(|(ast_id, call_id)| { | ||
89 | let item = ast_id.with_value(ast_id.to_node(db.upcast())); | ||
90 | res[keys::ATTR_MACRO].insert(item, call_id); | ||
91 | }); | ||
88 | 92 | ||
89 | fn add_module_def(db: &dyn DefDatabase, map: &mut DynMap, item: ModuleDefId) { | 93 | fn add_module_def(db: &dyn DefDatabase, map: &mut DynMap, item: ModuleDefId) { |
90 | match item { | 94 | match item { |
diff --git a/crates/hir_def/src/data.rs b/crates/hir_def/src/data.rs index d2bb381be..52cb7777b 100644 --- a/crates/hir_def/src/data.rs +++ b/crates/hir_def/src/data.rs | |||
@@ -143,6 +143,10 @@ pub struct TraitData { | |||
143 | pub is_auto: bool, | 143 | pub is_auto: bool, |
144 | pub is_unsafe: bool, | 144 | pub is_unsafe: bool, |
145 | pub visibility: RawVisibility, | 145 | pub visibility: RawVisibility, |
146 | /// Whether the trait has `#[rust_skip_array_during_method_dispatch]`. `hir_ty` will ignore | ||
147 | /// method calls to this trait's methods when the receiver is an array and the crate edition is | ||
148 | /// 2015 or 2018. | ||
149 | pub skip_array_during_method_dispatch: bool, | ||
146 | } | 150 | } |
147 | 151 | ||
148 | impl TraitData { | 152 | impl TraitData { |
@@ -157,6 +161,10 @@ impl TraitData { | |||
157 | let container = AssocContainerId::TraitId(tr); | 161 | let container = AssocContainerId::TraitId(tr); |
158 | let visibility = item_tree[tr_def.visibility].clone(); | 162 | let visibility = item_tree[tr_def.visibility].clone(); |
159 | let mut expander = Expander::new(db, tr_loc.id.file_id(), module_id); | 163 | let mut expander = Expander::new(db, tr_loc.id.file_id(), module_id); |
164 | let skip_array_during_method_dispatch = item_tree | ||
165 | .attrs(db, tr_loc.container.krate(), ModItem::from(tr_loc.id.value).into()) | ||
166 | .by_key("rustc_skip_array_during_method_dispatch") | ||
167 | .exists(); | ||
160 | 168 | ||
161 | let items = collect_items( | 169 | let items = collect_items( |
162 | db, | 170 | db, |
@@ -168,7 +176,14 @@ impl TraitData { | |||
168 | 100, | 176 | 100, |
169 | ); | 177 | ); |
170 | 178 | ||
171 | Arc::new(TraitData { name, items, is_auto, is_unsafe, visibility }) | 179 | Arc::new(TraitData { |
180 | name, | ||
181 | items, | ||
182 | is_auto, | ||
183 | is_unsafe, | ||
184 | visibility, | ||
185 | skip_array_during_method_dispatch, | ||
186 | }) | ||
172 | } | 187 | } |
173 | 188 | ||
174 | pub fn associated_types(&self) -> impl Iterator<Item = TypeAliasId> + '_ { | 189 | pub fn associated_types(&self) -> impl Iterator<Item = TypeAliasId> + '_ { |
diff --git a/crates/hir_def/src/db.rs b/crates/hir_def/src/db.rs index 7eadc8e0d..c977971cd 100644 --- a/crates/hir_def/src/db.rs +++ b/crates/hir_def/src/db.rs | |||
@@ -51,6 +51,9 @@ pub trait InternDatabase: SourceDatabase { | |||
51 | 51 | ||
52 | #[salsa::query_group(DefDatabaseStorage)] | 52 | #[salsa::query_group(DefDatabaseStorage)] |
53 | pub trait DefDatabase: InternDatabase + AstDatabase + Upcast<dyn AstDatabase> { | 53 | pub trait DefDatabase: InternDatabase + AstDatabase + Upcast<dyn AstDatabase> { |
54 | #[salsa::input] | ||
55 | fn enable_proc_attr_macros(&self) -> bool; | ||
56 | |||
54 | #[salsa::invoke(ItemTree::file_item_tree_query)] | 57 | #[salsa::invoke(ItemTree::file_item_tree_query)] |
55 | fn file_item_tree(&self, file_id: HirFileId) -> Arc<ItemTree>; | 58 | fn file_item_tree(&self, file_id: HirFileId) -> Arc<ItemTree>; |
56 | 59 | ||
diff --git a/crates/hir_def/src/generics.rs b/crates/hir_def/src/generics.rs index 44d22b918..6933f6e3c 100644 --- a/crates/hir_def/src/generics.rs +++ b/crates/hir_def/src/generics.rs | |||
@@ -280,7 +280,7 @@ impl GenericParams { | |||
280 | sm.type_params.insert(param_id, Either::Right(type_param.clone())); | 280 | sm.type_params.insert(param_id, Either::Right(type_param.clone())); |
281 | 281 | ||
282 | let type_ref = TypeRef::Path(name.into()); | 282 | let type_ref = TypeRef::Path(name.into()); |
283 | self.fill_bounds(&lower_ctx, &type_param, Either::Left(type_ref)); | 283 | self.fill_bounds(lower_ctx, &type_param, Either::Left(type_ref)); |
284 | } | 284 | } |
285 | for lifetime_param in params.lifetime_params() { | 285 | for lifetime_param in params.lifetime_params() { |
286 | let name = | 286 | let name = |
@@ -289,7 +289,7 @@ impl GenericParams { | |||
289 | let param_id = self.lifetimes.alloc(param); | 289 | let param_id = self.lifetimes.alloc(param); |
290 | sm.lifetime_params.insert(param_id, lifetime_param.clone()); | 290 | sm.lifetime_params.insert(param_id, lifetime_param.clone()); |
291 | let lifetime_ref = LifetimeRef::new_name(name); | 291 | let lifetime_ref = LifetimeRef::new_name(name); |
292 | self.fill_bounds(&lower_ctx, &lifetime_param, Either::Right(lifetime_ref)); | 292 | self.fill_bounds(lower_ctx, &lifetime_param, Either::Right(lifetime_ref)); |
293 | } | 293 | } |
294 | for const_param in params.const_params() { | 294 | for const_param in params.const_params() { |
295 | let name = const_param.name().map_or_else(Name::missing, |it| it.as_name()); | 295 | let name = const_param.name().map_or_else(Name::missing, |it| it.as_name()); |
diff --git a/crates/hir_def/src/import_map.rs b/crates/hir_def/src/import_map.rs index 960cabb5f..404e3e153 100644 --- a/crates/hir_def/src/import_map.rs +++ b/crates/hir_def/src/import_map.rs | |||
@@ -1,6 +1,6 @@ | |||
1 | //! A map of all publicly exported items in a crate. | 1 | //! A map of all publicly exported items in a crate. |
2 | 2 | ||
3 | use std::{cmp::Ordering, fmt, hash::BuildHasherDefault, sync::Arc}; | 3 | use std::{fmt, hash::BuildHasherDefault, sync::Arc}; |
4 | 4 | ||
5 | use base_db::CrateId; | 5 | use base_db::CrateId; |
6 | use fst::{self, Streamer}; | 6 | use fst::{self, Streamer}; |
@@ -69,81 +69,11 @@ pub struct ImportMap { | |||
69 | impl ImportMap { | 69 | impl ImportMap { |
70 | pub fn import_map_query(db: &dyn DefDatabase, krate: CrateId) -> Arc<Self> { | 70 | pub fn import_map_query(db: &dyn DefDatabase, krate: CrateId) -> Arc<Self> { |
71 | let _p = profile::span("import_map_query"); | 71 | let _p = profile::span("import_map_query"); |
72 | let def_map = db.crate_def_map(krate); | ||
73 | let mut import_map = Self::default(); | ||
74 | |||
75 | // We look only into modules that are public(ly reexported), starting with the crate root. | ||
76 | let empty = ImportPath { segments: vec![] }; | ||
77 | let root = def_map.module_id(def_map.root()); | ||
78 | let mut worklist = vec![(root, empty)]; | ||
79 | while let Some((module, mod_path)) = worklist.pop() { | ||
80 | let ext_def_map; | ||
81 | let mod_data = if module.krate == krate { | ||
82 | &def_map[module.local_id] | ||
83 | } else { | ||
84 | // The crate might reexport a module defined in another crate. | ||
85 | ext_def_map = module.def_map(db); | ||
86 | &ext_def_map[module.local_id] | ||
87 | }; | ||
88 | |||
89 | let visible_items = mod_data.scope.entries().filter_map(|(name, per_ns)| { | ||
90 | let per_ns = per_ns.filter_visibility(|vis| vis == Visibility::Public); | ||
91 | if per_ns.is_none() { | ||
92 | None | ||
93 | } else { | ||
94 | Some((name, per_ns)) | ||
95 | } | ||
96 | }); | ||
97 | |||
98 | for (name, per_ns) in visible_items { | ||
99 | let mk_path = || { | ||
100 | let mut path = mod_path.clone(); | ||
101 | path.segments.push(name.clone()); | ||
102 | path | ||
103 | }; | ||
104 | |||
105 | for item in per_ns.iter_items() { | ||
106 | let path = mk_path(); | ||
107 | let path_len = path.len(); | ||
108 | let import_info = | ||
109 | ImportInfo { path, container: module, is_trait_assoc_item: false }; | ||
110 | |||
111 | if let Some(ModuleDefId::TraitId(tr)) = item.as_module_def_id() { | ||
112 | import_map.collect_trait_assoc_items( | ||
113 | db, | ||
114 | tr, | ||
115 | matches!(item, ItemInNs::Types(_)), | ||
116 | &import_info, | ||
117 | ); | ||
118 | } | ||
119 | 72 | ||
120 | match import_map.map.entry(item) { | 73 | let mut import_map = collect_import_map(db, krate); |
121 | Entry::Vacant(entry) => { | ||
122 | entry.insert(import_info); | ||
123 | } | ||
124 | Entry::Occupied(mut entry) => { | ||
125 | // If the new path is shorter, prefer that one. | ||
126 | if path_len < entry.get().path.len() { | ||
127 | *entry.get_mut() = import_info; | ||
128 | } else { | ||
129 | continue; | ||
130 | } | ||
131 | } | ||
132 | } | ||
133 | |||
134 | // If we've just added a path to a module, descend into it. We might traverse | ||
135 | // modules multiple times, but only if the new path to it is shorter than the | ||
136 | // first (else we `continue` above). | ||
137 | if let Some(ModuleDefId::ModuleId(mod_id)) = item.as_module_def_id() { | ||
138 | worklist.push((mod_id, mk_path())); | ||
139 | } | ||
140 | } | ||
141 | } | ||
142 | } | ||
143 | 74 | ||
144 | let mut importables = import_map.map.iter().collect::<Vec<_>>(); | 75 | let mut importables = import_map.map.iter().collect::<Vec<_>>(); |
145 | 76 | importables.sort_by_cached_key(|(_, import_info)| fst_path(&import_info.path)); | |
146 | importables.sort_by(cmp); | ||
147 | 77 | ||
148 | // Build the FST, taking care not to insert duplicate values. | 78 | // Build the FST, taking care not to insert duplicate values. |
149 | 79 | ||
@@ -151,13 +81,13 @@ impl ImportMap { | |||
151 | let mut last_batch_start = 0; | 81 | let mut last_batch_start = 0; |
152 | 82 | ||
153 | for idx in 0..importables.len() { | 83 | for idx in 0..importables.len() { |
154 | if let Some(next_item) = importables.get(idx + 1) { | 84 | let key = fst_path(&importables[last_batch_start].1.path); |
155 | if cmp(&importables[last_batch_start], next_item) == Ordering::Equal { | 85 | if let Some((_, next_import_info)) = importables.get(idx + 1) { |
86 | if key == fst_path(&next_import_info.path) { | ||
156 | continue; | 87 | continue; |
157 | } | 88 | } |
158 | } | 89 | } |
159 | 90 | ||
160 | let key = fst_path(&importables[last_batch_start].1.path); | ||
161 | builder.insert(key, last_batch_start as u64).unwrap(); | 91 | builder.insert(key, last_batch_start as u64).unwrap(); |
162 | 92 | ||
163 | last_batch_start = idx + 1; | 93 | last_batch_start = idx + 1; |
@@ -185,6 +115,7 @@ impl ImportMap { | |||
185 | is_type_in_ns: bool, | 115 | is_type_in_ns: bool, |
186 | original_import_info: &ImportInfo, | 116 | original_import_info: &ImportInfo, |
187 | ) { | 117 | ) { |
118 | let _p = profile::span("collect_trait_assoc_items"); | ||
188 | for (assoc_item_name, item) in &db.trait_data(tr).items { | 119 | for (assoc_item_name, item) in &db.trait_data(tr).items { |
189 | let module_def_id = match item { | 120 | let module_def_id = match item { |
190 | AssocItemId::FunctionId(f) => ModuleDefId::from(*f), | 121 | AssocItemId::FunctionId(f) => ModuleDefId::from(*f), |
@@ -210,6 +141,84 @@ impl ImportMap { | |||
210 | } | 141 | } |
211 | } | 142 | } |
212 | 143 | ||
144 | fn collect_import_map(db: &dyn DefDatabase, krate: CrateId) -> ImportMap { | ||
145 | let _p = profile::span("collect_import_map"); | ||
146 | |||
147 | let def_map = db.crate_def_map(krate); | ||
148 | let mut import_map = ImportMap::default(); | ||
149 | |||
150 | // We look only into modules that are public(ly reexported), starting with the crate root. | ||
151 | let empty = ImportPath { segments: vec![] }; | ||
152 | let root = def_map.module_id(def_map.root()); | ||
153 | let mut worklist = vec![(root, empty)]; | ||
154 | while let Some((module, mod_path)) = worklist.pop() { | ||
155 | let ext_def_map; | ||
156 | let mod_data = if module.krate == krate { | ||
157 | &def_map[module.local_id] | ||
158 | } else { | ||
159 | // The crate might reexport a module defined in another crate. | ||
160 | ext_def_map = module.def_map(db); | ||
161 | &ext_def_map[module.local_id] | ||
162 | }; | ||
163 | |||
164 | let visible_items = mod_data.scope.entries().filter_map(|(name, per_ns)| { | ||
165 | let per_ns = per_ns.filter_visibility(|vis| vis == Visibility::Public); | ||
166 | if per_ns.is_none() { | ||
167 | None | ||
168 | } else { | ||
169 | Some((name, per_ns)) | ||
170 | } | ||
171 | }); | ||
172 | |||
173 | for (name, per_ns) in visible_items { | ||
174 | let mk_path = || { | ||
175 | let mut path = mod_path.clone(); | ||
176 | path.segments.push(name.clone()); | ||
177 | path | ||
178 | }; | ||
179 | |||
180 | for item in per_ns.iter_items() { | ||
181 | let path = mk_path(); | ||
182 | let path_len = path.len(); | ||
183 | let import_info = | ||
184 | ImportInfo { path, container: module, is_trait_assoc_item: false }; | ||
185 | |||
186 | if let Some(ModuleDefId::TraitId(tr)) = item.as_module_def_id() { | ||
187 | import_map.collect_trait_assoc_items( | ||
188 | db, | ||
189 | tr, | ||
190 | matches!(item, ItemInNs::Types(_)), | ||
191 | &import_info, | ||
192 | ); | ||
193 | } | ||
194 | |||
195 | match import_map.map.entry(item) { | ||
196 | Entry::Vacant(entry) => { | ||
197 | entry.insert(import_info); | ||
198 | } | ||
199 | Entry::Occupied(mut entry) => { | ||
200 | // If the new path is shorter, prefer that one. | ||
201 | if path_len < entry.get().path.len() { | ||
202 | *entry.get_mut() = import_info; | ||
203 | } else { | ||
204 | continue; | ||
205 | } | ||
206 | } | ||
207 | } | ||
208 | |||
209 | // If we've just added a path to a module, descend into it. We might traverse | ||
210 | // modules multiple times, but only if the new path to it is shorter than the | ||
211 | // first (else we `continue` above). | ||
212 | if let Some(ModuleDefId::ModuleId(mod_id)) = item.as_module_def_id() { | ||
213 | worklist.push((mod_id, mk_path())); | ||
214 | } | ||
215 | } | ||
216 | } | ||
217 | } | ||
218 | |||
219 | import_map | ||
220 | } | ||
221 | |||
213 | impl PartialEq for ImportMap { | 222 | impl PartialEq for ImportMap { |
214 | fn eq(&self, other: &Self) -> bool { | 223 | fn eq(&self, other: &Self) -> bool { |
215 | // `fst` and `importables` are built from `map`, so we don't need to compare them. | 224 | // `fst` and `importables` are built from `map`, so we don't need to compare them. |
@@ -240,17 +249,12 @@ impl fmt::Debug for ImportMap { | |||
240 | } | 249 | } |
241 | 250 | ||
242 | fn fst_path(path: &ImportPath) -> String { | 251 | fn fst_path(path: &ImportPath) -> String { |
252 | let _p = profile::span("fst_path"); | ||
243 | let mut s = path.to_string(); | 253 | let mut s = path.to_string(); |
244 | s.make_ascii_lowercase(); | 254 | s.make_ascii_lowercase(); |
245 | s | 255 | s |
246 | } | 256 | } |
247 | 257 | ||
248 | fn cmp((_, lhs): &(&ItemInNs, &ImportInfo), (_, rhs): &(&ItemInNs, &ImportInfo)) -> Ordering { | ||
249 | let lhs_str = fst_path(&lhs.path); | ||
250 | let rhs_str = fst_path(&rhs.path); | ||
251 | lhs_str.cmp(&rhs_str) | ||
252 | } | ||
253 | |||
254 | #[derive(Debug, Eq, PartialEq, Hash)] | 258 | #[derive(Debug, Eq, PartialEq, Hash)] |
255 | pub enum ImportKind { | 259 | pub enum ImportKind { |
256 | Module, | 260 | Module, |
@@ -338,6 +342,7 @@ impl Query { | |||
338 | } | 342 | } |
339 | 343 | ||
340 | fn import_matches(&self, import: &ImportInfo, enforce_lowercase: bool) -> bool { | 344 | fn import_matches(&self, import: &ImportInfo, enforce_lowercase: bool) -> bool { |
345 | let _p = profile::span("import_map::Query::import_matches"); | ||
341 | if import.is_trait_assoc_item { | 346 | if import.is_trait_assoc_item { |
342 | if self.exclude_import_kinds.contains(&ImportKind::AssociatedItem) { | 347 | if self.exclude_import_kinds.contains(&ImportKind::AssociatedItem) { |
343 | return false; | 348 | return false; |
diff --git a/crates/hir_def/src/item_scope.rs b/crates/hir_def/src/item_scope.rs index 9014468ea..08407ebfa 100644 --- a/crates/hir_def/src/item_scope.rs +++ b/crates/hir_def/src/item_scope.rs | |||
@@ -4,11 +4,11 @@ | |||
4 | use std::collections::hash_map::Entry; | 4 | use std::collections::hash_map::Entry; |
5 | 5 | ||
6 | use base_db::CrateId; | 6 | use base_db::CrateId; |
7 | use hir_expand::name::Name; | 7 | use hir_expand::{name::Name, AstId, MacroCallId, MacroDefKind}; |
8 | use hir_expand::MacroDefKind; | ||
9 | use once_cell::sync::Lazy; | 8 | use once_cell::sync::Lazy; |
10 | use rustc_hash::{FxHashMap, FxHashSet}; | 9 | use rustc_hash::{FxHashMap, FxHashSet}; |
11 | use stdx::format_to; | 10 | use stdx::format_to; |
11 | use syntax::ast; | ||
12 | 12 | ||
13 | use crate::{ | 13 | use crate::{ |
14 | db::DefDatabase, per_ns::PerNs, visibility::Visibility, AdtId, BuiltinType, ConstId, ImplId, | 14 | db::DefDatabase, per_ns::PerNs, visibility::Visibility, AdtId, BuiltinType, ConstId, ImplId, |
@@ -53,12 +53,13 @@ pub struct ItemScope { | |||
53 | // FIXME: Macro shadowing in one module is not properly handled. Non-item place macros will | 53 | // FIXME: Macro shadowing in one module is not properly handled. Non-item place macros will |
54 | // be all resolved to the last one defined if shadowing happens. | 54 | // be all resolved to the last one defined if shadowing happens. |
55 | legacy_macros: FxHashMap<Name, MacroDefId>, | 55 | legacy_macros: FxHashMap<Name, MacroDefId>, |
56 | attr_macros: FxHashMap<AstId<ast::Item>, MacroCallId>, | ||
56 | } | 57 | } |
57 | 58 | ||
58 | pub(crate) static BUILTIN_SCOPE: Lazy<FxHashMap<Name, PerNs>> = Lazy::new(|| { | 59 | pub(crate) static BUILTIN_SCOPE: Lazy<FxHashMap<Name, PerNs>> = Lazy::new(|| { |
59 | BuiltinType::ALL | 60 | BuiltinType::ALL |
60 | .iter() | 61 | .iter() |
61 | .map(|(name, ty)| (name.clone(), PerNs::types(ty.clone().into(), Visibility::Public))) | 62 | .map(|(name, ty)| (name.clone(), PerNs::types((*ty).into(), Visibility::Public))) |
62 | .collect() | 63 | .collect() |
63 | }); | 64 | }); |
64 | 65 | ||
@@ -169,6 +170,16 @@ impl ItemScope { | |||
169 | self.legacy_macros.insert(name, mac); | 170 | self.legacy_macros.insert(name, mac); |
170 | } | 171 | } |
171 | 172 | ||
173 | pub(crate) fn add_attr_macro_invoc(&mut self, item: AstId<ast::Item>, call: MacroCallId) { | ||
174 | self.attr_macros.insert(item, call); | ||
175 | } | ||
176 | |||
177 | pub(crate) fn attr_macro_invocs( | ||
178 | &self, | ||
179 | ) -> impl Iterator<Item = (AstId<ast::Item>, MacroCallId)> + '_ { | ||
180 | self.attr_macros.iter().map(|(k, v)| (*k, *v)) | ||
181 | } | ||
182 | |||
172 | pub(crate) fn unnamed_trait_vis(&self, tr: TraitId) -> Option<Visibility> { | 183 | pub(crate) fn unnamed_trait_vis(&self, tr: TraitId) -> Option<Visibility> { |
173 | self.unnamed_trait_imports.get(&tr).copied() | 184 | self.unnamed_trait_imports.get(&tr).copied() |
174 | } | 185 | } |
@@ -307,6 +318,7 @@ impl ItemScope { | |||
307 | unnamed_consts, | 318 | unnamed_consts, |
308 | unnamed_trait_imports, | 319 | unnamed_trait_imports, |
309 | legacy_macros, | 320 | legacy_macros, |
321 | attr_macros, | ||
310 | } = self; | 322 | } = self; |
311 | types.shrink_to_fit(); | 323 | types.shrink_to_fit(); |
312 | values.shrink_to_fit(); | 324 | values.shrink_to_fit(); |
@@ -317,6 +329,7 @@ impl ItemScope { | |||
317 | unnamed_consts.shrink_to_fit(); | 329 | unnamed_consts.shrink_to_fit(); |
318 | unnamed_trait_imports.shrink_to_fit(); | 330 | unnamed_trait_imports.shrink_to_fit(); |
319 | legacy_macros.shrink_to_fit(); | 331 | legacy_macros.shrink_to_fit(); |
332 | attr_macros.shrink_to_fit(); | ||
320 | } | 333 | } |
321 | } | 334 | } |
322 | 335 | ||
diff --git a/crates/hir_def/src/item_tree/lower.rs b/crates/hir_def/src/item_tree/lower.rs index 6208facd5..3f90bda74 100644 --- a/crates/hir_def/src/item_tree/lower.rs +++ b/crates/hir_def/src/item_tree/lower.rs | |||
@@ -130,7 +130,7 @@ impl<'a> Ctx<'a> { | |||
130 | ast::Item::ExternBlock(ast) => self.lower_extern_block(ast).into(), | 130 | ast::Item::ExternBlock(ast) => self.lower_extern_block(ast).into(), |
131 | }; | 131 | }; |
132 | 132 | ||
133 | self.add_attrs(item.into(), attrs.clone()); | 133 | self.add_attrs(item.into(), attrs); |
134 | 134 | ||
135 | Some(item) | 135 | Some(item) |
136 | } | 136 | } |
@@ -276,10 +276,11 @@ impl<'a> Ctx<'a> { | |||
276 | let visibility = self.lower_visibility(enum_); | 276 | let visibility = self.lower_visibility(enum_); |
277 | let name = enum_.name()?.as_name(); | 277 | let name = enum_.name()?.as_name(); |
278 | let generic_params = self.lower_generic_params(GenericsOwner::Enum, enum_); | 278 | let generic_params = self.lower_generic_params(GenericsOwner::Enum, enum_); |
279 | let variants = match &enum_.variant_list() { | 279 | let variants = |
280 | Some(variant_list) => self.lower_variants(variant_list), | 280 | self.with_inherited_visibility(visibility, |this| match &enum_.variant_list() { |
281 | None => IdRange::new(self.next_variant_idx()..self.next_variant_idx()), | 281 | Some(variant_list) => this.lower_variants(variant_list), |
282 | }; | 282 | None => IdRange::new(this.next_variant_idx()..this.next_variant_idx()), |
283 | }); | ||
283 | let ast_id = self.source_ast_id_map.ast_id(enum_); | 284 | let ast_id = self.source_ast_id_map.ast_id(enum_); |
284 | let res = Enum { name, visibility, generic_params, variants, ast_id }; | 285 | let res = Enum { name, visibility, generic_params, variants, ast_id }; |
285 | Some(id(self.data().enums.alloc(res))) | 286 | Some(id(self.data().enums.alloc(res))) |
@@ -822,7 +823,7 @@ fn is_intrinsic_fn_unsafe(name: &Name) -> bool { | |||
822 | known::type_name, | 823 | known::type_name, |
823 | known::variant_count, | 824 | known::variant_count, |
824 | ] | 825 | ] |
825 | .contains(&name) | 826 | .contains(name) |
826 | } | 827 | } |
827 | 828 | ||
828 | fn lower_abi(abi: ast::Abi) -> Interned<str> { | 829 | fn lower_abi(abi: ast::Abi) -> Interned<str> { |
@@ -854,7 +855,7 @@ impl UseTreeLowering<'_> { | |||
854 | // E.g. `use something::{inner}` (prefix is `None`, path is `something`) | 855 | // 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 | // or `use something::{path::{inner::{innerer}}}` (prefix is `something::path`, path is `inner`) |
856 | Some(path) => { | 857 | Some(path) => { |
857 | match ModPath::from_src(self.db, path, &self.hygiene) { | 858 | match ModPath::from_src(self.db, path, self.hygiene) { |
858 | Some(it) => Some(it), | 859 | Some(it) => Some(it), |
859 | None => return None, // FIXME: report errors somewhere | 860 | None => return None, // FIXME: report errors somewhere |
860 | } | 861 | } |
@@ -873,7 +874,7 @@ impl UseTreeLowering<'_> { | |||
873 | } else { | 874 | } else { |
874 | let is_glob = tree.star_token().is_some(); | 875 | let is_glob = tree.star_token().is_some(); |
875 | let path = match tree.path() { | 876 | let path = match tree.path() { |
876 | Some(path) => Some(ModPath::from_src(self.db, path, &self.hygiene)?), | 877 | Some(path) => Some(ModPath::from_src(self.db, path, self.hygiene)?), |
877 | None => None, | 878 | None => None, |
878 | }; | 879 | }; |
879 | let alias = tree.rename().map(|a| { | 880 | let alias = tree.rename().map(|a| { |
diff --git a/crates/hir_def/src/item_tree/pretty.rs b/crates/hir_def/src/item_tree/pretty.rs index cc9944a22..b1e1b70d0 100644 --- a/crates/hir_def/src/item_tree/pretty.rs +++ b/crates/hir_def/src/item_tree/pretty.rs | |||
@@ -426,7 +426,7 @@ impl<'a> Printer<'a> { | |||
426 | w!(self, " {{"); | 426 | w!(self, " {{"); |
427 | self.indented(|this| { | 427 | self.indented(|this| { |
428 | for item in &**items { | 428 | for item in &**items { |
429 | this.print_mod_item((*item).into()); | 429 | this.print_mod_item(*item); |
430 | } | 430 | } |
431 | }); | 431 | }); |
432 | wln!(self, "}}"); | 432 | wln!(self, "}}"); |
diff --git a/crates/hir_def/src/item_tree/tests.rs b/crates/hir_def/src/item_tree/tests.rs index b362add5c..57686dc6e 100644 --- a/crates/hir_def/src/item_tree/tests.rs +++ b/crates/hir_def/src/item_tree/tests.rs | |||
@@ -359,3 +359,41 @@ trait Tr<'a, T: 'a>: Super {} | |||
359 | "#]], | 359 | "#]], |
360 | ) | 360 | ) |
361 | } | 361 | } |
362 | |||
363 | #[test] | ||
364 | fn inherit_visibility() { | ||
365 | check( | ||
366 | r#" | ||
367 | pub(crate) enum En { | ||
368 | Var1(u8), | ||
369 | Var2 { | ||
370 | fld: u8, | ||
371 | }, | ||
372 | } | ||
373 | |||
374 | pub(crate) trait Tr { | ||
375 | fn f(); | ||