diff options
Diffstat (limited to 'crates/hir_def/src/body.rs')
-rw-r--r-- | crates/hir_def/src/body.rs | 73 |
1 files changed, 50 insertions, 23 deletions
diff --git a/crates/hir_def/src/body.rs b/crates/hir_def/src/body.rs index d10b1af01..33eb5e78c 100644 --- a/crates/hir_def/src/body.rs +++ b/crates/hir_def/src/body.rs | |||
@@ -14,8 +14,8 @@ use cfg::CfgOptions; | |||
14 | use drop_bomb::DropBomb; | 14 | use drop_bomb::DropBomb; |
15 | use either::Either; | 15 | use either::Either; |
16 | use hir_expand::{ | 16 | use hir_expand::{ |
17 | ast_id_map::AstIdMap, diagnostics::DiagnosticSink, hygiene::Hygiene, AstId, HirFileId, InFile, | 17 | ast_id_map::AstIdMap, diagnostics::DiagnosticSink, hygiene::Hygiene, AstId, ExpandResult, |
18 | MacroDefId, | 18 | HirFileId, InFile, MacroDefId, |
19 | }; | 19 | }; |
20 | use rustc_hash::FxHashMap; | 20 | use rustc_hash::FxHashMap; |
21 | use syntax::{ast, AstNode, AstPtr}; | 21 | use syntax::{ast, AstNode, AstPtr}; |
@@ -102,11 +102,11 @@ impl Expander { | |||
102 | db: &dyn DefDatabase, | 102 | db: &dyn DefDatabase, |
103 | local_scope: Option<&ItemScope>, | 103 | local_scope: Option<&ItemScope>, |
104 | macro_call: ast::MacroCall, | 104 | macro_call: ast::MacroCall, |
105 | ) -> Option<(Mark, T)> { | 105 | ) -> ExpandResult<Option<(Mark, T)>> { |
106 | self.recursion_limit += 1; | 106 | self.recursion_limit += 1; |
107 | if self.recursion_limit > EXPANSION_RECURSION_LIMIT { | 107 | if self.recursion_limit > EXPANSION_RECURSION_LIMIT { |
108 | mark::hit!(your_stack_belongs_to_me); | 108 | mark::hit!(your_stack_belongs_to_me); |
109 | return None; | 109 | return ExpandResult::str_err("reached recursion limit during macro expansion".into()); |
110 | } | 110 | } |
111 | 111 | ||
112 | let macro_call = InFile::new(self.current_file_id, ¯o_call); | 112 | let macro_call = InFile::new(self.current_file_id, ¯o_call); |
@@ -120,28 +120,55 @@ impl Expander { | |||
120 | self.resolve_path_as_macro(db, &path) | 120 | self.resolve_path_as_macro(db, &path) |
121 | }; | 121 | }; |
122 | 122 | ||
123 | if let Some(call_id) = macro_call.as_call_id(db, self.crate_def_map.krate, resolver) { | 123 | let call_id = match macro_call.as_call_id(db, self.crate_def_map.krate, resolver) { |
124 | let file_id = call_id.as_file(); | 124 | Some(it) => it, |
125 | if let Some(node) = db.parse_or_expand(file_id) { | 125 | None => { |
126 | if let Some(expr) = T::cast(node) { | 126 | // FIXME: this can mean other things too, but `as_call_id` doesn't provide enough |
127 | log::debug!("macro expansion {:#?}", expr.syntax()); | 127 | // info. |
128 | 128 | return ExpandResult::only_err(mbe::ExpandError::Other( | |
129 | let mark = Mark { | 129 | "failed to parse or resolve macro invocation".into(), |
130 | file_id: self.current_file_id, | 130 | )); |
131 | ast_id_map: mem::take(&mut self.ast_id_map), | 131 | } |
132 | bomb: DropBomb::new("expansion mark dropped"), | 132 | }; |
133 | }; | 133 | |
134 | self.cfg_expander.hygiene = Hygiene::new(db.upcast(), file_id); | 134 | let err = db.macro_expand_error(call_id); |
135 | self.current_file_id = file_id; | 135 | |
136 | self.ast_id_map = db.ast_id_map(file_id); | 136 | let file_id = call_id.as_file(); |
137 | return Some((mark, expr)); | 137 | |
138 | let raw_node = match db.parse_or_expand(file_id) { | ||
139 | Some(it) => it, | ||
140 | None => { | ||
141 | // Only `None` if the macro expansion produced no usable AST. | ||
142 | if err.is_none() { | ||
143 | log::warn!("no error despite `parse_or_expand` failing"); | ||
138 | } | 144 | } |
145 | |||
146 | return ExpandResult::only_err(err.unwrap_or_else(|| { | ||
147 | mbe::ExpandError::Other("failed to parse macro invocation".into()) | ||
148 | })); | ||
139 | } | 149 | } |
140 | } | 150 | }; |
151 | |||
152 | let node = match T::cast(raw_node) { | ||
153 | Some(it) => it, | ||
154 | None => { | ||
155 | // This can happen without being an error, so only forward previous errors. | ||
156 | return ExpandResult { value: None, err }; | ||
157 | } | ||
158 | }; | ||
159 | |||
160 | log::debug!("macro expansion {:#?}", node.syntax()); | ||
161 | |||
162 | let mark = Mark { | ||
163 | file_id: self.current_file_id, | ||
164 | ast_id_map: mem::take(&mut self.ast_id_map), | ||
165 | bomb: DropBomb::new("expansion mark dropped"), | ||
166 | }; | ||
167 | self.cfg_expander.hygiene = Hygiene::new(db.upcast(), file_id); | ||
168 | self.current_file_id = file_id; | ||
169 | self.ast_id_map = db.ast_id_map(file_id); | ||
141 | 170 | ||
142 | // FIXME: Instead of just dropping the error from expansion | 171 | ExpandResult { value: Some((mark, node)), err } |
143 | // report it | ||
144 | None | ||
145 | } | 172 | } |
146 | 173 | ||
147 | pub(crate) fn exit(&mut self, db: &dyn DefDatabase, mut mark: Mark) { | 174 | pub(crate) fn exit(&mut self, db: &dyn DefDatabase, mut mark: Mark) { |