diff options
author | bors[bot] <26634292+bors[bot]@users.noreply.github.com> | 2021-05-06 22:53:05 +0100 |
---|---|---|
committer | GitHub <[email protected]> | 2021-05-06 22:53:05 +0100 |
commit | 6fccb152b4646877e38dc29dce1b0cd826eb6908 (patch) | |
tree | 361153338ec7c32866a5477b3e7681d05a4b0b7c /crates/hir_expand | |
parent | b37b709459a4ff881a91965ebf0c39e3a449c304 (diff) | |
parent | 20ae41c1a12963e938cb3bd4c7c84007412d6fa6 (diff) |
Merge #8746
8746: Don't store call-site text offsets in hygiene info r=matklad a=jonas-schievink
This threads a lot more database references around in order to avoid storing a bare `TextOffset` in the hygiene info. This `TextOffset` made hygiene info and `ItemTree`s more volatile than they should be, leading to excessive recomputation of `ItemTree`s.
The incremental test added in https://github.com/rust-analyzer/rust-analyzer/pull/8721 is now passing with these changes.
closes https://github.com/rust-analyzer/rust-analyzer/pull/8721
Co-authored-by: Jonas Schievink <[email protected]>
Co-authored-by: Aleksey Kladov <[email protected]>
Diffstat (limited to 'crates/hir_expand')
-rw-r--r-- | crates/hir_expand/src/hygiene.rs | 57 |
1 files changed, 35 insertions, 22 deletions
diff --git a/crates/hir_expand/src/hygiene.rs b/crates/hir_expand/src/hygiene.rs index ed61ebca3..aca69e35a 100644 --- a/crates/hir_expand/src/hygiene.rs +++ b/crates/hir_expand/src/hygiene.rs | |||
@@ -32,10 +32,14 @@ impl Hygiene { | |||
32 | } | 32 | } |
33 | 33 | ||
34 | // FIXME: this should just return name | 34 | // FIXME: this should just return name |
35 | pub fn name_ref_to_name(&self, name_ref: ast::NameRef) -> Either<Name, CrateId> { | 35 | pub fn name_ref_to_name( |
36 | &self, | ||
37 | db: &dyn AstDatabase, | ||
38 | name_ref: ast::NameRef, | ||
39 | ) -> Either<Name, CrateId> { | ||
36 | if let Some(frames) = &self.frames { | 40 | if let Some(frames) = &self.frames { |
37 | if name_ref.text() == "$crate" { | 41 | if name_ref.text() == "$crate" { |
38 | if let Some(krate) = frames.root_crate(name_ref.syntax()) { | 42 | if let Some(krate) = frames.root_crate(db, name_ref.syntax()) { |
39 | return Either::Right(krate); | 43 | return Either::Right(krate); |
40 | } | 44 | } |
41 | } | 45 | } |
@@ -44,15 +48,19 @@ impl Hygiene { | |||
44 | Either::Left(name_ref.as_name()) | 48 | Either::Left(name_ref.as_name()) |
45 | } | 49 | } |
46 | 50 | ||
47 | pub fn local_inner_macros(&self, path: ast::Path) -> Option<CrateId> { | 51 | pub fn local_inner_macros(&self, db: &dyn AstDatabase, path: ast::Path) -> Option<CrateId> { |
48 | let mut token = path.syntax().first_token()?.text_range(); | 52 | let mut token = path.syntax().first_token()?.text_range(); |
49 | let frames = self.frames.as_ref()?; | 53 | let frames = self.frames.as_ref()?; |
50 | let mut current = frames.0.clone(); | 54 | let mut current = frames.0.clone(); |
51 | 55 | ||
52 | loop { | 56 | loop { |
53 | let (mapped, origin) = current.expansion.as_ref()?.map_ident_up(token)?; | 57 | let (mapped, origin) = current.expansion.as_ref()?.map_ident_up(db, token)?; |
54 | if origin == Origin::Def { | 58 | if origin == Origin::Def { |
55 | return if current.local_inner { frames.root_crate(path.syntax()) } else { None }; | 59 | return if current.local_inner { |
60 | frames.root_crate(db, path.syntax()) | ||
61 | } else { | ||
62 | None | ||
63 | }; | ||
56 | } | 64 | } |
57 | current = current.call_site.as_ref()?.clone(); | 65 | current = current.call_site.as_ref()?.clone(); |
58 | token = mapped.value; | 66 | token = mapped.value; |
@@ -82,13 +90,13 @@ impl HygieneFrames { | |||
82 | HygieneFrames(Arc::new(HygieneFrame::new(db, file_id))) | 90 | HygieneFrames(Arc::new(HygieneFrame::new(db, file_id))) |
83 | } | 91 | } |
84 | 92 | ||
85 | fn root_crate(&self, node: &SyntaxNode) -> Option<CrateId> { | 93 | fn root_crate(&self, db: &dyn AstDatabase, node: &SyntaxNode) -> Option<CrateId> { |
86 | let mut token = node.first_token()?.text_range(); | 94 | let mut token = node.first_token()?.text_range(); |
87 | let mut result = self.0.krate; | 95 | let mut result = self.0.krate; |
88 | let mut current = self.0.clone(); | 96 | let mut current = self.0.clone(); |
89 | 97 | ||
90 | while let Some((mapped, origin)) = | 98 | while let Some((mapped, origin)) = |
91 | current.expansion.as_ref().and_then(|it| it.map_ident_up(token)) | 99 | current.expansion.as_ref().and_then(|it| it.map_ident_up(db, token)) |
92 | { | 100 | { |
93 | result = current.krate; | 101 | result = current.krate; |
94 | 102 | ||
@@ -112,7 +120,7 @@ impl HygieneFrames { | |||
112 | 120 | ||
113 | #[derive(Debug, Clone, PartialEq, Eq)] | 121 | #[derive(Debug, Clone, PartialEq, Eq)] |
114 | struct HygieneInfo { | 122 | struct HygieneInfo { |
115 | arg_start: InFile<TextSize>, | 123 | file: MacroFile, |
116 | /// The `macro_rules!` arguments. | 124 | /// The `macro_rules!` arguments. |
117 | def_start: Option<InFile<TextSize>>, | 125 | def_start: Option<InFile<TextSize>>, |
118 | 126 | ||
@@ -122,12 +130,24 @@ struct HygieneInfo { | |||
122 | } | 130 | } |
123 | 131 | ||
124 | impl HygieneInfo { | 132 | impl HygieneInfo { |
125 | fn map_ident_up(&self, token: TextRange) -> Option<(InFile<TextRange>, Origin)> { | 133 | fn map_ident_up( |
134 | &self, | ||
135 | db: &dyn AstDatabase, | ||
136 | token: TextRange, | ||
137 | ) -> Option<(InFile<TextRange>, Origin)> { | ||
126 | let token_id = self.exp_map.token_by_range(token)?; | 138 | let token_id = self.exp_map.token_by_range(token)?; |
127 | 139 | ||
128 | let (token_id, origin) = self.macro_def.map_id_up(token_id); | 140 | let (token_id, origin) = self.macro_def.map_id_up(token_id); |
129 | let (token_map, tt) = match origin { | 141 | let (token_map, tt) = match origin { |
130 | mbe::Origin::Call => (&self.macro_arg.1, self.arg_start), | 142 | mbe::Origin::Call => { |
143 | let call_id = match self.file.macro_call_id { | ||
144 | MacroCallId::LazyMacro(lazy) => lazy, | ||
145 | MacroCallId::EagerMacro(_) => unreachable!(), | ||
146 | }; | ||
147 | let loc: MacroCallLoc = db.lookup_intern_macro(call_id); | ||
148 | let arg_start = loc.kind.arg(db)?.text_range().start(); | ||
149 | (&self.macro_arg.1, InFile::new(loc.kind.file_id(), arg_start)) | ||
150 | } | ||
131 | mbe::Origin::Def => match (&*self.macro_def, self.def_start) { | 151 | mbe::Origin::Def => match (&*self.macro_def, self.def_start) { |
132 | (TokenExpander::MacroDef { def_site_token_map, .. }, Some(tt)) | 152 | (TokenExpander::MacroDef { def_site_token_map, .. }, Some(tt)) |
133 | | (TokenExpander::MacroRules { def_site_token_map, .. }, Some(tt)) => { | 153 | | (TokenExpander::MacroRules { def_site_token_map, .. }, Some(tt)) => { |
@@ -147,8 +167,6 @@ fn make_hygiene_info( | |||
147 | macro_file: MacroFile, | 167 | macro_file: MacroFile, |
148 | loc: &MacroCallLoc, | 168 | loc: &MacroCallLoc, |
149 | ) -> Option<HygieneInfo> { | 169 | ) -> Option<HygieneInfo> { |
150 | let arg_tt = loc.kind.arg(db)?; | ||
151 | |||
152 | let def_offset = loc.def.ast_id().left().and_then(|id| { | 170 | let def_offset = loc.def.ast_id().left().and_then(|id| { |
153 | let def_tt = match id.to_node(db) { | 171 | let def_tt = match id.to_node(db) { |
154 | ast::Macro::MacroRules(mac) => mac.token_tree()?.syntax().text_range().start(), | 172 | ast::Macro::MacroRules(mac) => mac.token_tree()?.syntax().text_range().start(), |
@@ -161,13 +179,7 @@ fn make_hygiene_info( | |||
161 | let (_, exp_map) = db.parse_macro_expansion(macro_file).value?; | 179 | let (_, exp_map) = db.parse_macro_expansion(macro_file).value?; |
162 | let macro_arg = db.macro_arg(macro_file.macro_call_id)?; | 180 | let macro_arg = db.macro_arg(macro_file.macro_call_id)?; |
163 | 181 | ||
164 | Some(HygieneInfo { | 182 | Some(HygieneInfo { file: macro_file, def_start: def_offset, macro_arg, macro_def, exp_map }) |
165 | arg_start: InFile::new(loc.kind.file_id(), arg_tt.text_range().start()), | ||
166 | def_start: def_offset, | ||
167 | macro_arg, | ||
168 | macro_def, | ||
169 | exp_map, | ||
170 | }) | ||
171 | } | 183 | } |
172 | 184 | ||
173 | impl HygieneFrame { | 185 | impl HygieneFrame { |
@@ -178,7 +190,8 @@ impl HygieneFrame { | |||
178 | MacroCallId::EagerMacro(_id) => (None, None, false), | 190 | MacroCallId::EagerMacro(_id) => (None, None, false), |
179 | MacroCallId::LazyMacro(id) => { | 191 | MacroCallId::LazyMacro(id) => { |
180 | let loc = db.lookup_intern_macro(id); | 192 | let loc = db.lookup_intern_macro(id); |
181 | let info = make_hygiene_info(db, macro_file, &loc); | 193 | let info = make_hygiene_info(db, macro_file, &loc) |
194 | .map(|info| (loc.kind.file_id(), info)); | ||
182 | match loc.def.kind { | 195 | match loc.def.kind { |
183 | MacroDefKind::Declarative(_) => { | 196 | MacroDefKind::Declarative(_) => { |
184 | (info, Some(loc.def.krate), loc.def.local_inner) | 197 | (info, Some(loc.def.krate), loc.def.local_inner) |
@@ -192,7 +205,7 @@ impl HygieneFrame { | |||
192 | }, | 205 | }, |
193 | }; | 206 | }; |
194 | 207 | ||
195 | let info = match info { | 208 | let (calling_file, info) = match info { |
196 | None => { | 209 | None => { |
197 | return HygieneFrame { | 210 | return HygieneFrame { |
198 | expansion: None, | 211 | expansion: None, |
@@ -206,7 +219,7 @@ impl HygieneFrame { | |||
206 | }; | 219 | }; |
207 | 220 | ||
208 | let def_site = info.def_start.map(|it| db.hygiene_frame(it.file_id)); | 221 | let def_site = info.def_start.map(|it| db.hygiene_frame(it.file_id)); |
209 | let call_site = Some(db.hygiene_frame(info.arg_start.file_id)); | 222 | let call_site = Some(db.hygiene_frame(calling_file)); |
210 | 223 | ||
211 | HygieneFrame { expansion: Some(info), local_inner, krate, call_site, def_site } | 224 | HygieneFrame { expansion: Some(info), local_inner, krate, call_site, def_site } |
212 | } | 225 | } |