1use std::hash::Hash;
28use std::sync::Arc;
29use std::{fmt, iter, mem};
30
31use rustc_data_structures::fingerprint::Fingerprint;
32use rustc_data_structures::fx::{FxHashMap, FxHashSet};
33use rustc_data_structures::stable_hasher::{HashStable, HashingControls, StableHasher};
34use rustc_data_structures::sync::Lock;
35use rustc_data_structures::unhash::UnhashMap;
36use rustc_hashes::Hash64;
37use rustc_index::IndexVec;
38use rustc_macros::{Decodable, Encodable, HashStable_Generic};
39use rustc_serialize::{Decodable, Decoder, Encodable, Encoder};
40use tracing::{debug, trace};
41
42use crate::def_id::{CRATE_DEF_ID, CrateNum, DefId, LOCAL_CRATE, StableCrateId};
43use crate::edition::Edition;
44use crate::symbol::{Symbol, kw, sym};
45use crate::{DUMMY_SP, HashStableContext, Span, SpanDecoder, SpanEncoder, with_session_globals};
46
47#[derive(Clone, Copy, PartialEq, Eq, Hash)]
49pub struct SyntaxContext(u32);
50
51impl !Ord for SyntaxContext {}
55impl !PartialOrd for SyntaxContext {}
56
57pub type SyntaxContextKey = (SyntaxContext, ExpnId, Transparency);
60
61#[derive(Clone, Copy, PartialEq, Debug, Encodable, Decodable)]
62struct SyntaxContextData {
63 outer_expn: ExpnId,
64 outer_transparency: Transparency,
65 parent: SyntaxContext,
66 opaque: SyntaxContext,
68 opaque_and_semitransparent: SyntaxContext,
70 dollar_crate_name: Symbol,
72}
73
74impl SyntaxContextData {
75 fn root() -> SyntaxContextData {
76 SyntaxContextData {
77 outer_expn: ExpnId::root(),
78 outer_transparency: Transparency::Opaque,
79 parent: SyntaxContext::root(),
80 opaque: SyntaxContext::root(),
81 opaque_and_semitransparent: SyntaxContext::root(),
82 dollar_crate_name: kw::DollarCrate,
83 }
84 }
85
86 fn decode_placeholder() -> SyntaxContextData {
87 SyntaxContextData { dollar_crate_name: kw::Empty, ..SyntaxContextData::root() }
88 }
89
90 fn is_decode_placeholder(&self) -> bool {
91 self.dollar_crate_name == kw::Empty
92 }
93
94 fn new(
95 (parent, outer_expn, outer_transparency): SyntaxContextKey,
96 opaque: SyntaxContext,
97 opaque_and_semitransparent: SyntaxContext,
98 ) -> Self {
99 SyntaxContextData {
100 parent,
101 outer_expn,
102 outer_transparency,
103 opaque,
104 opaque_and_semitransparent,
105 dollar_crate_name: kw::DollarCrate,
106 }
107 }
108
109 fn key(&self) -> SyntaxContextKey {
110 (self.parent, self.outer_expn, self.outer_transparency)
111 }
112}
113
114rustc_index::newtype_index! {
115 #[orderable]
117 pub struct ExpnIndex {}
118}
119
120#[derive(Clone, Copy, PartialEq, Eq, Hash)]
122pub struct ExpnId {
123 pub krate: CrateNum,
124 pub local_id: ExpnIndex,
125}
126
127impl fmt::Debug for ExpnId {
128 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
129 write!(f, "{:?}::{{{{expn{}}}}}", self.krate, self.local_id.as_u32())
131 }
132}
133
134rustc_index::newtype_index! {
135 #[debug_format = "expn{}"]
137 pub struct LocalExpnId {}
138}
139
140impl !Ord for LocalExpnId {}
144impl !PartialOrd for LocalExpnId {}
145
146fn assert_default_hashing_controls<CTX: HashStableContext>(ctx: &CTX, msg: &str) {
152 match ctx.hashing_controls() {
153 HashingControls { hash_spans }
162 if hash_spans != ctx.unstable_opts_incremental_ignore_spans() => {}
163 other => panic!("Attempted hashing of {msg} with non-default HashingControls: {other:?}"),
164 }
165}
166
167#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, Encodable, Decodable, HashStable_Generic)]
169pub struct ExpnHash(Fingerprint);
170
171impl ExpnHash {
172 #[inline]
175 pub fn stable_crate_id(self) -> StableCrateId {
176 StableCrateId(self.0.split().0)
177 }
178
179 #[inline]
183 pub fn local_hash(self) -> Hash64 {
184 self.0.split().1
185 }
186
187 #[inline]
188 pub fn is_root(self) -> bool {
189 self.0 == Fingerprint::ZERO
190 }
191
192 fn new(stable_crate_id: StableCrateId, local_hash: Hash64) -> ExpnHash {
195 ExpnHash(Fingerprint::new(stable_crate_id.0, local_hash))
196 }
197}
198
199#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Hash, Debug, Encodable, Decodable)]
202#[derive(HashStable_Generic)]
203pub enum Transparency {
204 Transparent,
207 SemiTransparent,
214 Opaque,
217}
218
219impl Transparency {
220 pub fn fallback(macro_rules: bool) -> Self {
221 if macro_rules { Transparency::SemiTransparent } else { Transparency::Opaque }
222 }
223}
224
225impl LocalExpnId {
226 pub const ROOT: LocalExpnId = LocalExpnId::ZERO;
228
229 #[inline]
230 fn from_raw(idx: ExpnIndex) -> LocalExpnId {
231 LocalExpnId::from_u32(idx.as_u32())
232 }
233
234 #[inline]
235 pub fn as_raw(self) -> ExpnIndex {
236 ExpnIndex::from_u32(self.as_u32())
237 }
238
239 pub fn fresh_empty() -> LocalExpnId {
240 HygieneData::with(|data| {
241 let expn_id = data.local_expn_data.push(None);
242 let _eid = data.local_expn_hashes.push(ExpnHash(Fingerprint::ZERO));
243 debug_assert_eq!(expn_id, _eid);
244 expn_id
245 })
246 }
247
248 pub fn fresh(mut expn_data: ExpnData, ctx: impl HashStableContext) -> LocalExpnId {
249 debug_assert_eq!(expn_data.parent.krate, LOCAL_CRATE);
250 let expn_hash = update_disambiguator(&mut expn_data, ctx);
251 HygieneData::with(|data| {
252 let expn_id = data.local_expn_data.push(Some(expn_data));
253 let _eid = data.local_expn_hashes.push(expn_hash);
254 debug_assert_eq!(expn_id, _eid);
255 let _old_id = data.expn_hash_to_expn_id.insert(expn_hash, expn_id.to_expn_id());
256 debug_assert!(_old_id.is_none());
257 expn_id
258 })
259 }
260
261 #[inline]
262 pub fn expn_data(self) -> ExpnData {
263 HygieneData::with(|data| data.local_expn_data(self).clone())
264 }
265
266 #[inline]
267 pub fn to_expn_id(self) -> ExpnId {
268 ExpnId { krate: LOCAL_CRATE, local_id: self.as_raw() }
269 }
270
271 #[inline]
272 pub fn set_expn_data(self, mut expn_data: ExpnData, ctx: impl HashStableContext) {
273 debug_assert_eq!(expn_data.parent.krate, LOCAL_CRATE);
274 let expn_hash = update_disambiguator(&mut expn_data, ctx);
275 HygieneData::with(|data| {
276 let old_expn_data = &mut data.local_expn_data[self];
277 assert!(old_expn_data.is_none(), "expansion data is reset for an expansion ID");
278 *old_expn_data = Some(expn_data);
279 debug_assert_eq!(data.local_expn_hashes[self].0, Fingerprint::ZERO);
280 data.local_expn_hashes[self] = expn_hash;
281 let _old_id = data.expn_hash_to_expn_id.insert(expn_hash, self.to_expn_id());
282 debug_assert!(_old_id.is_none());
283 });
284 }
285
286 #[inline]
287 pub fn is_descendant_of(self, ancestor: LocalExpnId) -> bool {
288 self.to_expn_id().is_descendant_of(ancestor.to_expn_id())
289 }
290
291 #[inline]
295 pub fn expansion_cause(self) -> Option<Span> {
296 self.to_expn_id().expansion_cause()
297 }
298}
299
300impl ExpnId {
301 pub const fn root() -> ExpnId {
304 ExpnId { krate: LOCAL_CRATE, local_id: ExpnIndex::ZERO }
305 }
306
307 #[inline]
308 pub fn expn_hash(self) -> ExpnHash {
309 HygieneData::with(|data| data.expn_hash(self))
310 }
311
312 #[inline]
313 pub fn from_hash(hash: ExpnHash) -> Option<ExpnId> {
314 HygieneData::with(|data| data.expn_hash_to_expn_id.get(&hash).copied())
315 }
316
317 #[inline]
318 pub fn as_local(self) -> Option<LocalExpnId> {
319 if self.krate == LOCAL_CRATE { Some(LocalExpnId::from_raw(self.local_id)) } else { None }
320 }
321
322 #[inline]
323 #[track_caller]
324 pub fn expect_local(self) -> LocalExpnId {
325 self.as_local().unwrap()
326 }
327
328 #[inline]
329 pub fn expn_data(self) -> ExpnData {
330 HygieneData::with(|data| data.expn_data(self).clone())
331 }
332
333 #[inline]
334 pub fn is_descendant_of(self, ancestor: ExpnId) -> bool {
335 if ancestor == ExpnId::root() || ancestor == self {
337 return true;
338 }
339 if ancestor.krate != self.krate {
340 return false;
341 }
342 HygieneData::with(|data| data.is_descendant_of(self, ancestor))
343 }
344
345 pub fn outer_expn_is_descendant_of(self, ctxt: SyntaxContext) -> bool {
348 HygieneData::with(|data| data.is_descendant_of(self, data.outer_expn(ctxt)))
349 }
350
351 pub fn expansion_cause(mut self) -> Option<Span> {
355 let mut last_macro = None;
356 loop {
357 if self == ExpnId::root() {
359 break;
360 }
361 let expn_data = self.expn_data();
362 if expn_data.kind == ExpnKind::Macro(MacroKind::Bang, sym::include) {
364 break;
365 }
366 self = expn_data.call_site.ctxt().outer_expn();
367 last_macro = Some(expn_data.call_site);
368 }
369 last_macro
370 }
371}
372
373#[derive(Debug)]
374pub(crate) struct HygieneData {
375 local_expn_data: IndexVec<LocalExpnId, Option<ExpnData>>,
379 local_expn_hashes: IndexVec<LocalExpnId, ExpnHash>,
380 foreign_expn_data: FxHashMap<ExpnId, ExpnData>,
383 foreign_expn_hashes: FxHashMap<ExpnId, ExpnHash>,
384 expn_hash_to_expn_id: UnhashMap<ExpnHash, ExpnId>,
385 syntax_context_data: Vec<SyntaxContextData>,
386 syntax_context_map: FxHashMap<SyntaxContextKey, SyntaxContext>,
387 expn_data_disambiguators: UnhashMap<Hash64, u32>,
393}
394
395impl HygieneData {
396 pub(crate) fn new(edition: Edition) -> Self {
397 let root_data = ExpnData::default(
398 ExpnKind::Root,
399 DUMMY_SP,
400 edition,
401 Some(CRATE_DEF_ID.to_def_id()),
402 None,
403 );
404
405 let root_ctxt_data = SyntaxContextData::root();
406 HygieneData {
407 local_expn_data: IndexVec::from_elem_n(Some(root_data), 1),
408 local_expn_hashes: IndexVec::from_elem_n(ExpnHash(Fingerprint::ZERO), 1),
409 foreign_expn_data: FxHashMap::default(),
410 foreign_expn_hashes: FxHashMap::default(),
411 expn_hash_to_expn_id: iter::once((ExpnHash(Fingerprint::ZERO), ExpnId::root()))
412 .collect(),
413 syntax_context_data: vec![root_ctxt_data],
414 syntax_context_map: iter::once((root_ctxt_data.key(), SyntaxContext(0))).collect(),
415 expn_data_disambiguators: UnhashMap::default(),
416 }
417 }
418
419 fn with<T, F: FnOnce(&mut HygieneData) -> T>(f: F) -> T {
420 with_session_globals(|session_globals| f(&mut session_globals.hygiene_data.borrow_mut()))
421 }
422
423 #[inline]
424 fn expn_hash(&self, expn_id: ExpnId) -> ExpnHash {
425 match expn_id.as_local() {
426 Some(expn_id) => self.local_expn_hashes[expn_id],
427 None => self.foreign_expn_hashes[&expn_id],
428 }
429 }
430
431 fn local_expn_data(&self, expn_id: LocalExpnId) -> &ExpnData {
432 self.local_expn_data[expn_id].as_ref().expect("no expansion data for an expansion ID")
433 }
434
435 fn expn_data(&self, expn_id: ExpnId) -> &ExpnData {
436 if let Some(expn_id) = expn_id.as_local() {
437 self.local_expn_data[expn_id].as_ref().expect("no expansion data for an expansion ID")
438 } else {
439 &self.foreign_expn_data[&expn_id]
440 }
441 }
442
443 fn is_descendant_of(&self, mut expn_id: ExpnId, ancestor: ExpnId) -> bool {
444 if ancestor == ExpnId::root() {
446 return true;
447 }
448 if expn_id.krate != ancestor.krate {
449 return false;
450 }
451 loop {
452 if expn_id == ancestor {
453 return true;
454 }
455 if expn_id == ExpnId::root() {
456 return false;
457 }
458 expn_id = self.expn_data(expn_id).parent;
459 }
460 }
461
462 fn normalize_to_macros_2_0(&self, ctxt: SyntaxContext) -> SyntaxContext {
463 debug_assert!(!self.syntax_context_data[ctxt.0 as usize].is_decode_placeholder());
464 self.syntax_context_data[ctxt.0 as usize].opaque
465 }
466
467 fn normalize_to_macro_rules(&self, ctxt: SyntaxContext) -> SyntaxContext {
468 debug_assert!(!self.syntax_context_data[ctxt.0 as usize].is_decode_placeholder());
469 self.syntax_context_data[ctxt.0 as usize].opaque_and_semitransparent
470 }
471
472 fn outer_expn(&self, ctxt: SyntaxContext) -> ExpnId {
473 debug_assert!(!self.syntax_context_data[ctxt.0 as usize].is_decode_placeholder());
474 self.syntax_context_data[ctxt.0 as usize].outer_expn
475 }
476
477 fn outer_mark(&self, ctxt: SyntaxContext) -> (ExpnId, Transparency) {
478 debug_assert!(!self.syntax_context_data[ctxt.0 as usize].is_decode_placeholder());
479 let data = &self.syntax_context_data[ctxt.0 as usize];
480 (data.outer_expn, data.outer_transparency)
481 }
482
483 fn parent_ctxt(&self, ctxt: SyntaxContext) -> SyntaxContext {
484 debug_assert!(!self.syntax_context_data[ctxt.0 as usize].is_decode_placeholder());
485 self.syntax_context_data[ctxt.0 as usize].parent
486 }
487
488 fn remove_mark(&self, ctxt: &mut SyntaxContext) -> (ExpnId, Transparency) {
489 let outer_mark = self.outer_mark(*ctxt);
490 *ctxt = self.parent_ctxt(*ctxt);
491 outer_mark
492 }
493
494 fn marks(&self, mut ctxt: SyntaxContext) -> Vec<(ExpnId, Transparency)> {
495 let mut marks = Vec::new();
496 while !ctxt.is_root() {
497 debug!("marks: getting parent of {:?}", ctxt);
498 marks.push(self.outer_mark(ctxt));
499 ctxt = self.parent_ctxt(ctxt);
500 }
501 marks.reverse();
502 marks
503 }
504
505 fn walk_chain(&self, mut span: Span, to: SyntaxContext) -> Span {
506 let orig_span = span;
507 debug!("walk_chain({:?}, {:?})", span, to);
508 debug!("walk_chain: span ctxt = {:?}", span.ctxt());
509 while span.ctxt() != to && span.from_expansion() {
510 let outer_expn = self.outer_expn(span.ctxt());
511 debug!("walk_chain({:?}): outer_expn={:?}", span, outer_expn);
512 let expn_data = self.expn_data(outer_expn);
513 debug!("walk_chain({:?}): expn_data={:?}", span, expn_data);
514 span = expn_data.call_site;
515 }
516 debug!("walk_chain: for span {:?} >>> return span = {:?}", orig_span, span);
517 span
518 }
519
520 fn walk_chain_collapsed(&self, mut span: Span, to: Span) -> Span {
521 let orig_span = span;
522 let mut ret_span = span;
523 debug!("walk_chain_collapsed({:?}, {:?})", span, to);
524 debug!("walk_chain_collapsed: span ctxt = {:?}", span.ctxt());
525 while let ctxt = span.ctxt()
526 && !ctxt.is_root()
527 && ctxt != to.ctxt()
528 {
529 let outer_expn = self.outer_expn(ctxt);
530 debug!("walk_chain_collapsed({:?}): outer_expn={:?}", span, outer_expn);
531 let expn_data = self.expn_data(outer_expn);
532 debug!("walk_chain_collapsed({:?}): expn_data={:?}", span, expn_data);
533 span = expn_data.call_site;
534 if expn_data.collapse_debuginfo {
535 ret_span = span;
536 }
537 }
538 debug!("walk_chain_collapsed: for span {:?} >>> return span = {:?}", orig_span, ret_span);
539 ret_span
540 }
541
542 fn adjust(&self, ctxt: &mut SyntaxContext, expn_id: ExpnId) -> Option<ExpnId> {
543 let mut scope = None;
544 while !self.is_descendant_of(expn_id, self.outer_expn(*ctxt)) {
545 scope = Some(self.remove_mark(ctxt).0);
546 }
547 scope
548 }
549
550 fn apply_mark(
551 &mut self,
552 ctxt: SyntaxContext,
553 expn_id: ExpnId,
554 transparency: Transparency,
555 ) -> SyntaxContext {
556 assert_ne!(expn_id, ExpnId::root());
557 if transparency == Transparency::Opaque {
558 return self.apply_mark_internal(ctxt, expn_id, transparency);
559 }
560
561 let call_site_ctxt = self.expn_data(expn_id).call_site.ctxt();
562 let mut call_site_ctxt = if transparency == Transparency::SemiTransparent {
563 self.normalize_to_macros_2_0(call_site_ctxt)
564 } else {
565 self.normalize_to_macro_rules(call_site_ctxt)
566 };
567
568 if call_site_ctxt.is_root() {
569 return self.apply_mark_internal(ctxt, expn_id, transparency);
570 }
571
572 for (expn_id, transparency) in self.marks(ctxt) {
582 call_site_ctxt = self.apply_mark_internal(call_site_ctxt, expn_id, transparency);
583 }
584 self.apply_mark_internal(call_site_ctxt, expn_id, transparency)
585 }
586
587 fn apply_mark_internal(
588 &mut self,
589 parent: SyntaxContext,
590 expn_id: ExpnId,
591 transparency: Transparency,
592 ) -> SyntaxContext {
593 debug_assert!(!self.syntax_context_data[parent.0 as usize].is_decode_placeholder());
594 let key = (parent, expn_id, transparency);
596 if let Some(ctxt) = self.syntax_context_map.get(&key) {
597 return *ctxt;
598 }
599 let ctxt = SyntaxContext::from_usize(self.syntax_context_data.len());
601 self.syntax_context_data.push(SyntaxContextData::decode_placeholder());
602 self.syntax_context_map.insert(key, ctxt);
603
604 let parent_opaque = self.syntax_context_data[parent.0 as usize].opaque;
609 let parent_opaque_and_semitransparent =
610 self.syntax_context_data[parent.0 as usize].opaque_and_semitransparent;
611
612 let (opaque, opaque_and_semitransparent) = match transparency {
614 Transparency::Transparent => (parent_opaque, parent_opaque_and_semitransparent),
615 Transparency::SemiTransparent => (
616 parent_opaque,
617 self.apply_mark_internal(parent_opaque_and_semitransparent, expn_id, transparency),
619 ),
620 Transparency::Opaque => (
621 self.apply_mark_internal(parent_opaque, expn_id, transparency),
623 self.apply_mark_internal(parent_opaque_and_semitransparent, expn_id, transparency),
625 ),
626 };
627
628 self.syntax_context_data[ctxt.as_u32() as usize] =
630 SyntaxContextData::new(key, opaque, opaque_and_semitransparent);
631 ctxt
632 }
633}
634
635pub fn walk_chain(span: Span, to: SyntaxContext) -> Span {
636 HygieneData::with(|data| data.walk_chain(span, to))
637}
638
639pub fn walk_chain_collapsed(span: Span, to: Span) -> Span {
645 HygieneData::with(|data| data.walk_chain_collapsed(span, to))
646}
647
648pub fn update_dollar_crate_names(mut get_name: impl FnMut(SyntaxContext) -> Symbol) {
649 let mut to_update = vec![];
652 HygieneData::with(|data| {
653 for (idx, scdata) in data.syntax_context_data.iter().enumerate().rev() {
654 if scdata.dollar_crate_name == kw::DollarCrate {
655 to_update.push((idx, kw::DollarCrate));
656 } else if !scdata.is_decode_placeholder() {
657 break;
658 }
659 }
660 });
661 for (idx, name) in &mut to_update {
664 *name = get_name(SyntaxContext::from_usize(*idx));
665 }
666 HygieneData::with(|data| {
667 for (idx, name) in to_update {
668 data.syntax_context_data[idx].dollar_crate_name = name;
669 }
670 })
671}
672
673pub fn debug_hygiene_data(verbose: bool) -> String {
674 HygieneData::with(|data| {
675 if verbose {
676 format!("{data:#?}")
677 } else {
678 let mut s = String::from("Expansions:");
679 let mut debug_expn_data = |(id, expn_data): (&ExpnId, &ExpnData)| {
680 s.push_str(&format!(
681 "\n{:?}: parent: {:?}, call_site_ctxt: {:?}, def_site_ctxt: {:?}, kind: {:?}",
682 id,
683 expn_data.parent,
684 expn_data.call_site.ctxt(),
685 expn_data.def_site.ctxt(),
686 expn_data.kind,
687 ))
688 };
689 data.local_expn_data.iter_enumerated().for_each(|(id, expn_data)| {
690 let expn_data = expn_data.as_ref().expect("no expansion data for an expansion ID");
691 debug_expn_data((&id.to_expn_id(), expn_data))
692 });
693
694 #[allow(rustc::potential_query_instability)]
697 let mut foreign_expn_data: Vec<_> = data.foreign_expn_data.iter().collect();
698 foreign_expn_data.sort_by_key(|(id, _)| (id.krate, id.local_id));
699 foreign_expn_data.into_iter().for_each(debug_expn_data);
700 s.push_str("\n\nSyntaxContexts:");
701 data.syntax_context_data.iter().enumerate().for_each(|(id, ctxt)| {
702 s.push_str(&format!(
703 "\n#{}: parent: {:?}, outer_mark: ({:?}, {:?})",
704 id, ctxt.parent, ctxt.outer_expn, ctxt.outer_transparency,
705 ));
706 });
707 s
708 }
709 })
710}
711
712impl SyntaxContext {
713 #[inline]
714 pub const fn root() -> Self {
715 SyntaxContext(0)
716 }
717
718 #[inline]
719 pub const fn is_root(self) -> bool {
720 self.0 == SyntaxContext::root().as_u32()
721 }
722
723 #[inline]
724 pub(crate) const fn as_u32(self) -> u32 {
725 self.0
726 }
727
728 #[inline]
729 pub(crate) const fn from_u32(raw: u32) -> SyntaxContext {
730 SyntaxContext(raw)
731 }
732
733 #[inline]
734 pub(crate) const fn from_u16(raw: u16) -> SyntaxContext {
735 SyntaxContext(raw as u32)
736 }
737
738 fn from_usize(raw: usize) -> SyntaxContext {
739 SyntaxContext(u32::try_from(raw).unwrap())
740 }
741
742 pub fn apply_mark(self, expn_id: ExpnId, transparency: Transparency) -> SyntaxContext {
744 HygieneData::with(|data| data.apply_mark(self, expn_id, transparency))
745 }
746
747 pub fn remove_mark(&mut self) -> ExpnId {
764 HygieneData::with(|data| data.remove_mark(self).0)
765 }
766
767 pub fn marks(self) -> Vec<(ExpnId, Transparency)> {
768 HygieneData::with(|data| data.marks(self))
769 }
770
771 pub fn adjust(&mut self, expn_id: ExpnId) -> Option<ExpnId> {
797 HygieneData::with(|data| data.adjust(self, expn_id))
798 }
799
800 pub(crate) fn normalize_to_macros_2_0_and_adjust(&mut self, expn_id: ExpnId) -> Option<ExpnId> {
802 HygieneData::with(|data| {
803 *self = data.normalize_to_macros_2_0(*self);
804 data.adjust(self, expn_id)
805 })
806 }
807
808 pub(crate) fn glob_adjust(
835 &mut self,
836 expn_id: ExpnId,
837 glob_span: Span,
838 ) -> Option<Option<ExpnId>> {
839 HygieneData::with(|data| {
840 let mut scope = None;
841 let mut glob_ctxt = data.normalize_to_macros_2_0(glob_span.ctxt());
842 while !data.is_descendant_of(expn_id, data.outer_expn(glob_ctxt)) {
843 scope = Some(data.remove_mark(&mut glob_ctxt).0);
844 if data.remove_mark(self).0 != scope.unwrap() {
845 return None;
846 }
847 }
848 if data.adjust(self, expn_id).is_some() {
849 return None;
850 }
851 Some(scope)
852 })
853 }
854
855 pub(crate) fn reverse_glob_adjust(
863 &mut self,
864 expn_id: ExpnId,
865 glob_span: Span,
866 ) -> Option<Option<ExpnId>> {
867 HygieneData::with(|data| {
868 if data.adjust(self, expn_id).is_some() {
869 return None;
870 }
871
872 let mut glob_ctxt = data.normalize_to_macros_2_0(glob_span.ctxt());
873 let mut marks = Vec::new();
874 while !data.is_descendant_of(expn_id, data.outer_expn(glob_ctxt)) {
875 marks.push(data.remove_mark(&mut glob_ctxt));
876 }
877
878 let scope = marks.last().map(|mark| mark.0);
879 while let Some((expn_id, transparency)) = marks.pop() {
880 *self = data.apply_mark(*self, expn_id, transparency);
881 }
882 Some(scope)
883 })
884 }
885
886 pub fn hygienic_eq(self, other: SyntaxContext, expn_id: ExpnId) -> bool {
887 HygieneData::with(|data| {
888 let mut self_normalized = data.normalize_to_macros_2_0(self);
889 data.adjust(&mut self_normalized, expn_id);
890 self_normalized == data.normalize_to_macros_2_0(other)
891 })
892 }
893
894 #[inline]
895 pub fn normalize_to_macros_2_0(self) -> SyntaxContext {
896 HygieneData::with(|data| data.normalize_to_macros_2_0(self))
897 }
898
899 #[inline]
900 pub fn normalize_to_macro_rules(self) -> SyntaxContext {
901 HygieneData::with(|data| data.normalize_to_macro_rules(self))
902 }
903
904 #[inline]
905 pub fn outer_expn(self) -> ExpnId {
906 HygieneData::with(|data| data.outer_expn(self))
907 }
908
909 #[inline]
912 pub fn outer_expn_data(self) -> ExpnData {
913 HygieneData::with(|data| data.expn_data(data.outer_expn(self)).clone())
914 }
915
916 #[inline]
917 fn outer_mark(self) -> (ExpnId, Transparency) {
918 HygieneData::with(|data| data.outer_mark(self))
919 }
920
921 pub(crate) fn dollar_crate_name(self) -> Symbol {
922 HygieneData::with(|data| {
923 debug_assert!(!data.syntax_context_data[self.0 as usize].is_decode_placeholder());
924 data.syntax_context_data[self.0 as usize].dollar_crate_name
925 })
926 }
927
928 pub fn edition(self) -> Edition {
929 HygieneData::with(|data| data.expn_data(data.outer_expn(self)).edition)
930 }
931}
932
933impl fmt::Debug for SyntaxContext {
934 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
935 write!(f, "#{}", self.0)
936 }
937}
938
939impl Span {
940 pub fn mark_with_reason(
943 self,
944 allow_internal_unstable: Option<Arc<[Symbol]>>,
945 reason: DesugaringKind,
946 edition: Edition,
947 ctx: impl HashStableContext,
948 ) -> Span {
949 let expn_data = ExpnData {
950 allow_internal_unstable,
951 ..ExpnData::default(ExpnKind::Desugaring(reason), self, edition, None, None)
952 };
953 let expn_id = LocalExpnId::fresh(expn_data, ctx);
954 self.apply_mark(expn_id.to_expn_id(), Transparency::Transparent)
955 }
956}
957
958#[derive(Clone, Debug, Encodable, Decodable, HashStable_Generic)]
961pub struct ExpnData {
962 pub kind: ExpnKind,
965 pub parent: ExpnId,
967 pub call_site: Span,
977 disambiguator: u32,
988
989 pub def_site: Span,
996 pub allow_internal_unstable: Option<Arc<[Symbol]>>,
1000 pub edition: Edition,
1002 pub macro_def_id: Option<DefId>,
1005 pub parent_module: Option<DefId>,
1007 pub(crate) allow_internal_unsafe: bool,
1009 pub local_inner_macros: bool,
1011 pub(crate) collapse_debuginfo: bool,
1014 pub hide_backtrace: bool,
1016}
1017
1018impl !PartialEq for ExpnData {}
1019impl !Hash for ExpnData {}
1020
1021impl ExpnData {
1022 pub fn new(
1023 kind: ExpnKind,
1024 parent: ExpnId,
1025 call_site: Span,
1026 def_site: Span,
1027 allow_internal_unstable: Option<Arc<[Symbol]>>,
1028 edition: Edition,
1029 macro_def_id: Option<DefId>,
1030 parent_module: Option<DefId>,
1031 allow_internal_unsafe: bool,
1032 local_inner_macros: bool,
1033 collapse_debuginfo: bool,
1034 hide_backtrace: bool,
1035 ) -> ExpnData {
1036 ExpnData {
1037 kind,
1038 parent,
1039 call_site,
1040 def_site,
1041 allow_internal_unstable,
1042 edition,
1043 macro_def_id,
1044 parent_module,
1045 disambiguator: 0,
1046 allow_internal_unsafe,
1047 local_inner_macros,
1048 collapse_debuginfo,
1049 hide_backtrace,
1050 }
1051 }
1052
1053 pub fn default(
1055 kind: ExpnKind,
1056 call_site: Span,
1057 edition: Edition,
1058 macro_def_id: Option<DefId>,
1059 parent_module: Option<DefId>,
1060 ) -> ExpnData {
1061 ExpnData {
1062 kind,
1063 parent: ExpnId::root(),
1064 call_site,
1065 def_site: DUMMY_SP,
1066 allow_internal_unstable: None,
1067 edition,
1068 macro_def_id,
1069 parent_module,
1070 disambiguator: 0,
1071 allow_internal_unsafe: false,
1072 local_inner_macros: false,
1073 collapse_debuginfo: false,
1074 hide_backtrace: false,
1075 }
1076 }
1077
1078 pub fn allow_unstable(
1079 kind: ExpnKind,
1080 call_site: Span,
1081 edition: Edition,
1082 allow_internal_unstable: Arc<[Symbol]>,
1083 macro_def_id: Option<DefId>,
1084 parent_module: Option<DefId>,
1085 ) -> ExpnData {
1086 ExpnData {
1087 allow_internal_unstable: Some(allow_internal_unstable),
1088 ..ExpnData::default(kind, call_site, edition, macro_def_id, parent_module)
1089 }
1090 }
1091
1092 #[inline]
1093 pub fn is_root(&self) -> bool {
1094 matches!(self.kind, ExpnKind::Root)
1095 }
1096
1097 #[inline]
1098 fn hash_expn(&self, ctx: &mut impl HashStableContext) -> Hash64 {
1099 let mut hasher = StableHasher::new();
1100 self.hash_stable(ctx, &mut hasher);
1101 hasher.finish()
1102 }
1103}
1104
1105#[derive(Clone, Debug, PartialEq, Encodable, Decodable, HashStable_Generic)]
1107pub enum ExpnKind {
1108 Root,
1110 Macro(MacroKind, Symbol),
1112 AstPass(AstPass),
1114 Desugaring(DesugaringKind),
1116}
1117
1118impl ExpnKind {
1119 pub fn descr(&self) -> String {
1120 match *self {
1121 ExpnKind::Root => kw::PathRoot.to_string(),
1122 ExpnKind::Macro(macro_kind, name) => match macro_kind {
1123 MacroKind::Bang => format!("{name}!"),
1124 MacroKind::Attr => format!("#[{name}]"),
1125 MacroKind::Derive => format!("#[derive({name})]"),
1126 },
1127 ExpnKind::AstPass(kind) => kind.descr().to_string(),
1128 ExpnKind::Desugaring(kind) => format!("desugaring of {}", kind.descr()),
1129 }
1130 }
1131}
1132
1133#[derive(Clone, Copy, PartialEq, Eq, Encodable, Decodable, Hash, Debug)]
1135#[derive(HashStable_Generic)]
1136pub enum MacroKind {
1137 Bang,
1139 Attr,
1141 Derive,
1143}
1144
1145impl MacroKind {
1146 pub fn descr(self) -> &'static str {
1147 match self {
1148 MacroKind::Bang => "macro",
1149 MacroKind::Attr => "attribute macro",
1150 MacroKind::Derive => "derive macro",
1151 }
1152 }
1153
1154 pub fn descr_expected(self) -> &'static str {
1155 match self {
1156 MacroKind::Attr => "attribute",
1157 _ => self.descr(),
1158 }
1159 }
1160
1161 pub fn article(self) -> &'static str {
1162 match self {
1163 MacroKind::Attr => "an",
1164 _ => "a",
1165 }
1166 }
1167}
1168
1169#[derive(Clone, Copy, Debug, PartialEq, Encodable, Decodable, HashStable_Generic)]
1171pub enum AstPass {
1172 StdImports,
1173 TestHarness,
1174 ProcMacroHarness,
1175}
1176
1177impl AstPass {
1178 pub fn descr(self) -> &'static str {
1179 match self {
1180 AstPass::StdImports => "standard library imports",
1181 AstPass::TestHarness => "test harness",
1182 AstPass::ProcMacroHarness => "proc macro harness",
1183 }
1184 }
1185}
1186
1187#[derive(Clone, Copy, PartialEq, Debug, Encodable, Decodable, HashStable_Generic)]
1189pub enum DesugaringKind {
1190 CondTemporary,
1195 QuestionMark,
1196 TryBlock,
1197 YeetExpr,
1198 OpaqueTy,
1202 Async,
1203 Await,
1204 ForLoop,
1205 WhileLoop,
1206 BoundModifier,
1208 Contract,
1210 PatTyRange,
1212}
1213
1214impl DesugaringKind {
1215 pub fn descr(self) -> &'static str {
1217 match self {
1218 DesugaringKind::CondTemporary => "`if` or `while` condition",
1219 DesugaringKind::Async => "`async` block or function",
1220 DesugaringKind::Await => "`await` expression",
1221 DesugaringKind::QuestionMark => "operator `?`",
1222 DesugaringKind::TryBlock => "`try` block",
1223 DesugaringKind::YeetExpr => "`do yeet` expression",
1224 DesugaringKind::OpaqueTy => "`impl Trait`",
1225 DesugaringKind::ForLoop => "`for` loop",
1226 DesugaringKind::WhileLoop => "`while` loop",
1227 DesugaringKind::BoundModifier => "trait bound modifier",
1228 DesugaringKind::Contract => "contract check",
1229 DesugaringKind::PatTyRange => "pattern type",
1230 }
1231 }
1232}
1233
1234#[derive(Default)]
1235pub struct HygieneEncodeContext {
1236 serialized_ctxts: Lock<FxHashSet<SyntaxContext>>,
1240 latest_ctxts: Lock<FxHashSet<SyntaxContext>>,
1245
1246 serialized_expns: Lock<FxHashSet<ExpnId>>,
1247
1248 latest_expns: Lock<FxHashSet<ExpnId>>,
1249}
1250
1251impl HygieneEncodeContext {
1252 pub fn schedule_expn_data_for_encoding(&self, expn: ExpnId) {
1254 if !self.serialized_expns.lock().contains(&expn) {
1255 self.latest_expns.lock().insert(expn);
1256 }
1257 }
1258
1259 pub fn encode<T>(
1260 &self,
1261 encoder: &mut T,
1262 mut encode_ctxt: impl FnMut(&mut T, u32, &SyntaxContextKey),
1263 mut encode_expn: impl FnMut(&mut T, ExpnId, &ExpnData, ExpnHash),
1264 ) {
1265 while !self.latest_ctxts.lock().is_empty() || !self.latest_expns.lock().is_empty() {
1268 debug!(
1269 "encode_hygiene: Serializing a round of {:?} SyntaxContextData: {:?}",
1270 self.latest_ctxts.lock().len(),
1271 self.latest_ctxts
1272 );
1273
1274 let latest_ctxts = { mem::take(&mut *self.latest_ctxts.lock()) };
1277
1278 #[allow(rustc::potential_query_instability)]
1282 for_all_ctxts_in(latest_ctxts.into_iter(), |index, ctxt, data| {
1283 if self.serialized_ctxts.lock().insert(ctxt) {
1284 encode_ctxt(encoder, index, data);
1285 }
1286 });
1287
1288 let latest_expns = { mem::take(&mut *self.latest_expns.lock()) };
1289
1290 #[allow(rustc::potential_query_instability)]
1292 for_all_expns_in(latest_expns.into_iter(), |expn, data, hash| {
1293 if self.serialized_expns.lock().insert(expn) {
1294 encode_expn(encoder, expn, data, hash);
1295 }
1296 });
1297 }
1298 debug!("encode_hygiene: Done serializing SyntaxContextData");
1299 }
1300}
1301
1302#[derive(Default)]
1303struct HygieneDecodeContextInner {
1305 remapped_ctxts: Vec<Option<SyntaxContext>>,
1311
1312 decoding: FxHashMap<u32, SyntaxContext>,
1314}
1315
1316#[derive(Default)]
1317pub struct HygieneDecodeContext {
1319 inner: Lock<HygieneDecodeContextInner>,
1320}
1321
1322pub fn register_local_expn_id(data: ExpnData, hash: ExpnHash) -> ExpnId {
1324 HygieneData::with(|hygiene_data| {
1325 let expn_id = hygiene_data.local_expn_data.next_index();
1326 hygiene_data.local_expn_data.push(Some(data));
1327 let _eid = hygiene_data.local_expn_hashes.push(hash);
1328 debug_assert_eq!(expn_id, _eid);
1329
1330 let expn_id = expn_id.to_expn_id();
1331
1332 let _old_id = hygiene_data.expn_hash_to_expn_id.insert(hash, expn_id);
1333 debug_assert!(_old_id.is_none());
1334 expn_id
1335 })
1336}
1337
1338pub fn register_expn_id(
1340 krate: CrateNum,
1341 local_id: ExpnIndex,
1342 data: ExpnData,
1343 hash: ExpnHash,
1344) -> ExpnId {
1345 debug_assert!(data.parent == ExpnId::root() || krate == data.parent.krate);
1346 let expn_id = ExpnId { krate, local_id };
1347 HygieneData::with(|hygiene_data| {
1348 let _old_data = hygiene_data.foreign_expn_data.insert(expn_id, data);
1349 let _old_hash = hygiene_data.foreign_expn_hashes.insert(expn_id, hash);
1350 debug_assert!(_old_hash.is_none() || _old_hash == Some(hash));
1351 let _old_id = hygiene_data.expn_hash_to_expn_id.insert(hash, expn_id);
1352 debug_assert!(_old_id.is_none() || _old_id == Some(expn_id));
1353 });
1354 expn_id
1355}
1356
1357pub fn decode_expn_id(
1359 krate: CrateNum,
1360 index: u32,
1361 decode_data: impl FnOnce(ExpnId) -> (ExpnData, ExpnHash),
1362) -> ExpnId {
1363 if index == 0 {
1364 trace!("decode_expn_id: deserialized root");
1365 return ExpnId::root();
1366 }
1367
1368 let index = ExpnIndex::from_u32(index);
1369
1370 debug_assert_ne!(krate, LOCAL_CRATE);
1372 let expn_id = ExpnId { krate, local_id: index };
1373
1374 if HygieneData::with(|hygiene_data| hygiene_data.foreign_expn_data.contains_key(&expn_id)) {
1376 return expn_id;
1377 }
1378
1379 let (expn_data, hash) = decode_data(expn_id);
1382
1383 register_expn_id(krate, index, expn_data, hash)
1384}
1385
1386pub fn decode_syntax_context<D: Decoder, F: FnOnce(&mut D, u32) -> SyntaxContextKey>(
1391 d: &mut D,
1392 context: &HygieneDecodeContext,
1393 decode_ctxt_key: F,
1394) -> SyntaxContext {
1395 let raw_id: u32 = Decodable::decode(d);
1396 if raw_id == 0 {
1397 trace!("decode_syntax_context: deserialized root");
1398 return SyntaxContext::root();
1400 }
1401
1402 let ctxt_key = decode_ctxt_key(d, raw_id);
1405
1406 let ctxt = HygieneData::with(|hygiene_data| {
1407 match hygiene_data.syntax_context_map.get(&ctxt_key) {
1408 Some(&ctxt) => ctxt,
1416 None => hygiene_data.apply_mark_internal(ctxt_key.0, ctxt_key.1, ctxt_key.2),
1419 }
1420 });
1421
1422 let mut inner = context.inner.lock();
1423 let new_len = raw_id as usize + 1;
1424 if inner.remapped_ctxts.len() < new_len {
1425 inner.remapped_ctxts.resize(new_len, None);
1426 }
1427 inner.remapped_ctxts[raw_id as usize] = Some(ctxt);
1428 inner.decoding.remove(&raw_id);
1429
1430 ctxt
1431}
1432
1433fn for_all_ctxts_in<F: FnMut(u32, SyntaxContext, &SyntaxContextKey)>(
1434 ctxts: impl Iterator<Item = SyntaxContext>,
1435 mut f: F,
1436) {
1437 let all_data: Vec<_> = HygieneData::with(|data| {
1438 ctxts.map(|ctxt| (ctxt, data.syntax_context_data[ctxt.0 as usize].clone())).collect()
1439 });
1440 for (ctxt, data) in all_data.into_iter() {
1441 f(ctxt.0, ctxt, &data.key());
1442 }
1443}
1444
1445fn for_all_expns_in(
1446 expns: impl Iterator<Item = ExpnId>,
1447 mut f: impl FnMut(ExpnId, &ExpnData, ExpnHash),
1448) {
1449 let all_data: Vec<_> = HygieneData::with(|data| {
1450 expns.map(|expn| (expn, data.expn_data(expn).clone(), data.expn_hash(expn))).collect()
1451 });
1452 for (expn, data, hash) in all_data.into_iter() {
1453 f(expn, &data, hash);
1454 }
1455}
1456
1457impl<E: SpanEncoder> Encodable<E> for LocalExpnId {
1458 fn encode(&self, e: &mut E) {
1459 self.to_expn_id().encode(e);
1460 }
1461}
1462
1463impl<D: SpanDecoder> Decodable<D> for LocalExpnId {
1464 fn decode(d: &mut D) -> Self {
1465 ExpnId::expect_local(ExpnId::decode(d))
1466 }
1467}
1468
1469pub fn raw_encode_syntax_context<E: Encoder>(
1470 ctxt: SyntaxContext,
1471 context: &HygieneEncodeContext,
1472 e: &mut E,
1473) {
1474 if !context.serialized_ctxts.lock().contains(&ctxt) {
1475 context.latest_ctxts.lock().insert(ctxt);
1476 }
1477 ctxt.0.encode(e);
1478}
1479
1480fn update_disambiguator(expn_data: &mut ExpnData, mut ctx: impl HashStableContext) -> ExpnHash {
1490 assert_eq!(expn_data.disambiguator, 0, "Already set disambiguator for ExpnData: {expn_data:?}");
1492 assert_default_hashing_controls(&ctx, "ExpnData (disambiguator)");
1493 let mut expn_hash = expn_data.hash_expn(&mut ctx);
1494
1495 let disambiguator = HygieneData::with(|data| {
1496 let disambig = data.expn_data_disambiguators.entry(expn_hash).or_default();
1499 let disambiguator = *disambig;
1500 *disambig += 1;
1501 disambiguator
1502 });
1503
1504 if disambiguator != 0 {
1505 debug!("Set disambiguator for expn_data={:?} expn_hash={:?}", expn_data, expn_hash);
1506
1507 expn_data.disambiguator = disambiguator;
1508 expn_hash = expn_data.hash_expn(&mut ctx);
1509
1510 #[cfg(debug_assertions)]
1512 HygieneData::with(|data| {
1513 assert_eq!(
1514 data.expn_data_disambiguators.get(&expn_hash),
1515 None,
1516 "Hash collision after disambiguator update!",
1517 );
1518 });
1519 }
1520
1521 ExpnHash::new(ctx.def_path_hash(LOCAL_CRATE.as_def_id()).stable_crate_id(), expn_hash)
1522}
1523
1524impl<CTX: HashStableContext> HashStable<CTX> for SyntaxContext {
1525 fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) {
1526 const TAG_EXPANSION: u8 = 0;
1527 const TAG_NO_EXPANSION: u8 = 1;
1528
1529 if self.is_root() {
1530 TAG_NO_EXPANSION.hash_stable(ctx, hasher);
1531 } else {
1532 TAG_EXPANSION.hash_stable(ctx, hasher);
1533 let (expn_id, transparency) = self.outer_mark();
1534 expn_id.hash_stable(ctx, hasher);
1535 transparency.hash_stable(ctx, hasher);
1536 }
1537 }
1538}
1539
1540impl<CTX: HashStableContext> HashStable<CTX> for ExpnId {
1541 fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) {
1542 assert_default_hashing_controls(ctx, "ExpnId");
1543 let hash = if *self == ExpnId::root() {
1544 Fingerprint::ZERO
1546 } else {
1547 self.expn_hash().0
1548 };
1549
1550 hash.hash_stable(ctx, hasher);
1551 }
1552}