]> git.lizzy.rs Git - rust.git/blob - src/libsyntax_pos/hygiene.rs
Add `modernize_and_adjust` methods.
[rust.git] / src / libsyntax_pos / hygiene.rs
1 //! Machinery for hygienic macros, inspired by the `MTWT[1]` paper.
2 //!
3 //! `[1]` Matthew Flatt, Ryan Culpepper, David Darais, and Robert Bruce Findler. 2012.
4 //! *Macros that work together: Compile-time bindings, partial expansion,
5 //! and definition contexts*. J. Funct. Program. 22, 2 (March 2012), 181-216.
6 //! DOI=10.1017/S0956796812000093 <https://doi.org/10.1017/S0956796812000093>
7
8 // Hygiene data is stored in a global variable and accessed via TLS, which
9 // means that accesses are somewhat expensive. (`HygieneData::with`
10 // encapsulates a single access.) Therefore, on hot code paths it is worth
11 // ensuring that multiple HygieneData accesses are combined into a single
12 // `HygieneData::with`.
13 //
14 // This explains why `HygieneData`, `SyntaxContext` and `Mark` have interfaces
15 // with a certain amount of redundancy in them. For example,
16 // `SyntaxContext::outer_expn_info` combines `SyntaxContext::outer` and
17 // `Mark::expn_info` so that two `HygieneData` accesses can be performed within
18 // a single `HygieneData::with` call.
19 //
20 // It also explains why many functions appear in `HygieneData` and again in
21 // `SyntaxContext` or `Mark`. For example, `HygieneData::outer` and
22 // `SyntaxContext::outer` do the same thing, but the former is for use within a
23 // `HygieneData::with` call while the latter is for use outside such a call.
24 // When modifying this file it is important to understand this distinction,
25 // because getting it wrong can lead to nested `HygieneData::with` calls that
26 // trigger runtime aborts. (Fortunately these are obvious and easy to fix.)
27
28 use crate::GLOBALS;
29 use crate::Span;
30 use crate::edition::Edition;
31 use crate::symbol::{kw, Symbol};
32
33 use serialize::{Encodable, Decodable, Encoder, Decoder};
34 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
35 use rustc_data_structures::sync::Lrc;
36 use std::{fmt, mem};
37
38 /// A SyntaxContext represents a chain of macro expansions (represented by marks).
39 #[derive(Clone, Copy, PartialEq, Eq, Default, PartialOrd, Ord, Hash)]
40 pub struct SyntaxContext(u32);
41
42 #[derive(Copy, Clone, Debug)]
43 struct SyntaxContextData {
44     outer_mark: Mark,
45     transparency: Transparency,
46     prev_ctxt: SyntaxContext,
47     /// This context, but with all transparent and semi-transparent marks filtered away.
48     opaque: SyntaxContext,
49     /// This context, but with all transparent marks filtered away.
50     opaque_and_semitransparent: SyntaxContext,
51     /// Name of the crate to which `$crate` with this context would resolve.
52     dollar_crate_name: Symbol,
53 }
54
55 /// A mark is a unique ID associated with a macro expansion.
56 #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, RustcEncodable, RustcDecodable)]
57 pub struct Mark(u32);
58
59 #[derive(Clone, Debug)]
60 struct MarkData {
61     parent: Mark,
62     default_transparency: Transparency,
63     expn_info: Option<ExpnInfo>,
64 }
65
66 /// A property of a macro expansion that determines how identifiers
67 /// produced by that expansion are resolved.
68 #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Hash, Debug)]
69 pub enum Transparency {
70     /// Identifier produced by a transparent expansion is always resolved at call-site.
71     /// Call-site spans in procedural macros, hygiene opt-out in `macro` should use this.
72     Transparent,
73     /// Identifier produced by a semi-transparent expansion may be resolved
74     /// either at call-site or at definition-site.
75     /// If it's a local variable, label or `$crate` then it's resolved at def-site.
76     /// Otherwise it's resolved at call-site.
77     /// `macro_rules` macros behave like this, built-in macros currently behave like this too,
78     /// but that's an implementation detail.
79     SemiTransparent,
80     /// Identifier produced by an opaque expansion is always resolved at definition-site.
81     /// Def-site spans in procedural macros, identifiers from `macro` by default use this.
82     Opaque,
83 }
84
85 impl Mark {
86     pub fn fresh(parent: Mark) -> Self {
87         HygieneData::with(|data| {
88             data.marks.push(MarkData {
89                 parent,
90                 // By default expansions behave like `macro_rules`.
91                 default_transparency: Transparency::SemiTransparent,
92                 expn_info: None,
93             });
94             Mark(data.marks.len() as u32 - 1)
95         })
96     }
97
98     /// The mark of the theoretical expansion that generates freshly parsed, unexpanded AST.
99     #[inline]
100     pub fn root() -> Self {
101         Mark(0)
102     }
103
104     #[inline]
105     pub fn as_u32(self) -> u32 {
106         self.0
107     }
108
109     #[inline]
110     pub fn from_u32(raw: u32) -> Mark {
111         Mark(raw)
112     }
113
114     #[inline]
115     pub fn parent(self) -> Mark {
116         HygieneData::with(|data| data.marks[self.0 as usize].parent)
117     }
118
119     #[inline]
120     pub fn expn_info(self) -> Option<ExpnInfo> {
121         HygieneData::with(|data| data.expn_info(self))
122     }
123
124     #[inline]
125     pub fn set_expn_info(self, info: ExpnInfo) {
126         HygieneData::with(|data| data.marks[self.0 as usize].expn_info = Some(info))
127     }
128
129     #[inline]
130     pub fn set_default_transparency(self, transparency: Transparency) {
131         assert_ne!(self, Mark::root());
132         HygieneData::with(|data| data.marks[self.0 as usize].default_transparency = transparency)
133     }
134
135     pub fn is_descendant_of(self, ancestor: Mark) -> bool {
136         HygieneData::with(|data| data.is_descendant_of(self, ancestor))
137     }
138
139     /// `mark.outer_is_descendant_of(ctxt)` is equivalent to but faster than
140     /// `mark.is_descendant_of(ctxt.outer())`.
141     pub fn outer_is_descendant_of(self, ctxt: SyntaxContext) -> bool {
142         HygieneData::with(|data| data.is_descendant_of(self, data.outer(ctxt)))
143     }
144
145     /// Computes a mark such that both input marks are descendants of (or equal to) the returned
146     /// mark. That is, the following holds:
147     ///
148     /// ```rust
149     /// let la = least_ancestor(a, b);
150     /// assert!(a.is_descendant_of(la))
151     /// assert!(b.is_descendant_of(la))
152     /// ```
153     pub fn least_ancestor(mut a: Mark, mut b: Mark) -> Mark {
154         HygieneData::with(|data| {
155             // Compute the path from a to the root
156             let mut a_path = FxHashSet::<Mark>::default();
157             while a != Mark::root() {
158                 a_path.insert(a);
159                 a = data.marks[a.0 as usize].parent;
160             }
161
162             // While the path from b to the root hasn't intersected, move up the tree
163             while !a_path.contains(&b) {
164                 b = data.marks[b.0 as usize].parent;
165             }
166
167             b
168         })
169     }
170
171     // Used for enabling some compatibility fallback in resolve.
172     #[inline]
173     pub fn looks_like_proc_macro_derive(self) -> bool {
174         HygieneData::with(|data| {
175             let mark_data = &data.marks[self.0 as usize];
176             if mark_data.default_transparency == Transparency::Opaque {
177                 if let Some(expn_info) = &mark_data.expn_info {
178                     if let ExpnFormat::MacroAttribute(name) = expn_info.format {
179                         if name.as_str().starts_with("derive(") {
180                             return true;
181                         }
182                     }
183                 }
184             }
185             false
186         })
187     }
188 }
189
190 #[derive(Debug)]
191 crate struct HygieneData {
192     marks: Vec<MarkData>,
193     syntax_contexts: Vec<SyntaxContextData>,
194     markings: FxHashMap<(SyntaxContext, Mark, Transparency), SyntaxContext>,
195 }
196
197 impl HygieneData {
198     crate fn new() -> Self {
199         HygieneData {
200             marks: vec![MarkData {
201                 parent: Mark::root(),
202                 // If the root is opaque, then loops searching for an opaque mark
203                 // will automatically stop after reaching it.
204                 default_transparency: Transparency::Opaque,
205                 expn_info: None,
206             }],
207             syntax_contexts: vec![SyntaxContextData {
208                 outer_mark: Mark::root(),
209                 transparency: Transparency::Opaque,
210                 prev_ctxt: SyntaxContext(0),
211                 opaque: SyntaxContext(0),
212                 opaque_and_semitransparent: SyntaxContext(0),
213                 dollar_crate_name: kw::DollarCrate,
214             }],
215             markings: FxHashMap::default(),
216         }
217     }
218
219     fn with<T, F: FnOnce(&mut HygieneData) -> T>(f: F) -> T {
220         GLOBALS.with(|globals| f(&mut *globals.hygiene_data.borrow_mut()))
221     }
222
223     fn expn_info(&self, mark: Mark) -> Option<ExpnInfo> {
224         self.marks[mark.0 as usize].expn_info.clone()
225     }
226
227     fn is_descendant_of(&self, mut mark: Mark, ancestor: Mark) -> bool {
228         while mark != ancestor {
229             if mark == Mark::root() {
230                 return false;
231             }
232             mark = self.marks[mark.0 as usize].parent;
233         }
234         true
235     }
236
237     fn default_transparency(&self, mark: Mark) -> Transparency {
238         self.marks[mark.0 as usize].default_transparency
239     }
240
241     fn modern(&self, ctxt: SyntaxContext) -> SyntaxContext {
242         self.syntax_contexts[ctxt.0 as usize].opaque
243     }
244
245     fn modern_and_legacy(&self, ctxt: SyntaxContext) -> SyntaxContext {
246         self.syntax_contexts[ctxt.0 as usize].opaque_and_semitransparent
247     }
248
249     fn outer(&self, ctxt: SyntaxContext) -> Mark {
250         self.syntax_contexts[ctxt.0 as usize].outer_mark
251     }
252
253     fn transparency(&self, ctxt: SyntaxContext) -> Transparency {
254         self.syntax_contexts[ctxt.0 as usize].transparency
255     }
256
257     fn prev_ctxt(&self, ctxt: SyntaxContext) -> SyntaxContext {
258         self.syntax_contexts[ctxt.0 as usize].prev_ctxt
259     }
260
261     fn remove_mark(&self, ctxt: &mut SyntaxContext) -> Mark {
262         let outer_mark = self.syntax_contexts[ctxt.0 as usize].outer_mark;
263         *ctxt = self.prev_ctxt(*ctxt);
264         outer_mark
265     }
266
267     fn marks(&self, mut ctxt: SyntaxContext) -> Vec<(Mark, Transparency)> {
268         let mut marks = Vec::new();
269         while ctxt != SyntaxContext::empty() {
270             let outer_mark = self.outer(ctxt);
271             let transparency = self.transparency(ctxt);
272             let prev_ctxt = self.prev_ctxt(ctxt);
273             marks.push((outer_mark, transparency));
274             ctxt = prev_ctxt;
275         }
276         marks.reverse();
277         marks
278     }
279
280     fn walk_chain(&self, mut span: Span, to: SyntaxContext) -> Span {
281         while span.ctxt() != crate::NO_EXPANSION && span.ctxt() != to {
282             if let Some(info) = self.expn_info(self.outer(span.ctxt())) {
283                 span = info.call_site;
284             } else {
285                 break;
286             }
287         }
288         span
289     }
290
291     fn adjust(&self, ctxt: &mut SyntaxContext, expansion: Mark) -> Option<Mark> {
292         let mut scope = None;
293         while !self.is_descendant_of(expansion, self.outer(*ctxt)) {
294             scope = Some(self.remove_mark(ctxt));
295         }
296         scope
297     }
298
299     fn apply_mark(&mut self, ctxt: SyntaxContext, mark: Mark) -> SyntaxContext {
300         assert_ne!(mark, Mark::root());
301         self.apply_mark_with_transparency(ctxt, mark, self.default_transparency(mark))
302     }
303
304     fn apply_mark_with_transparency(&mut self, ctxt: SyntaxContext, mark: Mark,
305                                     transparency: Transparency) -> SyntaxContext {
306         assert_ne!(mark, Mark::root());
307         if transparency == Transparency::Opaque {
308             return self.apply_mark_internal(ctxt, mark, transparency);
309         }
310
311         let call_site_ctxt =
312             self.expn_info(mark).map_or(SyntaxContext::empty(), |info| info.call_site.ctxt());
313         let mut call_site_ctxt = if transparency == Transparency::SemiTransparent {
314             self.modern(call_site_ctxt)
315         } else {
316             self.modern_and_legacy(call_site_ctxt)
317         };
318
319         if call_site_ctxt == SyntaxContext::empty() {
320             return self.apply_mark_internal(ctxt, mark, transparency);
321         }
322
323         // Otherwise, `mark` is a macros 1.0 definition and the call site is in a
324         // macros 2.0 expansion, i.e., a macros 1.0 invocation is in a macros 2.0 definition.
325         //
326         // In this case, the tokens from the macros 1.0 definition inherit the hygiene
327         // at their invocation. That is, we pretend that the macros 1.0 definition
328         // was defined at its invocation (i.e., inside the macros 2.0 definition)
329         // so that the macros 2.0 definition remains hygienic.
330         //
331         // See the example at `test/run-pass/hygiene/legacy_interaction.rs`.
332         for (mark, transparency) in self.marks(ctxt) {
333             call_site_ctxt = self.apply_mark_internal(call_site_ctxt, mark, transparency);
334         }
335         self.apply_mark_internal(call_site_ctxt, mark, transparency)
336     }
337
338     fn apply_mark_internal(&mut self, ctxt: SyntaxContext, mark: Mark, transparency: Transparency)
339                            -> SyntaxContext {
340         let syntax_contexts = &mut self.syntax_contexts;
341         let mut opaque = syntax_contexts[ctxt.0 as usize].opaque;
342         let mut opaque_and_semitransparent =
343             syntax_contexts[ctxt.0 as usize].opaque_and_semitransparent;
344
345         if transparency >= Transparency::Opaque {
346             let prev_ctxt = opaque;
347             opaque = *self.markings.entry((prev_ctxt, mark, transparency)).or_insert_with(|| {
348                 let new_opaque = SyntaxContext(syntax_contexts.len() as u32);
349                 syntax_contexts.push(SyntaxContextData {
350                     outer_mark: mark,
351                     transparency,
352                     prev_ctxt,
353                     opaque: new_opaque,
354                     opaque_and_semitransparent: new_opaque,
355                     dollar_crate_name: kw::DollarCrate,
356                 });
357                 new_opaque
358             });
359         }
360
361         if transparency >= Transparency::SemiTransparent {
362             let prev_ctxt = opaque_and_semitransparent;
363             opaque_and_semitransparent =
364                     *self.markings.entry((prev_ctxt, mark, transparency)).or_insert_with(|| {
365                 let new_opaque_and_semitransparent =
366                     SyntaxContext(syntax_contexts.len() as u32);
367                 syntax_contexts.push(SyntaxContextData {
368                     outer_mark: mark,
369                     transparency,
370                     prev_ctxt,
371                     opaque,
372                     opaque_and_semitransparent: new_opaque_and_semitransparent,
373                     dollar_crate_name: kw::DollarCrate,
374                 });
375                 new_opaque_and_semitransparent
376             });
377         }
378
379         let prev_ctxt = ctxt;
380         *self.markings.entry((prev_ctxt, mark, transparency)).or_insert_with(|| {
381             let new_opaque_and_semitransparent_and_transparent =
382                 SyntaxContext(syntax_contexts.len() as u32);
383             syntax_contexts.push(SyntaxContextData {
384                 outer_mark: mark,
385                 transparency,
386                 prev_ctxt,
387                 opaque,
388                 opaque_and_semitransparent,
389                 dollar_crate_name: kw::DollarCrate,
390             });
391             new_opaque_and_semitransparent_and_transparent
392         })
393     }
394 }
395
396 pub fn clear_markings() {
397     HygieneData::with(|data| data.markings = FxHashMap::default());
398 }
399
400 pub fn walk_chain(span: Span, to: SyntaxContext) -> Span {
401     HygieneData::with(|data| data.walk_chain(span, to))
402 }
403
404 impl SyntaxContext {
405     #[inline]
406     pub const fn empty() -> Self {
407         SyntaxContext(0)
408     }
409
410     #[inline]
411     crate fn as_u32(self) -> u32 {
412         self.0
413     }
414
415     #[inline]
416     crate fn from_u32(raw: u32) -> SyntaxContext {
417         SyntaxContext(raw)
418     }
419
420     // Allocate a new SyntaxContext with the given ExpnInfo. This is used when
421     // deserializing Spans from the incr. comp. cache.
422     // FIXME(mw): This method does not restore MarkData::parent or
423     // SyntaxContextData::prev_ctxt or SyntaxContextData::opaque. These things
424     // don't seem to be used after HIR lowering, so everything should be fine
425     // as long as incremental compilation does not kick in before that.
426     pub fn allocate_directly(expansion_info: ExpnInfo) -> Self {
427         HygieneData::with(|data| {
428             data.marks.push(MarkData {
429                 parent: Mark::root(),
430                 default_transparency: Transparency::SemiTransparent,
431                 expn_info: Some(expansion_info),
432             });
433
434             let mark = Mark(data.marks.len() as u32 - 1);
435
436             data.syntax_contexts.push(SyntaxContextData {
437                 outer_mark: mark,
438                 transparency: Transparency::SemiTransparent,
439                 prev_ctxt: SyntaxContext::empty(),
440                 opaque: SyntaxContext::empty(),
441                 opaque_and_semitransparent: SyntaxContext::empty(),
442                 dollar_crate_name: kw::DollarCrate,
443             });
444             SyntaxContext(data.syntax_contexts.len() as u32 - 1)
445         })
446     }
447
448     /// Extend a syntax context with a given mark and default transparency for that mark.
449     pub fn apply_mark(self, mark: Mark) -> SyntaxContext {
450         HygieneData::with(|data| data.apply_mark(self, mark))
451     }
452
453     /// Extend a syntax context with a given mark and transparency
454     pub fn apply_mark_with_transparency(self, mark: Mark, transparency: Transparency)
455                                         -> SyntaxContext {
456         HygieneData::with(|data| data.apply_mark_with_transparency(self, mark, transparency))
457     }
458
459     /// Pulls a single mark off of the syntax context. This effectively moves the
460     /// context up one macro definition level. That is, if we have a nested macro
461     /// definition as follows:
462     ///
463     /// ```rust
464     /// macro_rules! f {
465     ///    macro_rules! g {
466     ///        ...
467     ///    }
468     /// }
469     /// ```
470     ///
471     /// and we have a SyntaxContext that is referring to something declared by an invocation
472     /// of g (call it g1), calling remove_mark will result in the SyntaxContext for the
473     /// invocation of f that created g1.
474     /// Returns the mark that was removed.
475     pub fn remove_mark(&mut self) -> Mark {
476         HygieneData::with(|data| data.remove_mark(self))
477     }
478
479     pub fn marks(self) -> Vec<(Mark, Transparency)> {
480         HygieneData::with(|data| data.marks(self))
481     }
482
483     /// Adjust this context for resolution in a scope created by the given expansion.
484     /// For example, consider the following three resolutions of `f`:
485     ///
486     /// ```rust
487     /// mod foo { pub fn f() {} } // `f`'s `SyntaxContext` is empty.
488     /// m!(f);
489     /// macro m($f:ident) {
490     ///     mod bar {
491     ///         pub fn f() {} // `f`'s `SyntaxContext` has a single `Mark` from `m`.
492     ///         pub fn $f() {} // `$f`'s `SyntaxContext` is empty.
493     ///     }
494     ///     foo::f(); // `f`'s `SyntaxContext` has a single `Mark` from `m`
495     ///     //^ Since `mod foo` is outside this expansion, `adjust` removes the mark from `f`,
496     ///     //| and it resolves to `::foo::f`.
497     ///     bar::f(); // `f`'s `SyntaxContext` has a single `Mark` from `m`
498     ///     //^ Since `mod bar` not outside this expansion, `adjust` does not change `f`,
499     ///     //| and it resolves to `::bar::f`.
500     ///     bar::$f(); // `f`'s `SyntaxContext` is empty.
501     ///     //^ Since `mod bar` is not outside this expansion, `adjust` does not change `$f`,
502     ///     //| and it resolves to `::bar::$f`.
503     /// }
504     /// ```
505     /// This returns the expansion whose definition scope we use to privacy check the resolution,
506     /// or `None` if we privacy check as usual (i.e., not w.r.t. a macro definition scope).
507     pub fn adjust(&mut self, expansion: Mark) -> Option<Mark> {
508         HygieneData::with(|data| data.adjust(self, expansion))
509     }
510
511     /// Like `SyntaxContext::adjust`, but also modernizes `self`.
512     pub fn modernize_and_adjust(&mut self, expansion: Mark) -> Option<Mark> {
513         HygieneData::with(|data| {
514             *self = data.modern(*self);
515             data.adjust(self, expansion)
516         })
517     }
518
519     /// Adjust this context for resolution in a scope created by the given expansion
520     /// via a glob import with the given `SyntaxContext`.
521     /// For example:
522     ///
523     /// ```rust
524     /// m!(f);
525     /// macro m($i:ident) {
526     ///     mod foo {
527     ///         pub fn f() {} // `f`'s `SyntaxContext` has a single `Mark` from `m`.
528     ///         pub fn $i() {} // `$i`'s `SyntaxContext` is empty.
529     ///     }
530     ///     n(f);
531     ///     macro n($j:ident) {
532     ///         use foo::*;
533     ///         f(); // `f`'s `SyntaxContext` has a mark from `m` and a mark from `n`
534     ///         //^ `glob_adjust` removes the mark from `n`, so this resolves to `foo::f`.
535     ///         $i(); // `$i`'s `SyntaxContext` has a mark from `n`
536     ///         //^ `glob_adjust` removes the mark from `n`, so this resolves to `foo::$i`.
537     ///         $j(); // `$j`'s `SyntaxContext` has a mark from `m`
538     ///         //^ This cannot be glob-adjusted, so this is a resolution error.
539     ///     }
540     /// }
541     /// ```
542     /// This returns `None` if the context cannot be glob-adjusted.
543     /// Otherwise, it returns the scope to use when privacy checking (see `adjust` for details).
544     pub fn glob_adjust(&mut self, expansion: Mark, glob_span: Span) -> Option<Option<Mark>> {
545         HygieneData::with(|data| {
546             let mut scope = None;
547             let mut glob_ctxt = data.modern(glob_span.ctxt());
548             while !data.is_descendant_of(expansion, data.outer(glob_ctxt)) {
549                 scope = Some(data.remove_mark(&mut glob_ctxt));
550                 if data.remove_mark(self) != scope.unwrap() {
551                     return None;
552                 }
553             }
554             if data.adjust(self, expansion).is_some() {
555                 return None;
556             }
557             Some(scope)
558         })
559     }
560
561     /// Undo `glob_adjust` if possible:
562     ///
563     /// ```rust
564     /// if let Some(privacy_checking_scope) = self.reverse_glob_adjust(expansion, glob_ctxt) {
565     ///     assert!(self.glob_adjust(expansion, glob_ctxt) == Some(privacy_checking_scope));
566     /// }
567     /// ```
568     pub fn reverse_glob_adjust(&mut self, expansion: Mark, glob_span: Span)
569                                -> Option<Option<Mark>> {
570         HygieneData::with(|data| {
571             if data.adjust(self, expansion).is_some() {
572                 return None;
573             }
574
575             let mut glob_ctxt = data.modern(glob_span.ctxt());
576             let mut marks = Vec::new();
577             while !data.is_descendant_of(expansion, data.outer(glob_ctxt)) {
578                 marks.push(data.remove_mark(&mut glob_ctxt));
579             }
580
581             let scope = marks.last().cloned();
582             while let Some(mark) = marks.pop() {
583                 *self = data.apply_mark(*self, mark);
584             }
585             Some(scope)
586         })
587     }
588
589     pub fn hygienic_eq(self, other: SyntaxContext, mark: Mark) -> bool {
590         HygieneData::with(|data| {
591             let mut self_modern = data.modern(self);
592             data.adjust(&mut self_modern, mark);
593             self_modern == data.modern(other)
594         })
595     }
596
597     #[inline]
598     pub fn modern(self) -> SyntaxContext {
599         HygieneData::with(|data| data.modern(self))
600     }
601
602     #[inline]
603     pub fn modern_and_legacy(self) -> SyntaxContext {
604         HygieneData::with(|data| data.modern_and_legacy(self))
605     }
606
607     #[inline]
608     pub fn outer(self) -> Mark {
609         HygieneData::with(|data| data.outer(self))
610     }
611
612     /// `ctxt.outer_expn_info()` is equivalent to but faster than
613     /// `ctxt.outer().expn_info()`.
614     #[inline]
615     pub fn outer_expn_info(self) -> Option<ExpnInfo> {
616         HygieneData::with(|data| data.expn_info(data.outer(self)))
617     }
618
619     /// `ctxt.outer_and_expn_info()` is equivalent to but faster than
620     /// `{ let outer = ctxt.outer(); (outer, outer.expn_info()) }`.
621     #[inline]
622     pub fn outer_and_expn_info(self) -> (Mark, Option<ExpnInfo>) {
623         HygieneData::with(|data| {
624             let outer = data.outer(self);
625             (outer, data.expn_info(outer))
626         })
627     }
628
629     pub fn dollar_crate_name(self) -> Symbol {
630         HygieneData::with(|data| data.syntax_contexts[self.0 as usize].dollar_crate_name)
631     }
632
633     pub fn set_dollar_crate_name(self, dollar_crate_name: Symbol) {
634         HygieneData::with(|data| {
635             let prev_dollar_crate_name = mem::replace(
636                 &mut data.syntax_contexts[self.0 as usize].dollar_crate_name, dollar_crate_name
637             );
638             assert!(dollar_crate_name == prev_dollar_crate_name ||
639                     prev_dollar_crate_name == kw::DollarCrate,
640                     "$crate name is reset for a syntax context");
641         })
642     }
643 }
644
645 impl fmt::Debug for SyntaxContext {
646     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
647         write!(f, "#{}", self.0)
648     }
649 }
650
651 /// Extra information for tracking spans of macro and syntax sugar expansion
652 #[derive(Clone, Hash, Debug, RustcEncodable, RustcDecodable)]
653 pub struct ExpnInfo {
654     /// The location of the actual macro invocation or syntax sugar , e.g.
655     /// `let x = foo!();` or `if let Some(y) = x {}`
656     ///
657     /// This may recursively refer to other macro invocations, e.g., if
658     /// `foo!()` invoked `bar!()` internally, and there was an
659     /// expression inside `bar!`; the call_site of the expression in
660     /// the expansion would point to the `bar!` invocation; that
661     /// call_site span would have its own ExpnInfo, with the call_site
662     /// pointing to the `foo!` invocation.
663     pub call_site: Span,
664     /// The span of the macro definition itself. The macro may not
665     /// have a sensible definition span (e.g., something defined
666     /// completely inside libsyntax) in which case this is None.
667     /// This span serves only informational purpose and is not used for resolution.
668     pub def_site: Option<Span>,
669     /// The format with which the macro was invoked.
670     pub format: ExpnFormat,
671     /// List of #[unstable]/feature-gated features that the macro is allowed to use
672     /// internally without forcing the whole crate to opt-in
673     /// to them.
674     pub allow_internal_unstable: Option<Lrc<[Symbol]>>,
675     /// Whether the macro is allowed to use `unsafe` internally
676     /// even if the user crate has `#![forbid(unsafe_code)]`.
677     pub allow_internal_unsafe: bool,
678     /// Enables the macro helper hack (`ident!(...)` -> `$crate::ident!(...)`)
679     /// for a given macro.
680     pub local_inner_macros: bool,
681     /// Edition of the crate in which the macro is defined.
682     pub edition: Edition,
683 }
684
685 /// The source of expansion.
686 #[derive(Clone, Hash, Debug, PartialEq, Eq, RustcEncodable, RustcDecodable)]
687 pub enum ExpnFormat {
688     /// e.g., #[derive(...)] <item>
689     MacroAttribute(Symbol),
690     /// e.g., `format!()`
691     MacroBang(Symbol),
692     /// Desugaring done by the compiler during HIR lowering.
693     CompilerDesugaring(CompilerDesugaringKind)
694 }
695
696 impl ExpnFormat {
697     pub fn name(&self) -> Symbol {
698         match *self {
699             ExpnFormat::MacroBang(name) | ExpnFormat::MacroAttribute(name) => name,
700             ExpnFormat::CompilerDesugaring(kind) => kind.name(),
701         }
702     }
703 }
704
705 /// The kind of compiler desugaring.
706 #[derive(Clone, Copy, Hash, Debug, PartialEq, Eq, RustcEncodable, RustcDecodable)]
707 pub enum CompilerDesugaringKind {
708     /// We desugar `if c { i } else { e }` to `match $ExprKind::Use(c) { true => i, _ => e }`.
709     /// However, we do not want to blame `c` for unreachability but rather say that `i`
710     /// is unreachable. This desugaring kind allows us to avoid blaming `c`.
711     IfTemporary,
712     QuestionMark,
713     TryBlock,
714     /// Desugaring of an `impl Trait` in return type position
715     /// to an `existential type Foo: Trait;` and replacing the
716     /// `impl Trait` with `Foo`.
717     ExistentialReturnType,
718     Async,
719     Await,
720     ForLoop,
721 }
722
723 impl CompilerDesugaringKind {
724     pub fn name(self) -> Symbol {
725         Symbol::intern(match self {
726             CompilerDesugaringKind::IfTemporary => "if",
727             CompilerDesugaringKind::Async => "async",
728             CompilerDesugaringKind::Await => "await",
729             CompilerDesugaringKind::QuestionMark => "?",
730             CompilerDesugaringKind::TryBlock => "try block",
731             CompilerDesugaringKind::ExistentialReturnType => "existential type",
732             CompilerDesugaringKind::ForLoop => "for loop",
733         })
734     }
735 }
736
737 impl Encodable for SyntaxContext {
738     fn encode<E: Encoder>(&self, _: &mut E) -> Result<(), E::Error> {
739         Ok(()) // FIXME(jseyfried) intercrate hygiene
740     }
741 }
742
743 impl Decodable for SyntaxContext {
744     fn decode<D: Decoder>(_: &mut D) -> Result<SyntaxContext, D::Error> {
745         Ok(SyntaxContext::empty()) // FIXME(jseyfried) intercrate hygiene
746     }
747 }