about summary refs log tree commit diff
path: root/src/libsyntax_pos
diff options
context:
space:
mode:
authorMazdak Farrokhzad <twingoow@gmail.com>2019-08-16 08:26:36 +0200
committerGitHub <noreply@github.com>2019-08-16 08:26:36 +0200
commit6e9e6ea39bbc2c9e58cdc854c55dfc1487a77ae1 (patch)
tree3f954fcac1528b39e95ca78bc3ebad58a30613e0 /src/libsyntax_pos
parent32c10056525d427292fdb5e7db7497e2bbe9551b (diff)
parentc76277340e3e5e8d6aca9c926c45cac3484eb5f8 (diff)
downloadrust-6e9e6ea39bbc2c9e58cdc854c55dfc1487a77ae1.tar.gz
rust-6e9e6ea39bbc2c9e58cdc854c55dfc1487a77ae1.zip
Rollup merge of #63535 - petrochenkov:expndata, r=matthewjasper
Continue refactoring resolve and hygiene

The general goal is addressing FIXMEs from the previous PRs.

Merging similar data structures (+ prerequisites for such merging), accounting for the fact that all `ExpnId`s have associated data in `HygieneData` now (less `Option`s).

Also, some renaming.
This should be the last renaming session in this area, I think.

r? @matthewjasper
Diffstat (limited to 'src/libsyntax_pos')
-rw-r--r--src/libsyntax_pos/edition.rs5
-rw-r--r--src/libsyntax_pos/hygiene.rs180
-rw-r--r--src/libsyntax_pos/lib.rs108
-rw-r--r--src/libsyntax_pos/symbol.rs13
4 files changed, 141 insertions, 165 deletions
diff --git a/src/libsyntax_pos/edition.rs b/src/libsyntax_pos/edition.rs
index 20216568426..00cd00f2837 100644
--- a/src/libsyntax_pos/edition.rs
+++ b/src/libsyntax_pos/edition.rs
@@ -1,7 +1,6 @@
 use crate::symbol::{Symbol, sym};
 use std::fmt;
 use std::str::FromStr;
-use crate::GLOBALS;
 
 /// The edition of the compiler (RFC 2052)
 #[derive(Clone, Copy, Hash, PartialEq, PartialOrd, Debug, RustcEncodable, RustcDecodable, Eq)]
@@ -39,10 +38,6 @@ impl fmt::Display for Edition {
 }
 
 impl Edition {
-    pub fn from_session() -> Edition {
-        GLOBALS.with(|globals| globals.edition)
-    }
-
     pub fn lint_name(&self) -> &'static str {
         match *self {
             Edition::Edition2015 => "rust_2015_compatibility",
diff --git a/src/libsyntax_pos/hygiene.rs b/src/libsyntax_pos/hygiene.rs
index f91a2291544..87d930f897a 100644
--- a/src/libsyntax_pos/hygiene.rs
+++ b/src/libsyntax_pos/hygiene.rs
@@ -13,8 +13,8 @@
 //
 // This explains why `HygieneData`, `SyntaxContext` and `ExpnId` have interfaces
 // with a certain amount of redundancy in them. For example,
-// `SyntaxContext::outer_expn_info` combines `SyntaxContext::outer` and
-// `ExpnId::expn_info` so that two `HygieneData` accesses can be performed within
+// `SyntaxContext::outer_expn_data` combines `SyntaxContext::outer` and
+// `ExpnId::expn_data` so that two `HygieneData` accesses can be performed within
 // a single `HygieneData::with` call.
 //
 // It also explains why many functions appear in `HygieneData` and again in
@@ -56,16 +56,6 @@ struct SyntaxContextData {
 #[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
 pub struct ExpnId(u32);
 
-// FIXME: Find a way to merge this with `ExpnInfo`.
-#[derive(Debug)]
-struct InternalExpnData {
-    parent: ExpnId,
-    /// Each expansion should have an associated expansion info, but sometimes there's a delay
-    /// between creation of an expansion ID and obtaining its info (e.g. macros are collected
-    /// first and then resolved later), so we use an `Option` here.
-    expn_info: Option<ExpnInfo>,
-}
-
 /// A property of a macro expansion that determines how identifiers
 /// produced by that expansion are resolved.
 #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Hash, Debug, RustcEncodable, RustcDecodable)]
@@ -86,8 +76,8 @@ pub enum Transparency {
 }
 
 impl ExpnId {
-    pub fn fresh(parent: ExpnId, expn_info: Option<ExpnInfo>) -> Self {
-        HygieneData::with(|data| data.fresh_expn(parent, expn_info))
+    pub fn fresh(expn_data: Option<ExpnData>) -> Self {
+        HygieneData::with(|data| data.fresh_expn(expn_data))
     }
 
     /// The ID of the theoretical expansion that generates freshly parsed, unexpanded AST.
@@ -107,21 +97,16 @@ impl ExpnId {
     }
 
     #[inline]
-    pub fn parent(self) -> ExpnId {
-        HygieneData::with(|data| data.parent_expn(self))
+    pub fn expn_data(self) -> ExpnData {
+        HygieneData::with(|data| data.expn_data(self).clone())
     }
 
     #[inline]
-    pub fn expn_info(self) -> Option<ExpnInfo> {
-        HygieneData::with(|data| data.expn_info(self).cloned())
-    }
-
-    #[inline]
-    pub fn set_expn_info(self, info: ExpnInfo) {
+    pub fn set_expn_data(self, expn_data: ExpnData) {
         HygieneData::with(|data| {
-            let old_info = &mut data.expn_data[self.0 as usize].expn_info;
-            assert!(old_info.is_none(), "expansion info is reset for an expansion ID");
-            *old_info = Some(info);
+            let old_expn_data = &mut data.expn_data[self.0 as usize];
+            assert!(old_expn_data.is_none(), "expansion data is reset for an expansion ID");
+            *old_expn_data = Some(expn_data);
         })
     }
 
@@ -139,12 +124,9 @@ impl ExpnId {
     #[inline]
     pub fn looks_like_proc_macro_derive(self) -> bool {
         HygieneData::with(|data| {
-            if data.default_transparency(self) == Transparency::Opaque {
-                if let Some(expn_info) = data.expn_info(self) {
-                    if let ExpnKind::Macro(MacroKind::Derive, _) = expn_info.kind {
-                        return true;
-                    }
-                }
+            let expn_data = data.expn_data(self);
+            if let ExpnKind::Macro(MacroKind::Derive, _) = expn_data.kind {
+                return expn_data.default_transparency == Transparency::Opaque;
             }
             false
         })
@@ -153,7 +135,10 @@ impl ExpnId {
 
 #[derive(Debug)]
 crate struct HygieneData {
-    expn_data: Vec<InternalExpnData>,
+    /// Each expansion should have an associated expansion data, but sometimes there's a delay
+    /// between creation of an expansion ID and obtaining its data (e.g. macros are collected
+    /// first and then resolved later), so we use an `Option` here.
+    expn_data: Vec<Option<ExpnData>>,
     syntax_context_data: Vec<SyntaxContextData>,
     syntax_context_map: FxHashMap<(SyntaxContext, ExpnId, Transparency), SyntaxContext>,
 }
@@ -161,10 +146,7 @@ crate struct HygieneData {
 impl HygieneData {
     crate fn new(edition: Edition) -> Self {
         HygieneData {
-            expn_data: vec![InternalExpnData {
-                parent: ExpnId::root(),
-                expn_info: Some(ExpnInfo::default(ExpnKind::Root, DUMMY_SP, edition)),
-            }],
+            expn_data: vec![Some(ExpnData::default(ExpnKind::Root, DUMMY_SP, edition))],
             syntax_context_data: vec![SyntaxContextData {
                 outer_expn: ExpnId::root(),
                 outer_transparency: Transparency::Opaque,
@@ -181,25 +163,14 @@ impl HygieneData {
         GLOBALS.with(|globals| f(&mut *globals.hygiene_data.borrow_mut()))
     }
 
-    fn fresh_expn(&mut self, parent: ExpnId, expn_info: Option<ExpnInfo>) -> ExpnId {
-        self.expn_data.push(InternalExpnData { parent, expn_info });
+    fn fresh_expn(&mut self, expn_data: Option<ExpnData>) -> ExpnId {
+        self.expn_data.push(expn_data);
         ExpnId(self.expn_data.len() as u32 - 1)
     }
 
-    fn parent_expn(&self, expn_id: ExpnId) -> ExpnId {
-        self.expn_data[expn_id.0 as usize].parent
-    }
-
-    fn expn_info(&self, expn_id: ExpnId) -> Option<&ExpnInfo> {
-        if expn_id != ExpnId::root() {
-            Some(self.expn_data[expn_id.0 as usize].expn_info.as_ref()
-                     .expect("no expansion info for an expansion ID"))
-        } else {
-            // FIXME: Some code relies on `expn_info().is_none()` meaning "no expansion".
-            // Introduce a method for checking for "no expansion" instead and always return
-            // `ExpnInfo` from this function instead of the `Option`.
-            None
-        }
+    fn expn_data(&self, expn_id: ExpnId) -> &ExpnData {
+        self.expn_data[expn_id.0 as usize].as_ref()
+            .expect("no expansion data for an expansion ID")
     }
 
     fn is_descendant_of(&self, mut expn_id: ExpnId, ancestor: ExpnId) -> bool {
@@ -207,17 +178,11 @@ impl HygieneData {
             if expn_id == ExpnId::root() {
                 return false;
             }
-            expn_id = self.parent_expn(expn_id);
+            expn_id = self.expn_data(expn_id).parent;
         }
         true
     }
 
-    fn default_transparency(&self, expn_id: ExpnId) -> Transparency {
-        self.expn_info(expn_id).map_or(
-            Transparency::SemiTransparent, |einfo| einfo.default_transparency
-        )
-    }
-
     fn modern(&self, ctxt: SyntaxContext) -> SyntaxContext {
         self.syntax_context_data[ctxt.0 as usize].opaque
     }
@@ -246,7 +211,7 @@ impl HygieneData {
 
     fn marks(&self, mut ctxt: SyntaxContext) -> Vec<(ExpnId, Transparency)> {
         let mut marks = Vec::new();
-        while ctxt != SyntaxContext::empty() {
+        while ctxt != SyntaxContext::root() {
             marks.push((self.outer_expn(ctxt), self.outer_transparency(ctxt)));
             ctxt = self.parent_ctxt(ctxt);
         }
@@ -255,12 +220,8 @@ impl HygieneData {
     }
 
     fn walk_chain(&self, mut span: Span, to: SyntaxContext) -> Span {
-        while span.ctxt() != crate::NO_EXPANSION && span.ctxt() != to {
-            if let Some(info) = self.expn_info(self.outer_expn(span.ctxt())) {
-                span = info.call_site;
-            } else {
-                break;
-            }
+        while span.from_expansion() && span.ctxt() != to {
+            span = self.expn_data(self.outer_expn(span.ctxt())).call_site;
         }
         span
     }
@@ -275,7 +236,9 @@ impl HygieneData {
 
     fn apply_mark(&mut self, ctxt: SyntaxContext, expn_id: ExpnId) -> SyntaxContext {
         assert_ne!(expn_id, ExpnId::root());
-        self.apply_mark_with_transparency(ctxt, expn_id, self.default_transparency(expn_id))
+        self.apply_mark_with_transparency(
+            ctxt, expn_id, self.expn_data(expn_id).default_transparency
+        )
     }
 
     fn apply_mark_with_transparency(&mut self, ctxt: SyntaxContext, expn_id: ExpnId,
@@ -285,15 +248,14 @@ impl HygieneData {
             return self.apply_mark_internal(ctxt, expn_id, transparency);
         }
 
-        let call_site_ctxt =
-            self.expn_info(expn_id).map_or(SyntaxContext::empty(), |info| info.call_site.ctxt());
+        let call_site_ctxt = self.expn_data(expn_id).call_site.ctxt();
         let mut call_site_ctxt = if transparency == Transparency::SemiTransparent {
             self.modern(call_site_ctxt)
         } else {
             self.modern_and_legacy(call_site_ctxt)
         };
 
-        if call_site_ctxt == SyntaxContext::empty() {
+        if call_site_ctxt == SyntaxContext::root() {
             return self.apply_mark_internal(ctxt, expn_id, transparency);
         }
 
@@ -400,7 +362,7 @@ pub fn update_dollar_crate_names(mut get_name: impl FnMut(SyntaxContext) -> Symb
 
 impl SyntaxContext {
     #[inline]
-    pub const fn empty() -> Self {
+    pub const fn root() -> Self {
         SyntaxContext(0)
     }
 
@@ -578,20 +540,20 @@ impl SyntaxContext {
         HygieneData::with(|data| data.outer_expn(self))
     }
 
-    /// `ctxt.outer_expn_info()` is equivalent to but faster than
-    /// `ctxt.outer_expn().expn_info()`.
+    /// `ctxt.outer_expn_data()` is equivalent to but faster than
+    /// `ctxt.outer_expn().expn_data()`.
     #[inline]
-    pub fn outer_expn_info(self) -> Option<ExpnInfo> {
-        HygieneData::with(|data| data.expn_info(data.outer_expn(self)).cloned())
+    pub fn outer_expn_data(self) -> ExpnData {
+        HygieneData::with(|data| data.expn_data(data.outer_expn(self)).clone())
     }
 
-    /// `ctxt.outer_expn_with_info()` is equivalent to but faster than
-    /// `{ let outer = ctxt.outer_expn(); (outer, outer.expn_info()) }`.
+    /// `ctxt.outer_expn_with_data()` is equivalent to but faster than
+    /// `{ let outer = ctxt.outer_expn(); (outer, outer.expn_data()) }`.
     #[inline]
-    pub fn outer_expn_with_info(self) -> (ExpnId, Option<ExpnInfo>) {
+    pub fn outer_expn_with_data(self) -> (ExpnId, ExpnData) {
         HygieneData::with(|data| {
             let outer = data.outer_expn(self);
-            (outer, data.expn_info(outer).cloned())
+            (outer, data.expn_data(outer).clone())
         })
     }
 
@@ -612,10 +574,10 @@ impl Span {
     /// other compiler-generated code to set per-span properties like allowed unstable features.
     /// The returned span belongs to the created expansion and has the new properties,
     /// but its location is inherited from the current span.
-    pub fn fresh_expansion(self, parent: ExpnId, expn_info: ExpnInfo) -> Span {
+    pub fn fresh_expansion(self, expn_data: ExpnData) -> Span {
         HygieneData::with(|data| {
-            let expn_id = data.fresh_expn(parent, Some(expn_info));
-            self.with_ctxt(data.apply_mark(SyntaxContext::empty(), expn_id))
+            let expn_id = data.fresh_expn(Some(expn_data));
+            self.with_ctxt(data.apply_mark(SyntaxContext::root(), expn_id))
         })
     }
 }
@@ -623,8 +585,12 @@ impl Span {
 /// A subset of properties from both macro definition and macro call available through global data.
 /// Avoid using this if you have access to the original definition or call structures.
 #[derive(Clone, Debug, RustcEncodable, RustcDecodable)]
-pub struct ExpnInfo {
+pub struct ExpnData {
     // --- The part unique to each expansion.
+    /// The kind of this expansion - macro or compiler desugaring.
+    pub kind: ExpnKind,
+    /// The expansion that produced this expansion.
+    pub parent: ExpnId,
     /// The location of the actual macro invocation or syntax sugar , e.g.
     /// `let x = foo!();` or `if let Some(y) = x {}`
     ///
@@ -632,18 +598,18 @@ pub struct ExpnInfo {
     /// `foo!()` invoked `bar!()` internally, and there was an
     /// expression inside `bar!`; the call_site of the expression in
     /// the expansion would point to the `bar!` invocation; that
-    /// call_site span would have its own ExpnInfo, with the call_site
+    /// call_site span would have its own ExpnData, with the call_site
     /// pointing to the `foo!` invocation.
     pub call_site: Span,
-    /// The kind of this expansion - macro or compiler desugaring.
-    pub kind: ExpnKind,
 
     // --- The part specific to the macro/desugaring definition.
-    // --- FIXME: Share it between expansions with the same definition.
+    // --- It may be reasonable to share this part between expansions with the same definition,
+    // --- but such sharing is known to bring some minor inconveniences without also bringing
+    // --- noticeable perf improvements (PR #62898).
     /// The span of the macro definition (possibly dummy).
     /// This span serves only informational purpose and is not used for resolution.
     pub def_site: Span,
-    /// Transparency used by `apply_mark` for the expansion with this expansion info by default.
+    /// Transparency used by `apply_mark` for the expansion with this expansion data by default.
     pub default_transparency: Transparency,
     /// List of #[unstable]/feature-gated features that the macro is allowed to use
     /// internally without forcing the whole crate to opt-in
@@ -659,12 +625,13 @@ pub struct ExpnInfo {
     pub edition: Edition,
 }
 
-impl ExpnInfo {
-    /// Constructs an expansion info with default properties.
-    pub fn default(kind: ExpnKind, call_site: Span, edition: Edition) -> ExpnInfo {
-        ExpnInfo {
-            call_site,
+impl ExpnData {
+    /// Constructs expansion data with default properties.
+    pub fn default(kind: ExpnKind, call_site: Span, edition: Edition) -> ExpnData {
+        ExpnData {
             kind,
+            parent: ExpnId::root(),
+            call_site,
             def_site: DUMMY_SP,
             default_transparency: Transparency::SemiTransparent,
             allow_internal_unstable: None,
@@ -675,12 +642,17 @@ impl ExpnInfo {
     }
 
     pub fn allow_unstable(kind: ExpnKind, call_site: Span, edition: Edition,
-                          allow_internal_unstable: Lrc<[Symbol]>) -> ExpnInfo {
-        ExpnInfo {
+                          allow_internal_unstable: Lrc<[Symbol]>) -> ExpnData {
+        ExpnData {
             allow_internal_unstable: Some(allow_internal_unstable),
-            ..ExpnInfo::default(kind, call_site, edition)
+            ..ExpnData::default(kind, call_site, edition)
         }
     }
+
+    #[inline]
+    pub fn is_root(&self) -> bool {
+        if let ExpnKind::Root = self.kind { true } else { false }
+    }
 }
 
 /// Expansion kind.
@@ -767,6 +739,18 @@ impl DesugaringKind {
     }
 }
 
+impl Encodable for ExpnId {
+    fn encode<E: Encoder>(&self, _: &mut E) -> Result<(), E::Error> {
+        Ok(()) // FIXME(jseyfried) intercrate hygiene
+    }
+}
+
+impl Decodable for ExpnId {
+    fn decode<D: Decoder>(_: &mut D) -> Result<Self, D::Error> {
+        Ok(ExpnId::root()) // FIXME(jseyfried) intercrate hygiene
+    }
+}
+
 impl Encodable for SyntaxContext {
     fn encode<E: Encoder>(&self, _: &mut E) -> Result<(), E::Error> {
         Ok(()) // FIXME(jseyfried) intercrate hygiene
@@ -774,7 +758,7 @@ impl Encodable for SyntaxContext {
 }
 
 impl Decodable for SyntaxContext {
-    fn decode<D: Decoder>(_: &mut D) -> Result<SyntaxContext, D::Error> {
-        Ok(SyntaxContext::empty()) // FIXME(jseyfried) intercrate hygiene
+    fn decode<D: Decoder>(_: &mut D) -> Result<Self, D::Error> {
+        Ok(SyntaxContext::root()) // FIXME(jseyfried) intercrate hygiene
     }
 }
diff --git a/src/libsyntax_pos/lib.rs b/src/libsyntax_pos/lib.rs
index 02a7433d946..aa36fe27d8e 100644
--- a/src/libsyntax_pos/lib.rs
+++ b/src/libsyntax_pos/lib.rs
@@ -21,7 +21,7 @@ use rustc_serialize::{Encodable, Decodable, Encoder, Decoder};
 pub mod edition;
 use edition::Edition;
 pub mod hygiene;
-pub use hygiene::{ExpnId, SyntaxContext, ExpnInfo, ExpnKind, MacroKind, DesugaringKind};
+pub use hygiene::{ExpnId, SyntaxContext, ExpnData, ExpnKind, MacroKind, DesugaringKind};
 
 mod span_encoding;
 pub use span_encoding::{Span, DUMMY_SP};
@@ -49,7 +49,6 @@ pub struct Globals {
     symbol_interner: Lock<symbol::Interner>,
     span_interner: Lock<span_encoding::SpanInterner>,
     hygiene_data: Lock<hygiene::HygieneData>,
-    edition: Edition,
 }
 
 impl Globals {
@@ -58,7 +57,6 @@ impl Globals {
             symbol_interner: Lock::new(symbol::Interner::fresh()),
             span_interner: Lock::new(span_encoding::SpanInterner::default()),
             hygiene_data: Lock::new(hygiene::HygieneData::new(edition)),
-            edition,
         }
     }
 }
@@ -288,6 +286,17 @@ impl Span {
         span.lo.0 == 0 && span.hi.0 == 0
     }
 
+    /// Returns `true` if this span comes from a macro or desugaring.
+    #[inline]
+    pub fn from_expansion(self) -> bool {
+        self.ctxt() != SyntaxContext::root()
+    }
+
+    #[inline]
+    pub fn with_root_ctxt(lo: BytePos, hi: BytePos) -> Span {
+        Span::new(lo, hi, SyntaxContext::root())
+    }
+
     /// Returns a new span representing an empty span at the beginning of this span
     #[inline]
     pub fn shrink_to_lo(self) -> Span {
@@ -344,20 +353,20 @@ impl Span {
     /// Returns the source span -- this is either the supplied span, or the span for
     /// the macro callsite that expanded to it.
     pub fn source_callsite(self) -> Span {
-        self.ctxt().outer_expn_info().map(|info| info.call_site.source_callsite()).unwrap_or(self)
+        let expn_data = self.ctxt().outer_expn_data();
+        if !expn_data.is_root() { expn_data.call_site.source_callsite() } else { self }
     }
 
     /// The `Span` for the tokens in the previous macro expansion from which `self` was generated,
     /// if any.
     pub fn parent(self) -> Option<Span> {
-        self.ctxt().outer_expn_info().map(|i| i.call_site)
+        let expn_data = self.ctxt().outer_expn_data();
+        if !expn_data.is_root() { Some(expn_data.call_site) } else { None }
     }
 
     /// Edition of the crate from which this span came.
     pub fn edition(self) -> edition::Edition {
-        self.ctxt().outer_expn_info().map_or_else(|| {
-            Edition::from_session()
-        }, |einfo| einfo.edition)
+        self.ctxt().outer_expn_data().edition
     }
 
     #[inline]
@@ -373,52 +382,42 @@ impl Span {
     /// Returns the source callee.
     ///
     /// Returns `None` if the supplied span has no expansion trace,
-    /// else returns the `ExpnInfo` for the macro definition
+    /// else returns the `ExpnData` for the macro definition
     /// corresponding to the source callsite.
-    pub fn source_callee(self) -> Option<ExpnInfo> {
-        fn source_callee(info: ExpnInfo) -> ExpnInfo {
-            match info.call_site.ctxt().outer_expn_info() {
-                Some(info) => source_callee(info),
-                None => info,
-            }
+    pub fn source_callee(self) -> Option<ExpnData> {
+        fn source_callee(expn_data: ExpnData) -> ExpnData {
+            let next_expn_data = expn_data.call_site.ctxt().outer_expn_data();
+            if !next_expn_data.is_root() { source_callee(next_expn_data) } else { expn_data }
         }
-        self.ctxt().outer_expn_info().map(source_callee)
+        let expn_data = self.ctxt().outer_expn_data();
+        if !expn_data.is_root() { Some(source_callee(expn_data)) } else { None }
     }
 
     /// Checks if a span is "internal" to a macro in which `#[unstable]`
     /// items can be used (that is, a macro marked with
     /// `#[allow_internal_unstable]`).
     pub fn allows_unstable(&self, feature: Symbol) -> bool {
-        match self.ctxt().outer_expn_info() {
-            Some(info) => info
-                .allow_internal_unstable
-                .map_or(false, |features| features.iter().any(|&f|
-                    f == feature || f == sym::allow_internal_unstable_backcompat_hack
-                )),
-            None => false,
-        }
+        self.ctxt().outer_expn_data().allow_internal_unstable.map_or(false, |features| {
+            features.iter().any(|&f| {
+                f == feature || f == sym::allow_internal_unstable_backcompat_hack
+            })
+        })
     }
 
     /// Checks if this span arises from a compiler desugaring of kind `kind`.
     pub fn is_desugaring(&self, kind: DesugaringKind) -> bool {
-        match self.ctxt().outer_expn_info() {
-            Some(info) => match info.kind {
-                ExpnKind::Desugaring(k) => k == kind,
-                _ => false,
-            },
-            None => false,
+        match self.ctxt().outer_expn_data().kind {
+            ExpnKind::Desugaring(k) => k == kind,
+            _ => false,
         }
     }
 
     /// Returns the compiler desugaring that created this span, or `None`
     /// if this span is not from a desugaring.
     pub fn desugaring_kind(&self) -> Option<DesugaringKind> {
-        match self.ctxt().outer_expn_info() {
-            Some(info) => match info.kind {
-                ExpnKind::Desugaring(k) => Some(k),
-                _ => None
-            },
-            None => None
+        match self.ctxt().outer_expn_data().kind {
+            ExpnKind::Desugaring(k) => Some(k),
+            _ => None
         }
     }
 
@@ -426,19 +425,20 @@ impl Span {
     /// can be used without triggering the `unsafe_code` lint
     //  (that is, a macro marked with `#[allow_internal_unsafe]`).
     pub fn allows_unsafe(&self) -> bool {
-        match self.ctxt().outer_expn_info() {
-            Some(info) => info.allow_internal_unsafe,
-            None => false,
-        }
+        self.ctxt().outer_expn_data().allow_internal_unsafe
     }
 
     pub fn macro_backtrace(mut self) -> Vec<MacroBacktrace> {
         let mut prev_span = DUMMY_SP;
         let mut result = vec![];
-        while let Some(info) = self.ctxt().outer_expn_info() {
+        loop {
+            let expn_data = self.ctxt().outer_expn_data();
+            if expn_data.is_root() {
+                break;
+            }
             // Don't print recursive invocations.
-            if !info.call_site.source_equal(&prev_span) {
-                let (pre, post) = match info.kind {
+            if !expn_data.call_site.source_equal(&prev_span) {
+                let (pre, post) = match expn_data.kind {
                     ExpnKind::Root => break,
                     ExpnKind::Desugaring(..) => ("desugaring of ", ""),
                     ExpnKind::Macro(macro_kind, _) => match macro_kind {
@@ -448,14 +448,14 @@ impl Span {
                     }
                 };
                 result.push(MacroBacktrace {
-                    call_site: info.call_site,
-                    macro_decl_name: format!("{}{}{}", pre, info.kind.descr(), post),
-                    def_site_span: info.def_site,
+                    call_site: expn_data.call_site,
+                    macro_decl_name: format!("{}{}{}", pre, expn_data.kind.descr(), post),
+                    def_site_span: expn_data.def_site,
                 });
             }
 
             prev_span = self;
-            self = info.call_site;
+            self = expn_data.call_site;
         }
         result
     }
@@ -468,9 +468,9 @@ impl Span {
         // Return the macro span on its own to avoid weird diagnostic output. It is preferable to
         // have an incomplete span than a completely nonsensical one.
         if span_data.ctxt != end_data.ctxt {
-            if span_data.ctxt == SyntaxContext::empty() {
+            if span_data.ctxt == SyntaxContext::root() {
                 return end;
-            } else if end_data.ctxt == SyntaxContext::empty() {
+            } else if end_data.ctxt == SyntaxContext::root() {
                 return self;
             }
             // Both spans fall within a macro.
@@ -479,7 +479,7 @@ impl Span {
         Span::new(
             cmp::min(span_data.lo, end_data.lo),
             cmp::max(span_data.hi, end_data.hi),
-            if span_data.ctxt == SyntaxContext::empty() { end_data.ctxt } else { span_data.ctxt },
+            if span_data.ctxt == SyntaxContext::root() { end_data.ctxt } else { span_data.ctxt },
         )
     }
 
@@ -490,7 +490,7 @@ impl Span {
         Span::new(
             span.hi,
             end.lo,
-            if end.ctxt == SyntaxContext::empty() { end.ctxt } else { span.ctxt },
+            if end.ctxt == SyntaxContext::root() { end.ctxt } else { span.ctxt },
         )
     }
 
@@ -501,7 +501,7 @@ impl Span {
         Span::new(
             span.lo,
             end.lo,
-            if end.ctxt == SyntaxContext::empty() { end.ctxt } else { span.ctxt },
+            if end.ctxt == SyntaxContext::root() { end.ctxt } else { span.ctxt },
         )
     }
 
@@ -611,7 +611,7 @@ impl rustc_serialize::UseSpecializedDecodable for Span {
         d.read_struct("Span", 2, |d| {
             let lo = d.read_struct_field("lo", 0, Decodable::decode)?;
             let hi = d.read_struct_field("hi", 1, Decodable::decode)?;
-            Ok(Span::new(lo, hi, NO_EXPANSION))
+            Ok(Span::with_root_ctxt(lo, hi))
         })
     }
 }
@@ -755,8 +755,6 @@ impl From<Vec<Span>> for MultiSpan {
     }
 }
 
-pub const NO_EXPANSION: SyntaxContext = SyntaxContext::empty();
-
 /// Identifies an offset of a multi-byte character in a `SourceFile`.
 #[derive(Copy, Clone, RustcEncodable, RustcDecodable, Eq, PartialEq, Debug)]
 pub struct MultiByteChar {
diff --git a/src/libsyntax_pos/symbol.rs b/src/libsyntax_pos/symbol.rs
index 2d9556233d1..e2d1635f312 100644
--- a/src/libsyntax_pos/symbol.rs
+++ b/src/libsyntax_pos/symbol.rs
@@ -14,7 +14,6 @@ use std::fmt;
 use std::hash::{Hash, Hasher};
 use std::str;
 
-use crate::hygiene::SyntaxContext;
 use crate::{Span, DUMMY_SP, GLOBALS};
 
 #[cfg(test)]
@@ -745,25 +744,25 @@ impl Ident {
         Ident { name, span }
     }
 
-    /// Constructs a new identifier with an empty syntax context.
+    /// Constructs a new identifier with a dummy span.
     #[inline]
-    pub const fn with_empty_ctxt(name: Symbol) -> Ident {
+    pub const fn with_dummy_span(name: Symbol) -> Ident {
         Ident::new(name, DUMMY_SP)
     }
 
     #[inline]
     pub fn invalid() -> Ident {
-        Ident::with_empty_ctxt(kw::Invalid)
+        Ident::with_dummy_span(kw::Invalid)
     }
 
     /// Maps an interned string to an identifier with an empty syntax context.
     pub fn from_interned_str(string: InternedString) -> Ident {
-        Ident::with_empty_ctxt(string.as_symbol())
+        Ident::with_dummy_span(string.as_symbol())
     }
 
     /// Maps a string to an identifier with an empty span.
     pub fn from_str(string: &str) -> Ident {
-        Ident::with_empty_ctxt(Symbol::intern(string))
+        Ident::with_dummy_span(Symbol::intern(string))
     }
 
     /// Maps a string and a span to an identifier.
@@ -851,7 +850,7 @@ impl fmt::Display for Ident {
 
 impl Encodable for Ident {
     fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
-        if self.span.ctxt().modern() == SyntaxContext::empty() {
+        if !self.span.modern().from_expansion() {
             s.emit_str(&self.as_str())
         } else { // FIXME(jseyfried): intercrate hygiene
             let mut string = "#".to_owned();