diff options
Diffstat (limited to 'crates/hir_expand')
-rw-r--r-- | crates/hir_expand/src/db.rs | 80 | ||||
-rw-r--r-- | crates/hir_expand/src/lib.rs | 2 |
2 files changed, 30 insertions, 52 deletions
diff --git a/crates/hir_expand/src/db.rs b/crates/hir_expand/src/db.rs index 3deac1711..46ebdbc74 100644 --- a/crates/hir_expand/src/db.rs +++ b/crates/hir_expand/src/db.rs | |||
@@ -13,19 +13,6 @@ use crate::{ | |||
13 | MacroFile, ProcMacroExpander, | 13 | MacroFile, ProcMacroExpander, |
14 | }; | 14 | }; |
15 | 15 | ||
16 | /// A result of some macro expansion. | ||
17 | #[derive(Debug, Clone, Eq, PartialEq)] | ||
18 | pub struct MacroResult<T> { | ||
19 | /// The result of the expansion. Might be `None` when error recovery was impossible and no | ||
20 | /// usable result was produced. | ||
21 | pub value: Option<T>, | ||
22 | |||
23 | /// The error that occurred during expansion or processing. | ||
24 | /// | ||
25 | /// Since we do error recovery, getting an error here does not mean that `value` will be absent. | ||
26 | pub error: Option<String>, | ||
27 | } | ||
28 | |||
29 | #[derive(Debug, Clone, Eq, PartialEq)] | 16 | #[derive(Debug, Clone, Eq, PartialEq)] |
30 | pub enum TokenExpander { | 17 | pub enum TokenExpander { |
31 | MacroRules(mbe::MacroRules), | 18 | MacroRules(mbe::MacroRules), |
@@ -91,8 +78,8 @@ pub trait AstDatabase: SourceDatabase { | |||
91 | fn parse_macro_expansion( | 78 | fn parse_macro_expansion( |
92 | &self, | 79 | &self, |
93 | macro_file: MacroFile, | 80 | macro_file: MacroFile, |
94 | ) -> MacroResult<(Parse<SyntaxNode>, Arc<mbe::TokenMap>)>; | 81 | ) -> ExpandResult<Option<(Parse<SyntaxNode>, Arc<mbe::TokenMap>)>>; |
95 | fn macro_expand(&self, macro_call: MacroCallId) -> MacroResult<Arc<tt::Subtree>>; | 82 | fn macro_expand(&self, macro_call: MacroCallId) -> ExpandResult<Option<Arc<tt::Subtree>>>; |
96 | 83 | ||
97 | #[salsa::interned] | 84 | #[salsa::interned] |
98 | fn intern_eager_expansion(&self, eager: EagerCallLoc) -> EagerMacroId; | 85 | fn intern_eager_expansion(&self, eager: EagerCallLoc) -> EagerMacroId; |
@@ -100,20 +87,6 @@ pub trait AstDatabase: SourceDatabase { | |||
100 | fn expand_proc_macro(&self, call: MacroCallId) -> Result<tt::Subtree, mbe::ExpandError>; | 87 | fn expand_proc_macro(&self, call: MacroCallId) -> Result<tt::Subtree, mbe::ExpandError>; |
101 | } | 88 | } |
102 | 89 | ||
103 | impl<T> MacroResult<T> { | ||
104 | fn error(message: String) -> Self { | ||
105 | Self { value: None, error: Some(message) } | ||
106 | } | ||
107 | |||
108 | fn map<U>(self, f: impl FnOnce(T) -> U) -> MacroResult<U> { | ||
109 | MacroResult { value: self.value.map(f), error: self.error } | ||
110 | } | ||
111 | |||
112 | fn drop_value<U>(self) -> MacroResult<U> { | ||
113 | MacroResult { value: None, error: self.error } | ||
114 | } | ||
115 | } | ||
116 | |||
117 | /// This expands the given macro call, but with different arguments. This is | 90 | /// This expands the given macro call, but with different arguments. This is |
118 | /// used for completion, where we want to see what 'would happen' if we insert a | 91 | /// used for completion, where we want to see what 'would happen' if we insert a |
119 | /// token. The `token_to_map` mapped down into the expansion, with the mapped | 92 | /// token. The `token_to_map` mapped down into the expansion, with the mapped |
@@ -194,7 +167,7 @@ fn macro_arg(db: &dyn AstDatabase, id: MacroCallId) -> Option<Arc<(tt::Subtree, | |||
194 | Some(Arc::new((tt, tmap))) | 167 | Some(Arc::new((tt, tmap))) |
195 | } | 168 | } |
196 | 169 | ||
197 | fn macro_expand(db: &dyn AstDatabase, id: MacroCallId) -> MacroResult<Arc<tt::Subtree>> { | 170 | fn macro_expand(db: &dyn AstDatabase, id: MacroCallId) -> ExpandResult<Option<Arc<tt::Subtree>>> { |
198 | macro_expand_with_arg(db, id, None) | 171 | macro_expand_with_arg(db, id, None) |
199 | } | 172 | } |
200 | 173 | ||
@@ -215,18 +188,18 @@ fn macro_expand_with_arg( | |||
215 | db: &dyn AstDatabase, | 188 | db: &dyn AstDatabase, |
216 | id: MacroCallId, | 189 | id: MacroCallId, |
217 | arg: Option<Arc<(tt::Subtree, mbe::TokenMap)>>, | 190 | arg: Option<Arc<(tt::Subtree, mbe::TokenMap)>>, |
218 | ) -> MacroResult<Arc<tt::Subtree>> { | 191 | ) -> ExpandResult<Option<Arc<tt::Subtree>>> { |
219 | let lazy_id = match id { | 192 | let lazy_id = match id { |
220 | MacroCallId::LazyMacro(id) => id, | 193 | MacroCallId::LazyMacro(id) => id, |
221 | MacroCallId::EagerMacro(id) => { | 194 | MacroCallId::EagerMacro(id) => { |
222 | if arg.is_some() { | 195 | if arg.is_some() { |
223 | return MacroResult::error( | 196 | return ExpandResult::str_err( |
224 | "hypothetical macro expansion not implemented for eager macro".to_owned(), | 197 | "hypothetical macro expansion not implemented for eager macro".to_owned(), |
225 | ); | 198 | ); |
226 | } else { | 199 | } else { |
227 | return MacroResult { | 200 | return ExpandResult { |
228 | value: Some(db.lookup_intern_eager_expansion(id).subtree), | 201 | value: Some(db.lookup_intern_eager_expansion(id).subtree), |
229 | error: None, | 202 | err: None, |
230 | }; | 203 | }; |
231 | } | 204 | } |
232 | } | 205 | } |
@@ -235,21 +208,24 @@ fn macro_expand_with_arg( | |||
235 | let loc = db.lookup_intern_macro(lazy_id); | 208 | let loc = db.lookup_intern_macro(lazy_id); |
236 | let macro_arg = match arg.or_else(|| db.macro_arg(id)) { | 209 | let macro_arg = match arg.or_else(|| db.macro_arg(id)) { |
237 | Some(it) => it, | 210 | Some(it) => it, |
238 | None => return MacroResult::error("Fail to args in to tt::TokenTree".into()), | 211 | None => return ExpandResult::str_err("Fail to args in to tt::TokenTree".into()), |
239 | }; | 212 | }; |
240 | 213 | ||
241 | let macro_rules = match db.macro_def(loc.def) { | 214 | let macro_rules = match db.macro_def(loc.def) { |
242 | Some(it) => it, | 215 | Some(it) => it, |
243 | None => return MacroResult::error("Fail to find macro definition".into()), | 216 | None => return ExpandResult::str_err("Fail to find macro definition".into()), |
244 | }; | 217 | }; |
245 | let ExpandResult { value: tt, err } = macro_rules.0.expand(db, lazy_id, ¯o_arg.0); | 218 | let ExpandResult { value: tt, err } = macro_rules.0.expand(db, lazy_id, ¯o_arg.0); |
246 | // Set a hard limit for the expanded tt | 219 | // Set a hard limit for the expanded tt |
247 | let count = tt.count(); | 220 | let count = tt.count(); |
248 | if count > 262144 { | 221 | if count > 262144 { |
249 | return MacroResult::error(format!("Total tokens count exceed limit : count = {}", count)); | 222 | return ExpandResult::str_err(format!( |
223 | "Total tokens count exceed limit : count = {}", | ||
224 | count | ||
225 | )); | ||
250 | } | 226 | } |
251 | 227 | ||
252 | MacroResult { value: Some(Arc::new(tt)), error: err.map(|e| format!("{:?}", e)) } | 228 | ExpandResult { value: Some(Arc::new(tt)), err } |
253 | } | 229 | } |
254 | 230 | ||
255 | fn expand_proc_macro( | 231 | fn expand_proc_macro( |
@@ -283,7 +259,7 @@ fn parse_or_expand(db: &dyn AstDatabase, file_id: HirFileId) -> Option<SyntaxNod | |||
283 | match file_id.0 { | 259 | match file_id.0 { |
284 | HirFileIdRepr::FileId(file_id) => Some(db.parse(file_id).tree().syntax().clone()), | 260 | HirFileIdRepr::FileId(file_id) => Some(db.parse(file_id).tree().syntax().clone()), |
285 | HirFileIdRepr::MacroFile(macro_file) => { | 261 | HirFileIdRepr::MacroFile(macro_file) => { |
286 | db.parse_macro_expansion(macro_file).map(|(it, _)| it.syntax_node()).value | 262 | db.parse_macro_expansion(macro_file).value.map(|(it, _)| it.syntax_node()) |
287 | } | 263 | } |
288 | } | 264 | } |
289 | } | 265 | } |
@@ -291,7 +267,7 @@ fn parse_or_expand(db: &dyn AstDatabase, file_id: HirFileId) -> Option<SyntaxNod | |||
291 | fn parse_macro_expansion( | 267 | fn parse_macro_expansion( |
292 | db: &dyn AstDatabase, | 268 | db: &dyn AstDatabase, |
293 | macro_file: MacroFile, | 269 | macro_file: MacroFile, |
294 | ) -> MacroResult<(Parse<SyntaxNode>, Arc<mbe::TokenMap>)> { | 270 | ) -> ExpandResult<Option<(Parse<SyntaxNode>, Arc<mbe::TokenMap>)>> { |
295 | parse_macro_with_arg(db, macro_file, None) | 271 | parse_macro_with_arg(db, macro_file, None) |
296 | } | 272 | } |
297 | 273 | ||
@@ -299,7 +275,7 @@ fn parse_macro_with_arg( | |||
299 | db: &dyn AstDatabase, | 275 | db: &dyn AstDatabase, |
300 | macro_file: MacroFile, | 276 | macro_file: MacroFile, |
301 | arg: Option<Arc<(tt::Subtree, mbe::TokenMap)>>, | 277 | arg: Option<Arc<(tt::Subtree, mbe::TokenMap)>>, |
302 | ) -> MacroResult<(Parse<SyntaxNode>, Arc<mbe::TokenMap>)> { | 278 | ) -> ExpandResult<Option<(Parse<SyntaxNode>, Arc<mbe::TokenMap>)>> { |
303 | let _p = profile::span("parse_macro_query"); | 279 | let _p = profile::span("parse_macro_query"); |
304 | 280 | ||
305 | let macro_call_id = macro_file.macro_call_id; | 281 | let macro_call_id = macro_file.macro_call_id; |
@@ -308,7 +284,7 @@ fn parse_macro_with_arg( | |||
308 | } else { | 284 | } else { |
309 | db.macro_expand(macro_call_id) | 285 | db.macro_expand(macro_call_id) |
310 | }; | 286 | }; |
311 | if let Some(err) = &result.error { | 287 | if let Some(err) = &result.err { |
312 | // Note: | 288 | // Note: |
313 | // The final goal we would like to make all parse_macro success, | 289 | // The final goal we would like to make all parse_macro success, |
314 | // such that the following log will not call anyway. | 290 | // such that the following log will not call anyway. |
@@ -326,20 +302,20 @@ fn parse_macro_with_arg( | |||
326 | .join("\n"); | 302 | .join("\n"); |
327 | 303 | ||
328 | log::warn!( | 304 | log::warn!( |
329 | "fail on macro_parse: (reason: {} macro_call: {:#}) parents: {}", | 305 | "fail on macro_parse: (reason: {:?} macro_call: {:#}) parents: {}", |
330 | err, | 306 | err, |
331 | node.value, | 307 | node.value, |
332 | parents | 308 | parents |
333 | ); | 309 | ); |
334 | } | 310 | } |
335 | _ => { | 311 | _ => { |
336 | log::warn!("fail on macro_parse: (reason: {})", err); | 312 | log::warn!("fail on macro_parse: (reason: {:?})", err); |
337 | } | 313 | } |
338 | } | 314 | } |
339 | } | 315 | } |
340 | let tt = match result.value { | 316 | let tt = match result.value { |
341 | Some(tt) => tt, | 317 | Some(tt) => tt, |
342 | None => return result.drop_value(), | 318 | None => return ExpandResult { value: None, err: result.err }, |
343 | }; | 319 | }; |
344 | 320 | ||
345 | let fragment_kind = to_fragment_kind(db, macro_call_id); | 321 | let fragment_kind = to_fragment_kind(db, macro_call_id); |
@@ -347,29 +323,29 @@ fn parse_macro_with_arg( | |||
347 | let (parse, rev_token_map) = match mbe::token_tree_to_syntax_node(&tt, fragment_kind) { | 323 | let (parse, rev_token_map) = match mbe::token_tree_to_syntax_node(&tt, fragment_kind) { |
348 | Ok(it) => it, | 324 | Ok(it) => it, |
349 | Err(err) => { | 325 | Err(err) => { |
350 | return MacroResult::error(format!("{:?}", err)); | 326 | return ExpandResult::only_err(err); |
351 | } | 327 | } |
352 | }; | 328 | }; |
353 | 329 | ||
354 | match result.error { | 330 | match result.err { |
355 | Some(error) => { | 331 | Some(err) => { |
356 | // Safety check for recursive identity macro. | 332 | // Safety check for recursive identity macro. |
357 | let node = parse.syntax_node(); | 333 | let node = parse.syntax_node(); |
358 | let file: HirFileId = macro_file.into(); | 334 | let file: HirFileId = macro_file.into(); |
359 | let call_node = match file.call_node(db) { | 335 | let call_node = match file.call_node(db) { |
360 | Some(it) => it, | 336 | Some(it) => it, |
361 | None => { | 337 | None => { |
362 | return MacroResult::error(error); | 338 | return ExpandResult::only_err(err); |
363 | } | 339 | } |
364 | }; | 340 | }; |
365 | 341 | ||
366 | if !diff(&node, &call_node.value).is_empty() { | 342 | if !diff(&node, &call_node.value).is_empty() { |
367 | MacroResult { value: Some((parse, Arc::new(rev_token_map))), error: Some(error) } | 343 | ExpandResult { value: Some((parse, Arc::new(rev_token_map))), err: Some(err) } |
368 | } else { | 344 | } else { |
369 | return MacroResult::error(error); | 345 | return ExpandResult::only_err(err); |
370 | } | 346 | } |
371 | } | 347 | } |
372 | None => MacroResult { value: Some((parse, Arc::new(rev_token_map))), error: None }, | 348 | None => ExpandResult { value: Some((parse, Arc::new(rev_token_map))), err: None }, |
373 | } | 349 | } |
374 | } | 350 | } |
375 | 351 | ||
diff --git a/crates/hir_expand/src/lib.rs b/crates/hir_expand/src/lib.rs index 83e09738b..d5ba691b7 100644 --- a/crates/hir_expand/src/lib.rs +++ b/crates/hir_expand/src/lib.rs | |||
@@ -15,6 +15,8 @@ pub mod proc_macro; | |||
15 | pub mod quote; | 15 | pub mod quote; |
16 | pub mod eager; | 16 | pub mod eager; |
17 | 17 | ||
18 | pub use mbe::{ExpandError, ExpandResult}; | ||
19 | |||
18 | use std::hash::Hash; | 20 | use std::hash::Hash; |
19 | use std::sync::Arc; | 21 | use std::sync::Arc; |
20 | 22 | ||