diff options
author | Aleksey Kladov <[email protected]> | 2020-04-11 16:52:26 +0100 |
---|---|---|
committer | Aleksey Kladov <[email protected]> | 2020-04-11 16:52:26 +0100 |
commit | 38c67e5c0d4297f45ab2b78a00b59f737796d160 (patch) | |
tree | b96b64b2be660a35b6bb706d0ce8c5ee27f7433a /crates | |
parent | deb40d52aaa1989402fc01d65da389dc92fb66fa (diff) |
Avoid cyclic queries in name resolution when processing enums
Diffstat (limited to 'crates')
-rw-r--r-- | crates/ra_hir_def/src/adt.rs | 8 | ||||
-rw-r--r-- | crates/ra_hir_def/src/body.rs | 47 | ||||
-rw-r--r-- | crates/ra_hir_def/src/nameres/collector.rs | 8 |
3 files changed, 48 insertions, 15 deletions
diff --git a/crates/ra_hir_def/src/adt.rs b/crates/ra_hir_def/src/adt.rs index c7c3c0bc7..7c0d93691 100644 --- a/crates/ra_hir_def/src/adt.rs +++ b/crates/ra_hir_def/src/adt.rs | |||
@@ -12,7 +12,7 @@ use ra_prof::profile; | |||
12 | use ra_syntax::ast::{self, NameOwner, TypeAscriptionOwner, VisibilityOwner}; | 12 | use ra_syntax::ast::{self, NameOwner, TypeAscriptionOwner, VisibilityOwner}; |
13 | 13 | ||
14 | use crate::{ | 14 | use crate::{ |
15 | body::Expander, db::DefDatabase, src::HasChildSource, src::HasSource, trace::Trace, | 15 | body::CfgExpander, db::DefDatabase, src::HasChildSource, src::HasSource, trace::Trace, |
16 | type_ref::TypeRef, visibility::RawVisibility, EnumId, HasModule, LocalEnumVariantId, | 16 | type_ref::TypeRef, visibility::RawVisibility, EnumId, HasModule, LocalEnumVariantId, |
17 | LocalStructFieldId, Lookup, ModuleId, StructId, UnionId, VariantId, | 17 | LocalStructFieldId, Lookup, ModuleId, StructId, UnionId, VariantId, |
18 | }; | 18 | }; |
@@ -124,7 +124,7 @@ fn lower_enum( | |||
124 | 124 | ||
125 | impl VariantData { | 125 | impl VariantData { |
126 | fn new(db: &dyn DefDatabase, flavor: InFile<ast::StructKind>, module_id: ModuleId) -> Self { | 126 | fn new(db: &dyn DefDatabase, flavor: InFile<ast::StructKind>, module_id: ModuleId) -> Self { |
127 | let mut expander = Expander::new(db, flavor.file_id, module_id); | 127 | let mut expander = CfgExpander::new(db, flavor.file_id, module_id.krate); |
128 | let mut trace = Trace::new_for_arena(); | 128 | let mut trace = Trace::new_for_arena(); |
129 | match lower_struct(db, &mut expander, &mut trace, &flavor) { | 129 | match lower_struct(db, &mut expander, &mut trace, &flavor) { |
130 | StructKind::Tuple => VariantData::Tuple(trace.into_arena()), | 130 | StructKind::Tuple => VariantData::Tuple(trace.into_arena()), |
@@ -178,7 +178,7 @@ impl HasChildSource for VariantId { | |||
178 | it.lookup(db).container.module(db), | 178 | it.lookup(db).container.module(db), |
179 | ), | 179 | ), |
180 | }; | 180 | }; |
181 | let mut expander = Expander::new(db, src.file_id, module_id); | 181 | let mut expander = CfgExpander::new(db, src.file_id, module_id.krate); |
182 | let mut trace = Trace::new_for_map(); | 182 | let mut trace = Trace::new_for_map(); |
183 | lower_struct(db, &mut expander, &mut trace, &src); | 183 | lower_struct(db, &mut expander, &mut trace, &src); |
184 | src.with_value(trace.into_map()) | 184 | src.with_value(trace.into_map()) |
@@ -194,7 +194,7 @@ pub enum StructKind { | |||
194 | 194 | ||
195 | fn lower_struct( | 195 | fn lower_struct( |
196 | db: &dyn DefDatabase, | 196 | db: &dyn DefDatabase, |
197 | expander: &mut Expander, | 197 | expander: &mut CfgExpander, |
198 | trace: &mut Trace<StructFieldData, Either<ast::TupleFieldDef, ast::RecordFieldDef>>, | 198 | trace: &mut Trace<StructFieldData, Either<ast::TupleFieldDef, ast::RecordFieldDef>>, |
199 | ast: &InFile<ast::StructKind>, | 199 | ast: &InFile<ast::StructKind>, |
200 | ) -> StructKind { | 200 | ) -> StructKind { |
diff --git a/crates/ra_hir_def/src/body.rs b/crates/ra_hir_def/src/body.rs index 7fe5403c0..7fac6ce66 100644 --- a/crates/ra_hir_def/src/body.rs +++ b/crates/ra_hir_def/src/body.rs | |||
@@ -25,32 +25,57 @@ use crate::{ | |||
25 | AsMacroCall, DefWithBodyId, HasModule, Lookup, ModuleId, | 25 | AsMacroCall, DefWithBodyId, HasModule, Lookup, ModuleId, |
26 | }; | 26 | }; |
27 | use ra_cfg::CfgOptions; | 27 | use ra_cfg::CfgOptions; |
28 | use ra_db::CrateId; | ||
29 | |||
30 | /// A subser of Exander that only deals with cfg attributes. We only need it to | ||
31 | /// avoid cyclic queries in crate def map during enum processing. | ||
32 | pub(crate) struct CfgExpander { | ||
33 | cfg_options: CfgOptions, | ||
34 | hygiene: Hygiene, | ||
35 | } | ||
28 | 36 | ||
29 | pub(crate) struct Expander { | 37 | pub(crate) struct Expander { |
38 | cfg_expander: CfgExpander, | ||
30 | crate_def_map: Arc<CrateDefMap>, | 39 | crate_def_map: Arc<CrateDefMap>, |
31 | cfg_options: CfgOptions, | ||
32 | current_file_id: HirFileId, | 40 | current_file_id: HirFileId, |
33 | hygiene: Hygiene, | ||
34 | ast_id_map: Arc<AstIdMap>, | 41 | ast_id_map: Arc<AstIdMap>, |
35 | module: ModuleId, | 42 | module: ModuleId, |
36 | recursive_limit: usize, | 43 | recursive_limit: usize, |
37 | } | 44 | } |
38 | 45 | ||
46 | impl CfgExpander { | ||
47 | pub(crate) fn new( | ||
48 | db: &dyn DefDatabase, | ||
49 | current_file_id: HirFileId, | ||
50 | krate: CrateId, | ||
51 | ) -> CfgExpander { | ||
52 | let hygiene = Hygiene::new(db.upcast(), current_file_id); | ||
53 | let cfg_options = db.crate_graph()[krate].cfg_options.clone(); | ||
54 | CfgExpander { cfg_options, hygiene } | ||
55 | } | ||
56 | |||
57 | pub(crate) fn parse_attrs(&self, owner: &dyn ast::AttrsOwner) -> Attrs { | ||
58 | Attrs::new(owner, &self.hygiene) | ||
59 | } | ||
60 | |||
61 | pub(crate) fn is_cfg_enabled(&self, attrs: &Attrs) -> bool { | ||
62 | attrs.is_cfg_enabled(&self.cfg_options) | ||
63 | } | ||
64 | } | ||
65 | |||
39 | impl Expander { | 66 | impl Expander { |
40 | pub(crate) fn new( | 67 | pub(crate) fn new( |
41 | db: &dyn DefDatabase, | 68 | db: &dyn DefDatabase, |
42 | current_file_id: HirFileId, | 69 | current_file_id: HirFileId, |
43 | module: ModuleId, | 70 | module: ModuleId, |
44 | ) -> Expander { | 71 | ) -> Expander { |
72 | let cfg_expander = CfgExpander::new(db, current_file_id, module.krate); | ||
45 | let crate_def_map = db.crate_def_map(module.krate); | 73 | let crate_def_map = db.crate_def_map(module.krate); |
46 | let hygiene = Hygiene::new(db.upcast(), current_file_id); | ||
47 | let ast_id_map = db.ast_id_map(current_file_id); | 74 | let ast_id_map = db.ast_id_map(current_file_id); |
48 | let cfg_options = db.crate_graph()[module.krate].cfg_options.clone(); | ||
49 | Expander { | 75 | Expander { |
76 | cfg_expander, | ||
50 | crate_def_map, | 77 | crate_def_map, |
51 | cfg_options, | ||
52 | current_file_id, | 78 | current_file_id, |
53 | hygiene, | ||
54 | ast_id_map, | 79 | ast_id_map, |
55 | module, | 80 | module, |
56 | recursive_limit: 0, | 81 | recursive_limit: 0, |
@@ -87,7 +112,7 @@ impl Expander { | |||
87 | ast_id_map: mem::take(&mut self.ast_id_map), | 112 | ast_id_map: mem::take(&mut self.ast_id_map), |
88 | bomb: DropBomb::new("expansion mark dropped"), | 113 | bomb: DropBomb::new("expansion mark dropped"), |
89 | }; | 114 | }; |
90 | self.hygiene = Hygiene::new(db.upcast(), file_id); | 115 | self.cfg_expander.hygiene = Hygiene::new(db.upcast(), file_id); |
91 | self.current_file_id = file_id; | 116 | self.current_file_id = file_id; |
92 | self.ast_id_map = db.ast_id_map(file_id); | 117 | self.ast_id_map = db.ast_id_map(file_id); |
93 | self.recursive_limit += 1; | 118 | self.recursive_limit += 1; |
@@ -103,7 +128,7 @@ impl Expander { | |||
103 | } | 128 | } |
104 | 129 | ||
105 | pub(crate) fn exit(&mut self, db: &dyn DefDatabase, mut mark: Mark) { | 130 | pub(crate) fn exit(&mut self, db: &dyn DefDatabase, mut mark: Mark) { |
106 | self.hygiene = Hygiene::new(db.upcast(), mark.file_id); | 131 | self.cfg_expander.hygiene = Hygiene::new(db.upcast(), mark.file_id); |
107 | self.current_file_id = mark.file_id; | 132 | self.current_file_id = mark.file_id; |
108 | self.ast_id_map = mem::take(&mut mark.ast_id_map); | 133 | self.ast_id_map = mem::take(&mut mark.ast_id_map); |
109 | self.recursive_limit -= 1; | 134 | self.recursive_limit -= 1; |
@@ -115,15 +140,15 @@ impl Expander { | |||
115 | } | 140 | } |
116 | 141 | ||
117 | pub(crate) fn parse_attrs(&self, owner: &dyn ast::AttrsOwner) -> Attrs { | 142 | pub(crate) fn parse_attrs(&self, owner: &dyn ast::AttrsOwner) -> Attrs { |
118 | Attrs::new(owner, &self.hygiene) | 143 | self.cfg_expander.parse_attrs(owner) |
119 | } | 144 | } |
120 | 145 | ||
121 | pub(crate) fn is_cfg_enabled(&self, attrs: &Attrs) -> bool { | 146 | pub(crate) fn is_cfg_enabled(&self, attrs: &Attrs) -> bool { |
122 | attrs.is_cfg_enabled(&self.cfg_options) | 147 | self.cfg_expander.is_cfg_enabled(attrs) |
123 | } | 148 | } |
124 | 149 | ||
125 | fn parse_path(&mut self, path: ast::Path) -> Option<Path> { | 150 | fn parse_path(&mut self, path: ast::Path) -> Option<Path> { |
126 | Path::from_src(path, &self.hygiene) | 151 | Path::from_src(path, &self.cfg_expander.hygiene) |
127 | } | 152 | } |
128 | 153 | ||
129 | fn resolve_path_as_macro(&self, db: &dyn DefDatabase, path: &ModPath) -> Option<MacroDefId> { | 154 | fn resolve_path_as_macro(&self, db: &dyn DefDatabase, path: &ModPath) -> Option<MacroDefId> { |
diff --git a/crates/ra_hir_def/src/nameres/collector.rs b/crates/ra_hir_def/src/nameres/collector.rs index 1c33a6520..98c74fe25 100644 --- a/crates/ra_hir_def/src/nameres/collector.rs +++ b/crates/ra_hir_def/src/nameres/collector.rs | |||
@@ -462,6 +462,14 @@ impl DefCollector<'_> { | |||
462 | Some(ModuleDefId::AdtId(AdtId::EnumId(e))) => { | 462 | Some(ModuleDefId::AdtId(AdtId::EnumId(e))) => { |
463 | tested_by!(glob_enum); | 463 | tested_by!(glob_enum); |
464 | // glob import from enum => just import all the variants | 464 | // glob import from enum => just import all the variants |
465 | |||
466 | // XXX: urgh, so this works by accident! Here, we look at | ||
467 | // the enum data, and, in theory, this might require us to | ||
468 | // look back at the crate_def_map, creating a cycle. For | ||
469 | // example, `enum E { crate::some_macro!(); }`. Luckely, the | ||
470 | // only kind of macro that is allowed inside enum is a | ||
471 | // `cfg_macro`, and we don't need to run name resolution for | ||
472 | // it, but this is sheer luck! | ||
465 | let enum_data = self.db.enum_data(e); | 473 | let enum_data = self.db.enum_data(e); |
466 | let resolutions = enum_data | 474 | let resolutions = enum_data |
467 | .variants | 475 | .variants |