aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_hir_expand
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_hir_expand')
-rw-r--r--crates/ra_hir_expand/src/db.rs99
1 files changed, 53 insertions, 46 deletions
diff --git a/crates/ra_hir_expand/src/db.rs b/crates/ra_hir_expand/src/db.rs
index c3e1c68b7..d171d2dfd 100644
--- a/crates/ra_hir_expand/src/db.rs
+++ b/crates/ra_hir_expand/src/db.rs
@@ -2,7 +2,7 @@
2 2
3use std::sync::Arc; 3use std::sync::Arc;
4 4
5use mbe::MacroRules; 5use mbe::{ExpandResult, MacroRules};
6use ra_db::{salsa, SourceDatabase}; 6use ra_db::{salsa, SourceDatabase};
7use ra_parser::FragmentKind; 7use ra_parser::FragmentKind;
8use ra_prof::profile; 8use ra_prof::profile;
@@ -27,11 +27,12 @@ impl TokenExpander {
27 db: &dyn AstDatabase, 27 db: &dyn AstDatabase,
28 id: LazyMacroId, 28 id: LazyMacroId,
29 tt: &tt::Subtree, 29 tt: &tt::Subtree,
30 ) -> Result<tt::Subtree, mbe::ExpandError> { 30 ) -> mbe::ExpandResult<tt::Subtree> {
31 match self { 31 match self {
32 TokenExpander::MacroRules(it) => it.expand(tt), 32 TokenExpander::MacroRules(it) => it.expand(tt),
33 TokenExpander::Builtin(it) => it.expand(db, id, tt), 33 // FIXME switch these to ExpandResult as well
34 TokenExpander::BuiltinDerive(it) => it.expand(db, id, tt), 34 TokenExpander::Builtin(it) => it.expand(db, id, tt).into(),
35 TokenExpander::BuiltinDerive(it) => it.expand(db, id, tt).into(),
35 } 36 }
36 } 37 }
37 38
@@ -66,7 +67,7 @@ pub trait AstDatabase: SourceDatabase {
66 fn macro_def(&self, id: MacroDefId) -> Option<Arc<(TokenExpander, mbe::TokenMap)>>; 67 fn macro_def(&self, id: MacroDefId) -> Option<Arc<(TokenExpander, mbe::TokenMap)>>;
67 fn parse_macro(&self, macro_file: MacroFile) 68 fn parse_macro(&self, macro_file: MacroFile)
68 -> Option<(Parse<SyntaxNode>, Arc<mbe::TokenMap>)>; 69 -> Option<(Parse<SyntaxNode>, Arc<mbe::TokenMap>)>;
69 fn macro_expand(&self, macro_call: MacroCallId) -> Result<Arc<tt::Subtree>, String>; 70 fn macro_expand(&self, macro_call: MacroCallId) -> (Option<Arc<tt::Subtree>>, Option<String>);
70 71
71 #[salsa::interned] 72 #[salsa::interned]
72 fn intern_eager_expansion(&self, eager: EagerCallLoc) -> EagerMacroId; 73 fn intern_eager_expansion(&self, eager: EagerCallLoc) -> EagerMacroId;
@@ -153,7 +154,7 @@ pub(crate) fn macro_arg(
153pub(crate) fn macro_expand( 154pub(crate) fn macro_expand(
154 db: &dyn AstDatabase, 155 db: &dyn AstDatabase,
155 id: MacroCallId, 156 id: MacroCallId,
156) -> Result<Arc<tt::Subtree>, String> { 157) -> (Option<Arc<tt::Subtree>>, Option<String>) {
157 macro_expand_with_arg(db, id, None) 158 macro_expand_with_arg(db, id, None)
158} 159}
159 160
@@ -174,31 +175,38 @@ fn macro_expand_with_arg(
174 db: &dyn AstDatabase, 175 db: &dyn AstDatabase,
175 id: MacroCallId, 176 id: MacroCallId,
176 arg: Option<Arc<(tt::Subtree, mbe::TokenMap)>>, 177 arg: Option<Arc<(tt::Subtree, mbe::TokenMap)>>,
177) -> Result<Arc<tt::Subtree>, String> { 178) -> (Option<Arc<tt::Subtree>>, Option<String>) {
178 let lazy_id = match id { 179 let lazy_id = match id {
179 MacroCallId::LazyMacro(id) => id, 180 MacroCallId::LazyMacro(id) => id,
180 MacroCallId::EagerMacro(id) => { 181 MacroCallId::EagerMacro(id) => {
181 if arg.is_some() { 182 if arg.is_some() {
182 return Err( 183 return (
183 "hypothetical macro expansion not implemented for eager macro".to_owned() 184 None,
185 Some("hypothetical macro expansion not implemented for eager macro".to_owned()),
184 ); 186 );
185 } else { 187 } else {
186 return Ok(db.lookup_intern_eager_expansion(id).subtree); 188 return (Some(db.lookup_intern_eager_expansion(id).subtree), None);
187 } 189 }
188 } 190 }
189 }; 191 };
190 192
191 let loc = db.lookup_intern_macro(lazy_id); 193 let loc = db.lookup_intern_macro(lazy_id);
192 let macro_arg = arg.or_else(|| db.macro_arg(id)).ok_or("Fail to args in to tt::TokenTree")?; 194 let macro_arg = match arg.or_else(|| db.macro_arg(id)) {
195 Some(it) => it,
196 None => return (None, Some("Fail to args in to tt::TokenTree".into())),
197 };
193 198
194 let macro_rules = db.macro_def(loc.def).ok_or("Fail to find macro definition")?; 199 let macro_rules = match db.macro_def(loc.def) {
195 let tt = macro_rules.0.expand(db, lazy_id, &macro_arg.0).map_err(|err| format!("{:?}", err))?; 200 Some(it) => it,
201 None => return (None, Some("Fail to find macro definition".into())),
202 };
203 let ExpandResult(tt, err) = macro_rules.0.expand(db, lazy_id, &macro_arg.0);
196 // Set a hard limit for the expanded tt 204 // Set a hard limit for the expanded tt
197 let count = tt.count(); 205 let count = tt.count();
198 if count > 65536 { 206 if count > 65536 {
199 return Err(format!("Total tokens count exceed limit : count = {}", count)); 207 return (None, Some(format!("Total tokens count exceed limit : count = {}", count)));
200 } 208 }
201 Ok(Arc::new(tt)) 209 (Some(Arc::new(tt)), err.map(|e| format!("{:?}", e)))
202} 210}
203 211
204pub(crate) fn parse_or_expand(db: &dyn AstDatabase, file_id: HirFileId) -> Option<SyntaxNode> { 212pub(crate) fn parse_or_expand(db: &dyn AstDatabase, file_id: HirFileId) -> Option<SyntaxNode> {
@@ -225,42 +233,41 @@ pub fn parse_macro_with_arg(
225 let _p = profile("parse_macro_query"); 233 let _p = profile("parse_macro_query");
226 234
227 let macro_call_id = macro_file.macro_call_id; 235 let macro_call_id = macro_file.macro_call_id;
228 let expansion = if let Some(arg) = arg { 236 let (tt, err) = if let Some(arg) = arg {
229 macro_expand_with_arg(db, macro_call_id, Some(arg)) 237 macro_expand_with_arg(db, macro_call_id, Some(arg))
230 } else { 238 } else {
231 db.macro_expand(macro_call_id) 239 db.macro_expand(macro_call_id)
232 }; 240 };
233 let tt = expansion 241 if let Some(err) = err {
234 .map_err(|err| { 242 // Note:
235 // Note: 243 // The final goal we would like to make all parse_macro success,
236 // The final goal we would like to make all parse_macro success, 244 // such that the following log will not call anyway.
237 // such that the following log will not call anyway. 245 match macro_call_id {
238 match macro_call_id { 246 MacroCallId::LazyMacro(id) => {
239 MacroCallId::LazyMacro(id) => { 247 let loc: MacroCallLoc = db.lookup_intern_macro(id);
240 let loc: MacroCallLoc = db.lookup_intern_macro(id); 248 let node = loc.kind.node(db);
241 let node = loc.kind.node(db); 249
242 250 // collect parent information for warning log
243 // collect parent information for warning log 251 let parents = std::iter::successors(loc.kind.file_id().call_node(db), |it| {
244 let parents = std::iter::successors(loc.kind.file_id().call_node(db), |it| { 252 it.file_id.call_node(db)
245 it.file_id.call_node(db) 253 })
246 }) 254 .map(|n| format!("{:#}", n.value))
247 .map(|n| format!("{:#}", n.value)) 255 .collect::<Vec<_>>()
248 .collect::<Vec<_>>() 256 .join("\n");
249 .join("\n"); 257
250 258 log::warn!(
251 log::warn!( 259 "fail on macro_parse: (reason: {} macro_call: {:#}) parents: {}",
252 "fail on macro_parse: (reason: {} macro_call: {:#}) parents: {}", 260 err,
253 err, 261 node.value,
254 node.value, 262 parents
255 parents 263 );
256 ); 264 }
257 } 265 _ => {
258 _ => { 266 log::warn!("fail on macro_parse: (reason: {})", err);
259 log::warn!("fail on macro_parse: (reason: {})", err);
260 }
261 } 267 }
262 }) 268 }
263 .ok()?; 269 };
270 let tt = tt?;
264 271
265 let fragment_kind = to_fragment_kind(db, macro_call_id); 272 let fragment_kind = to_fragment_kind(db, macro_call_id);
266 273