1use base_db::{Crate, RootQueryDb};
4use mbe::MatchedArmIndex;
5use span::{AstIdMap, Edition, Span, SyntaxContext};
6use syntax::{AstNode, Parse, SyntaxError, SyntaxNode, SyntaxToken, T, ast};
7use syntax_bridge::{DocCommentDesugarMode, syntax_node_to_token_tree};
8use triomphe::Arc;
9
10use crate::{
11 AstId, BuiltinAttrExpander, BuiltinDeriveExpander, BuiltinFnLikeExpander, EagerCallInfo,
12 EagerExpander, EditionedFileId, ExpandError, ExpandResult, ExpandTo, HirFileId, MacroCallId,
13 MacroCallKind, MacroCallLoc, MacroDefId, MacroDefKind,
14 attrs::Meta,
15 builtin::pseudo_derive_attr_expansion,
16 cfg_process::attr_macro_input_to_token_tree,
17 declarative::DeclarativeMacroExpander,
18 fixup::{self, SyntaxFixupUndoInfo},
19 hygiene::{span_with_call_site_ctxt, span_with_def_site_ctxt, span_with_mixed_site_ctxt},
20 proc_macro::{CrateProcMacros, CustomProcMacroExpander, ProcMacros},
21 span_map::{ExpansionSpanMap, RealSpanMap, SpanMap, SpanMapRef},
22 tt,
23};
24type MacroArgResult = (Arc<tt::TopSubtree>, SyntaxFixupUndoInfo, Span);
26const TOKEN_LIMIT: usize = 2_097_152;
33
34#[derive(Debug, Clone, Eq, PartialEq)]
35pub enum TokenExpander {
36 DeclarativeMacro(Arc<DeclarativeMacroExpander>),
38 BuiltIn(BuiltinFnLikeExpander),
40 BuiltInEager(EagerExpander),
42 BuiltInAttr(BuiltinAttrExpander),
44 BuiltInDerive(BuiltinDeriveExpander),
46 ProcMacro(CustomProcMacroExpander),
48}
49
50#[query_group::query_group]
51pub trait ExpandDatabase: RootQueryDb {
52 #[salsa::input]
54 fn proc_macros(&self) -> Arc<ProcMacros>;
55
56 #[salsa::invoke(crate::proc_macro::proc_macros_for_crate)]
58 fn proc_macros_for_crate(&self, krate: Crate) -> Option<Arc<CrateProcMacros>>;
59
60 #[salsa::invoke(ast_id_map)]
61 #[salsa::lru(1024)]
62 fn ast_id_map(&self, file_id: HirFileId) -> Arc<AstIdMap>;
63
64 #[salsa::transparent]
65 fn parse_or_expand(&self, file_id: HirFileId) -> SyntaxNode;
66
67 #[salsa::lru(512)]
69 fn parse_macro_expansion(
70 &self,
71 macro_file: MacroCallId,
72 ) -> ExpandResult<(Parse<SyntaxNode>, Arc<ExpansionSpanMap>)>;
73
74 #[salsa::transparent]
75 #[salsa::invoke(SpanMap::new)]
76 fn span_map(&self, file_id: HirFileId) -> SpanMap;
77
78 #[salsa::transparent]
79 #[salsa::invoke(crate::span_map::expansion_span_map)]
80 fn expansion_span_map(&self, file_id: MacroCallId) -> Arc<ExpansionSpanMap>;
81 #[salsa::invoke(crate::span_map::real_span_map)]
82 fn real_span_map(&self, file_id: EditionedFileId) -> Arc<RealSpanMap>;
83
84 #[salsa::transparent]
90 fn intern_macro_call(&self, macro_call: MacroCallLoc) -> MacroCallId;
91 #[salsa::transparent]
92 fn lookup_intern_macro_call(&self, macro_call: MacroCallId) -> MacroCallLoc;
93
94 #[deprecated = "calling this is incorrect, call `macro_arg_considering_derives` instead"]
98 #[salsa::invoke(macro_arg)]
99 fn macro_arg(&self, id: MacroCallId) -> MacroArgResult;
100
101 #[salsa::transparent]
102 fn macro_arg_considering_derives(
103 &self,
104 id: MacroCallId,
105 kind: &MacroCallKind,
106 ) -> MacroArgResult;
107
108 #[salsa::transparent]
110 #[salsa::invoke(TokenExpander::macro_expander)]
111 fn macro_expander(&self, id: MacroDefId) -> TokenExpander;
112
113 #[salsa::invoke(DeclarativeMacroExpander::expander)]
115 fn decl_macro_expander(
116 &self,
117 def_crate: Crate,
118 id: AstId<ast::Macro>,
119 ) -> Arc<DeclarativeMacroExpander>;
120
121 #[salsa::invoke(expand_proc_macro)]
126 fn expand_proc_macro(&self, call: MacroCallId) -> ExpandResult<Arc<tt::TopSubtree>>;
127 #[salsa::invoke_interned(proc_macro_span)]
133 fn proc_macro_span(&self, fun: AstId<ast::Fn>) -> Span;
134
135 #[salsa::invoke(parse_macro_expansion_error)]
137 fn parse_macro_expansion_error(
138 &self,
139 macro_call: MacroCallId,
140 ) -> Option<Arc<ExpandResult<Arc<[SyntaxError]>>>>;
141
142 #[salsa::transparent]
143 fn syntax_context(&self, file: HirFileId, edition: Edition) -> SyntaxContext;
144}
145
146#[salsa_macros::interned(no_lifetime, id = span::SyntaxContext, revisions = usize::MAX)]
147pub struct SyntaxContextWrapper {
148 pub data: SyntaxContext,
149}
150
151fn syntax_context(db: &dyn ExpandDatabase, file: HirFileId, edition: Edition) -> SyntaxContext {
152 match file {
153 HirFileId::FileId(_) => SyntaxContext::root(edition),
154 HirFileId::MacroFile(m) => {
155 let kind = db.lookup_intern_macro_call(m).kind;
156 db.macro_arg_considering_derives(m, &kind).2.ctx
157 }
158 }
159}
160
161pub fn expand_speculative(
166 db: &dyn ExpandDatabase,
167 actual_macro_call: MacroCallId,
168 speculative_args: &SyntaxNode,
169 token_to_map: SyntaxToken,
170) -> Option<(SyntaxNode, Vec<(SyntaxToken, u8)>)> {
171 let loc = db.lookup_intern_macro_call(actual_macro_call);
172 let (_, _, span) = db.macro_arg_considering_derives(actual_macro_call, &loc.kind);
173
174 let span_map = RealSpanMap::absolute(span.anchor.file_id);
175 let span_map = SpanMapRef::RealSpanMap(&span_map);
176
177 let (mut tt, undo_info) = match &loc.kind {
179 MacroCallKind::FnLike { .. } => (
180 syntax_bridge::syntax_node_to_token_tree(
181 speculative_args,
182 span_map,
183 span,
184 if loc.def.is_proc_macro() {
185 DocCommentDesugarMode::ProcMacro
186 } else {
187 DocCommentDesugarMode::Mbe
188 },
189 ),
190 SyntaxFixupUndoInfo::NONE,
191 ),
192 MacroCallKind::Attr { .. } if loc.def.is_attribute_derive() => (
193 syntax_bridge::syntax_node_to_token_tree(
194 speculative_args,
195 span_map,
196 span,
197 DocCommentDesugarMode::ProcMacro,
198 ),
199 SyntaxFixupUndoInfo::NONE,
200 ),
201 MacroCallKind::Derive { derive_macro_id, .. } => {
202 let MacroCallKind::Attr { censored_attr_ids: attr_ids, .. } =
203 &derive_macro_id.loc(db).kind
204 else {
205 unreachable!("`derive_macro_id` should be `MacroCallKind::Attr`");
206 };
207 attr_macro_input_to_token_tree(
208 db,
209 speculative_args,
210 span_map,
211 span,
212 true,
213 attr_ids,
214 loc.krate,
215 )
216 }
217 MacroCallKind::Attr { censored_attr_ids: attr_ids, .. } => attr_macro_input_to_token_tree(
218 db,
219 speculative_args,
220 span_map,
221 span,
222 false,
223 attr_ids,
224 loc.krate,
225 ),
226 };
227
228 let attr_arg = match &loc.kind {
229 MacroCallKind::Attr { censored_attr_ids: attr_ids, .. } => {
230 if loc.def.is_attribute_derive() {
231 ast::Attr::cast(speculative_args.clone()).and_then(|attr| attr.token_tree()).map(
233 |token_tree| {
234 let mut tree = syntax_node_to_token_tree(
235 token_tree.syntax(),
236 span_map,
237 span,
238 DocCommentDesugarMode::ProcMacro,
239 );
240 *tree.top_subtree_delimiter_mut() = tt::Delimiter::invisible_spanned(span);
241 tree
242 },
243 )
244 } else {
245 let item = ast::Item::cast(speculative_args.clone())?;
248 let (_, _, _, meta) =
249 attr_ids.invoc_attr().find_attr_range_with_source(db, loc.krate, &item);
250 match meta {
251 Meta::TokenTree { tt, .. } => {
252 let mut attr_arg = syntax_bridge::syntax_node_to_token_tree(
253 tt.syntax(),
254 span_map,
255 span,
256 DocCommentDesugarMode::ProcMacro,
257 );
258 attr_arg.top_subtree_delimiter_mut().kind = tt::DelimiterKind::Invisible;
259 Some(attr_arg)
260 }
261 _ => None,
262 }
263 }
264 }
265 _ => None,
266 };
267
268 let mut speculative_expansion = match loc.def.kind {
271 MacroDefKind::ProcMacro(ast, expander, _) => {
272 let span = db.proc_macro_span(ast);
273 *tt.top_subtree_delimiter_mut() = tt::Delimiter::invisible_spanned(span);
274 expander.expand(
275 db,
276 loc.def.krate,
277 loc.krate,
278 &tt,
279 attr_arg.as_ref(),
280 span_with_def_site_ctxt(db, span, actual_macro_call.into(), loc.def.edition),
281 span_with_call_site_ctxt(db, span, actual_macro_call.into(), loc.def.edition),
282 span_with_mixed_site_ctxt(db, span, actual_macro_call.into(), loc.def.edition),
283 )
284 }
285 MacroDefKind::BuiltInAttr(_, it) if it.is_derive() => {
286 pseudo_derive_attr_expansion(&tt, attr_arg.as_ref()?, span)
287 }
288 MacroDefKind::Declarative(it, _) => db
289 .decl_macro_expander(loc.krate, it)
290 .expand_unhygienic(db, tt, loc.kind.call_style(), span),
291 MacroDefKind::BuiltIn(_, it) => {
292 it.expand(db, actual_macro_call, &tt, span).map_err(Into::into)
293 }
294 MacroDefKind::BuiltInDerive(_, it) => {
295 it.expand(db, actual_macro_call, &tt, span).map_err(Into::into)
296 }
297 MacroDefKind::BuiltInEager(_, it) => {
298 it.expand(db, actual_macro_call, &tt, span).map_err(Into::into)
299 }
300 MacroDefKind::BuiltInAttr(_, it) => it.expand(db, actual_macro_call, &tt, span),
301 };
302
303 let expand_to = loc.expand_to();
304
305 fixup::reverse_fixups(&mut speculative_expansion.value, &undo_info);
306 let (node, rev_tmap) = token_tree_to_syntax_node(db, &speculative_expansion.value, expand_to);
307
308 let syntax_node = node.syntax_node();
309 let token = rev_tmap
310 .ranges_with_span(span_map.span_for_range(token_to_map.text_range()))
311 .filter_map(|(range, ctx)| syntax_node.covering_element(range).into_token().zip(Some(ctx)))
312 .map(|(t, ctx)| {
313 let ranking = ctx.is_opaque(db) as u8
317 + 2 * (t.kind() != token_to_map.kind()) as u8
318 + 4 * ((t.text() != token_to_map.text()) as u8);
319 (t, ranking)
320 })
321 .collect();
322 Some((node.syntax_node(), token))
323}
324
325fn ast_id_map(db: &dyn ExpandDatabase, file_id: HirFileId) -> triomphe::Arc<AstIdMap> {
326 triomphe::Arc::new(AstIdMap::from_source(&db.parse_or_expand(file_id)))
327}
328
329fn parse_or_expand(db: &dyn ExpandDatabase, file_id: HirFileId) -> SyntaxNode {
332 match file_id {
333 HirFileId::FileId(file_id) => db.parse(file_id).syntax_node(),
334 HirFileId::MacroFile(macro_file) => {
335 db.parse_macro_expansion(macro_file).value.0.syntax_node()
336 }
337 }
338}
339
340fn parse_macro_expansion(
343 db: &dyn ExpandDatabase,
344 macro_file: MacroCallId,
345) -> ExpandResult<(Parse<SyntaxNode>, Arc<ExpansionSpanMap>)> {
346 let _p = tracing::info_span!("parse_macro_expansion").entered();
347 let loc = db.lookup_intern_macro_call(macro_file);
348 let expand_to = loc.expand_to();
349 let mbe::ValueResult { value: (tt, matched_arm), err } = macro_expand(db, macro_file, loc);
350
351 let (parse, mut rev_token_map) = token_tree_to_syntax_node(
352 db,
353 match &tt {
354 CowArc::Arc(it) => it,
355 CowArc::Owned(it) => it,
356 },
357 expand_to,
358 );
359 rev_token_map.matched_arm = matched_arm;
360
361 ExpandResult { value: (parse, Arc::new(rev_token_map)), err }
362}
363
364fn parse_macro_expansion_error(
365 db: &dyn ExpandDatabase,
366 macro_call_id: MacroCallId,
367) -> Option<Arc<ExpandResult<Arc<[SyntaxError]>>>> {
368 let e: ExpandResult<Arc<[SyntaxError]>> =
369 db.parse_macro_expansion(macro_call_id).map(|it| Arc::from(it.0.errors()));
370 if e.value.is_empty() && e.err.is_none() { None } else { Some(Arc::new(e)) }
371}
372
373pub(crate) fn parse_with_map(
374 db: &dyn ExpandDatabase,
375 file_id: HirFileId,
376) -> (Parse<SyntaxNode>, SpanMap) {
377 match file_id {
378 HirFileId::FileId(file_id) => {
379 (db.parse(file_id).to_syntax(), SpanMap::RealSpanMap(db.real_span_map(file_id)))
380 }
381 HirFileId::MacroFile(macro_file) => {
382 let (parse, map) = db.parse_macro_expansion(macro_file).value;
383 (parse, SpanMap::ExpansionSpanMap(map))
384 }
385 }
386}
387
388#[allow(deprecated)] fn macro_arg_considering_derives(
394 db: &dyn ExpandDatabase,
395 id: MacroCallId,
396 kind: &MacroCallKind,
397) -> MacroArgResult {
398 match kind {
399 MacroCallKind::Derive { derive_macro_id, .. } => db.macro_arg(*derive_macro_id),
401 _ => db.macro_arg(id),
403 }
404}
405
406fn macro_arg(db: &dyn ExpandDatabase, id: MacroCallId) -> MacroArgResult {
407 let loc = db.lookup_intern_macro_call(id);
408
409 if let MacroCallLoc {
410 def: MacroDefId { kind: MacroDefKind::BuiltInEager(..), .. },
411 kind: MacroCallKind::FnLike { eager: Some(eager), .. },
412 ..
413 } = &loc
414 {
415 return (eager.arg.clone(), SyntaxFixupUndoInfo::NONE, eager.span);
416 }
417
418 let (parse, map) = parse_with_map(db, loc.kind.file_id());
419 let root = parse.syntax_node();
420
421 let (is_derive, censor_item_tree_attr_ids, item_node, span) = match &loc.kind {
422 MacroCallKind::FnLike { ast_id, .. } => {
423 let node = &ast_id.to_ptr(db).to_node(&root);
424 let path_range = node
425 .path()
426 .map_or_else(|| node.syntax().text_range(), |path| path.syntax().text_range());
427 let span = map.span_for_range(path_range);
428
429 let dummy_tt = |kind| {
430 (
431 Arc::new(tt::TopSubtree::from_token_trees(
432 tt::Delimiter { open: span, close: span, kind },
433 tt::TokenTreesView::new(&[]),
434 )),
435 SyntaxFixupUndoInfo::default(),
436 span,
437 )
438 };
439
440 let Some(tt) = node.token_tree() else {
441 return dummy_tt(tt::DelimiterKind::Invisible);
442 };
443 let first = tt.left_delimiter_token().map(|it| it.kind()).unwrap_or(T!['(']);
444 let last = tt.right_delimiter_token().map(|it| it.kind()).unwrap_or(T![.]);
445
446 let mismatched_delimiters = !matches!(
447 (first, last),
448 (T!['('], T![')']) | (T!['['], T![']']) | (T!['{'], T!['}'])
449 );
450 if mismatched_delimiters {
451 cov_mark::hit!(issue9358_bad_macro_stack_overflow);
458
459 let kind = match first {
460 _ if loc.def.is_proc_macro() => tt::DelimiterKind::Invisible,
461 T!['('] => tt::DelimiterKind::Parenthesis,
462 T!['['] => tt::DelimiterKind::Bracket,
463 T!['{'] => tt::DelimiterKind::Brace,
464 _ => tt::DelimiterKind::Invisible,
465 };
466 return dummy_tt(kind);
467 }
468
469 let mut tt = syntax_bridge::syntax_node_to_token_tree(
470 tt.syntax(),
471 map.as_ref(),
472 span,
473 if loc.def.is_proc_macro() {
474 DocCommentDesugarMode::ProcMacro
475 } else {
476 DocCommentDesugarMode::Mbe
477 },
478 );
479 if loc.def.is_proc_macro() {
480 tt.top_subtree_delimiter_mut().kind = tt::DelimiterKind::Invisible;
482 }
483 return (Arc::new(tt), SyntaxFixupUndoInfo::NONE, span);
484 }
485 MacroCallKind::Derive { .. } => {
487 unreachable!("`ExpandDatabase::macro_arg` called with `MacroCallKind::Derive`")
488 }
489 MacroCallKind::Attr { ast_id, censored_attr_ids: attr_ids, .. } => {
490 let node = ast_id.to_ptr(db).to_node(&root);
491 let range = attr_ids
492 .invoc_attr()
493 .find_attr_range_with_source(db, loc.krate, &node)
494 .3
495 .path_range();
496 let span = map.span_for_range(range);
497
498 let is_derive = matches!(loc.def.kind, MacroDefKind::BuiltInAttr(_, expander) if expander.is_derive());
499 (is_derive, &**attr_ids, node, span)
500 }
501 };
502
503 let (mut tt, undo_info) = attr_macro_input_to_token_tree(
504 db,
505 item_node.syntax(),
506 map.as_ref(),
507 span,
508 is_derive,
509 censor_item_tree_attr_ids,
510 loc.krate,
511 );
512
513 if loc.def.is_proc_macro() {
514 tt.top_subtree_delimiter_mut().kind = tt::DelimiterKind::Invisible;
516 }
517
518 (Arc::new(tt), undo_info, span)
519}
520
521impl TokenExpander {
522 fn macro_expander(db: &dyn ExpandDatabase, id: MacroDefId) -> TokenExpander {
523 match id.kind {
524 MacroDefKind::Declarative(ast_id, _) => {
525 TokenExpander::DeclarativeMacro(db.decl_macro_expander(id.krate, ast_id))
526 }
527 MacroDefKind::BuiltIn(_, expander) => TokenExpander::BuiltIn(expander),
528 MacroDefKind::BuiltInAttr(_, expander) => TokenExpander::BuiltInAttr(expander),
529 MacroDefKind::BuiltInDerive(_, expander) => TokenExpander::BuiltInDerive(expander),
530 MacroDefKind::BuiltInEager(_, expander) => TokenExpander::BuiltInEager(expander),
531 MacroDefKind::ProcMacro(_, expander, _) => TokenExpander::ProcMacro(expander),
532 }
533 }
534}
535
536enum CowArc<T> {
537 Arc(Arc<T>),
538 Owned(T),
539}
540
541fn macro_expand(
542 db: &dyn ExpandDatabase,
543 macro_call_id: MacroCallId,
544 loc: MacroCallLoc,
545) -> ExpandResult<(CowArc<tt::TopSubtree>, MatchedArmIndex)> {
546 let _p = tracing::info_span!("macro_expand").entered();
547
548 let (ExpandResult { value: (tt, matched_arm), err }, span) = match loc.def.kind {
549 MacroDefKind::ProcMacro(..) => {
550 return db.expand_proc_macro(macro_call_id).map(CowArc::Arc).zip_val(None);
551 }
552 _ => {
553 let (macro_arg, undo_info, span) =
554 db.macro_arg_considering_derives(macro_call_id, &loc.kind);
555
556 let arg = &*macro_arg;
557 let res = match loc.def.kind {
558 MacroDefKind::Declarative(id, _) => db
559 .decl_macro_expander(loc.def.krate, id)
560 .expand(db, arg.clone(), macro_call_id, span),
561 MacroDefKind::BuiltIn(_, it) => {
562 it.expand(db, macro_call_id, arg, span).map_err(Into::into).zip_val(None)
563 }
564 MacroDefKind::BuiltInDerive(_, it) => {
565 it.expand(db, macro_call_id, arg, span).map_err(Into::into).zip_val(None)
566 }
567 MacroDefKind::BuiltInEager(_, it) => {
568 let eager = match &loc.kind {
575 MacroCallKind::FnLike { eager: None, .. } => {
576 return ExpandResult::ok(CowArc::Arc(macro_arg.clone())).zip_val(None);
577 }
578 MacroCallKind::FnLike { eager: Some(eager), .. } => Some(&**eager),
579 _ => None,
580 };
581
582 let mut res = it.expand(db, macro_call_id, arg, span).map_err(Into::into);
583
584 if let Some(EagerCallInfo { error, .. }) = eager {
585 res.err = error.clone().or(res.err);
587 }
588 res.zip_val(None)
589 }
590 MacroDefKind::BuiltInAttr(_, it) => {
591 let mut res = it.expand(db, macro_call_id, arg, span);
592 fixup::reverse_fixups(&mut res.value, &undo_info);
593 res.zip_val(None)
594 }
595 MacroDefKind::ProcMacro(_, _, _) => unreachable!(),
596 };
597 (ExpandResult { value: res.value, err: res.err }, span)
598 }
599 };
600
601 if !loc.def.is_include() {
603 if let Err(value) = check_tt_count(&tt) {
605 return value
606 .map(|()| CowArc::Owned(tt::TopSubtree::empty(tt::DelimSpan::from_single(span))))
607 .zip_val(matched_arm);
608 }
609 }
610
611 ExpandResult { value: (CowArc::Owned(tt), matched_arm), err }
612}
613
614fn proc_macro_span(db: &dyn ExpandDatabase, ast: AstId<ast::Fn>) -> Span {
615 let root = db.parse_or_expand(ast.file_id);
616 let ast_id_map = &db.ast_id_map(ast.file_id);
617 let span_map = &db.span_map(ast.file_id);
618
619 let node = ast_id_map.get(ast.value).to_node(&root);
620 let range = ast::HasName::name(&node)
621 .map_or_else(|| node.syntax().text_range(), |name| name.syntax().text_range());
622 span_map.span_for_range(range)
623}
624
625fn expand_proc_macro(
626 db: &dyn ExpandDatabase,
627 id: MacroCallId,
628) -> ExpandResult<Arc<tt::TopSubtree>> {
629 let loc = db.lookup_intern_macro_call(id);
630 let (macro_arg, undo_info, span) = db.macro_arg_considering_derives(id, &loc.kind);
631
632 let (ast, expander) = match loc.def.kind {
633 MacroDefKind::ProcMacro(ast, expander, _) => (ast, expander),
634 _ => unreachable!(),
635 };
636
637 let attr_arg = match &loc.kind {
638 MacroCallKind::Attr { attr_args: Some(attr_args), .. } => Some(&**attr_args),
639 _ => None,
640 };
641
642 let ExpandResult { value: mut tt, err } = {
643 let span = db.proc_macro_span(ast);
644 expander.expand(
645 db,
646 loc.def.krate,
647 loc.krate,
648 ¯o_arg,
649 attr_arg,
650 span_with_def_site_ctxt(db, span, id.into(), loc.def.edition),
651 span_with_call_site_ctxt(db, span, id.into(), loc.def.edition),
652 span_with_mixed_site_ctxt(db, span, id.into(), loc.def.edition),
653 )
654 };
655
656 if let Err(value) = check_tt_count(&tt) {
658 return value.map(|()| Arc::new(tt::TopSubtree::empty(tt::DelimSpan::from_single(span))));
659 }
660
661 fixup::reverse_fixups(&mut tt, &undo_info);
662
663 ExpandResult { value: Arc::new(tt), err }
664}
665
666pub(crate) fn token_tree_to_syntax_node(
667 db: &dyn ExpandDatabase,
668 tt: &tt::TopSubtree,
669 expand_to: ExpandTo,
670) -> (Parse<SyntaxNode>, ExpansionSpanMap) {
671 let entry_point = match expand_to {
672 ExpandTo::Statements => syntax_bridge::TopEntryPoint::MacroStmts,
673 ExpandTo::Items => syntax_bridge::TopEntryPoint::MacroItems,
674 ExpandTo::Pattern => syntax_bridge::TopEntryPoint::Pattern,
675 ExpandTo::Type => syntax_bridge::TopEntryPoint::Type,
676 ExpandTo::Expr => syntax_bridge::TopEntryPoint::Expr,
677 };
678 syntax_bridge::token_tree_to_syntax_node(tt, entry_point, &mut |ctx| ctx.edition(db))
679}
680
681fn check_tt_count(tt: &tt::TopSubtree) -> Result<(), ExpandResult<()>> {
682 let tt = tt.top_subtree();
683 let count = tt.count();
684 if count <= TOKEN_LIMIT {
685 Ok(())
686 } else {
687 Err(ExpandResult {
688 value: (),
689 err: Some(ExpandError::other(
690 tt.delimiter.open,
691 format!(
692 "macro invocation exceeds token limit: produced {count} tokens, limit is {TOKEN_LIMIT}",
693 ),
694 )),
695 })
696 }
697}
698
699fn intern_macro_call(db: &dyn ExpandDatabase, macro_call: MacroCallLoc) -> MacroCallId {
700 MacroCallId::new(db, macro_call)
701}
702
703fn lookup_intern_macro_call(db: &dyn ExpandDatabase, macro_call: MacroCallId) -> MacroCallLoc {
704 macro_call.loc(db)
705}