diff options
Diffstat (limited to 'crates/hir_def')
-rw-r--r-- | crates/hir_def/src/attr.rs | 2 | ||||
-rw-r--r-- | crates/hir_def/src/body/scope.rs | 57 | ||||
-rw-r--r-- | crates/hir_def/src/find_path.rs | 56 | ||||
-rw-r--r-- | crates/hir_def/src/nameres.rs | 17 | ||||
-rw-r--r-- | crates/hir_def/src/nameres/collector.rs | 178 | ||||
-rw-r--r-- | crates/hir_def/src/nameres/mod_resolution.rs | 13 | ||||
-rw-r--r-- | crates/hir_def/src/nameres/path_resolution.rs | 2 | ||||
-rw-r--r-- | crates/hir_def/src/nameres/tests/macros.rs | 21 | ||||
-rw-r--r-- | crates/hir_def/src/resolver.rs | 24 |
9 files changed, 250 insertions, 120 deletions
diff --git a/crates/hir_def/src/attr.rs b/crates/hir_def/src/attr.rs index 2c10f46d8..52a2bce9b 100644 --- a/crates/hir_def/src/attr.rs +++ b/crates/hir_def/src/attr.rs | |||
@@ -638,7 +638,7 @@ fn collect_attrs( | |||
638 | owner: &dyn ast::AttrsOwner, | 638 | owner: &dyn ast::AttrsOwner, |
639 | ) -> impl Iterator<Item = Either<ast::Attr, ast::Comment>> { | 639 | ) -> impl Iterator<Item = Either<ast::Attr, ast::Comment>> { |
640 | let (inner_attrs, inner_docs) = inner_attributes(owner.syntax()) | 640 | let (inner_attrs, inner_docs) = inner_attributes(owner.syntax()) |
641 | .map_or((None, None), |(attrs, docs)| ((Some(attrs), Some(docs)))); | 641 | .map_or((None, None), |(attrs, docs)| (Some(attrs), Some(docs))); |
642 | 642 | ||
643 | let outer_attrs = owner.attrs().filter(|attr| attr.excl_token().is_none()); | 643 | let outer_attrs = owner.attrs().filter(|attr| attr.excl_token().is_none()); |
644 | let attrs = outer_attrs | 644 | let attrs = outer_attrs |
diff --git a/crates/hir_def/src/body/scope.rs b/crates/hir_def/src/body/scope.rs index 1bbb54fc6..bd7005ca6 100644 --- a/crates/hir_def/src/body/scope.rs +++ b/crates/hir_def/src/body/scope.rs | |||
@@ -8,7 +8,7 @@ use rustc_hash::FxHashMap; | |||
8 | use crate::{ | 8 | use crate::{ |
9 | body::Body, | 9 | body::Body, |
10 | db::DefDatabase, | 10 | db::DefDatabase, |
11 | expr::{Expr, ExprId, Pat, PatId, Statement}, | 11 | expr::{Expr, ExprId, LabelId, Pat, PatId, Statement}, |
12 | BlockId, DefWithBodyId, | 12 | BlockId, DefWithBodyId, |
13 | }; | 13 | }; |
14 | 14 | ||
@@ -40,6 +40,7 @@ impl ScopeEntry { | |||
40 | pub struct ScopeData { | 40 | pub struct ScopeData { |
41 | parent: Option<ScopeId>, | 41 | parent: Option<ScopeId>, |
42 | block: Option<BlockId>, | 42 | block: Option<BlockId>, |
43 | label: Option<(LabelId, Name)>, | ||
43 | entries: Vec<ScopeEntry>, | 44 | entries: Vec<ScopeEntry>, |
44 | } | 45 | } |
45 | 46 | ||
@@ -67,6 +68,11 @@ impl ExprScopes { | |||
67 | self.scopes[scope].block | 68 | self.scopes[scope].block |
68 | } | 69 | } |
69 | 70 | ||
71 | /// If `scope` refers to a labeled expression scope, returns the corresponding `Label`. | ||
72 | pub fn label(&self, scope: ScopeId) -> Option<(LabelId, Name)> { | ||
73 | self.scopes[scope].label.clone() | ||
74 | } | ||
75 | |||
70 | pub fn scope_chain(&self, scope: Option<ScopeId>) -> impl Iterator<Item = ScopeId> + '_ { | 76 | pub fn scope_chain(&self, scope: Option<ScopeId>) -> impl Iterator<Item = ScopeId> + '_ { |
71 | std::iter::successors(scope, move |&scope| self.scopes[scope].parent) | 77 | std::iter::successors(scope, move |&scope| self.scopes[scope].parent) |
72 | } | 78 | } |
@@ -85,15 +91,34 @@ impl ExprScopes { | |||
85 | } | 91 | } |
86 | 92 | ||
87 | fn root_scope(&mut self) -> ScopeId { | 93 | fn root_scope(&mut self) -> ScopeId { |
88 | self.scopes.alloc(ScopeData { parent: None, block: None, entries: vec![] }) | 94 | self.scopes.alloc(ScopeData { parent: None, block: None, label: None, entries: vec![] }) |
89 | } | 95 | } |
90 | 96 | ||
91 | fn new_scope(&mut self, parent: ScopeId) -> ScopeId { | 97 | fn new_scope(&mut self, parent: ScopeId) -> ScopeId { |
92 | self.scopes.alloc(ScopeData { parent: Some(parent), block: None, entries: vec![] }) | 98 | self.scopes.alloc(ScopeData { |
99 | parent: Some(parent), | ||
100 | block: None, | ||
101 | label: None, | ||
102 | entries: vec![], | ||
103 | }) | ||
93 | } | 104 | } |
94 | 105 | ||
95 | fn new_block_scope(&mut self, parent: ScopeId, block: BlockId) -> ScopeId { | 106 | fn new_labeled_scope(&mut self, parent: ScopeId, label: Option<(LabelId, Name)>) -> ScopeId { |
96 | self.scopes.alloc(ScopeData { parent: Some(parent), block: Some(block), entries: vec![] }) | 107 | self.scopes.alloc(ScopeData { parent: Some(parent), block: None, label, entries: vec![] }) |
108 | } | ||
109 | |||
110 | fn new_block_scope( | ||
111 | &mut self, | ||
112 | parent: ScopeId, | ||
113 | block: BlockId, | ||
114 | label: Option<(LabelId, Name)>, | ||
115 | ) -> ScopeId { | ||
116 | self.scopes.alloc(ScopeData { | ||
117 | parent: Some(parent), | ||
118 | block: Some(block), | ||
119 | label, | ||
120 | entries: vec![], | ||
121 | }) | ||
97 | } | 122 | } |
98 | 123 | ||
99 | fn add_bindings(&mut self, body: &Body, scope: ScopeId, pat: PatId) { | 124 | fn add_bindings(&mut self, body: &Body, scope: ScopeId, pat: PatId) { |
@@ -144,21 +169,33 @@ fn compute_block_scopes( | |||
144 | } | 169 | } |
145 | 170 | ||
146 | fn compute_expr_scopes(expr: ExprId, body: &Body, scopes: &mut ExprScopes, scope: ScopeId) { | 171 | fn compute_expr_scopes(expr: ExprId, body: &Body, scopes: &mut ExprScopes, scope: ScopeId) { |
172 | let make_label = | ||
173 | |label: &Option<_>| label.map(|label| (label, body.labels[label].name.clone())); | ||
174 | |||
147 | scopes.set_scope(expr, scope); | 175 | scopes.set_scope(expr, scope); |
148 | match &body[expr] { | 176 | match &body[expr] { |
149 | Expr::Block { statements, tail, id, .. } => { | 177 | Expr::Block { statements, tail, id, label } => { |
150 | let scope = scopes.new_block_scope(scope, *id); | 178 | let scope = scopes.new_block_scope(scope, *id, make_label(label)); |
151 | // Overwrite the old scope for the block expr, so that every block scope can be found | 179 | // Overwrite the old scope for the block expr, so that every block scope can be found |
152 | // via the block itself (important for blocks that only contain items, no expressions). | 180 | // via the block itself (important for blocks that only contain items, no expressions). |
153 | scopes.set_scope(expr, scope); | 181 | scopes.set_scope(expr, scope); |
154 | compute_block_scopes(&statements, *tail, body, scopes, scope); | 182 | compute_block_scopes(statements, *tail, body, scopes, scope); |
155 | } | 183 | } |
156 | Expr::For { iterable, pat, body: body_expr, .. } => { | 184 | Expr::For { iterable, pat, body: body_expr, label } => { |
157 | compute_expr_scopes(*iterable, body, scopes, scope); | 185 | compute_expr_scopes(*iterable, body, scopes, scope); |
158 | let scope = scopes.new_scope(scope); | 186 | let scope = scopes.new_labeled_scope(scope, make_label(label)); |
159 | scopes.add_bindings(body, scope, *pat); | 187 | scopes.add_bindings(body, scope, *pat); |
160 | compute_expr_scopes(*body_expr, body, scopes, scope); | 188 | compute_expr_scopes(*body_expr, body, scopes, scope); |
161 | } | 189 | } |
190 | Expr::While { condition, body: body_expr, label } => { | ||
191 | let scope = scopes.new_labeled_scope(scope, make_label(label)); | ||
192 | compute_expr_scopes(*condition, body, scopes, scope); | ||
193 | compute_expr_scopes(*body_expr, body, scopes, scope); | ||
194 | } | ||
195 | Expr::Loop { body: body_expr, label } => { | ||
196 | let scope = scopes.new_labeled_scope(scope, make_label(label)); | ||
197 | compute_expr_scopes(*body_expr, body, scopes, scope); | ||
198 | } | ||
162 | Expr::Lambda { args, body: body_expr, .. } => { | 199 | Expr::Lambda { args, body: body_expr, .. } => { |
163 | let scope = scopes.new_scope(scope); | 200 | let scope = scopes.new_scope(scope); |
164 | scopes.add_params_bindings(body, scope, &args); | 201 | scopes.add_params_bindings(body, scope, &args); |
diff --git a/crates/hir_def/src/find_path.rs b/crates/hir_def/src/find_path.rs index de08e2737..109d3552f 100644 --- a/crates/hir_def/src/find_path.rs +++ b/crates/hir_def/src/find_path.rs | |||
@@ -18,7 +18,8 @@ use crate::{ | |||
18 | /// *from where* you're referring to the item, hence the `from` parameter. | 18 | /// *from where* you're referring to the item, hence the `from` parameter. |
19 | pub fn find_path(db: &dyn DefDatabase, item: ItemInNs, from: ModuleId) -> Option<ModPath> { | 19 | pub fn find_path(db: &dyn DefDatabase, item: ItemInNs, from: ModuleId) -> Option<ModPath> { |
20 | let _p = profile::span("find_path"); | 20 | let _p = profile::span("find_path"); |
21 | find_path_inner(db, item, from, MAX_PATH_LEN, None) | 21 | let mut visited_modules = FxHashSet::default(); |
22 | find_path_inner(db, item, from, MAX_PATH_LEN, None, &mut visited_modules) | ||
22 | } | 23 | } |
23 | 24 | ||
24 | pub fn find_path_prefixed( | 25 | pub fn find_path_prefixed( |
@@ -28,7 +29,8 @@ pub fn find_path_prefixed( | |||
28 | prefix_kind: PrefixKind, | 29 | prefix_kind: PrefixKind, |
29 | ) -> Option<ModPath> { | 30 | ) -> Option<ModPath> { |
30 | let _p = profile::span("find_path_prefixed"); | 31 | let _p = profile::span("find_path_prefixed"); |
31 | find_path_inner(db, item, from, MAX_PATH_LEN, Some(prefix_kind)) | 32 | let mut visited_modules = FxHashSet::default(); |
33 | find_path_inner(db, item, from, MAX_PATH_LEN, Some(prefix_kind), &mut visited_modules) | ||
32 | } | 34 | } |
33 | 35 | ||
34 | const MAX_PATH_LEN: usize = 15; | 36 | const MAX_PATH_LEN: usize = 15; |
@@ -97,6 +99,7 @@ fn find_path_inner( | |||
97 | from: ModuleId, | 99 | from: ModuleId, |
98 | max_len: usize, | 100 | max_len: usize, |
99 | mut prefixed: Option<PrefixKind>, | 101 | mut prefixed: Option<PrefixKind>, |
102 | visited_modules: &mut FxHashSet<ModuleId>, | ||
100 | ) -> Option<ModPath> { | 103 | ) -> Option<ModPath> { |
101 | if max_len == 0 { | 104 | if max_len == 0 { |
102 | return None; | 105 | return None; |
@@ -176,15 +179,18 @@ fn find_path_inner( | |||
176 | if item.krate(db) == Some(from.krate) { | 179 | if item.krate(db) == Some(from.krate) { |
177 | // Item was defined in the same crate that wants to import it. It cannot be found in any | 180 | // Item was defined in the same crate that wants to import it. It cannot be found in any |
178 | // dependency in this case. | 181 | // dependency in this case. |
179 | 182 | for (module_id, name) in find_local_import_locations(db, item, from) { | |
180 | let local_imports = find_local_import_locations(db, item, from); | 183 | if !visited_modules.insert(module_id) { |
181 | for (module_id, name) in local_imports { | 184 | cov_mark::hit!(recursive_imports); |
185 | continue; | ||
186 | } | ||
182 | if let Some(mut path) = find_path_inner( | 187 | if let Some(mut path) = find_path_inner( |
183 | db, | 188 | db, |
184 | ItemInNs::Types(ModuleDefId::ModuleId(module_id)), | 189 | ItemInNs::Types(ModuleDefId::ModuleId(module_id)), |
185 | from, | 190 | from, |
186 | best_path_len - 1, | 191 | best_path_len - 1, |
187 | prefixed, | 192 | prefixed, |
193 | visited_modules, | ||
188 | ) { | 194 | ) { |
189 | path.push_segment(name); | 195 | path.push_segment(name); |
190 | 196 | ||
@@ -213,6 +219,7 @@ fn find_path_inner( | |||
213 | from, | 219 | from, |
214 | best_path_len - 1, | 220 | best_path_len - 1, |
215 | prefixed, | 221 | prefixed, |
222 | visited_modules, | ||
216 | )?; | 223 | )?; |
217 | cov_mark::hit!(partially_imported); | 224 | cov_mark::hit!(partially_imported); |
218 | path.push_segment(info.path.segments.last().unwrap().clone()); | 225 | path.push_segment(info.path.segments.last().unwrap().clone()); |
@@ -391,8 +398,15 @@ mod tests { | |||
391 | .take_types() | 398 | .take_types() |
392 | .unwrap(); | 399 | .unwrap(); |
393 | 400 | ||
394 | let found_path = | 401 | let mut visited_modules = FxHashSet::default(); |
395 | find_path_inner(&db, ItemInNs::Types(resolved), module, MAX_PATH_LEN, prefix_kind); | 402 | let found_path = find_path_inner( |
403 | &db, | ||
404 | ItemInNs::Types(resolved), | ||
405 | module, | ||
406 | MAX_PATH_LEN, | ||
407 | prefix_kind, | ||
408 | &mut visited_modules, | ||
409 | ); | ||
396 | assert_eq!(found_path, Some(mod_path), "{:?}", prefix_kind); | 410 | assert_eq!(found_path, Some(mod_path), "{:?}", prefix_kind); |
397 | } | 411 | } |
398 | 412 | ||
@@ -878,4 +892,32 @@ mod tests { | |||
878 | "self::module::CompleteMe", | 892 | "self::module::CompleteMe", |
879 | ) | 893 | ) |
880 | } | 894 | } |
895 | |||
896 | #[test] | ||
897 | fn recursive_pub_mod_reexport() { | ||
898 | cov_mark::check!(recursive_imports); | ||
899 | check_found_path( | ||
900 | r#" | ||
901 | fn main() { | ||
902 | let _ = 22_i32.as_name$0(); | ||
903 | } | ||
904 | |||
905 | pub mod name { | ||
906 | pub trait AsName { | ||
907 | fn as_name(&self) -> String; | ||
908 | } | ||
909 | impl AsName for i32 { | ||
910 | fn as_name(&self) -> String { | ||
911 | format!("Name: {}", self) | ||
912 | } | ||
913 | } | ||
914 | pub use crate::name; | ||
915 | } | ||
916 | "#, | ||
917 | "name::AsName", | ||
918 | "name::AsName", | ||
919 | "crate::name::AsName", | ||
920 | "self::name::AsName", | ||
921 | ); | ||
922 | } | ||
881 | } | 923 | } |
diff --git a/crates/hir_def/src/nameres.rs b/crates/hir_def/src/nameres.rs index 0d3a0b54f..9e8e4e9ec 100644 --- a/crates/hir_def/src/nameres.rs +++ b/crates/hir_def/src/nameres.rs | |||
@@ -322,6 +322,23 @@ impl DefMap { | |||
322 | (res.resolved_def, res.segment_index) | 322 | (res.resolved_def, res.segment_index) |
323 | } | 323 | } |
324 | 324 | ||
325 | pub(crate) fn resolve_path_locally( | ||
326 | &self, | ||
327 | db: &dyn DefDatabase, | ||
328 | original_module: LocalModuleId, | ||
329 | path: &ModPath, | ||
330 | shadow: BuiltinShadowMode, | ||
331 | ) -> (PerNs, Option<usize>) { | ||
332 | let res = self.resolve_path_fp_with_macro_single( | ||
333 | db, | ||
334 | ResolveMode::Other, | ||
335 | original_module, | ||
336 | path, | ||
337 | shadow, | ||
338 | ); | ||
339 | (res.resolved_def, res.segment_index) | ||
340 | } | ||
341 | |||
325 | /// Ascends the `DefMap` hierarchy and calls `f` with every `DefMap` and containing module. | 342 | /// Ascends the `DefMap` hierarchy and calls `f` with every `DefMap` and containing module. |
326 | /// | 343 | /// |
327 | /// If `f` returns `Some(val)`, iteration is stopped and `Some(val)` is returned. If `f` returns | 344 | /// If `f` returns `Some(val)`, iteration is stopped and `Some(val)` is returned. If `f` returns |
diff --git a/crates/hir_def/src/nameres/collector.rs b/crates/hir_def/src/nameres/collector.rs index 46a3c60cd..d8fabe49b 100644 --- a/crates/hir_def/src/nameres/collector.rs +++ b/crates/hir_def/src/nameres/collector.rs | |||
@@ -91,7 +91,6 @@ pub(super) fn collect_defs( | |||
91 | resolved_imports: Vec::new(), | 91 | resolved_imports: Vec::new(), |
92 | 92 | ||
93 | unexpanded_macros: Vec::new(), | 93 | unexpanded_macros: Vec::new(), |
94 | unexpanded_attribute_macros: Vec::new(), | ||
95 | mod_dirs: FxHashMap::default(), | 94 | mod_dirs: FxHashMap::default(), |
96 | cfg_options, | 95 | cfg_options, |
97 | proc_macros, | 96 | proc_macros, |
@@ -202,15 +201,14 @@ struct ImportDirective { | |||
202 | #[derive(Clone, Debug, Eq, PartialEq)] | 201 | #[derive(Clone, Debug, Eq, PartialEq)] |
203 | struct MacroDirective { | 202 | struct MacroDirective { |
204 | module_id: LocalModuleId, | 203 | module_id: LocalModuleId, |
205 | ast_id: AstIdWithPath<ast::MacroCall>, | ||
206 | legacy: Option<MacroCallId>, | ||
207 | depth: usize, | 204 | depth: usize, |
205 | kind: MacroDirectiveKind, | ||
208 | } | 206 | } |
209 | 207 | ||
210 | #[derive(Clone, Debug, Eq, PartialEq)] | 208 | #[derive(Clone, Debug, Eq, PartialEq)] |
211 | struct DeriveDirective { | 209 | enum MacroDirectiveKind { |
212 | module_id: LocalModuleId, | 210 | FnLike { ast_id: AstIdWithPath<ast::MacroCall>, legacy: Option<MacroCallId> }, |
213 | ast_id: AstIdWithPath<ast::Item>, | 211 | Derive { ast_id: AstIdWithPath<ast::Item> }, |
214 | } | 212 | } |
215 | 213 | ||
216 | struct DefData<'a> { | 214 | struct DefData<'a> { |
@@ -228,7 +226,6 @@ struct DefCollector<'a> { | |||
228 | unresolved_imports: Vec<ImportDirective>, | 226 | unresolved_imports: Vec<ImportDirective>, |
229 | resolved_imports: Vec<ImportDirective>, | 227 | resolved_imports: Vec<ImportDirective>, |
230 | unexpanded_macros: Vec<MacroDirective>, | 228 | unexpanded_macros: Vec<MacroDirective>, |
231 | unexpanded_attribute_macros: Vec<DeriveDirective>, | ||
232 | mod_dirs: FxHashMap<LocalModuleId, ModDir>, | 229 | mod_dirs: FxHashMap<LocalModuleId, ModDir>, |
233 | cfg_options: &'a CfgOptions, | 230 | cfg_options: &'a CfgOptions, |
234 | /// List of procedural macros defined by this crate. This is read from the dynamic library | 231 | /// List of procedural macros defined by this crate. This is read from the dynamic library |
@@ -782,60 +779,58 @@ impl DefCollector<'_> { | |||
782 | 779 | ||
783 | fn resolve_macros(&mut self) -> ReachedFixedPoint { | 780 | fn resolve_macros(&mut self) -> ReachedFixedPoint { |
784 | let mut macros = std::mem::replace(&mut self.unexpanded_macros, Vec::new()); | 781 | let mut macros = std::mem::replace(&mut self.unexpanded_macros, Vec::new()); |
785 | let mut attribute_macros = | ||
786 | std::mem::replace(&mut self.unexpanded_attribute_macros, Vec::new()); | ||
787 | let mut resolved = Vec::new(); | 782 | let mut resolved = Vec::new(); |
788 | let mut res = ReachedFixedPoint::Yes; | 783 | let mut res = ReachedFixedPoint::Yes; |
789 | macros.retain(|directive| { | 784 | macros.retain(|directive| { |
790 | if let Some(call_id) = directive.legacy { | 785 | match &directive.kind { |
791 | res = ReachedFixedPoint::No; | 786 | MacroDirectiveKind::FnLike { ast_id, legacy } => { |
792 | resolved.push((directive.module_id, call_id, directive.depth)); | 787 | if let Some(call_id) = legacy { |
793 | return false; | 788 | res = ReachedFixedPoint::No; |
794 | } | 789 | resolved.push((directive.module_id, *call_id, directive.depth)); |
790 | return false; | ||
791 | } | ||
795 | 792 | ||
796 | match macro_call_as_call_id( | 793 | match macro_call_as_call_id( |
797 | &directive.ast_id, | 794 | ast_id, |
798 | self.db, | ||
799 | self.def_map.krate, | ||
800 | |path| { | ||
801 | let resolved_res = self.def_map.resolve_path_fp_with_macro( | ||
802 | self.db, | 795 | self.db, |
803 | ResolveMode::Other, | 796 | self.def_map.krate, |
804 | directive.module_id, | 797 | |path| { |
805 | &path, | 798 | let resolved_res = self.def_map.resolve_path_fp_with_macro( |
806 | BuiltinShadowMode::Module, | 799 | self.db, |
807 | ); | 800 | ResolveMode::Other, |
808 | resolved_res.resolved_def.take_macros() | 801 | directive.module_id, |
809 | }, | 802 | &path, |
810 | &mut |_err| (), | 803 | BuiltinShadowMode::Module, |
811 | ) { | 804 | ); |
812 | Ok(Ok(call_id)) => { | 805 | resolved_res.resolved_def.take_macros() |
813 | resolved.push((directive.module_id, call_id, directive.depth)); | 806 | }, |
814 | res = ReachedFixedPoint::No; | 807 | &mut |_err| (), |
815 | return false; | 808 | ) { |
809 | Ok(Ok(call_id)) => { | ||
810 | resolved.push((directive.module_id, call_id, directive.depth)); | ||
811 | res = ReachedFixedPoint::No; | ||
812 | return false; | ||
813 | } | ||
814 | Err(UnresolvedMacro) | Ok(Err(_)) => {} | ||
815 | } | ||
816 | } | 816 | } |
817 | Err(UnresolvedMacro) | Ok(Err(_)) => {} | 817 | MacroDirectiveKind::Derive { ast_id } => { |
818 | } | 818 | match derive_macro_as_call_id(ast_id, self.db, self.def_map.krate, |path| { |
819 | 819 | self.resolve_derive_macro(directive.module_id, &path) | |
820 | true | 820 | }) { |
821 | }); | 821 | Ok(call_id) => { |
822 | attribute_macros.retain(|directive| { | 822 | resolved.push((directive.module_id, call_id, 0)); |
823 | match derive_macro_as_call_id(&directive.ast_id, self.db, self.def_map.krate, |path| { | 823 | res = ReachedFixedPoint::No; |
824 | self.resolve_derive_macro(&directive, &path) | 824 | return false; |
825 | }) { | 825 | } |
826 | Ok(call_id) => { | 826 | Err(UnresolvedMacro) => (), |
827 | resolved.push((directive.module_id, call_id, 0)); | 827 | } |
828 | res = ReachedFixedPoint::No; | ||
829 | return false; | ||
830 | } | 828 | } |
831 | Err(UnresolvedMacro) => (), | ||
832 | } | 829 | } |
833 | 830 | ||
834 | true | 831 | true |
835 | }); | 832 | }); |
836 | |||
837 | self.unexpanded_macros = macros; | 833 | self.unexpanded_macros = macros; |
838 | self.unexpanded_attribute_macros = attribute_macros; | ||
839 | 834 | ||
840 | for (module_id, macro_call_id, depth) in resolved { | 835 | for (module_id, macro_call_id, depth) in resolved { |
841 | self.collect_macro_expansion(module_id, macro_call_id, depth); | 836 | self.collect_macro_expansion(module_id, macro_call_id, depth); |
@@ -844,15 +839,11 @@ impl DefCollector<'_> { | |||
844 | res | 839 | res |
845 | } | 840 | } |
846 | 841 | ||
847 | fn resolve_derive_macro( | 842 | fn resolve_derive_macro(&self, module: LocalModuleId, path: &ModPath) -> Option<MacroDefId> { |
848 | &self, | ||
849 | directive: &DeriveDirective, | ||
850 | path: &ModPath, | ||
851 | ) -> Option<MacroDefId> { | ||
852 | let resolved_res = self.def_map.resolve_path_fp_with_macro( | 843 | let resolved_res = self.def_map.resolve_path_fp_with_macro( |
853 | self.db, | 844 | self.db, |
854 | ResolveMode::Other, | 845 | ResolveMode::Other, |
855 | directive.module_id, | 846 | module, |
856 | &path, | 847 | &path, |
857 | BuiltinShadowMode::Module, | 848 | BuiltinShadowMode::Module, |
858 | ); | 849 | ); |
@@ -912,33 +903,35 @@ impl DefCollector<'_> { | |||
912 | // Emit diagnostics for all remaining unexpanded macros. | 903 | // Emit diagnostics for all remaining unexpanded macros. |
913 | 904 | ||
914 | for directive in &self.unexpanded_macros { | 905 | for directive in &self.unexpanded_macros { |
915 | let mut error = None; | 906 | match &directive.kind { |
916 | match macro_call_as_call_id( | 907 | MacroDirectiveKind::FnLike { ast_id, .. } => match macro_call_as_call_id( |
917 | &directive.ast_id, | 908 | ast_id, |
918 | self.db, | 909 | self.db, |
919 | self.def_map.krate, | 910 | self.def_map.krate, |
920 | |path| { | 911 | |path| { |
921 | let resolved_res = self.def_map.resolve_path_fp_with_macro( | 912 | let resolved_res = self.def_map.resolve_path_fp_with_macro( |
922 | self.db, | 913 | self.db, |
923 | ResolveMode::Other, | 914 | ResolveMode::Other, |
924 | directive.module_id, | 915 | directive.module_id, |
925 | &path, | 916 | &path, |
926 | BuiltinShadowMode::Module, | 917 | BuiltinShadowMode::Module, |
927 | ); | 918 | ); |
928 | resolved_res.resolved_def.take_macros() | 919 | resolved_res.resolved_def.take_macros() |
929 | }, | 920 | }, |
930 | &mut |e| { | 921 | &mut |_| (), |
931 | error.get_or_insert(e); | 922 | ) { |
923 | Ok(_) => (), | ||
924 | Err(UnresolvedMacro) => { | ||
925 | self.def_map.diagnostics.push(DefDiagnostic::unresolved_macro_call( | ||
926 | directive.module_id, | ||
927 | ast_id.ast_id, | ||
928 | )); | ||
929 | } | ||
932 | }, | 930 | }, |
933 | ) { | 931 | MacroDirectiveKind::Derive { .. } => { |
934 | Ok(_) => (), | 932 | // FIXME: we might want to diagnose this too |
935 | Err(UnresolvedMacro) => { | ||
936 | self.def_map.diagnostics.push(DefDiagnostic::unresolved_macro_call( | ||
937 | directive.module_id, | ||
938 | directive.ast_id.ast_id, | ||
939 | )); | ||
940 | } | 933 | } |
941 | }; | 934 | } |
942 | } | 935 | } |
943 | 936 | ||
944 | // Emit diagnostics for all remaining unresolved imports. | 937 | // Emit diagnostics for all remaining unresolved imports. |
@@ -1380,9 +1373,11 @@ impl ModCollector<'_, '_> { | |||
1380 | Some(derive_macros) => { | 1373 | Some(derive_macros) => { |
1381 | for path in derive_macros { | 1374 | for path in derive_macros { |
1382 | let ast_id = AstIdWithPath::new(self.file_id, ast_id, path); | 1375 | let ast_id = AstIdWithPath::new(self.file_id, ast_id, path); |
1383 | self.def_collector | 1376 | self.def_collector.unexpanded_macros.push(MacroDirective { |
1384 | .unexpanded_attribute_macros | 1377 | module_id: self.module_id, |
1385 | .push(DeriveDirective { module_id: self.module_id, ast_id }); | 1378 | depth: self.macro_depth + 1, |
1379 | kind: MacroDirectiveKind::Derive { ast_id }, | ||
1380 | }); | ||
1386 | } | 1381 | } |
1387 | } | 1382 | } |
1388 | None => { | 1383 | None => { |
@@ -1467,12 +1462,13 @@ impl ModCollector<'_, '_> { | |||
1467 | }, | 1462 | }, |
1468 | ) { | 1463 | ) { |
1469 | Ok(Ok(macro_call_id)) => { | 1464 | Ok(Ok(macro_call_id)) => { |
1470 | self.def_collector.unexpanded_macros.push(MacroDirective { | 1465 | // Legacy macros need to be expanded immediately, so that any macros they produce |
1471 | module_id: self.module_id, | 1466 | // are in scope. |
1472 | ast_id, | 1467 | self.def_collector.collect_macro_expansion( |
1473 | legacy: Some(macro_call_id), | 1468 | self.module_id, |
1474 | depth: self.macro_depth + 1, | 1469 | macro_call_id, |
1475 | }); | 1470 | self.macro_depth + 1, |
1471 | ); | ||
1476 | 1472 | ||
1477 | return; | 1473 | return; |
1478 | } | 1474 | } |
@@ -1496,9 +1492,8 @@ impl ModCollector<'_, '_> { | |||
1496 | 1492 | ||
1497 | self.def_collector.unexpanded_macros.push(MacroDirective { | 1493 | self.def_collector.unexpanded_macros.push(MacroDirective { |
1498 | module_id: self.module_id, | 1494 | module_id: self.module_id, |
1499 | ast_id, | ||
1500 | legacy: None, | ||
1501 | depth: self.macro_depth + 1, | 1495 | depth: self.macro_depth + 1, |
1496 | kind: MacroDirectiveKind::FnLike { ast_id, legacy: None }, | ||
1502 | }); | 1497 | }); |
1503 | } | 1498 | } |
1504 | 1499 | ||
@@ -1541,7 +1536,6 @@ mod tests { | |||
1541 | unresolved_imports: Vec::new(), | 1536 | unresolved_imports: Vec::new(), |
1542 | resolved_imports: Vec::new(), | 1537 | resolved_imports: Vec::new(), |
1543 | unexpanded_macros: Vec::new(), | 1538 | unexpanded_macros: Vec::new(), |
1544 | unexpanded_attribute_macros: Vec::new(), | ||
1545 | mod_dirs: FxHashMap::default(), | 1539 | mod_dirs: FxHashMap::default(), |
1546 | cfg_options: &CfgOptions::default(), | 1540 | cfg_options: &CfgOptions::default(), |
1547 | proc_macros: Default::default(), | 1541 | proc_macros: Default::default(), |
diff --git a/crates/hir_def/src/nameres/mod_resolution.rs b/crates/hir_def/src/nameres/mod_resolution.rs index d5de9899c..d9cec0e27 100644 --- a/crates/hir_def/src/nameres/mod_resolution.rs +++ b/crates/hir_def/src/nameres/mod_resolution.rs | |||
@@ -62,7 +62,7 @@ impl ModDir { | |||
62 | name: &Name, | 62 | name: &Name, |
63 | attr_path: Option<&SmolStr>, | 63 | attr_path: Option<&SmolStr>, |
64 | ) -> Result<(FileId, bool, ModDir), String> { | 64 | ) -> Result<(FileId, bool, ModDir), String> { |
65 | let file_id = file_id.original_file(db.upcast()); | 65 | let orig_file_id = file_id.original_file(db.upcast()); |
66 | 66 | ||
67 | let mut candidate_files = Vec::new(); | 67 | let mut candidate_files = Vec::new(); |
68 | match attr_path { | 68 | match attr_path { |
@@ -70,13 +70,18 @@ impl ModDir { | |||
70 | candidate_files.push(self.dir_path.join_attr(attr_path, self.root_non_dir_owner)) | 70 | candidate_files.push(self.dir_path.join_attr(attr_path, self.root_non_dir_owner)) |
71 | } | 71 | } |
72 | None => { | 72 | None => { |
73 | candidate_files.push(format!("{}{}.rs", self.dir_path.0, name)); | 73 | if file_id.is_include_macro(db.upcast()) { |
74 | candidate_files.push(format!("{}{}/mod.rs", self.dir_path.0, name)); | 74 | candidate_files.push(format!("{}.rs", name)); |
75 | candidate_files.push(format!("{}/mod.rs", name)); | ||
76 | } else { | ||
77 | candidate_files.push(format!("{}{}.rs", self.dir_path.0, name)); | ||
78 | candidate_files.push(format!("{}{}/mod.rs", self.dir_path.0, name)); | ||
79 | } | ||
75 | } | 80 | } |
76 | }; | 81 | }; |
77 | 82 | ||
78 | for candidate in candidate_files.iter() { | 83 | for candidate in candidate_files.iter() { |
79 | let path = AnchoredPath { anchor: file_id, path: candidate.as_str() }; | 84 | let path = AnchoredPath { anchor: orig_file_id, path: candidate.as_str() }; |
80 | if let Some(file_id) = db.resolve_path(path) { | 85 | if let Some(file_id) = db.resolve_path(path) { |
81 | let is_mod_rs = candidate.ends_with("/mod.rs"); | 86 | let is_mod_rs = candidate.ends_with("/mod.rs"); |
82 | 87 | ||
diff --git a/crates/hir_def/src/nameres/path_resolution.rs b/crates/hir_def/src/nameres/path_resolution.rs index db459b1ed..60471937c 100644 --- a/crates/hir_def/src/nameres/path_resolution.rs +++ b/crates/hir_def/src/nameres/path_resolution.rs | |||
@@ -156,7 +156,7 @@ impl DefMap { | |||
156 | } | 156 | } |
157 | } | 157 | } |
158 | 158 | ||
159 | fn resolve_path_fp_with_macro_single( | 159 | pub(super) fn resolve_path_fp_with_macro_single( |
160 | &self, | 160 | &self, |
161 | db: &dyn DefDatabase, | 161 | db: &dyn DefDatabase, |
162 | mode: ResolveMode, | 162 | mode: ResolveMode, |
diff --git a/crates/hir_def/src/nameres/tests/macros.rs b/crates/hir_def/src/nameres/tests/macros.rs index d59d3c0db..6d3cb8d7a 100644 --- a/crates/hir_def/src/nameres/tests/macros.rs +++ b/crates/hir_def/src/nameres/tests/macros.rs | |||
@@ -713,6 +713,27 @@ b! { static = #[] ();} | |||
713 | } | 713 | } |
714 | 714 | ||
715 | #[test] | 715 | #[test] |
716 | fn macros_defining_macros() { | ||
717 | check( | ||
718 | r#" | ||
719 | macro_rules! item { | ||
720 | ($item:item) => { $item } | ||
721 | } | ||
722 | |||
723 | item! { | ||
724 | macro_rules! indirect_macro { () => { struct S {} } } | ||
725 | } | ||
726 | |||
727 | indirect_macro!(); | ||
728 | "#, | ||
729 | expect![[r#" | ||
730 | crate | ||
731 | S: t | ||
732 | "#]], | ||
733 | ); | ||
734 | } | ||
735 | |||
736 | #[test] | ||
716 | fn resolves_proc_macros() { | 737 | fn resolves_proc_macros() { |
717 | check( | 738 | check( |
718 | r" | 739 | r" |
diff --git a/crates/hir_def/src/resolver.rs b/crates/hir_def/src/resolver.rs index 42736171e..a73585ee7 100644 --- a/crates/hir_def/src/resolver.rs +++ b/crates/hir_def/src/resolver.rs | |||
@@ -12,7 +12,7 @@ use crate::{ | |||
12 | body::scope::{ExprScopes, ScopeId}, | 12 | body::scope::{ExprScopes, ScopeId}, |
13 | builtin_type::BuiltinType, | 13 | builtin_type::BuiltinType, |
14 | db::DefDatabase, | 14 | db::DefDatabase, |
15 | expr::{ExprId, PatId}, | 15 | expr::{ExprId, LabelId, PatId}, |
16 | generics::GenericParams, | 16 | generics::GenericParams, |
17 | item_scope::{BuiltinShadowMode, BUILTIN_SCOPE}, | 17 | item_scope::{BuiltinShadowMode, BUILTIN_SCOPE}, |
18 | nameres::DefMap, | 18 | nameres::DefMap, |
@@ -409,6 +409,7 @@ pub enum ScopeDef { | |||
409 | AdtSelfType(AdtId), | 409 | AdtSelfType(AdtId), |
410 | GenericParam(GenericParamId), | 410 | GenericParam(GenericParamId), |
411 | Local(PatId), | 411 | Local(PatId), |
412 | Label(LabelId), | ||
412 | } | 413 | } |
413 | 414 | ||
414 | impl Scope { | 415 | impl Scope { |
@@ -470,6 +471,9 @@ impl Scope { | |||
470 | f(name![Self], ScopeDef::AdtSelfType(*i)); | 471 | f(name![Self], ScopeDef::AdtSelfType(*i)); |
471 | } | 472 | } |
472 | Scope::ExprScope(scope) => { | 473 | Scope::ExprScope(scope) => { |
474 | if let Some((label, name)) = scope.expr_scopes.label(scope.scope_id) { | ||
475 | f(name, ScopeDef::Label(label)) | ||
476 | } | ||
473 | scope.expr_scopes.entries(scope.scope_id).iter().for_each(|e| { | 477 | scope.expr_scopes.entries(scope.scope_id).iter().for_each(|e| { |
474 | f(e.name().clone(), ScopeDef::Local(e.pat())); | 478 | f(e.name().clone(), ScopeDef::Local(e.pat())); |
475 | }); | 479 | }); |
@@ -544,7 +548,7 @@ impl ModuleItemMap { | |||
544 | path: &ModPath, | 548 | path: &ModPath, |
545 | ) -> Option<ResolveValueResult> { | 549 | ) -> Option<ResolveValueResult> { |
546 | let (module_def, idx) = | 550 | let (module_def, idx) = |
547 | self.def_map.resolve_path(db, self.module_id, &path, BuiltinShadowMode::Other); | 551 | self.def_map.resolve_path_locally(db, self.module_id, &path, BuiltinShadowMode::Other); |
548 | match idx { | 552 | match idx { |
549 | None => { | 553 | None => { |
550 | let value = to_value_ns(module_def)?; | 554 | let value = to_value_ns(module_def)?; |
@@ -574,7 +578,7 @@ impl ModuleItemMap { | |||
574 | path: &ModPath, | 578 | path: &ModPath, |
575 | ) -> Option<(TypeNs, Option<usize>)> { | 579 | ) -> Option<(TypeNs, Option<usize>)> { |
576 | let (module_def, idx) = | 580 | let (module_def, idx) = |
577 | self.def_map.resolve_path(db, self.module_id, &path, BuiltinShadowMode::Other); | 581 | self.def_map.resolve_path_locally(db, self.module_id, &path, BuiltinShadowMode::Other); |
578 | let res = to_type_ns(module_def)?; | 582 | let res = to_type_ns(module_def)?; |
579 | Some((res, idx)) | 583 | Some((res, idx)) |
580 | } | 584 | } |
@@ -623,8 +627,18 @@ pub trait HasResolver: Copy { | |||
623 | 627 | ||
624 | impl HasResolver for ModuleId { | 628 | impl HasResolver for ModuleId { |
625 | fn resolver(self, db: &dyn DefDatabase) -> Resolver { | 629 | fn resolver(self, db: &dyn DefDatabase) -> Resolver { |
626 | let def_map = self.def_map(db); | 630 | let mut def_map = self.def_map(db); |
627 | Resolver::default().push_module_scope(def_map, self.local_id) | 631 | let mut modules = Vec::new(); |
632 | modules.push((def_map.clone(), self.local_id)); | ||
633 | while let Some(parent) = def_map.parent() { | ||
634 | def_map = parent.def_map(db); | ||
635 | modules.push((def_map.clone(), parent.local_id)); | ||
636 | } | ||
637 | let mut resolver = Resolver::default(); | ||
638 | for (def_map, module) in modules.into_iter().rev() { | ||
639 | resolver = resolver.push_module_scope(def_map, module); | ||
640 | } | ||
641 | resolver | ||
628 | } | 642 | } |
629 | } | 643 | } |
630 | 644 | ||