]> git.lizzy.rs Git - rust.git/blob - src/libsyntax_pos/hygiene.rs
libsyntax: Remove `Mark` into `ExpnId`
[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 `ExpnId` have interfaces
15 // with a certain amount of redundancy in them. For example,
16 // `SyntaxContext::outer_expn_info` combines `SyntaxContext::outer` and
17 // `ExpnId::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 `ExpnId`. 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, DUMMY_SP};
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;
35 use rustc_data_structures::sync::Lrc;
36 use std::fmt;
37
38 /// A SyntaxContext represents a chain of macro expansions (represented by marks).
39 #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
40 pub struct SyntaxContext(u32);
41
42 #[derive(Debug)]
43 struct SyntaxContextData {
44     outer_mark: ExpnId,
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(Clone, Copy, PartialEq, Eq, Hash, Debug)]
57 pub struct ExpnId(u32);
58
59 #[derive(Debug)]
60 struct MarkData {
61     parent: ExpnId,
62     /// Each mark should have an associated expansion info, but sometimes there's a delay between
63     /// creation of a mark and obtaining its info (e.g. macros are collected first and then
64     /// resolved later), so we use an `Option` here.
65     expn_info: Option<ExpnInfo>,
66 }
67
68 /// A property of a macro expansion that determines how identifiers
69 /// produced by that expansion are resolved.
70 #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Hash, Debug, RustcEncodable, RustcDecodable)]
71 pub enum Transparency {
72     /// Identifier produced by a transparent expansion is always resolved at call-site.
73     /// Call-site spans in procedural macros, hygiene opt-out in `macro` should use this.
74     Transparent,
75     /// Identifier produced by a semi-transparent expansion may be resolved
76     /// either at call-site or at definition-site.
77     /// If it's a local variable, label or `$crate` then it's resolved at def-site.
78     /// Otherwise it's resolved at call-site.
79     /// `macro_rules` macros behave like this, built-in macros currently behave like this too,
80     /// but that's an implementation detail.
81     SemiTransparent,
82     /// Identifier produced by an opaque expansion is always resolved at definition-site.
83     /// Def-site spans in procedural macros, identifiers from `macro` by default use this.
84     Opaque,
85 }
86
87 impl ExpnId {
88     pub fn fresh(parent: ExpnId, expn_info: Option<ExpnInfo>) -> Self {
89         HygieneData::with(|data| data.fresh_mark(parent, expn_info))
90     }
91
92     /// The mark of the theoretical expansion that generates freshly parsed, unexpanded AST.
93     #[inline]
94     pub fn root() -> Self {
95         ExpnId(0)
96     }
97
98     #[inline]
99     pub fn as_u32(self) -> u32 {
100         self.0
101     }
102
103     #[inline]
104     pub fn from_u32(raw: u32) -> ExpnId {
105         ExpnId(raw)
106     }
107
108     #[inline]
109     pub fn parent(self) -> ExpnId {
110         HygieneData::with(|data| data.marks[self.0 as usize].parent)
111     }
112
113     #[inline]
114     pub fn expn_info(self) -> Option<ExpnInfo> {
115         HygieneData::with(|data| data.expn_info(self).cloned())
116     }
117
118     #[inline]
119     pub fn set_expn_info(self, info: ExpnInfo) {
120         HygieneData::with(|data| {
121             let old_info = &mut data.marks[self.0 as usize].expn_info;
122             assert!(old_info.is_none(), "expansion info is reset for a mark");
123             *old_info = Some(info);
124         })
125     }
126
127     pub fn is_descendant_of(self, ancestor: ExpnId) -> bool {
128         HygieneData::with(|data| data.is_descendant_of(self, ancestor))
129     }
130
131     /// `mark.outer_is_descendant_of(ctxt)` is equivalent to but faster than
132     /// `mark.is_descendant_of(ctxt.outer())`.
133     pub fn outer_is_descendant_of(self, ctxt: SyntaxContext) -> bool {
134         HygieneData::with(|data| data.is_descendant_of(self, data.outer(ctxt)))
135     }
136
137     // Used for enabling some compatibility fallback in resolve.
138     #[inline]
139     pub fn looks_like_proc_macro_derive(self) -> bool {
140         HygieneData::with(|data| {
141             if data.default_transparency(self) == Transparency::Opaque {
142                 if let Some(expn_info) = data.expn_info(self) {
143                     if let ExpnKind::Macro(MacroKind::Derive, _) = expn_info.kind {
144                         return true;
145                     }
146                 }
147             }
148             false
149         })
150     }
151 }
152
153 #[derive(Debug)]
154 crate struct HygieneData {
155     marks: Vec<MarkData>,
156     syntax_contexts: Vec<SyntaxContextData>,
157     markings: FxHashMap<(SyntaxContext, ExpnId, Transparency), SyntaxContext>,
158 }
159
160 impl HygieneData {
161     crate fn new(edition: Edition) -> Self {
162         HygieneData {
163             marks: vec![MarkData {
164                 parent: ExpnId::root(),
165                 expn_info: Some(ExpnInfo::default(ExpnKind::Root, DUMMY_SP, edition)),
166             }],
167             syntax_contexts: vec![SyntaxContextData {
168                 outer_mark: ExpnId::root(),
169                 transparency: Transparency::Opaque,
170                 prev_ctxt: SyntaxContext(0),
171                 opaque: SyntaxContext(0),
172                 opaque_and_semitransparent: SyntaxContext(0),
173                 dollar_crate_name: kw::DollarCrate,
174             }],
175             markings: FxHashMap::default(),
176         }
177     }
178
179     fn with<T, F: FnOnce(&mut HygieneData) -> T>(f: F) -> T {
180         GLOBALS.with(|globals| f(&mut *globals.hygiene_data.borrow_mut()))
181     }
182
183     fn fresh_mark(&mut self, parent: ExpnId, expn_info: Option<ExpnInfo>) -> ExpnId {
184         self.marks.push(MarkData { parent, expn_info });
185         ExpnId(self.marks.len() as u32 - 1)
186     }
187
188     fn expn_info(&self, mark: ExpnId) -> Option<&ExpnInfo> {
189         if mark != ExpnId::root() {
190             Some(self.marks[mark.0 as usize].expn_info.as_ref()
191                      .expect("no expansion info for a mark"))
192         } else {
193             // FIXME: Some code relies on `expn_info().is_none()` meaning "no expansion".
194             // Introduce a method for checking for "no expansion" instead and always return
195             // `ExpnInfo` from this function instead of the `Option`.
196             None
197         }
198     }
199
200     fn is_descendant_of(&self, mut mark: ExpnId, ancestor: ExpnId) -> bool {
201         while mark != ancestor {
202             if mark == ExpnId::root() {
203                 return false;
204             }
205             mark = self.marks[mark.0 as usize].parent;
206         }
207         true
208     }
209
210     fn default_transparency(&self, mark: ExpnId) -> Transparency {
211         self.expn_info(mark).map_or(
212             Transparency::SemiTransparent, |einfo| einfo.default_transparency
213         )
214     }
215
216     fn modern(&self, ctxt: SyntaxContext) -> SyntaxContext {
217         self.syntax_contexts[ctxt.0 as usize].opaque
218     }
219
220     fn modern_and_legacy(&self, ctxt: SyntaxContext) -> SyntaxContext {
221         self.syntax_contexts[ctxt.0 as usize].opaque_and_semitransparent
222     }
223
224     fn outer(&self, ctxt: SyntaxContext) -> ExpnId {
225         self.syntax_contexts[ctxt.0 as usize].outer_mark
226     }
227
228     fn transparency(&self, ctxt: SyntaxContext) -> Transparency {
229         self.syntax_contexts[ctxt.0 as usize].transparency
230     }
231
232     fn prev_ctxt(&self, ctxt: SyntaxContext) -> SyntaxContext {
233         self.syntax_contexts[ctxt.0 as usize].prev_ctxt
234     }
235
236     fn remove_mark(&self, ctxt: &mut SyntaxContext) -> ExpnId {
237         let outer_mark = self.syntax_contexts[ctxt.0 as usize].outer_mark;
238         *ctxt = self.prev_ctxt(*ctxt);
239         outer_mark
240     }
241
242     fn marks(&self, mut ctxt: SyntaxContext) -> Vec<(ExpnId, Transparency)> {
243         let mut marks = Vec::new();
244         while ctxt != SyntaxContext::empty() {
245             let outer_mark = self.outer(ctxt);
246             let transparency = self.transparency(ctxt);
247             let prev_ctxt = self.prev_ctxt(ctxt);
248             marks.push((outer_mark, transparency));
249             ctxt = prev_ctxt;
250         }
251         marks.reverse();
252         marks
253     }
254
255     fn walk_chain(&self, mut span: Span, to: SyntaxContext) -> Span {
256         while span.ctxt() != crate::NO_EXPANSION && span.ctxt() != to {
257             if let Some(info) = self.expn_info(self.outer(span.ctxt())) {
258                 span = info.call_site;
259             } else {
260                 break;
261             }
262         }
263         span
264     }
265
266     fn adjust(&self, ctxt: &mut SyntaxContext, expansion: ExpnId) -> Option<ExpnId> {
267         let mut scope = None;
268         while !self.is_descendant_of(expansion, self.outer(*ctxt)) {
269             scope = Some(self.remove_mark(ctxt));
270         }
271         scope
272     }
273
274     fn apply_mark(&mut self, ctxt: SyntaxContext, mark: ExpnId) -> SyntaxContext {
275         assert_ne!(mark, ExpnId::root());
276         self.apply_mark_with_transparency(ctxt, mark, self.default_transparency(mark))
277     }
278
279     fn apply_mark_with_transparency(&mut self, ctxt: SyntaxContext, mark: ExpnId,
280                                     transparency: Transparency) -> SyntaxContext {
281         assert_ne!(mark, ExpnId::root());
282         if transparency == Transparency::Opaque {
283             return self.apply_mark_internal(ctxt, mark, transparency);
284         }
285
286         let call_site_ctxt =
287             self.expn_info(mark).map_or(SyntaxContext::empty(), |info| info.call_site.ctxt());
288         let mut call_site_ctxt = if transparency == Transparency::SemiTransparent {
289             self.modern(call_site_ctxt)
290         } else {
291             self.modern_and_legacy(call_site_ctxt)
292         };
293
294         if call_site_ctxt == SyntaxContext::empty() {
295             return self.apply_mark_internal(ctxt, mark, transparency);
296         }
297
298         // Otherwise, `mark` is a macros 1.0 definition and the call site is in a
299         // macros 2.0 expansion, i.e., a macros 1.0 invocation is in a macros 2.0 definition.
300         //
301         // In this case, the tokens from the macros 1.0 definition inherit the hygiene
302         // at their invocation. That is, we pretend that the macros 1.0 definition
303         // was defined at its invocation (i.e., inside the macros 2.0 definition)
304         // so that the macros 2.0 definition remains hygienic.
305         //
306         // See the example at `test/run-pass/hygiene/legacy_interaction.rs`.
307         for (mark, transparency) in self.marks(ctxt) {
308             call_site_ctxt = self.apply_mark_internal(call_site_ctxt, mark, transparency);
309         }
310         self.apply_mark_internal(call_site_ctxt, mark, transparency)
311     }
312
313     fn apply_mark_internal(&mut self, ctxt: SyntaxContext, mark: ExpnId, transparency: Transparency)
314                            -> SyntaxContext {
315         let syntax_contexts = &mut self.syntax_contexts;
316         let mut opaque = syntax_contexts[ctxt.0 as usize].opaque;
317         let mut opaque_and_semitransparent =
318             syntax_contexts[ctxt.0 as usize].opaque_and_semitransparent;
319
320         if transparency >= Transparency::Opaque {
321             let prev_ctxt = opaque;
322             opaque = *self.markings.entry((prev_ctxt, mark, transparency)).or_insert_with(|| {
323                 let new_opaque = SyntaxContext(syntax_contexts.len() as u32);
324                 syntax_contexts.push(SyntaxContextData {
325                     outer_mark: mark,
326                     transparency,
327                     prev_ctxt,
328                     opaque: new_opaque,
329                     opaque_and_semitransparent: new_opaque,
330                     dollar_crate_name: kw::DollarCrate,
331                 });
332                 new_opaque
333             });
334         }
335
336         if transparency >= Transparency::SemiTransparent {
337             let prev_ctxt = opaque_and_semitransparent;
338             opaque_and_semitransparent =
339                     *self.markings.entry((prev_ctxt, mark, transparency)).or_insert_with(|| {
340                 let new_opaque_and_semitransparent =
341                     SyntaxContext(syntax_contexts.len() as u32);
342                 syntax_contexts.push(SyntaxContextData {
343                     outer_mark: mark,
344                     transparency,
345                     prev_ctxt,
346                     opaque,
347                     opaque_and_semitransparent: new_opaque_and_semitransparent,
348                     dollar_crate_name: kw::DollarCrate,
349                 });
350                 new_opaque_and_semitransparent
351             });
352         }
353
354         let prev_ctxt = ctxt;
355         *self.markings.entry((prev_ctxt, mark, transparency)).or_insert_with(|| {
356             let new_opaque_and_semitransparent_and_transparent =
357                 SyntaxContext(syntax_contexts.len() as u32);
358             syntax_contexts.push(SyntaxContextData {
359                 outer_mark: mark,
360                 transparency,
361                 prev_ctxt,
362                 opaque,
363                 opaque_and_semitransparent,
364                 dollar_crate_name: kw::DollarCrate,
365             });
366             new_opaque_and_semitransparent_and_transparent
367         })
368     }
369 }
370
371 pub fn clear_markings() {
372     HygieneData::with(|data| data.markings = FxHashMap::default());
373 }
374
375 pub fn walk_chain(span: Span, to: SyntaxContext) -> Span {
376     HygieneData::with(|data| data.walk_chain(span, to))
377 }
378
379 pub fn update_dollar_crate_names(mut get_name: impl FnMut(SyntaxContext) -> Symbol) {
380     // The new contexts that need updating are at the end of the list and have `$crate` as a name.
381     let (len, to_update) = HygieneData::with(|data| (
382         data.syntax_contexts.len(),
383         data.syntax_contexts.iter().rev()
384             .take_while(|scdata| scdata.dollar_crate_name == kw::DollarCrate).count()
385     ));
386     // The callback must be called from outside of the `HygieneData` lock,
387     // since it will try to acquire it too.
388     let range_to_update = len - to_update .. len;
389     let names: Vec<_> =
390         range_to_update.clone().map(|idx| get_name(SyntaxContext::from_u32(idx as u32))).collect();
391     HygieneData::with(|data| range_to_update.zip(names.into_iter()).for_each(|(idx, name)| {
392         data.syntax_contexts[idx].dollar_crate_name = name;
393     }))
394 }
395
396 impl SyntaxContext {
397     #[inline]
398     pub const fn empty() -> Self {
399         SyntaxContext(0)
400     }
401
402     #[inline]
403     crate fn as_u32(self) -> u32 {
404         self.0
405     }
406
407     #[inline]
408     crate fn from_u32(raw: u32) -> SyntaxContext {
409         SyntaxContext(raw)
410     }
411
412     /// Extend a syntax context with a given mark and default transparency for that mark.
413     pub fn apply_mark(self, mark: ExpnId) -> SyntaxContext {
414         HygieneData::with(|data| data.apply_mark(self, mark))
415     }
416
417     /// Extend a syntax context with a given mark and transparency
418     pub fn apply_mark_with_transparency(self, mark: ExpnId, transparency: Transparency)
419                                         -> SyntaxContext {
420         HygieneData::with(|data| data.apply_mark_with_transparency(self, mark, transparency))
421     }
422
423     /// Pulls a single mark off of the syntax context. This effectively moves the
424     /// context up one macro definition level. That is, if we have a nested macro
425     /// definition as follows:
426     ///
427     /// ```rust
428     /// macro_rules! f {
429     ///    macro_rules! g {
430     ///        ...
431     ///    }
432     /// }
433     /// ```
434     ///
435     /// and we have a SyntaxContext that is referring to something declared by an invocation
436     /// of g (call it g1), calling remove_mark will result in the SyntaxContext for the
437     /// invocation of f that created g1.
438     /// Returns the mark that was removed.
439     pub fn remove_mark(&mut self) -> ExpnId {
440         HygieneData::with(|data| data.remove_mark(self))
441     }
442
443     pub fn marks(self) -> Vec<(ExpnId, Transparency)> {
444         HygieneData::with(|data| data.marks(self))
445     }
446
447     /// Adjust this context for resolution in a scope created by the given expansion.
448     /// For example, consider the following three resolutions of `f`:
449     ///
450     /// ```rust
451     /// mod foo { pub fn f() {} } // `f`'s `SyntaxContext` is empty.
452     /// m!(f);
453     /// macro m($f:ident) {
454     ///     mod bar {
455     ///         pub fn f() {} // `f`'s `SyntaxContext` has a single `ExpnId` from `m`.
456     ///         pub fn $f() {} // `$f`'s `SyntaxContext` is empty.
457     ///     }
458     ///     foo::f(); // `f`'s `SyntaxContext` has a single `ExpnId` from `m`
459     ///     //^ Since `mod foo` is outside this expansion, `adjust` removes the mark from `f`,
460     ///     //| and it resolves to `::foo::f`.
461     ///     bar::f(); // `f`'s `SyntaxContext` has a single `ExpnId` from `m`
462     ///     //^ Since `mod bar` not outside this expansion, `adjust` does not change `f`,
463     ///     //| and it resolves to `::bar::f`.
464     ///     bar::$f(); // `f`'s `SyntaxContext` is empty.
465     ///     //^ Since `mod bar` is not outside this expansion, `adjust` does not change `$f`,
466     ///     //| and it resolves to `::bar::$f`.
467     /// }
468     /// ```
469     /// This returns the expansion whose definition scope we use to privacy check the resolution,
470     /// or `None` if we privacy check as usual (i.e., not w.r.t. a macro definition scope).
471     pub fn adjust(&mut self, expansion: ExpnId) -> Option<ExpnId> {
472         HygieneData::with(|data| data.adjust(self, expansion))
473     }
474
475     /// Like `SyntaxContext::adjust`, but also modernizes `self`.
476     pub fn modernize_and_adjust(&mut self, expansion: ExpnId) -> Option<ExpnId> {
477         HygieneData::with(|data| {
478             *self = data.modern(*self);
479             data.adjust(self, expansion)
480         })
481     }
482
483     /// Adjust this context for resolution in a scope created by the given expansion
484     /// via a glob import with the given `SyntaxContext`.
485     /// For example:
486     ///
487     /// ```rust
488     /// m!(f);
489     /// macro m($i:ident) {
490     ///     mod foo {
491     ///         pub fn f() {} // `f`'s `SyntaxContext` has a single `ExpnId` from `m`.
492     ///         pub fn $i() {} // `$i`'s `SyntaxContext` is empty.
493     ///     }
494     ///     n(f);
495     ///     macro n($j:ident) {
496     ///         use foo::*;
497     ///         f(); // `f`'s `SyntaxContext` has a mark from `m` and a mark from `n`
498     ///         //^ `glob_adjust` removes the mark from `n`, so this resolves to `foo::f`.
499     ///         $i(); // `$i`'s `SyntaxContext` has a mark from `n`
500     ///         //^ `glob_adjust` removes the mark from `n`, so this resolves to `foo::$i`.
501     ///         $j(); // `$j`'s `SyntaxContext` has a mark from `m`
502     ///         //^ This cannot be glob-adjusted, so this is a resolution error.
503     ///     }
504     /// }
505     /// ```
506     /// This returns `None` if the context cannot be glob-adjusted.
507     /// Otherwise, it returns the scope to use when privacy checking (see `adjust` for details).
508     pub fn glob_adjust(&mut self, expansion: ExpnId, glob_span: Span) -> Option<Option<ExpnId>> {
509         HygieneData::with(|data| {
510             let mut scope = None;
511             let mut glob_ctxt = data.modern(glob_span.ctxt());
512             while !data.is_descendant_of(expansion, data.outer(glob_ctxt)) {
513                 scope = Some(data.remove_mark(&mut glob_ctxt));
514                 if data.remove_mark(self) != scope.unwrap() {
515                     return None;
516                 }
517             }
518             if data.adjust(self, expansion).is_some() {
519                 return None;
520             }
521             Some(scope)
522         })
523     }
524
525     /// Undo `glob_adjust` if possible:
526     ///
527     /// ```rust
528     /// if let Some(privacy_checking_scope) = self.reverse_glob_adjust(expansion, glob_ctxt) {
529     ///     assert!(self.glob_adjust(expansion, glob_ctxt) == Some(privacy_checking_scope));
530     /// }
531     /// ```
532     pub fn reverse_glob_adjust(&mut self, expansion: ExpnId, glob_span: Span)
533                                -> Option<Option<ExpnId>> {
534         HygieneData::with(|data| {
535             if data.adjust(self, expansion).is_some() {
536                 return None;
537             }
538
539             let mut glob_ctxt = data.modern(glob_span.ctxt());
540             let mut marks = Vec::new();
541             while !data.is_descendant_of(expansion, data.outer(glob_ctxt)) {
542                 marks.push(data.remove_mark(&mut glob_ctxt));
543             }
544
545             let scope = marks.last().cloned();
546             while let Some(mark) = marks.pop() {
547                 *self = data.apply_mark(*self, mark);
548             }
549             Some(scope)
550         })
551     }
552
553     pub fn hygienic_eq(self, other: SyntaxContext, mark: ExpnId) -> bool {
554         HygieneData::with(|data| {
555             let mut self_modern = data.modern(self);
556             data.adjust(&mut self_modern, mark);
557             self_modern == data.modern(other)
558         })
559     }
560
561     #[inline]
562     pub fn modern(self) -> SyntaxContext {
563         HygieneData::with(|data| data.modern(self))
564     }
565
566     #[inline]
567     pub fn modern_and_legacy(self) -> SyntaxContext {
568         HygieneData::with(|data| data.modern_and_legacy(self))
569     }
570
571     #[inline]
572     pub fn outer(self) -> ExpnId {
573         HygieneData::with(|data| data.outer(self))
574     }
575
576     /// `ctxt.outer_expn_info()` is equivalent to but faster than
577     /// `ctxt.outer().expn_info()`.
578     #[inline]
579     pub fn outer_expn_info(self) -> Option<ExpnInfo> {
580         HygieneData::with(|data| data.expn_info(data.outer(self)).cloned())
581     }
582
583     /// `ctxt.outer_and_expn_info()` is equivalent to but faster than
584     /// `{ let outer = ctxt.outer(); (outer, outer.expn_info()) }`.
585     #[inline]
586     pub fn outer_and_expn_info(self) -> (ExpnId, Option<ExpnInfo>) {
587         HygieneData::with(|data| {
588             let outer = data.outer(self);
589             (outer, data.expn_info(outer).cloned())
590         })
591     }
592
593     pub fn dollar_crate_name(self) -> Symbol {
594         HygieneData::with(|data| data.syntax_contexts[self.0 as usize].dollar_crate_name)
595     }
596 }
597
598 impl fmt::Debug for SyntaxContext {
599     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
600         write!(f, "#{}", self.0)
601     }
602 }
603
604 impl Span {
605     /// Creates a fresh expansion with given properties.
606     /// Expansions are normally created by macros, but in some cases expansions are created for
607     /// other compiler-generated code to set per-span properties like allowed unstable features.
608     /// The returned span belongs to the created expansion and has the new properties,
609     /// but its location is inherited from the current span.
610     pub fn fresh_expansion(self, parent: ExpnId, expn_info: ExpnInfo) -> Span {
611         HygieneData::with(|data| {
612             let mark = data.fresh_mark(parent, Some(expn_info));
613             self.with_ctxt(data.apply_mark(SyntaxContext::empty(), mark))
614         })
615     }
616 }
617
618 /// A subset of properties from both macro definition and macro call available through global data.
619 /// Avoid using this if you have access to the original definition or call structures.
620 #[derive(Clone, Debug, RustcEncodable, RustcDecodable)]
621 pub struct ExpnInfo {
622     // --- The part unique to each expansion.
623     /// The location of the actual macro invocation or syntax sugar , e.g.
624     /// `let x = foo!();` or `if let Some(y) = x {}`
625     ///
626     /// This may recursively refer to other macro invocations, e.g., if
627     /// `foo!()` invoked `bar!()` internally, and there was an
628     /// expression inside `bar!`; the call_site of the expression in
629     /// the expansion would point to the `bar!` invocation; that
630     /// call_site span would have its own ExpnInfo, with the call_site
631     /// pointing to the `foo!` invocation.
632     pub call_site: Span,
633     /// The kind of this expansion - macro or compiler desugaring.
634     pub kind: ExpnKind,
635
636     // --- The part specific to the macro/desugaring definition.
637     // --- FIXME: Share it between expansions with the same definition.
638     /// The span of the macro definition (possibly dummy).
639     /// This span serves only informational purpose and is not used for resolution.
640     pub def_site: Span,
641     /// Transparency used by `apply_mark` for mark with this expansion info by default.
642     pub default_transparency: Transparency,
643     /// List of #[unstable]/feature-gated features that the macro is allowed to use
644     /// internally without forcing the whole crate to opt-in
645     /// to them.
646     pub allow_internal_unstable: Option<Lrc<[Symbol]>>,
647     /// Whether the macro is allowed to use `unsafe` internally
648     /// even if the user crate has `#![forbid(unsafe_code)]`.
649     pub allow_internal_unsafe: bool,
650     /// Enables the macro helper hack (`ident!(...)` -> `$crate::ident!(...)`)
651     /// for a given macro.
652     pub local_inner_macros: bool,
653     /// Edition of the crate in which the macro is defined.
654     pub edition: Edition,
655 }
656
657 impl ExpnInfo {
658     /// Constructs an expansion info with default properties.
659     pub fn default(kind: ExpnKind, call_site: Span, edition: Edition) -> ExpnInfo {
660         ExpnInfo {
661             call_site,
662             kind,
663             def_site: DUMMY_SP,
664             default_transparency: Transparency::SemiTransparent,
665             allow_internal_unstable: None,
666             allow_internal_unsafe: false,
667             local_inner_macros: false,
668             edition,
669         }
670     }
671
672     pub fn allow_unstable(kind: ExpnKind, call_site: Span, edition: Edition,
673                           allow_internal_unstable: Lrc<[Symbol]>) -> ExpnInfo {
674         ExpnInfo {
675             allow_internal_unstable: Some(allow_internal_unstable),
676             ..ExpnInfo::default(kind, call_site, edition)
677         }
678     }
679 }
680
681 /// Expansion kind.
682 #[derive(Clone, Debug, RustcEncodable, RustcDecodable)]
683 pub enum ExpnKind {
684     /// No expansion, aka root expansion. Only `ExpnId::root()` has this kind.
685     Root,
686     /// Expansion produced by a macro.
687     /// FIXME: Some code injected by the compiler before HIR lowering also gets this kind.
688     Macro(MacroKind, Symbol),
689     /// Desugaring done by the compiler during HIR lowering.
690     Desugaring(DesugaringKind)
691 }
692
693 impl ExpnKind {
694     pub fn descr(&self) -> Symbol {
695         match *self {
696             ExpnKind::Root => kw::PathRoot,
697             ExpnKind::Macro(_, descr) => descr,
698             ExpnKind::Desugaring(kind) => Symbol::intern(kind.descr()),
699         }
700     }
701 }
702
703 /// The kind of macro invocation or definition.
704 #[derive(Clone, Copy, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
705 pub enum MacroKind {
706     /// A bang macro `foo!()`.
707     Bang,
708     /// An attribute macro `#[foo]`.
709     Attr,
710     /// A derive macro `#[derive(Foo)]`
711     Derive,
712 }
713
714 impl MacroKind {
715     pub fn descr(self) -> &'static str {
716         match self {
717             MacroKind::Bang => "macro",
718             MacroKind::Attr => "attribute macro",
719             MacroKind::Derive => "derive macro",
720         }
721     }
722
723     pub fn article(self) -> &'static str {
724         match self {
725             MacroKind::Attr => "an",
726             _ => "a",
727         }
728     }
729 }
730
731 /// The kind of compiler desugaring.
732 #[derive(Clone, Copy, PartialEq, Debug, RustcEncodable, RustcDecodable)]
733 pub enum DesugaringKind {
734     /// We desugar `if c { i } else { e }` to `match $ExprKind::Use(c) { true => i, _ => e }`.
735     /// However, we do not want to blame `c` for unreachability but rather say that `i`
736     /// is unreachable. This desugaring kind allows us to avoid blaming `c`.
737     /// This also applies to `while` loops.
738     CondTemporary,
739     QuestionMark,
740     TryBlock,
741     /// Desugaring of an `impl Trait` in return type position
742     /// to an `existential type Foo: Trait;` and replacing the
743     /// `impl Trait` with `Foo`.
744     ExistentialType,
745     Async,
746     Await,
747     ForLoop,
748 }
749
750 impl DesugaringKind {
751     /// The description wording should combine well with "desugaring of {}".
752     fn descr(self) -> &'static str {
753         match self {
754             DesugaringKind::CondTemporary => "`if` or `while` condition",
755             DesugaringKind::Async => "`async` block or function",
756             DesugaringKind::Await => "`await` expression",
757             DesugaringKind::QuestionMark => "operator `?`",
758             DesugaringKind::TryBlock => "`try` block",
759             DesugaringKind::ExistentialType => "`existential type`",
760             DesugaringKind::ForLoop => "`for` loop",
761         }
762     }
763 }
764
765 impl Encodable for SyntaxContext {
766     fn encode<E: Encoder>(&self, _: &mut E) -> Result<(), E::Error> {
767         Ok(()) // FIXME(jseyfried) intercrate hygiene
768     }
769 }
770
771 impl Decodable for SyntaxContext {
772     fn decode<D: Decoder>(_: &mut D) -> Result<SyntaxContext, D::Error> {
773         Ok(SyntaxContext::empty()) // FIXME(jseyfried) intercrate hygiene
774     }
775 }