]> git.proxmox.com Git - rustc.git/blame - src/tools/rust-analyzer/crates/hir-expand/src/eager.rs
bump version to 1.80.1+dfsg1-1~bpo12+pve1
[rustc.git] / src / tools / rust-analyzer / crates / hir-expand / src / eager.rs
CommitLineData
064997fb
FG
1//! Eager expansion related utils
2//!
3//! Here is a dump of a discussion from Vadim Petrochenkov about Eager Expansion and
4//! Its name resolution :
5//!
6//! > Eagerly expanded macros (and also macros eagerly expanded by eagerly expanded macros,
7//! > which actually happens in practice too!) are resolved at the location of the "root" macro
8//! > that performs the eager expansion on its arguments.
9//! > If some name cannot be resolved at the eager expansion time it's considered unresolved,
10//! > even if becomes available later (e.g. from a glob import or other macro).
11//!
12//! > Eagerly expanded macros don't add anything to the module structure of the crate and
13//! > don't build any speculative module structures, i.e. they are expanded in a "flat"
14//! > way even if tokens in them look like modules.
15//!
16//! > In other words, it kinda works for simple cases for which it was originally intended,
17//! > and we need to live with it because it's available on stable and widely relied upon.
18//!
19//!
20//! See the full discussion : <https://rust-lang.zulipchat.com/#narrow/stream/131828-t-compiler/topic/Eager.20expansion.20of.20built-in.20macros>
c0240ec0 21use base_db::CrateId;
31ef2f64 22use mbe::DocCommentDesugarMode;
e8be2606 23use span::SyntaxContextId;
4b012472 24use syntax::{ted, Parse, SyntaxElement, SyntaxNode, TextSize, WalkEvent};
fe692bf9 25use triomphe::Arc;
064997fb
FG
26
27use crate::{
28 ast::{self, AstNode},
353b0b11 29 db::ExpandDatabase,
064997fb 30 mod_path::ModPath,
e8be2606 31 AstId, EagerCallInfo, ExpandError, ExpandResult, ExpandTo, ExpansionSpanMap, InFile, Intern,
c0240ec0 32 MacroCallId, MacroCallKind, MacroCallLoc, MacroDefId, MacroDefKind,
064997fb
FG
33};
34
fe692bf9 35pub fn expand_eager_macro_input(
353b0b11 36 db: &dyn ExpandDatabase,
064997fb 37 krate: CrateId,
e8be2606
FG
38 macro_call: &ast::MacroCall,
39 ast_id: AstId<ast::MacroCall>,
064997fb 40 def: MacroDefId,
e8be2606 41 call_site: SyntaxContextId,
064997fb 42 resolver: &dyn Fn(ModPath) -> Option<MacroDefId>,
add651ee 43) -> ExpandResult<Option<MacroCallId>> {
e8be2606 44 let expand_to = ExpandTo::from_call_site(macro_call);
064997fb
FG
45
46 // Note:
fe692bf9
FG
47 // When `lazy_expand` is called, its *parent* file must already exist.
48 // Here we store an eager macro id for the argument expanded subtree
064997fb 49 // for that purpose.
c0240ec0 50 let arg_id = MacroCallLoc {
064997fb
FG
51 def,
52 krate,
e8be2606
FG
53 kind: MacroCallKind::FnLike { ast_id, expand_to: ExpandTo::Expr, eager: None },
54 ctxt: call_site,
c0240ec0
FG
55 }
56 .intern(db);
e8be2606 57 let (_, _, span) = db.macro_arg(arg_id);
add651ee
FG
58 let ExpandResult { value: (arg_exp, arg_exp_map), err: parse_err } =
59 db.parse_macro_expansion(arg_id.as_macro_file());
4b012472
FG
60
61 let mut arg_map = ExpansionSpanMap::empty();
add651ee
FG
62
63 let ExpandResult { value: expanded_eager_input, err } = {
64 eager_macro_recur(
65 db,
4b012472
FG
66 &arg_exp_map,
67 &mut arg_map,
68 TextSize::new(0),
add651ee
FG
69 InFile::new(arg_id.as_file(), arg_exp.syntax_node()),
70 krate,
4b012472 71 call_site,
add651ee
FG
72 resolver,
73 )
fe692bf9 74 };
add651ee 75 let err = parse_err.or(err);
4b012472
FG
76 if cfg!(debug_assertions) {
77 arg_map.finish();
78 }
add651ee 79
4b012472 80 let Some((expanded_eager_input, _mapping)) = expanded_eager_input else {
add651ee
FG
81 return ExpandResult { value: None, err };
82 };
83
31ef2f64
FG
84 let mut subtree = mbe::syntax_node_to_token_tree(
85 &expanded_eager_input,
86 arg_map,
87 span,
88 DocCommentDesugarMode::Mbe,
89 );
add651ee 90
c0240ec0 91 subtree.delimiter.kind = crate::tt::DelimiterKind::Invisible;
064997fb 92
fe692bf9
FG
93 let loc = MacroCallLoc {
94 def,
95 krate,
e8be2606
FG
96 kind: MacroCallKind::FnLike {
97 ast_id,
98 expand_to,
99 eager: Some(Arc::new(EagerCallInfo {
100 arg: Arc::new(subtree),
101 arg_id,
102 error: err.clone(),
103 span,
104 })),
105 },
106 ctxt: call_site,
fe692bf9 107 };
064997fb 108
c0240ec0 109 ExpandResult { value: Some(loc.intern(db)), err }
064997fb
FG
110}
111
112fn lazy_expand(
353b0b11 113 db: &dyn ExpandDatabase,
064997fb 114 def: &MacroDefId,
e8be2606
FG
115 macro_call: &ast::MacroCall,
116 ast_id: AstId<ast::MacroCall>,
064997fb 117 krate: CrateId,
e8be2606 118 call_site: SyntaxContextId,
4b012472 119) -> ExpandResult<(InFile<Parse<SyntaxNode>>, Arc<ExpansionSpanMap>)> {
e8be2606
FG
120 let expand_to = ExpandTo::from_call_site(macro_call);
121 let id = def.make_call(
122 db,
123 krate,
124 MacroCallKind::FnLike { ast_id, expand_to, eager: None },
125 call_site,
126 );
fe692bf9 127 let macro_file = id.as_macro_file();
064997fb 128
add651ee
FG
129 db.parse_macro_expansion(macro_file)
130 .map(|parse| (InFile::new(macro_file.into(), parse.0), parse.1))
064997fb
FG
131}
132
133fn eager_macro_recur(
353b0b11 134 db: &dyn ExpandDatabase,
4b012472
FG
135 span_map: &ExpansionSpanMap,
136 expanded_map: &mut ExpansionSpanMap,
137 mut offset: TextSize,
064997fb
FG
138 curr: InFile<SyntaxNode>,
139 krate: CrateId,
e8be2606 140 call_site: SyntaxContextId,
064997fb 141 macro_resolver: &dyn Fn(ModPath) -> Option<MacroDefId>,
4b012472 142) -> ExpandResult<Option<(SyntaxNode, TextSize)>> {
064997fb
FG
143 let original = curr.value.clone_for_update();
144
064997fb
FG
145 let mut replacements = Vec::new();
146
add651ee 147 // FIXME: We only report a single error inside of eager expansions
fe692bf9 148 let mut error = None;
add651ee 149 let mut children = original.preorder_with_tokens();
fe692bf9 150
064997fb 151 // Collect replacement
add651ee 152 while let Some(child) = children.next() {
add651ee 153 let call = match child {
4b012472 154 WalkEvent::Enter(SyntaxElement::Node(child)) => match ast::MacroCall::cast(child) {
add651ee
FG
155 Some(it) => {
156 children.skip_subtree();
157 it
158 }
4b012472 159 _ => continue,
add651ee 160 },
4b012472
FG
161 WalkEvent::Enter(_) => continue,
162 WalkEvent::Leave(child) => {
163 if let SyntaxElement::Token(t) = child {
164 let start = t.text_range().start();
165 offset += t.text_range().len();
166 expanded_map.push(offset, span_map.span_at(start));
167 }
add651ee
FG
168 continue;
169 }
170 };
4b012472 171
c620b35d
FG
172 let def = match call.path().and_then(|path| {
173 ModPath::from_src(db, path, &mut |range| span_map.span_at(range.start()).ctx)
174 }) {
add651ee
FG
175 Some(path) => match macro_resolver(path.clone()) {
176 Some(def) => def,
177 None => {
178 error =
179 Some(ExpandError::other(format!("unresolved macro {}", path.display(db))));
4b012472 180 offset += call.syntax().text_range().len();
add651ee
FG
181 continue;
182 }
183 },
064997fb 184 None => {
fe692bf9 185 error = Some(ExpandError::other("malformed macro invocation"));
4b012472 186 offset += call.syntax().text_range().len();
064997fb
FG
187 continue;
188 }
189 };
e8be2606 190 let ast_id = db.ast_id_map(curr.file_id).ast_id(&call);
fe692bf9 191 let ExpandResult { value, err } = match def.kind {
064997fb 192 MacroDefKind::BuiltInEager(..) => {
add651ee 193 let ExpandResult { value, err } = expand_eager_macro_input(
064997fb
FG
194 db,
195 krate,
e8be2606
FG
196 &call,
197 curr.with_value(ast_id),
064997fb 198 def,
4b012472 199 call_site,
064997fb 200 macro_resolver,
add651ee 201 );
fe692bf9 202 match value {
add651ee 203 Some(call_id) => {
4b012472 204 let ExpandResult { value: (parse, map), err: err2 } =
add651ee
FG
205 db.parse_macro_expansion(call_id.as_macro_file());
206
4b012472 207 map.iter().for_each(|(o, span)| expanded_map.push(o + offset, span));
add651ee 208
4b012472 209 let syntax_node = parse.syntax_node();
fe692bf9 210 ExpandResult {
4b012472
FG
211 value: Some((
212 syntax_node.clone_for_update(),
213 offset + syntax_node.text_range().len(),
214 )),
fe692bf9
FG
215 err: err.or(err2),
216 }
217 }
218 None => ExpandResult { value: None, err },
219 }
064997fb
FG
220 }
221 MacroDefKind::Declarative(_)
222 | MacroDefKind::BuiltIn(..)
223 | MacroDefKind::BuiltInAttr(..)
224 | MacroDefKind::BuiltInDerive(..)
225 | MacroDefKind::ProcMacro(..) => {
add651ee 226 let ExpandResult { value: (parse, tm), err } =
e8be2606 227 lazy_expand(db, &def, &call, curr.with_value(ast_id), krate, call_site);
064997fb
FG
228
229 // replace macro inside
fe692bf9
FG
230 let ExpandResult { value, err: error } = eager_macro_recur(
231 db,
4b012472
FG
232 &tm,
233 expanded_map,
234 offset,
fe692bf9 235 // FIXME: We discard parse errors here
add651ee 236 parse.as_ref().map(|it| it.syntax_node()),
fe692bf9 237 krate,
4b012472 238 call_site,
fe692bf9 239 macro_resolver,
add651ee 240 );
fe692bf9 241 let err = err.or(error);
add651ee 242
4b012472 243 ExpandResult { value, err }
064997fb
FG
244 }
245 };
fe692bf9
FG
246 if err.is_some() {
247 error = err;
248 }
064997fb 249 // check if the whole original syntax is replaced
add651ee 250 if call.syntax() == &original {
4b012472 251 return ExpandResult { value, err: error };
064997fb
FG
252 }
253
4b012472
FG
254 match value {
255 Some((insert, new_offset)) => {
256 replacements.push((call, insert));
257 offset = new_offset;
258 }
259 None => offset += call.syntax().text_range().len(),
fe692bf9 260 }
064997fb
FG
261 }
262
263 replacements.into_iter().rev().for_each(|(old, new)| ted::replace(old.syntax(), new));
4b012472 264 ExpandResult { value: Some((original, offset)), err: error }
064997fb 265}