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::source_map::SourceMap;
45use crate::symbol::{Symbol, kw, sym};
46use crate::{DUMMY_SP, HashStableContext, Span, SpanDecoder, SpanEncoder, with_session_globals};
47
48#[derive(Clone, Copy, PartialEq, Eq, Hash)]
52pub struct SyntaxContext(u32);
53
54impl !Ord for SyntaxContext {}
58impl !PartialOrd for SyntaxContext {}
59
60pub type SyntaxContextKey = (SyntaxContext, ExpnId, Transparency);
63
64#[derive(Clone, Copy, Debug)]
65struct SyntaxContextData {
66 outer_expn: ExpnId,
69 outer_transparency: Transparency,
71 parent: SyntaxContext,
72 opaque: SyntaxContext,
74 opaque_and_semiopaque: SyntaxContext,
76 dollar_crate_name: Symbol,
78}
79
80impl SyntaxContextData {
81 fn root() -> SyntaxContextData {
82 SyntaxContextData {
83 outer_expn: ExpnId::root(),
84 outer_transparency: Transparency::Opaque,
85 parent: SyntaxContext::root(),
86 opaque: SyntaxContext::root(),
87 opaque_and_semiopaque: SyntaxContext::root(),
88 dollar_crate_name: kw::DollarCrate,
89 }
90 }
91
92 fn key(&self) -> SyntaxContextKey {
93 (self.parent, self.outer_expn, self.outer_transparency)
94 }
95}
96
97rustc_index::newtype_index! {
98 #[orderable]
100 pub struct ExpnIndex {}
101}
102
103#[derive(Clone, Copy, PartialEq, Eq, Hash)]
105pub struct ExpnId {
106 pub krate: CrateNum,
107 pub local_id: ExpnIndex,
108}
109
110impl fmt::Debug for ExpnId {
111 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
112 write!(f, "{:?}::{{{{expn{}}}}}", self.krate, self.local_id.as_u32())
114 }
115}
116
117rustc_index::newtype_index! {
118 #[debug_format = "expn{}"]
120 pub struct LocalExpnId {}
121}
122
123impl !Ord for LocalExpnId {}
127impl !PartialOrd for LocalExpnId {}
128
129fn assert_default_hashing_controls(ctx: &impl HashStableContext, msg: &str) {
135 match ctx.hashing_controls() {
136 HashingControls { hash_spans }
145 if hash_spans != ctx.unstable_opts_incremental_ignore_spans() => {}
146 other => panic!("Attempted hashing of {msg} with non-default HashingControls: {other:?}"),
147 }
148}
149
150#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, Encodable, Decodable, HashStable_Generic)]
152pub struct ExpnHash(Fingerprint);
153
154impl ExpnHash {
155 #[inline]
158 pub fn stable_crate_id(self) -> StableCrateId {
159 StableCrateId(self.0.split().0)
160 }
161
162 #[inline]
166 pub fn local_hash(self) -> Hash64 {
167 self.0.split().1
168 }
169
170 #[inline]
171 pub fn is_root(self) -> bool {
172 self.0 == Fingerprint::ZERO
173 }
174
175 fn new(stable_crate_id: StableCrateId, local_hash: Hash64) -> ExpnHash {
178 ExpnHash(Fingerprint::new(stable_crate_id.0, local_hash))
179 }
180}
181
182#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Hash, Debug, Encodable, Decodable)]
185#[derive(HashStable_Generic)]
186pub enum Transparency {
187 Transparent,
190 SemiOpaque,
197 Opaque,
200}
201
202impl Transparency {
203 pub fn fallback(macro_rules: bool) -> Self {
204 if macro_rules { Transparency::SemiOpaque } else { Transparency::Opaque }
205 }
206}
207
208impl LocalExpnId {
209 pub const ROOT: LocalExpnId = LocalExpnId::ZERO;
211
212 #[inline]
213 fn from_raw(idx: ExpnIndex) -> LocalExpnId {
214 LocalExpnId::from_u32(idx.as_u32())
215 }
216
217 #[inline]
218 pub fn as_raw(self) -> ExpnIndex {
219 ExpnIndex::from_u32(self.as_u32())
220 }
221
222 pub fn fresh_empty() -> LocalExpnId {
223 HygieneData::with(|data| {
224 let expn_id = data.local_expn_data.push(None);
225 let _eid = data.local_expn_hashes.push(ExpnHash(Fingerprint::ZERO));
226 debug_assert_eq!(expn_id, _eid);
227 expn_id
228 })
229 }
230
231 pub fn fresh(mut expn_data: ExpnData, ctx: impl HashStableContext) -> LocalExpnId {
232 debug_assert_eq!(expn_data.parent.krate, LOCAL_CRATE);
233 let expn_hash = update_disambiguator(&mut expn_data, ctx);
234 HygieneData::with(|data| {
235 let expn_id = data.local_expn_data.push(Some(expn_data));
236 let _eid = data.local_expn_hashes.push(expn_hash);
237 debug_assert_eq!(expn_id, _eid);
238 let _old_id = data.expn_hash_to_expn_id.insert(expn_hash, expn_id.to_expn_id());
239 debug_assert!(_old_id.is_none());
240 expn_id
241 })
242 }
243
244 #[inline]
245 pub fn expn_data(self) -> ExpnData {
246 HygieneData::with(|data| data.local_expn_data(self).clone())
247 }
248
249 #[inline]
250 pub fn to_expn_id(self) -> ExpnId {
251 ExpnId { krate: LOCAL_CRATE, local_id: self.as_raw() }
252 }
253
254 #[inline]
255 pub fn set_expn_data(self, mut expn_data: ExpnData, ctx: impl HashStableContext) {
256 debug_assert_eq!(expn_data.parent.krate, LOCAL_CRATE);
257 let expn_hash = update_disambiguator(&mut expn_data, ctx);
258 HygieneData::with(|data| {
259 let old_expn_data = &mut data.local_expn_data[self];
260 assert!(old_expn_data.is_none(), "expansion data is reset for an expansion ID");
261 *old_expn_data = Some(expn_data);
262 debug_assert_eq!(data.local_expn_hashes[self].0, Fingerprint::ZERO);
263 data.local_expn_hashes[self] = expn_hash;
264 let _old_id = data.expn_hash_to_expn_id.insert(expn_hash, self.to_expn_id());
265 debug_assert!(_old_id.is_none());
266 });
267 }
268
269 #[inline]
270 pub fn is_descendant_of(self, ancestor: LocalExpnId) -> bool {
271 self.to_expn_id().is_descendant_of(ancestor.to_expn_id())
272 }
273
274 #[inline]
278 pub fn expansion_cause(self) -> Option<Span> {
279 self.to_expn_id().expansion_cause()
280 }
281}
282
283impl ExpnId {
284 pub const fn root() -> ExpnId {
287 ExpnId { krate: LOCAL_CRATE, local_id: ExpnIndex::ZERO }
288 }
289
290 #[inline]
291 pub fn expn_hash(self) -> ExpnHash {
292 HygieneData::with(|data| data.expn_hash(self))
293 }
294
295 #[inline]
296 pub fn from_hash(hash: ExpnHash) -> Option<ExpnId> {
297 HygieneData::with(|data| data.expn_hash_to_expn_id.get(&hash).copied())
298 }
299
300 #[inline]
301 pub fn as_local(self) -> Option<LocalExpnId> {
302 if self.krate == LOCAL_CRATE { Some(LocalExpnId::from_raw(self.local_id)) } else { None }
303 }
304
305 #[inline]
306 #[track_caller]
307 pub fn expect_local(self) -> LocalExpnId {
308 self.as_local().unwrap()
309 }
310
311 #[inline]
312 pub fn expn_data(self) -> ExpnData {
313 HygieneData::with(|data| data.expn_data(self).clone())
314 }
315
316 #[inline]
317 pub fn is_descendant_of(self, ancestor: ExpnId) -> bool {
318 if ancestor == ExpnId::root() || ancestor == self {
320 return true;
321 }
322 if ancestor.krate != self.krate {
323 return false;
324 }
325 HygieneData::with(|data| data.is_descendant_of(self, ancestor))
326 }
327
328 #[inline]
331 pub fn outer_expn_is_descendant_of(self, ctxt: SyntaxContext) -> bool {
332 HygieneData::with(|data| data.is_descendant_of(self, data.outer_expn(ctxt)))
333 }
334
335 pub fn expansion_cause(mut self) -> Option<Span> {
339 let mut last_macro = None;
340 loop {
341 if self == ExpnId::root() {
343 break;
344 }
345 let expn_data = self.expn_data();
346 if expn_data.kind == ExpnKind::Macro(MacroKind::Bang, sym::include) {
348 break;
349 }
350 self = expn_data.call_site.ctxt().outer_expn();
351 last_macro = Some(expn_data.call_site);
352 }
353 last_macro
354 }
355}
356
357#[derive(Debug)]
358pub(crate) struct HygieneData {
359 local_expn_data: IndexVec<LocalExpnId, Option<ExpnData>>,
363 local_expn_hashes: IndexVec<LocalExpnId, ExpnHash>,
364 foreign_expn_data: FxHashMap<ExpnId, ExpnData>,
367 foreign_expn_hashes: FxHashMap<ExpnId, ExpnHash>,
368 expn_hash_to_expn_id: UnhashMap<ExpnHash, ExpnId>,
369 syntax_context_data: Vec<SyntaxContextData>,
370 syntax_context_map: FxHashMap<SyntaxContextKey, SyntaxContext>,
371 expn_data_disambiguators: UnhashMap<Hash64, u32>,
377}
378
379impl HygieneData {
380 pub(crate) fn new(edition: Edition) -> Self {
381 let root_data = ExpnData::default(
382 ExpnKind::Root,
383 DUMMY_SP,
384 edition,
385 Some(CRATE_DEF_ID.to_def_id()),
386 None,
387 );
388
389 let root_ctxt_data = SyntaxContextData::root();
390 HygieneData {
391 local_expn_data: IndexVec::from_elem_n(Some(root_data), 1),
392 local_expn_hashes: IndexVec::from_elem_n(ExpnHash(Fingerprint::ZERO), 1),
393 foreign_expn_data: FxHashMap::default(),
394 foreign_expn_hashes: FxHashMap::default(),
395 expn_hash_to_expn_id: iter::once((ExpnHash(Fingerprint::ZERO), ExpnId::root()))
396 .collect(),
397 syntax_context_data: vec![root_ctxt_data],
398 syntax_context_map: iter::once((root_ctxt_data.key(), SyntaxContext(0))).collect(),
399 expn_data_disambiguators: UnhashMap::default(),
400 }
401 }
402
403 #[inline]
404 fn with<R>(f: impl FnOnce(&mut HygieneData) -> R) -> R {
405 with_session_globals(|session_globals| f(&mut session_globals.hygiene_data.borrow_mut()))
406 }
407
408 #[inline]
409 fn expn_hash(&self, expn_id: ExpnId) -> ExpnHash {
410 match expn_id.as_local() {
411 Some(expn_id) => self.local_expn_hashes[expn_id],
412 None => self.foreign_expn_hashes[&expn_id],
413 }
414 }
415
416 #[inline]
417 fn local_expn_data(&self, expn_id: LocalExpnId) -> &ExpnData {
418 self.local_expn_data[expn_id].as_ref().expect("no expansion data for an expansion ID")
419 }
420
421 fn expn_data(&self, expn_id: ExpnId) -> &ExpnData {
422 if let Some(expn_id) = expn_id.as_local() {
423 self.local_expn_data[expn_id].as_ref().expect("no expansion data for an expansion ID")
424 } else {
425 &self.foreign_expn_data[&expn_id]
426 }
427 }
428
429 fn is_descendant_of(&self, mut expn_id: ExpnId, ancestor: ExpnId) -> bool {
430 if ancestor == ExpnId::root() {
432 return true;
433 }
434 if expn_id.krate != ancestor.krate {
435 return false;
436 }
437 loop {
438 if expn_id == ancestor {
439 return true;
440 }
441 if expn_id == ExpnId::root() {
442 return false;
443 }
444 expn_id = self.expn_data(expn_id).parent;
445 }
446 }
447
448 #[inline]
449 fn normalize_to_macros_2_0(&self, ctxt: SyntaxContext) -> SyntaxContext {
450 self.syntax_context_data[ctxt.0 as usize].opaque
451 }
452
453 #[inline]
454 fn normalize_to_macro_rules(&self, ctxt: SyntaxContext) -> SyntaxContext {
455 self.syntax_context_data[ctxt.0 as usize].opaque_and_semiopaque
456 }
457
458 #[inline]
460 fn outer_expn(&self, ctxt: SyntaxContext) -> ExpnId {
461 self.syntax_context_data[ctxt.0 as usize].outer_expn
462 }
463
464 #[inline]
466 fn outer_mark(&self, ctxt: SyntaxContext) -> (ExpnId, Transparency) {
467 let data = &self.syntax_context_data[ctxt.0 as usize];
468 (data.outer_expn, data.outer_transparency)
469 }
470
471 #[inline]
472 fn parent_ctxt(&self, ctxt: SyntaxContext) -> SyntaxContext {
473 self.syntax_context_data[ctxt.0 as usize].parent
474 }
475
476 fn remove_mark(&self, ctxt: &mut SyntaxContext) -> (ExpnId, Transparency) {
477 let outer_mark = self.outer_mark(*ctxt);
478 *ctxt = self.parent_ctxt(*ctxt);
479 outer_mark
480 }
481
482 fn marks(&self, mut ctxt: SyntaxContext) -> Vec<(ExpnId, Transparency)> {
483 let mut marks = Vec::new();
484 while !ctxt.is_root() {
485 debug!("marks: getting parent of {:?}", ctxt);
486 marks.push(self.outer_mark(ctxt));
487 ctxt = self.parent_ctxt(ctxt);
488 }
489 marks.reverse();
490 marks
491 }
492
493 fn walk_chain(&self, mut span: Span, to: SyntaxContext) -> Span {
494 let orig_span = span;
495 debug!("walk_chain({:?}, {:?})", span, to);
496 debug!("walk_chain: span ctxt = {:?}", span.ctxt());
497 while span.ctxt() != to && span.from_expansion() {
498 let outer_expn = self.outer_expn(span.ctxt());
499 debug!("walk_chain({:?}): outer_expn={:?}", span, outer_expn);
500 let expn_data = self.expn_data(outer_expn);
501 debug!("walk_chain({:?}): expn_data={:?}", span, expn_data);
502 span = expn_data.call_site;
503 }
504 debug!("walk_chain: for span {:?} >>> return span = {:?}", orig_span, span);
505 span
506 }
507
508 fn walk_chain_collapsed(&self, mut span: Span, to: Span) -> Span {
509 let orig_span = span;
510 let mut ret_span = span;
511 debug!("walk_chain_collapsed({:?}, {:?})", span, to);
512 debug!("walk_chain_collapsed: span ctxt = {:?}", span.ctxt());
513 while let ctxt = span.ctxt()
514 && !ctxt.is_root()
515 && ctxt != to.ctxt()
516 {
517 let outer_expn = self.outer_expn(ctxt);
518 debug!("walk_chain_collapsed({:?}): outer_expn={:?}", span, outer_expn);
519 let expn_data = self.expn_data(outer_expn);
520 debug!("walk_chain_collapsed({:?}): expn_data={:?}", span, expn_data);
521 span = expn_data.call_site;
522 if expn_data.collapse_debuginfo {
523 ret_span = span;
524 }
525 }
526 debug!("walk_chain_collapsed: for span {:?} >>> return span = {:?}", orig_span, ret_span);
527 ret_span
528 }
529
530 fn adjust(&self, ctxt: &mut SyntaxContext, expn_id: ExpnId) -> Option<ExpnId> {
531 let mut scope = None;
532 while !self.is_descendant_of(expn_id, self.outer_expn(*ctxt)) {
533 scope = Some(self.remove_mark(ctxt).0);
534 }
535 scope
536 }
537
538 fn apply_mark(
539 &mut self,
540 ctxt: SyntaxContext,
541 expn_id: ExpnId,
542 transparency: Transparency,
543 ) -> SyntaxContext {
544 assert_ne!(expn_id, ExpnId::root());
545 if transparency == Transparency::Opaque {
546 return self.alloc_ctxt(ctxt, expn_id, transparency);
547 }
548
549 let call_site_ctxt = self.expn_data(expn_id).call_site.ctxt();
550 let mut call_site_ctxt = if transparency == Transparency::SemiOpaque {
551 self.normalize_to_macros_2_0(call_site_ctxt)
552 } else {
553 self.normalize_to_macro_rules(call_site_ctxt)
554 };
555
556 if call_site_ctxt.is_root() {
557 return self.alloc_ctxt(ctxt, expn_id, transparency);
558 }
559
560 for (expn_id, transparency) in self.marks(ctxt) {
570 call_site_ctxt = self.alloc_ctxt(call_site_ctxt, expn_id, transparency);
571 }
572 self.alloc_ctxt(call_site_ctxt, expn_id, transparency)
573 }
574
575 fn alloc_ctxt(
578 &mut self,
579 parent: SyntaxContext,
580 expn_id: ExpnId,
581 transparency: Transparency,
582 ) -> SyntaxContext {
583 let key = (parent, expn_id, transparency);
585 if let Some(ctxt) = self.syntax_context_map.get(&key) {
586 return *ctxt;
587 }
588
589 let ctxt = SyntaxContext::from_usize(self.syntax_context_data.len());
593 self.syntax_context_data
594 .push(SyntaxContextData { dollar_crate_name: sym::dummy, ..SyntaxContextData::root() });
595 self.syntax_context_map.insert(key, ctxt);
596
597 let parent_data = &self.syntax_context_data[parent.0 as usize];
601 assert_ne!(parent_data.dollar_crate_name, sym::dummy);
602 let parent_opaque = parent_data.opaque;
603 let parent_opaque_and_semiopaque = parent_data.opaque_and_semiopaque;
604
605 let (opaque, opaque_and_semiopaque) = match transparency {
607 Transparency::Transparent => (parent_opaque, parent_opaque_and_semiopaque),
608 Transparency::SemiOpaque => (
609 parent_opaque,
610 self.alloc_ctxt(parent_opaque_and_semiopaque, expn_id, transparency),
612 ),
613 Transparency::Opaque => (
614 self.alloc_ctxt(parent_opaque, expn_id, transparency),
616 self.alloc_ctxt(parent_opaque_and_semiopaque, expn_id, transparency),
618 ),
619 };
620
621 self.syntax_context_data[ctxt.as_u32() as usize] = SyntaxContextData {
623 outer_expn: expn_id,
624 outer_transparency: transparency,
625 parent,
626 opaque,
627 opaque_and_semiopaque,
628 dollar_crate_name: kw::DollarCrate,
629 };
630 ctxt
631 }
632}
633
634pub fn walk_chain(span: Span, to: SyntaxContext) -> Span {
635 HygieneData::with(|data| data.walk_chain(span, to))
636}
637
638pub fn walk_chain_collapsed(span: Span, to: Span) -> Span {
644 HygieneData::with(|data| data.walk_chain_collapsed(span, to))
645}
646
647pub fn update_dollar_crate_names(mut get_name: impl FnMut(SyntaxContext) -> Symbol) {
648 let mut to_update = vec![];
650 HygieneData::with(|data| {
651 for (idx, scdata) in data.syntax_context_data.iter().enumerate().rev() {
652 if scdata.dollar_crate_name == kw::DollarCrate {
653 to_update.push((idx, kw::DollarCrate));
654 } else {
655 break;
656 }
657 }
658 });
659 for (idx, name) in &mut to_update {
662 *name = get_name(SyntaxContext::from_usize(*idx));
663 }
664 HygieneData::with(|data| {
665 for (idx, name) in to_update {
666 data.syntax_context_data[idx].dollar_crate_name = name;
667 }
668 })
669}
670
671pub fn debug_hygiene_data(verbose: bool) -> String {
672 HygieneData::with(|data| {
673 if verbose {
674 format!("{data:#?}")
675 } else {
676 let mut s = String::from("Expansions:");
677 let mut debug_expn_data = |(id, expn_data): (&ExpnId, &ExpnData)| {
678 s.push_str(&format!(
679 "\n{:?}: parent: {:?}, call_site_ctxt: {:?}, def_site_ctxt: {:?}, kind: {:?}",
680 id,
681 expn_data.parent,
682 expn_data.call_site.ctxt(),
683 expn_data.def_site.ctxt(),
684 expn_data.kind,
685 ))
686 };
687 data.local_expn_data.iter_enumerated().for_each(|(id, expn_data)| {
688 let expn_data = expn_data.as_ref().expect("no expansion data for an expansion ID");
689 debug_expn_data((&id.to_expn_id(), expn_data))
690 });
691
692 #[allow(rustc::potential_query_instability)]
695 let mut foreign_expn_data: Vec<_> = data.foreign_expn_data.iter().collect();
696 foreign_expn_data.sort_by_key(|(id, _)| (id.krate, id.local_id));
697 foreign_expn_data.into_iter().for_each(debug_expn_data);
698 s.push_str("\n\nSyntaxContexts:");
699 data.syntax_context_data.iter().enumerate().for_each(|(id, ctxt)| {
700 s.push_str(&format!(
701 "\n#{}: parent: {:?}, outer_mark: ({:?}, {:?})",
702 id, ctxt.parent, ctxt.outer_expn, ctxt.outer_transparency,
703 ));
704 });
705 s
706 }
707 })
708}
709
710impl SyntaxContext {
711 #[inline]
712 pub const fn root() -> Self {
713 SyntaxContext(0)
714 }
715
716 #[inline]
717 pub const fn is_root(self) -> bool {
718 self.0 == SyntaxContext::root().as_u32()
719 }
720
721 #[inline]
722 pub(crate) const fn as_u32(self) -> u32 {
723 self.0
724 }
725
726 #[inline]
727 pub(crate) const fn from_u32(raw: u32) -> SyntaxContext {
728 SyntaxContext(raw)
729 }
730
731 #[inline]
732 pub(crate) const fn from_u16(raw: u16) -> SyntaxContext {
733 SyntaxContext(raw as u32)
734 }
735
736 #[inline]
737 fn from_usize(raw: usize) -> SyntaxContext {
738 SyntaxContext(u32::try_from(raw).unwrap())
739 }
740
741 #[inline]
743 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 #[inline]
764 pub fn remove_mark(&mut self) -> ExpnId {
765 HygieneData::with(|data| data.remove_mark(self).0)
766 }
767
768 #[inline]
769 pub fn marks(self) -> Vec<(ExpnId, Transparency)> {
770 HygieneData::with(|data| data.marks(self))
771 }
772
773 #[inline]
801 pub fn adjust(&mut self, expn_id: ExpnId) -> Option<ExpnId> {
802 HygieneData::with(|data| data.adjust(self, expn_id))
803 }
804
805 #[inline]
807 pub(crate) fn normalize_to_macros_2_0_and_adjust(&mut self, expn_id: ExpnId) -> Option<ExpnId> {
808 HygieneData::with(|data| {
809 *self = data.normalize_to_macros_2_0(*self);
810 data.adjust(self, expn_id)
811 })
812 }
813
814 pub(crate) fn glob_adjust(
841 &mut self,
842 expn_id: ExpnId,
843 glob_span: Span,
844 ) -> Option<Option<ExpnId>> {
845 HygieneData::with(|data| {
846 let mut scope = None;
847 let mut glob_ctxt = data.normalize_to_macros_2_0(glob_span.ctxt());
848 while !data.is_descendant_of(expn_id, data.outer_expn(glob_ctxt)) {
849 scope = Some(data.remove_mark(&mut glob_ctxt).0);
850 if data.remove_mark(self).0 != scope.unwrap() {
851 return None;
852 }
853 }
854 if data.adjust(self, expn_id).is_some() {
855 return None;
856 }
857 Some(scope)
858 })
859 }
860
861 pub(crate) fn reverse_glob_adjust(
869 &mut self,
870 expn_id: ExpnId,
871 glob_span: Span,
872 ) -> Option<Option<ExpnId>> {
873 HygieneData::with(|data| {
874 if data.adjust(self, expn_id).is_some() {
875 return None;
876 }
877
878 let mut glob_ctxt = data.normalize_to_macros_2_0(glob_span.ctxt());
879 let mut marks = Vec::new();
880 while !data.is_descendant_of(expn_id, data.outer_expn(glob_ctxt)) {
881 marks.push(data.remove_mark(&mut glob_ctxt));
882 }
883
884 let scope = marks.last().map(|mark| mark.0);
885 while let Some((expn_id, transparency)) = marks.pop() {
886 *self = data.apply_mark(*self, expn_id, transparency);
887 }
888 Some(scope)
889 })
890 }
891
892 pub fn hygienic_eq(self, other: SyntaxContext, expn_id: ExpnId) -> bool {
893 HygieneData::with(|data| {
894 let mut self_normalized = data.normalize_to_macros_2_0(self);
895 data.adjust(&mut self_normalized, expn_id);
896 self_normalized == data.normalize_to_macros_2_0(other)
897 })
898 }
899
900 #[inline]
901 pub fn normalize_to_macros_2_0(self) -> SyntaxContext {
902 HygieneData::with(|data| data.normalize_to_macros_2_0(self))
903 }
904
905 #[inline]
906 pub fn normalize_to_macro_rules(self) -> SyntaxContext {
907 HygieneData::with(|data| data.normalize_to_macro_rules(self))
908 }
909
910 #[inline]
912 pub fn outer_expn(self) -> ExpnId {
913 HygieneData::with(|data| data.outer_expn(self))
914 }
915
916 #[inline]
919 pub fn outer_expn_data(self) -> ExpnData {
920 HygieneData::with(|data| data.expn_data(data.outer_expn(self)).clone())
921 }
922
923 #[inline]
925 fn outer_mark(self) -> (ExpnId, Transparency) {
926 HygieneData::with(|data| data.outer_mark(self))
927 }
928
929 #[inline]
930 pub(crate) fn dollar_crate_name(self) -> Symbol {
931 HygieneData::with(|data| data.syntax_context_data[self.0 as usize].dollar_crate_name)
932 }
933
934 #[inline]
935 pub fn edition(self) -> Edition {
936 HygieneData::with(|data| data.expn_data(data.outer_expn(self)).edition)
937 }
938
939 pub fn in_external_macro(self, sm: &SourceMap) -> bool {
944 let expn_data = self.outer_expn_data();
945 match expn_data.kind {
946 ExpnKind::Root
947 | ExpnKind::Desugaring(
948 DesugaringKind::ForLoop
949 | DesugaringKind::WhileLoop
950 | DesugaringKind::OpaqueTy
951 | DesugaringKind::Async
952 | DesugaringKind::Await,
953 ) => false,
954 ExpnKind::AstPass(_) | ExpnKind::Desugaring(_) => true, ExpnKind::Macro(MacroKind::Bang, _) => {
956 expn_data.def_site.is_dummy() || sm.is_imported(expn_data.def_site)
958 }
959 ExpnKind::Macro { .. } => true, }
961 }
962}
963
964impl fmt::Debug for SyntaxContext {
965 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
966 write!(f, "#{}", self.0)
967 }
968}
969
970impl Span {
971 pub fn mark_with_reason(
974 self,
975 allow_internal_unstable: Option<Arc<[Symbol]>>,
976 reason: DesugaringKind,
977 edition: Edition,
978 ctx: impl HashStableContext,
979 ) -> Span {
980 let expn_data = ExpnData {
981 allow_internal_unstable,
982 ..ExpnData::default(ExpnKind::Desugaring(reason), self, edition, None, None)
983 };
984 let expn_id = LocalExpnId::fresh(expn_data, ctx);
985 self.apply_mark(expn_id.to_expn_id(), Transparency::Transparent)
986 }
987}
988
989#[derive(Clone, Debug, Encodable, Decodable, HashStable_Generic)]
992pub struct ExpnData {
993 pub kind: ExpnKind,
995 pub parent: ExpnId,
997 pub call_site: Span,
1009 disambiguator: u32,
1020
1021 pub def_site: Span,
1028 pub allow_internal_unstable: Option<Arc<[Symbol]>>,
1032 pub edition: Edition,
1034 pub macro_def_id: Option<DefId>,
1037 pub parent_module: Option<DefId>,
1039 pub(crate) allow_internal_unsafe: bool,
1041 pub local_inner_macros: bool,
1043 pub(crate) collapse_debuginfo: bool,
1046 pub hide_backtrace: bool,
1048}
1049
1050impl !PartialEq for ExpnData {}
1051impl !Hash for ExpnData {}
1052
1053impl ExpnData {
1054 pub fn new(
1055 kind: ExpnKind,
1056 parent: ExpnId,
1057 call_site: Span,
1058 def_site: Span,
1059 allow_internal_unstable: Option<Arc<[Symbol]>>,
1060 edition: Edition,
1061 macro_def_id: Option<DefId>,
1062 parent_module: Option<DefId>,
1063 allow_internal_unsafe: bool,
1064 local_inner_macros: bool,
1065 collapse_debuginfo: bool,
1066 hide_backtrace: bool,
1067 ) -> ExpnData {
1068 ExpnData {
1069 kind,
1070 parent,
1071 call_site,
1072 def_site,
1073 allow_internal_unstable,
1074 edition,
1075 macro_def_id,
1076 parent_module,
1077 disambiguator: 0,
1078 allow_internal_unsafe,
1079 local_inner_macros,
1080 collapse_debuginfo,
1081 hide_backtrace,
1082 }
1083 }
1084
1085 pub fn default(
1087 kind: ExpnKind,
1088 call_site: Span,
1089 edition: Edition,
1090 macro_def_id: Option<DefId>,
1091 parent_module: Option<DefId>,
1092 ) -> ExpnData {
1093 ExpnData {
1094 kind,
1095 parent: ExpnId::root(),
1096 call_site,
1097 def_site: DUMMY_SP,
1098 allow_internal_unstable: None,
1099 edition,
1100 macro_def_id,
1101 parent_module,
1102 disambiguator: 0,
1103 allow_internal_unsafe: false,
1104 local_inner_macros: false,
1105 collapse_debuginfo: false,
1106 hide_backtrace: false,
1107 }
1108 }
1109
1110 pub fn allow_unstable(
1111 kind: ExpnKind,
1112 call_site: Span,
1113 edition: Edition,
1114 allow_internal_unstable: Arc<[Symbol]>,
1115 macro_def_id: Option<DefId>,
1116 parent_module: Option<DefId>,
1117 ) -> ExpnData {
1118 ExpnData {
1119 allow_internal_unstable: Some(allow_internal_unstable),
1120 ..ExpnData::default(kind, call_site, edition, macro_def_id, parent_module)
1121 }
1122 }
1123
1124 #[inline]
1125 pub fn is_root(&self) -> bool {
1126 matches!(self.kind, ExpnKind::Root)
1127 }
1128
1129 #[inline]
1130 fn hash_expn(&self, ctx: &mut impl HashStableContext) -> Hash64 {
1131 let mut hasher = StableHasher::new();
1132 self.hash_stable(ctx, &mut hasher);
1133 hasher.finish()
1134 }
1135}
1136
1137#[derive(Clone, Debug, PartialEq, Encodable, Decodable, HashStable_Generic)]
1139pub enum ExpnKind {
1140 Root,
1142 Macro(MacroKind, Symbol),
1144 AstPass(AstPass),
1146 Desugaring(DesugaringKind),
1148}
1149
1150impl ExpnKind {
1151 pub fn descr(&self) -> String {
1152 match *self {
1153 ExpnKind::Root => kw::PathRoot.to_string(),
1154 ExpnKind::Macro(macro_kind, name) => match macro_kind {
1155 MacroKind::Bang => format!("{name}!"),
1156 MacroKind::Attr => format!("#[{name}]"),
1157 MacroKind::Derive => format!("#[derive({name})]"),
1158 },
1159 ExpnKind::AstPass(kind) => kind.descr().to_string(),
1160 ExpnKind::Desugaring(kind) => format!("desugaring of {}", kind.descr()),
1161 }
1162 }
1163}
1164
1165#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Encodable, Decodable, Hash, Debug)]
1167#[derive(HashStable_Generic)]
1168pub enum MacroKind {
1169 Bang,
1171 Attr,
1173 Derive,
1175}
1176
1177impl MacroKind {
1178 pub fn descr(self) -> &'static str {
1179 match self {
1180 MacroKind::Bang => "macro",
1181 MacroKind::Attr => "attribute macro",
1182 MacroKind::Derive => "derive macro",
1183 }
1184 }
1185
1186 pub fn descr_expected(self) -> &'static str {
1187 match self {
1188 MacroKind::Attr => "attribute",
1189 _ => self.descr(),
1190 }
1191 }
1192
1193 pub fn article(self) -> &'static str {
1194 match self {
1195 MacroKind::Attr => "an",
1196 _ => "a",
1197 }
1198 }
1199}
1200
1201#[derive(Clone, Copy, Debug, PartialEq, Encodable, Decodable, HashStable_Generic)]
1203pub enum AstPass {
1204 StdImports,
1205 TestHarness,
1206 ProcMacroHarness,
1207}
1208
1209impl AstPass {
1210 pub fn descr(self) -> &'static str {
1211 match self {
1212 AstPass::StdImports => "standard library imports",
1213 AstPass::TestHarness => "test harness",
1214 AstPass::ProcMacroHarness => "proc macro harness",
1215 }
1216 }
1217}
1218
1219#[derive(Clone, Copy, PartialEq, Debug, Encodable, Decodable, HashStable_Generic)]
1221pub enum DesugaringKind {
1222 QuestionMark,
1223 TryBlock,
1224 YeetExpr,
1225 OpaqueTy,
1229 Async,
1230 Await,
1231 ForLoop,
1232 WhileLoop,
1233 BoundModifier,
1235 Contract,
1237 PatTyRange,
1239 FormatLiteral {
1241 source: bool,
1249 },
1250}
1251
1252impl DesugaringKind {
1253 pub fn descr(self) -> &'static str {
1255 match self {
1256 DesugaringKind::Async => "`async` block or function",
1257 DesugaringKind::Await => "`await` expression",
1258 DesugaringKind::QuestionMark => "operator `?`",
1259 DesugaringKind::TryBlock => "`try` block",
1260 DesugaringKind::YeetExpr => "`do yeet` expression",
1261 DesugaringKind::OpaqueTy => "`impl Trait`",
1262 DesugaringKind::ForLoop => "`for` loop",
1263 DesugaringKind::WhileLoop => "`while` loop",
1264 DesugaringKind::BoundModifier => "trait bound modifier",
1265 DesugaringKind::Contract => "contract check",
1266 DesugaringKind::PatTyRange => "pattern type",
1267 DesugaringKind::FormatLiteral { source: true } => "format string literal",
1268 DesugaringKind::FormatLiteral { source: false } => {
1269 "expression that expanded into a format string literal"
1270 }
1271 }
1272 }
1273
1274 pub fn matches(&self, value: &str) -> bool {
1277 match self {
1278 DesugaringKind::Async => value == "Async",
1279 DesugaringKind::Await => value == "Await",
1280 DesugaringKind::QuestionMark => value == "QuestionMark",
1281 DesugaringKind::TryBlock => value == "TryBlock",
1282 DesugaringKind::YeetExpr => value == "YeetExpr",
1283 DesugaringKind::OpaqueTy => value == "OpaqueTy",
1284 DesugaringKind::ForLoop => value == "ForLoop",
1285 DesugaringKind::WhileLoop => value == "WhileLoop",
1286 DesugaringKind::BoundModifier => value == "BoundModifier",
1287 DesugaringKind::Contract => value == "Contract",
1288 DesugaringKind::PatTyRange => value == "PatTyRange",
1289 DesugaringKind::FormatLiteral { .. } => value == "FormatLiteral",
1290 }
1291 }
1292}
1293
1294#[derive(Default)]
1295pub struct HygieneEncodeContext {
1296 serialized_ctxts: Lock<FxHashSet<SyntaxContext>>,
1300 latest_ctxts: Lock<FxHashSet<SyntaxContext>>,
1305
1306 serialized_expns: Lock<FxHashSet<ExpnId>>,
1307
1308 latest_expns: Lock<FxHashSet<ExpnId>>,
1309}
1310
1311impl HygieneEncodeContext {
1312 pub fn schedule_expn_data_for_encoding(&self, expn: ExpnId) {
1314 if !self.serialized_expns.lock().contains(&expn) {
1315 self.latest_expns.lock().insert(expn);
1316 }
1317 }
1318
1319 pub fn encode<T>(
1320 &self,
1321 encoder: &mut T,
1322 mut encode_ctxt: impl FnMut(&mut T, u32, &SyntaxContextKey),
1323 mut encode_expn: impl FnMut(&mut T, ExpnId, &ExpnData, ExpnHash),
1324 ) {
1325 while !self.latest_ctxts.lock().is_empty() || !self.latest_expns.lock().is_empty() {
1328 debug!(
1329 "encode_hygiene: Serializing a round of {:?} SyntaxContextData: {:?}",
1330 self.latest_ctxts.lock().len(),
1331 self.latest_ctxts
1332 );
1333
1334 #[allow(rustc::potential_query_instability)]
1339 let latest_ctxts = { mem::take(&mut *self.latest_ctxts.lock()) }.into_iter();
1340 let all_ctxt_data: Vec<_> = HygieneData::with(|data| {
1341 latest_ctxts
1342 .map(|ctxt| (ctxt, data.syntax_context_data[ctxt.0 as usize].key()))
1343 .collect()
1344 });
1345 for (ctxt, ctxt_key) in all_ctxt_data {
1346 if self.serialized_ctxts.lock().insert(ctxt) {
1347 encode_ctxt(encoder, ctxt.0, &ctxt_key);
1348 }
1349 }
1350
1351 #[allow(rustc::potential_query_instability)]
1353 let latest_expns = { mem::take(&mut *self.latest_expns.lock()) }.into_iter();
1354 let all_expn_data: Vec<_> = HygieneData::with(|data| {
1355 latest_expns
1356 .map(|expn| (expn, data.expn_data(expn).clone(), data.expn_hash(expn)))
1357 .collect()
1358 });
1359 for (expn, expn_data, expn_hash) in all_expn_data {
1360 if self.serialized_expns.lock().insert(expn) {
1361 encode_expn(encoder, expn, &expn_data, expn_hash);
1362 }
1363 }
1364 }
1365 debug!("encode_hygiene: Done serializing SyntaxContextData");
1366 }
1367}
1368
1369#[derive(Default)]
1371pub struct HygieneDecodeContext {
1372 remapped_ctxts: Lock<IndexVec<u32, Option<SyntaxContext>>>,
1375}
1376
1377pub fn register_local_expn_id(data: ExpnData, hash: ExpnHash) -> ExpnId {
1379 HygieneData::with(|hygiene_data| {
1380 let expn_id = hygiene_data.local_expn_data.next_index();
1381 hygiene_data.local_expn_data.push(Some(data));
1382 let _eid = hygiene_data.local_expn_hashes.push(hash);
1383 debug_assert_eq!(expn_id, _eid);
1384
1385 let expn_id = expn_id.to_expn_id();
1386
1387 let _old_id = hygiene_data.expn_hash_to_expn_id.insert(hash, expn_id);
1388 debug_assert!(_old_id.is_none());
1389 expn_id
1390 })
1391}
1392
1393pub fn register_expn_id(
1395 krate: CrateNum,
1396 local_id: ExpnIndex,
1397 data: ExpnData,
1398 hash: ExpnHash,
1399) -> ExpnId {
1400 debug_assert!(data.parent == ExpnId::root() || krate == data.parent.krate);
1401 let expn_id = ExpnId { krate, local_id };
1402 HygieneData::with(|hygiene_data| {
1403 let _old_data = hygiene_data.foreign_expn_data.insert(expn_id, data);
1404 let _old_hash = hygiene_data.foreign_expn_hashes.insert(expn_id, hash);
1405 debug_assert!(_old_hash.is_none() || _old_hash == Some(hash));
1406 let _old_id = hygiene_data.expn_hash_to_expn_id.insert(hash, expn_id);
1407 debug_assert!(_old_id.is_none() || _old_id == Some(expn_id));
1408 });
1409 expn_id
1410}
1411
1412pub fn decode_expn_id(
1414 krate: CrateNum,
1415 index: u32,
1416 decode_data: impl FnOnce(ExpnId) -> (ExpnData, ExpnHash),
1417) -> ExpnId {
1418 if index == 0 {
1419 trace!("decode_expn_id: deserialized root");
1420 return ExpnId::root();
1421 }
1422
1423 let index = ExpnIndex::from_u32(index);
1424
1425 debug_assert_ne!(krate, LOCAL_CRATE);
1427 let expn_id = ExpnId { krate, local_id: index };
1428
1429 if HygieneData::with(|hygiene_data| hygiene_data.foreign_expn_data.contains_key(&expn_id)) {
1431 return expn_id;
1432 }
1433
1434 let (expn_data, hash) = decode_data(expn_id);
1437
1438 register_expn_id(krate, index, expn_data, hash)
1439}
1440
1441pub fn decode_syntax_context<D: Decoder>(
1446 d: &mut D,
1447 context: &HygieneDecodeContext,
1448 decode_data: impl FnOnce(&mut D, u32) -> SyntaxContextKey,
1449) -> SyntaxContext {
1450 let raw_id: u32 = Decodable::decode(d);
1451 if raw_id == 0 {
1452 trace!("decode_syntax_context: deserialized root");
1453 return SyntaxContext::root();
1455 }
1456
1457 if let Some(Some(ctxt)) = context.remapped_ctxts.lock().get(raw_id) {
1461 return *ctxt;
1462 }
1463
1464 let (parent, expn_id, transparency) = decode_data(d, raw_id);
1467 let ctxt =
1468 HygieneData::with(|hygiene_data| hygiene_data.alloc_ctxt(parent, expn_id, transparency));
1469
1470 context.remapped_ctxts.lock().insert(raw_id, ctxt);
1471
1472 ctxt
1473}
1474
1475impl<E: SpanEncoder> Encodable<E> for LocalExpnId {
1476 fn encode(&self, e: &mut E) {
1477 self.to_expn_id().encode(e);
1478 }
1479}
1480
1481impl<D: SpanDecoder> Decodable<D> for LocalExpnId {
1482 fn decode(d: &mut D) -> Self {
1483 ExpnId::expect_local(ExpnId::decode(d))
1484 }
1485}
1486
1487pub fn raw_encode_syntax_context(
1488 ctxt: SyntaxContext,
1489 context: &HygieneEncodeContext,
1490 e: &mut impl Encoder,
1491) {
1492 if !context.serialized_ctxts.lock().contains(&ctxt) {
1493 context.latest_ctxts.lock().insert(ctxt);
1494 }
1495 ctxt.0.encode(e);
1496}
1497
1498fn update_disambiguator(expn_data: &mut ExpnData, mut ctx: impl HashStableContext) -> ExpnHash {
1508 assert_eq!(expn_data.disambiguator, 0, "Already set disambiguator for ExpnData: {expn_data:?}");
1510 assert_default_hashing_controls(&ctx, "ExpnData (disambiguator)");
1511 let mut expn_hash = expn_data.hash_expn(&mut ctx);
1512
1513 let disambiguator = HygieneData::with(|data| {
1514 let disambig = data.expn_data_disambiguators.entry(expn_hash).or_default();
1517 let disambiguator = *disambig;
1518 *disambig += 1;
1519 disambiguator
1520 });
1521
1522 if disambiguator != 0 {
1523 debug!("Set disambiguator for expn_data={:?} expn_hash={:?}", expn_data, expn_hash);
1524
1525 expn_data.disambiguator = disambiguator;
1526 expn_hash = expn_data.hash_expn(&mut ctx);
1527
1528 #[cfg(debug_assertions)]
1530 HygieneData::with(|data| {
1531 assert_eq!(
1532 data.expn_data_disambiguators.get(&expn_hash),
1533 None,
1534 "Hash collision after disambiguator update!",
1535 );
1536 });
1537 }
1538
1539 ExpnHash::new(ctx.def_path_hash(LOCAL_CRATE.as_def_id()).stable_crate_id(), expn_hash)
1540}
1541
1542impl<CTX: HashStableContext> HashStable<CTX> for SyntaxContext {
1543 fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) {
1544 const TAG_EXPANSION: u8 = 0;
1545 const TAG_NO_EXPANSION: u8 = 1;
1546
1547 if self.is_root() {
1548 TAG_NO_EXPANSION.hash_stable(ctx, hasher);
1549 } else {
1550 TAG_EXPANSION.hash_stable(ctx, hasher);
1551 let (expn_id, transparency) = self.outer_mark();
1552 expn_id.hash_stable(ctx, hasher);
1553 transparency.hash_stable(ctx, hasher);
1554 }
1555 }
1556}
1557
1558impl<CTX: HashStableContext> HashStable<CTX> for ExpnId {
1559 fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) {
1560 assert_default_hashing_controls(ctx, "ExpnId");
1561 let hash = if *self == ExpnId::root() {
1562 Fingerprint::ZERO
1564 } else {
1565 self.expn_hash().0
1566 };
1567
1568 hash.hash_stable(ctx, hasher);
1569 }
1570}