aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_hir/src
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_hir/src')
-rw-r--r--crates/ra_hir/src/expr.rs26
-rw-r--r--crates/ra_hir/src/nameres.rs29
-rw-r--r--crates/ra_hir/src/nameres/collector.rs38
-rw-r--r--crates/ra_hir/src/nameres/tests/macros.rs13
-rw-r--r--crates/ra_hir/src/resolve.rs23
-rw-r--r--crates/ra_hir/src/source_binder.rs9
-rw-r--r--crates/ra_hir/src/ty/infer.rs37
-rw-r--r--crates/ra_hir/src/ty/lower.rs4
-rw-r--r--crates/ra_hir/src/ty/tests.rs6
9 files changed, 97 insertions, 88 deletions
diff --git a/crates/ra_hir/src/expr.rs b/crates/ra_hir/src/expr.rs
index 9d9769859..012f374ec 100644
--- a/crates/ra_hir/src/expr.rs
+++ b/crates/ra_hir/src/expr.rs
@@ -827,25 +827,25 @@ where
827 ast::ExprKind::IndexExpr(_e) => self.alloc_expr(Expr::Missing, syntax_ptr), 827 ast::ExprKind::IndexExpr(_e) => self.alloc_expr(Expr::Missing, syntax_ptr),
828 ast::ExprKind::RangeExpr(_e) => self.alloc_expr(Expr::Missing, syntax_ptr), 828 ast::ExprKind::RangeExpr(_e) => self.alloc_expr(Expr::Missing, syntax_ptr),
829 ast::ExprKind::MacroCall(e) => { 829 ast::ExprKind::MacroCall(e) => {
830 // very hacky.FIXME change to use the macro resolution
831 let path = e.path().and_then(Path::from_ast);
832
833 let ast_id = self 830 let ast_id = self
834 .db 831 .db
835 .ast_id_map(self.current_file_id) 832 .ast_id_map(self.current_file_id)
836 .ast_id(e) 833 .ast_id(e)
837 .with_file_id(self.current_file_id); 834 .with_file_id(self.current_file_id);
838 835
839 if let Some(def) = self.resolver.resolve_macro_call(self.db, path) { 836 if let Some(path) = e.path().and_then(Path::from_ast) {
840 let call_id = MacroCallLoc { def, ast_id }.id(self.db); 837 if let Some(def) = self.resolver.resolve_path_as_macro(self.db, &path) {
841 let file_id = call_id.as_file(MacroFileKind::Expr); 838 let call_id = MacroCallLoc { def: def.id, ast_id }.id(self.db);
842 if let Some(node) = self.db.parse_or_expand(file_id) { 839 let file_id = call_id.as_file(MacroFileKind::Expr);
843 if let Some(expr) = ast::Expr::cast(&*node) { 840 if let Some(node) = self.db.parse_or_expand(file_id) {
844 log::debug!("macro expansion {}", expr.syntax().debug_dump()); 841 if let Some(expr) = ast::Expr::cast(&*node) {
845 let old_file_id = std::mem::replace(&mut self.current_file_id, file_id); 842 log::debug!("macro expansion {}", expr.syntax().debug_dump());
846 let id = self.collect_expr(&expr); 843 let old_file_id =
847 self.current_file_id = old_file_id; 844 std::mem::replace(&mut self.current_file_id, file_id);
848 return id; 845 let id = self.collect_expr(&expr);
846 self.current_file_id = old_file_id;
847 return id;
848 }
849 } 849 }
850 } 850 }
851 } 851 }
diff --git a/crates/ra_hir/src/nameres.rs b/crates/ra_hir/src/nameres.rs
index dc0dd23c9..b5938fa03 100644
--- a/crates/ra_hir/src/nameres.rs
+++ b/crates/ra_hir/src/nameres.rs
@@ -92,7 +92,6 @@ pub struct CrateDefMap {
92 extern_prelude: FxHashMap<Name, ModuleDef>, 92 extern_prelude: FxHashMap<Name, ModuleDef>,
93 root: CrateModuleId, 93 root: CrateModuleId,
94 modules: Arena<CrateModuleId, ModuleData>, 94 modules: Arena<CrateModuleId, ModuleData>,
95 public_macros: FxHashMap<Name, MacroDefId>,
96 95
97 /// Some macros are not well-behavior, which leads to infinite loop 96 /// Some macros are not well-behavior, which leads to infinite loop
98 /// e.g. macro_rules! foo { ($ty:ty) => { foo!($ty); } } 97 /// e.g. macro_rules! foo { ($ty:ty) => { foo!($ty); } }
@@ -106,7 +105,6 @@ pub struct CrateDefMap {
106 /// However, do we want to put it as a global variable? 105 /// However, do we want to put it as a global variable?
107 poison_macros: FxHashSet<MacroDefId>, 106 poison_macros: FxHashSet<MacroDefId>,
108 107
109 local_macros: FxHashMap<Name, MacroDefId>,
110 diagnostics: Vec<DefDiagnostic>, 108 diagnostics: Vec<DefDiagnostic>,
111} 109}
112 110
@@ -249,9 +247,7 @@ impl CrateDefMap {
249 prelude: None, 247 prelude: None,
250 root, 248 root,
251 modules, 249 modules,
252 public_macros: FxHashMap::default(),
253 poison_macros: FxHashSet::default(), 250 poison_macros: FxHashSet::default(),
254 local_macros: FxHashMap::default(),
255 diagnostics: Vec::new(), 251 diagnostics: Vec::new(),
256 } 252 }
257 }; 253 };
@@ -313,7 +309,7 @@ impl CrateDefMap {
313 (res.resolved_def.left().unwrap_or_else(PerNs::none), res.segment_index) 309 (res.resolved_def.left().unwrap_or_else(PerNs::none), res.segment_index)
314 } 310 }
315 311
316 fn resolve_path_with_macro( 312 pub(crate) fn resolve_path_with_macro(
317 &self, 313 &self,
318 db: &impl DefDatabase, 314 db: &impl DefDatabase,
319 original_module: CrateModuleId, 315 original_module: CrateModuleId,
@@ -323,27 +319,6 @@ impl CrateDefMap {
323 (res.resolved_def, res.segment_index) 319 (res.resolved_def, res.segment_index)
324 } 320 }
325 321
326 // FIXME: This seems to do the same work as `resolve_path_with_macro`, but
327 // using a completely different code path. Seems bad, huh?
328 pub(crate) fn find_macro(
329 &self,
330 db: &impl DefDatabase,
331 original_module: CrateModuleId,
332 path: &Path,
333 ) -> Option<MacroDefId> {
334 let name = path.expand_macro_expr()?;
335 // search local first
336 // FIXME: Remove public_macros check when we have a correct local_macors implementation
337 let local =
338 self.public_macros.get(&name).or_else(|| self.local_macros.get(&name)).map(|it| *it);
339 if local.is_some() {
340 return local;
341 }
342
343 let res = self.resolve_path_fp_with_macro(db, ResolveMode::Other, original_module, path);
344 res.resolved_def.right().map(|m| m.id)
345 }
346
347 // Returns Yes if we are sure that additions to `ItemMap` wouldn't change 322 // Returns Yes if we are sure that additions to `ItemMap` wouldn't change
348 // the result. 323 // the result.
349 fn resolve_path_fp_with_macro( 324 fn resolve_path_fp_with_macro(
@@ -511,7 +486,7 @@ impl CrateDefMap {
511 let from_scope = self[module] 486 let from_scope = self[module]
512 .scope 487 .scope
513 .get_item_or_macro(name) 488 .get_item_or_macro(name)
514 .unwrap_or_else(|| Either::Left(PerNs::none()));; 489 .unwrap_or_else(|| Either::Left(PerNs::none()));
515 let from_extern_prelude = 490 let from_extern_prelude =
516 self.extern_prelude.get(name).map_or(PerNs::none(), |&it| PerNs::types(it)); 491 self.extern_prelude.get(name).map_or(PerNs::none(), |&it| PerNs::types(it));
517 let from_prelude = self.resolve_in_prelude(db, name); 492 let from_prelude = self.resolve_in_prelude(db, name);
diff --git a/crates/ra_hir/src/nameres/collector.rs b/crates/ra_hir/src/nameres/collector.rs
index 3bfef799d..99110d58d 100644
--- a/crates/ra_hir/src/nameres/collector.rs
+++ b/crates/ra_hir/src/nameres/collector.rs
@@ -138,15 +138,35 @@ where
138 } 138 }
139 } 139 }
140 140
141 fn define_macro(&mut self, name: Name, macro_id: MacroDefId, export: bool) { 141 fn define_macro(
142 &mut self,
143 module_id: CrateModuleId,
144 name: Name,
145 macro_id: MacroDefId,
146 export: bool,
147 ) {
148 // macro-by-example in Rust have completely weird name resolution logic,
149 // unlike anything else in the language. We'd don't fully implement yet,
150 // just give a somewhat precise approximation.
151 //
152 // Specifically, we store a set of visible macros in each module, just
153 // like how we do with usual items. This is wrong, however, because
154 // macros can be shadowed and their scopes are mostly unrelated to
155 // modules. To paper over the second problem, we also maintain
156 // `global_macro_scope` which works when we construct `CrateDefMap`, but
157 // is completely ignored in expressions.
158 //
159 // What we should do is that, in CrateDefMap, we should maintain a
160 // separate tower of macro scopes, with ids. Then, for each item in the
161 // module, we need to store it's macro scope.
162 let def = Either::Right(MacroDef { id: macro_id });
163
164 // In Rust, `#[macro_export]` macros are unconditionally visible at the
165 // crate root, even if the parent modules is **not** visible.
142 if export { 166 if export {
143 self.def_map.public_macros.insert(name.clone(), macro_id); 167 self.update(self.def_map.root, None, &[(name.clone(), def.clone())]);
144
145 let def = Either::Right(MacroDef { id: macro_id });
146 self.update(self.def_map.root, None, &[(name.clone(), def)]);
147 } else {
148 self.def_map.local_macros.insert(name.clone(), macro_id);
149 } 168 }
169 self.update(module_id, None, &[(name.clone(), def)]);
150 self.global_macro_scope.insert(name, macro_id); 170 self.global_macro_scope.insert(name, macro_id);
151 } 171 }
152 172
@@ -589,7 +609,7 @@ where
589 if is_macro_rules(&mac.path) { 609 if is_macro_rules(&mac.path) {
590 if let Some(name) = &mac.name { 610 if let Some(name) = &mac.name {
591 let macro_id = MacroDefId(mac.ast_id.with_file_id(self.file_id)); 611 let macro_id = MacroDefId(mac.ast_id.with_file_id(self.file_id));
592 self.def_collector.define_macro(name.clone(), macro_id, mac.export) 612 self.def_collector.define_macro(self.module_id, name.clone(), macro_id, mac.export)
593 } 613 }
594 return; 614 return;
595 } 615 }
@@ -694,9 +714,7 @@ mod tests {
694 prelude: None, 714 prelude: None,
695 root, 715 root,
696 modules, 716 modules,
697 public_macros: FxHashMap::default(),
698 poison_macros: FxHashSet::default(), 717 poison_macros: FxHashSet::default(),
699 local_macros: FxHashMap::default(),
700 diagnostics: Vec::new(), 718 diagnostics: Vec::new(),
701 } 719 }
702 }; 720 };
diff --git a/crates/ra_hir/src/nameres/tests/macros.rs b/crates/ra_hir/src/nameres/tests/macros.rs
index 42241aeff..4e04740eb 100644
--- a/crates/ra_hir/src/nameres/tests/macros.rs
+++ b/crates/ra_hir/src/nameres/tests/macros.rs
@@ -21,6 +21,7 @@ fn macro_rules_are_globally_visible() {
21 ⋮crate 21 ⋮crate
22 ⋮Foo: t v 22 ⋮Foo: t v
23 ⋮nested: t 23 ⋮nested: t
24 ⋮structs: m
24 25
25 ⋮crate::nested 26 ⋮crate::nested
26 ⋮Bar: t v 27 ⋮Bar: t v
@@ -46,6 +47,7 @@ fn macro_rules_can_define_modules() {
46 ); 47 );
47 assert_snapshot_matches!(map, @r###" 48 assert_snapshot_matches!(map, @r###"
48 ⋮crate 49 ⋮crate
50 ⋮m: m
49 ⋮n1: t 51 ⋮n1: t
50 52
51 ⋮crate::n1 53 ⋮crate::n1
@@ -127,8 +129,11 @@ fn unexpanded_macro_should_expand_by_fixedpoint_loop() {
127 "foo": ("/lib.rs", []), 129 "foo": ("/lib.rs", []),
128 }, 130 },
129 ); 131 );
130 assert_snapshot_matches!(map, @r###"crate 132 assert_snapshot_matches!(map, @r###"
131Foo: t v 133 ⋮crate
132bar: m 134 ⋮Foo: t v
133foo: m"###); 135 ⋮bar: m
136 ⋮baz: m
137 ⋮foo: m
138 "###);
134} 139}
diff --git a/crates/ra_hir/src/resolve.rs b/crates/ra_hir/src/resolve.rs
index d6956f45e..1b987c1b6 100644
--- a/crates/ra_hir/src/resolve.rs
+++ b/crates/ra_hir/src/resolve.rs
@@ -2,11 +2,11 @@
2use std::sync::Arc; 2use std::sync::Arc;
3 3
4use rustc_hash::{FxHashMap, FxHashSet}; 4use rustc_hash::{FxHashMap, FxHashSet};
5use either::Either;
5 6
6use crate::{ 7use crate::{
7 ModuleDef, Trait, 8 ModuleDef, Trait, MacroDef,
8 code_model::Crate, 9 code_model::Crate,
9 MacroDefId,
10 db::HirDatabase, 10 db::HirDatabase,
11 name::{Name, KnownName}, 11 name::{Name, KnownName},
12 nameres::{PerNs, CrateDefMap, CrateModuleId}, 12 nameres::{PerNs, CrateDefMap, CrateModuleId},
@@ -130,13 +130,16 @@ impl Resolver {
130 resolution 130 resolution
131 } 131 }
132 132
133 pub(crate) fn resolve_macro_call( 133 pub(crate) fn resolve_path_as_macro(
134 &self, 134 &self,
135 db: &impl HirDatabase, 135 db: &impl HirDatabase,
136 path: Option<Path>, 136 path: &Path,
137 ) -> Option<MacroDefId> { 137 ) -> Option<MacroDef> {
138 let m = self.module()?; 138 let (item_map, module) = self.module()?;
139 m.0.find_macro(db, m.1, &path?) 139 match item_map.resolve_path_with_macro(db, module, path) {
140 (Either::Right(macro_def), None) => Some(macro_def),
141 _ => None,
142 }
140 } 143 }
141 144
142 /// Returns the resolved path segments 145 /// Returns the resolved path segments
@@ -165,7 +168,11 @@ impl Resolver {
165 168
166 /// Returns the fully resolved path if we were able to resolve it. 169 /// Returns the fully resolved path if we were able to resolve it.
167 /// otherwise returns `PerNs::none` 170 /// otherwise returns `PerNs::none`
168 pub(crate) fn resolve_path(&self, db: &impl HirDatabase, path: &Path) -> PerNs<Resolution> { 171 pub(crate) fn resolve_path_without_assoc_items(
172 &self,
173 db: &impl HirDatabase,
174 path: &Path,
175 ) -> PerNs<Resolution> {
169 // into_fully_resolved() returns the fully resolved path or PerNs::none() otherwise 176 // into_fully_resolved() returns the fully resolved path or PerNs::none() otherwise
170 self.resolve_path_segments(db, path).into_fully_resolved() 177 self.resolve_path_segments(db, path).into_fully_resolved()
171 } 178 }
diff --git a/crates/ra_hir/src/source_binder.rs b/crates/ra_hir/src/source_binder.rs
index 410064d45..876ebe0e3 100644
--- a/crates/ra_hir/src/source_binder.rs
+++ b/crates/ra_hir/src/source_binder.rs
@@ -267,9 +267,8 @@ impl SourceAnalyzer {
267 db: &impl HirDatabase, 267 db: &impl HirDatabase,
268 macro_call: &ast::MacroCall, 268 macro_call: &ast::MacroCall,
269 ) -> Option<MacroDef> { 269 ) -> Option<MacroDef> {
270 let id = 270 let path = macro_call.path().and_then(Path::from_ast)?;
271 self.resolver.resolve_macro_call(db, macro_call.path().and_then(Path::from_ast))?; 271 self.resolver.resolve_path_as_macro(db, &path)
272 Some(MacroDef { id })
273 } 272 }
274 273
275 pub fn resolve_hir_path( 274 pub fn resolve_hir_path(
@@ -277,7 +276,7 @@ impl SourceAnalyzer {
277 db: &impl HirDatabase, 276 db: &impl HirDatabase,
278 path: &crate::Path, 277 path: &crate::Path,
279 ) -> PerNs<crate::Resolution> { 278 ) -> PerNs<crate::Resolution> {
280 self.resolver.resolve_path(db, path) 279 self.resolver.resolve_path_without_assoc_items(db, path)
281 } 280 }
282 281
283 pub fn resolve_path(&self, db: &impl HirDatabase, path: &ast::Path) -> Option<PathResolution> { 282 pub fn resolve_path(&self, db: &impl HirDatabase, path: &ast::Path) -> Option<PathResolution> {
@@ -294,7 +293,7 @@ impl SourceAnalyzer {
294 } 293 }
295 } 294 }
296 let hir_path = crate::Path::from_ast(path)?; 295 let hir_path = crate::Path::from_ast(path)?;
297 let res = self.resolver.resolve_path(db, &hir_path); 296 let res = self.resolver.resolve_path_without_assoc_items(db, &hir_path);
298 let res = res.clone().take_types().or_else(|| res.take_values())?; 297 let res = res.clone().take_types().or_else(|| res.take_values())?;
299 let res = match res { 298 let res = match res {
300 crate::Resolution::Def(it) => PathResolution::Def(it), 299 crate::Resolution::Def(it) => PathResolution::Def(it),
diff --git a/crates/ra_hir/src/ty/infer.rs b/crates/ra_hir/src/ty/infer.rs
index 6cc5dbc6f..6aa727ea1 100644
--- a/crates/ra_hir/src/ty/infer.rs
+++ b/crates/ra_hir/src/ty/infer.rs
@@ -610,23 +610,26 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
610 None => return (Ty::Unknown, None), 610 None => return (Ty::Unknown, None),
611 }; 611 };
612 let resolver = &self.resolver; 612 let resolver = &self.resolver;
613 let typable: Option<TypableDef> = match resolver.resolve_path(self.db, &path).take_types() { 613 let typable: Option<TypableDef> =
614 Some(Resolution::Def(def)) => def.into(), 614 // FIXME: this should resolve assoc items as well, see this example:
615 Some(Resolution::LocalBinding(..)) => { 615 // https://play.rust-lang.org/?gist=087992e9e22495446c01c0d4e2d69521
616 // this cannot happen 616 match resolver.resolve_path_without_assoc_items(self.db, &path).take_types() {
617 log::error!("path resolved to local binding in type ns"); 617 Some(Resolution::Def(def)) => def.into(),
618 return (Ty::Unknown, None); 618 Some(Resolution::LocalBinding(..)) => {
619 } 619 // this cannot happen
620 Some(Resolution::GenericParam(..)) => { 620 log::error!("path resolved to local binding in type ns");
621 // generic params can't be used in struct literals 621 return (Ty::Unknown, None);
622 return (Ty::Unknown, None); 622 }
623 } 623 Some(Resolution::GenericParam(..)) => {
624 Some(Resolution::SelfType(..)) => { 624 // generic params can't be used in struct literals
625 // FIXME this is allowed in an impl for a struct, handle this 625 return (Ty::Unknown, None);
626 return (Ty::Unknown, None); 626 }
627 } 627 Some(Resolution::SelfType(..)) => {
628 None => return (Ty::Unknown, None), 628 // FIXME this is allowed in an impl for a struct, handle this
629 }; 629 return (Ty::Unknown, None);
630 }
631 None => return (Ty::Unknown, None),
632 };
630 let def = match typable { 633 let def = match typable {
631 None => return (Ty::Unknown, None), 634 None => return (Ty::Unknown, None),
632 Some(it) => it, 635 Some(it) => it,
diff --git a/crates/ra_hir/src/ty/lower.rs b/crates/ra_hir/src/ty/lower.rs
index 71cd72234..26c213a41 100644
--- a/crates/ra_hir/src/ty/lower.rs
+++ b/crates/ra_hir/src/ty/lower.rs
@@ -65,7 +65,7 @@ impl Ty {
65 65
66 pub(crate) fn from_hir_path(db: &impl HirDatabase, resolver: &Resolver, path: &Path) -> Self { 66 pub(crate) fn from_hir_path(db: &impl HirDatabase, resolver: &Resolver, path: &Path) -> Self {
67 // Resolve the path (in type namespace) 67 // Resolve the path (in type namespace)
68 let resolution = resolver.resolve_path(db, path).take_types(); 68 let resolution = resolver.resolve_path_without_assoc_items(db, path).take_types();
69 69
70 let def = match resolution { 70 let def = match resolution {
71 Some(Resolution::Def(def)) => def, 71 Some(Resolution::Def(def)) => def,
@@ -216,7 +216,7 @@ impl TraitRef {
216 path: &Path, 216 path: &Path,
217 explicit_self_ty: Option<Ty>, 217 explicit_self_ty: Option<Ty>,
218 ) -> Option<Self> { 218 ) -> Option<Self> {
219 let resolved = match resolver.resolve_path(db, &path).take_types()? { 219 let resolved = match resolver.resolve_path_without_assoc_items(db, &path).take_types()? {
220 Resolution::Def(ModuleDef::Trait(tr)) => tr, 220 Resolution::Def(ModuleDef::Trait(tr)) => tr,
221 _ => return None, 221 _ => return None,
222 }; 222 };
diff --git a/crates/ra_hir/src/ty/tests.rs b/crates/ra_hir/src/ty/tests.rs
index c34e89af7..54b2a8c16 100644
--- a/crates/ra_hir/src/ty/tests.rs
+++ b/crates/ra_hir/src/ty/tests.rs
@@ -2481,8 +2481,10 @@ fn main() {
2481} 2481}
2482"#), 2482"#),
2483 @r###" 2483 @r###"
2484[156; 182) '{ ...,2); }': () 2484
2485[166; 167) 'x': Foo"### 2485 ⋮[156; 182) '{ ...,2); }': ()
2486 ⋮[166; 167) 'x': Foo
2487 "###
2486 ); 2488 );
2487} 2489}
2488 2490