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    RangeExpr,
1251}
1252
1253impl DesugaringKind {
1254    pub fn descr(self) -> &'static str {
1256        match self {
1257            DesugaringKind::Async => "`async` block or function",
1258            DesugaringKind::Await => "`await` expression",
1259            DesugaringKind::QuestionMark => "operator `?`",
1260            DesugaringKind::TryBlock => "`try` block",
1261            DesugaringKind::YeetExpr => "`do yeet` expression",
1262            DesugaringKind::OpaqueTy => "`impl Trait`",
1263            DesugaringKind::ForLoop => "`for` loop",
1264            DesugaringKind::WhileLoop => "`while` loop",
1265            DesugaringKind::BoundModifier => "trait bound modifier",
1266            DesugaringKind::Contract => "contract check",
1267            DesugaringKind::PatTyRange => "pattern type",
1268            DesugaringKind::FormatLiteral { source: true } => "format string literal",
1269            DesugaringKind::FormatLiteral { source: false } => {
1270                "expression that expanded into a format string literal"
1271            }
1272            DesugaringKind::RangeExpr => "range expression",
1273        }
1274    }
1275
1276    pub fn matches(&self, value: &str) -> bool {
1279        match self {
1280            DesugaringKind::Async => value == "Async",
1281            DesugaringKind::Await => value == "Await",
1282            DesugaringKind::QuestionMark => value == "QuestionMark",
1283            DesugaringKind::TryBlock => value == "TryBlock",
1284            DesugaringKind::YeetExpr => value == "YeetExpr",
1285            DesugaringKind::OpaqueTy => value == "OpaqueTy",
1286            DesugaringKind::ForLoop => value == "ForLoop",
1287            DesugaringKind::WhileLoop => value == "WhileLoop",
1288            DesugaringKind::BoundModifier => value == "BoundModifier",
1289            DesugaringKind::Contract => value == "Contract",
1290            DesugaringKind::PatTyRange => value == "PatTyRange",
1291            DesugaringKind::FormatLiteral { .. } => value == "FormatLiteral",
1292            DesugaringKind::RangeExpr => value == "RangeExpr",
1293        }
1294    }
1295}
1296
1297#[derive(Default)]
1298pub struct HygieneEncodeContext {
1299    serialized_ctxts: Lock<FxHashSet<SyntaxContext>>,
1303    latest_ctxts: Lock<FxHashSet<SyntaxContext>>,
1308
1309    serialized_expns: Lock<FxHashSet<ExpnId>>,
1310
1311    latest_expns: Lock<FxHashSet<ExpnId>>,
1312}
1313
1314impl HygieneEncodeContext {
1315    pub fn schedule_expn_data_for_encoding(&self, expn: ExpnId) {
1317        if !self.serialized_expns.lock().contains(&expn) {
1318            self.latest_expns.lock().insert(expn);
1319        }
1320    }
1321
1322    pub fn encode<T>(
1323        &self,
1324        encoder: &mut T,
1325        mut encode_ctxt: impl FnMut(&mut T, u32, &SyntaxContextKey),
1326        mut encode_expn: impl FnMut(&mut T, ExpnId, &ExpnData, ExpnHash),
1327    ) {
1328        while !self.latest_ctxts.lock().is_empty() || !self.latest_expns.lock().is_empty() {
1331            debug!(
1332                "encode_hygiene: Serializing a round of {:?} SyntaxContextData: {:?}",
1333                self.latest_ctxts.lock().len(),
1334                self.latest_ctxts
1335            );
1336
1337            #[allow(rustc::potential_query_instability)]
1342            let latest_ctxts = { mem::take(&mut *self.latest_ctxts.lock()) }.into_iter();
1343            let all_ctxt_data: Vec<_> = HygieneData::with(|data| {
1344                latest_ctxts
1345                    .map(|ctxt| (ctxt, data.syntax_context_data[ctxt.0 as usize].key()))
1346                    .collect()
1347            });
1348            for (ctxt, ctxt_key) in all_ctxt_data {
1349                if self.serialized_ctxts.lock().insert(ctxt) {
1350                    encode_ctxt(encoder, ctxt.0, &ctxt_key);
1351                }
1352            }
1353
1354            #[allow(rustc::potential_query_instability)]
1356            let latest_expns = { mem::take(&mut *self.latest_expns.lock()) }.into_iter();
1357            let all_expn_data: Vec<_> = HygieneData::with(|data| {
1358                latest_expns
1359                    .map(|expn| (expn, data.expn_data(expn).clone(), data.expn_hash(expn)))
1360                    .collect()
1361            });
1362            for (expn, expn_data, expn_hash) in all_expn_data {
1363                if self.serialized_expns.lock().insert(expn) {
1364                    encode_expn(encoder, expn, &expn_data, expn_hash);
1365                }
1366            }
1367        }
1368        debug!("encode_hygiene: Done serializing SyntaxContextData");
1369    }
1370}
1371
1372#[derive(Default)]
1374pub struct HygieneDecodeContext {
1375    remapped_ctxts: Lock<IndexVec<u32, Option<SyntaxContext>>>,
1378}
1379
1380pub fn register_local_expn_id(data: ExpnData, hash: ExpnHash) -> ExpnId {
1382    HygieneData::with(|hygiene_data| {
1383        let expn_id = hygiene_data.local_expn_data.next_index();
1384        hygiene_data.local_expn_data.push(Some(data));
1385        let _eid = hygiene_data.local_expn_hashes.push(hash);
1386        debug_assert_eq!(expn_id, _eid);
1387
1388        let expn_id = expn_id.to_expn_id();
1389
1390        let _old_id = hygiene_data.expn_hash_to_expn_id.insert(hash, expn_id);
1391        debug_assert!(_old_id.is_none());
1392        expn_id
1393    })
1394}
1395
1396pub fn register_expn_id(
1398    krate: CrateNum,
1399    local_id: ExpnIndex,
1400    data: ExpnData,
1401    hash: ExpnHash,
1402) -> ExpnId {
1403    debug_assert!(data.parent == ExpnId::root() || krate == data.parent.krate);
1404    let expn_id = ExpnId { krate, local_id };
1405    HygieneData::with(|hygiene_data| {
1406        let _old_data = hygiene_data.foreign_expn_data.insert(expn_id, data);
1407        let _old_hash = hygiene_data.foreign_expn_hashes.insert(expn_id, hash);
1408        debug_assert!(_old_hash.is_none() || _old_hash == Some(hash));
1409        let _old_id = hygiene_data.expn_hash_to_expn_id.insert(hash, expn_id);
1410        debug_assert!(_old_id.is_none() || _old_id == Some(expn_id));
1411    });
1412    expn_id
1413}
1414
1415pub fn decode_expn_id(
1417    krate: CrateNum,
1418    index: u32,
1419    decode_data: impl FnOnce(ExpnId) -> (ExpnData, ExpnHash),
1420) -> ExpnId {
1421    if index == 0 {
1422        trace!("decode_expn_id: deserialized root");
1423        return ExpnId::root();
1424    }
1425
1426    let index = ExpnIndex::from_u32(index);
1427
1428    debug_assert_ne!(krate, LOCAL_CRATE);
1430    let expn_id = ExpnId { krate, local_id: index };
1431
1432    if HygieneData::with(|hygiene_data| hygiene_data.foreign_expn_data.contains_key(&expn_id)) {
1434        return expn_id;
1435    }
1436
1437    let (expn_data, hash) = decode_data(expn_id);
1440
1441    register_expn_id(krate, index, expn_data, hash)
1442}
1443
1444pub fn decode_syntax_context<D: Decoder>(
1449    d: &mut D,
1450    context: &HygieneDecodeContext,
1451    decode_data: impl FnOnce(&mut D, u32) -> SyntaxContextKey,
1452) -> SyntaxContext {
1453    let raw_id: u32 = Decodable::decode(d);
1454    if raw_id == 0 {
1455        trace!("decode_syntax_context: deserialized root");
1456        return SyntaxContext::root();
1458    }
1459
1460    if let Some(Some(ctxt)) = context.remapped_ctxts.lock().get(raw_id) {
1464        return *ctxt;
1465    }
1466
1467    let (parent, expn_id, transparency) = decode_data(d, raw_id);
1470    let ctxt =
1471        HygieneData::with(|hygiene_data| hygiene_data.alloc_ctxt(parent, expn_id, transparency));
1472
1473    context.remapped_ctxts.lock().insert(raw_id, ctxt);
1474
1475    ctxt
1476}
1477
1478impl<E: SpanEncoder> Encodable<E> for LocalExpnId {
1479    fn encode(&self, e: &mut E) {
1480        self.to_expn_id().encode(e);
1481    }
1482}
1483
1484impl<D: SpanDecoder> Decodable<D> for LocalExpnId {
1485    fn decode(d: &mut D) -> Self {
1486        ExpnId::expect_local(ExpnId::decode(d))
1487    }
1488}
1489
1490pub fn raw_encode_syntax_context(
1491    ctxt: SyntaxContext,
1492    context: &HygieneEncodeContext,
1493    e: &mut impl Encoder,
1494) {
1495    if !context.serialized_ctxts.lock().contains(&ctxt) {
1496        context.latest_ctxts.lock().insert(ctxt);
1497    }
1498    ctxt.0.encode(e);
1499}
1500
1501fn update_disambiguator(expn_data: &mut ExpnData, mut ctx: impl HashStableContext) -> ExpnHash {
1511    assert_eq!(expn_data.disambiguator, 0, "Already set disambiguator for ExpnData: {expn_data:?}");
1513    assert_default_hashing_controls(&ctx, "ExpnData (disambiguator)");
1514    let mut expn_hash = expn_data.hash_expn(&mut ctx);
1515
1516    let disambiguator = HygieneData::with(|data| {
1517        let disambig = data.expn_data_disambiguators.entry(expn_hash).or_default();
1520        let disambiguator = *disambig;
1521        *disambig += 1;
1522        disambiguator
1523    });
1524
1525    if disambiguator != 0 {
1526        debug!("Set disambiguator for expn_data={:?} expn_hash={:?}", expn_data, expn_hash);
1527
1528        expn_data.disambiguator = disambiguator;
1529        expn_hash = expn_data.hash_expn(&mut ctx);
1530
1531        #[cfg(debug_assertions)]
1533        HygieneData::with(|data| {
1534            assert_eq!(
1535                data.expn_data_disambiguators.get(&expn_hash),
1536                None,
1537                "Hash collision after disambiguator update!",
1538            );
1539        });
1540    }
1541
1542    ExpnHash::new(ctx.def_path_hash(LOCAL_CRATE.as_def_id()).stable_crate_id(), expn_hash)
1543}
1544
1545impl<CTX: HashStableContext> HashStable<CTX> for SyntaxContext {
1546    fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) {
1547        const TAG_EXPANSION: u8 = 0;
1548        const TAG_NO_EXPANSION: u8 = 1;
1549
1550        if self.is_root() {
1551            TAG_NO_EXPANSION.hash_stable(ctx, hasher);
1552        } else {
1553            TAG_EXPANSION.hash_stable(ctx, hasher);
1554            let (expn_id, transparency) = self.outer_mark();
1555            expn_id.hash_stable(ctx, hasher);
1556            transparency.hash_stable(ctx, hasher);
1557        }
1558    }
1559}
1560
1561impl<CTX: HashStableContext> HashStable<CTX> for ExpnId {
1562    fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) {
1563        assert_default_hashing_controls(ctx, "ExpnId");
1564        let hash = if *self == ExpnId::root() {
1565            Fingerprint::ZERO
1567        } else {
1568            self.expn_hash().0
1569        };
1570
1571        hash.hash_stable(ctx, hasher);
1572    }
1573}