Repository: rust-analyzer/rust-analyzer
Pull request #7137 (2021-01-03 10:48:26)

Revert "Proper handling $crate and local_inner_macros"
Reverts rust-analyzer/rust-analyzer#7133

It caused a fairly significant performance regression.

bors r+


Patch:
diff --git a/crates/hir_def/src/path/lower.rs b/crates/hir_def/src/path/lower.rs
index 9518ac109b..8a01e6eead 100644
--- a/crates/hir_def/src/path/lower.rs
+++ b/crates/hir_def/src/path/lower.rs
@@ -123,7 +123,7 @@ pub(super) fn lower_path(mut path: ast::Path, hygiene: &Hygiene) -> Option<Path>
     // We follow what it did anyway :)
     if segments.len() == 1 && kind == PathKind::Plain {
         if let Some(_macro_call) = path.syntax().parent().and_then(ast::MacroCall::cast) {
-            if let Some(crate_id) = hygiene.local_inner_macros(path) {
+            if let Some(crate_id) = hygiene.local_inner_macros() {
                 kind = PathKind::DollarCrate(crate_id);
             }
         }
diff --git a/crates/hir_expand/src/hygiene.rs b/crates/hir_expand/src/hygiene.rs
index 6042e15b22..7ab0a5e52e 100644
--- a/crates/hir_expand/src/hygiene.rs
+++ b/crates/hir_expand/src/hygiene.rs
@@ -2,94 +2,30 @@
 //!
 //! Specifically, `ast` + `Hygiene` allows you to create a `Name`. Note that, at
 //! this moment, this is horribly incomplete and handles only `$crate`.
-use std::sync::Arc;
-
-use arena::{Arena, Idx};
 use base_db::CrateId;
 use either::Either;
-use mbe::Origin;
-use syntax::{ast, AstNode};
+use syntax::ast;
 
 use crate::{
     db::AstDatabase,
     name::{AsName, Name},
-    ExpansionInfo, HirFileId, HirFileIdRepr, MacroCallId, MacroDefKind,
+    HirFileId, HirFileIdRepr, MacroCallId, MacroDefKind,
 };
 
 #[derive(Clone, Debug)]
 pub struct Hygiene {
-    frames: Option<Arc<HygieneFrames>>,
-}
-
-impl Hygiene {
-    pub fn new(db: &dyn AstDatabase, file_id: HirFileId) -> Hygiene {
-        Hygiene { frames: Some(Arc::new(HygieneFrames::new(db, file_id.clone()))) }
-    }
-
-    pub fn new_unhygienic() -> Hygiene {
-        Hygiene { frames: None }
-    }
-
-    // FIXME: this should just return name
-    pub fn name_ref_to_name(&self, name_ref: ast::NameRef) -> Either<Name, CrateId> {
-        if let Some(frames) = &self.frames {
-            if name_ref.text() == "$crate" {
-                if let Some(krate) = frames.root_crate(&name_ref) {
-                    return Either::Right(krate);
-                }
-            }
-        }
-
-        Either::Left(name_ref.as_name())
-    }
-
-    pub fn local_inner_macros(&self, path: ast::Path) -> Option<CrateId> {
-        let frames = self.frames.as_ref()?;
-
-        let mut token = path.syntax().first_token()?;
-        let mut current = frames.first();
-
-        while let Some((frame, data)) =
-            current.and_then(|it| Some((it, it.expansion.as_ref()?.map_token_up(&token)?)))
-        {
-            let (mapped, origin) = data;
-            if origin == Origin::Def {
-                return if frame.local_inner { frame.krate } else { None };
-            }
-            current = Some(&frames.0[frame.call_site?]);
-            token = mapped.value;
-        }
-        None
-    }
-}
-
-#[derive(Default, Debug)]
-struct HygieneFrames(Arena<HygieneFrame>);
-
-#[derive(Clone, Debug)]
-struct HygieneFrame {
-    expansion: Option<ExpansionInfo>,
+    // This is what `$crate` expands to
+    def_crate: Option<CrateId>,
 
     // Indicate this is a local inner macro
     local_inner: bool,
-    krate: Option<CrateId>,
-
-    call_site: Option<Idx<HygieneFrame>>,
-    def_site: Option<Idx<HygieneFrame>>,
 }
 
-impl HygieneFrames {
-    fn new(db: &dyn AstDatabase, file_id: HirFileId) -> Self {
-        let mut frames = HygieneFrames::default();
-        frames.add(db, file_id);
-        frames
-    }
-
-    fn add(&mut self, db: &dyn AstDatabase, file_id: HirFileId) -> Option<Idx<HygieneFrame>> {
-        let (krate, local_inner) = match file_id.0 {
+impl Hygiene {
+    pub fn new(db: &dyn AstDatabase, file_id: HirFileId) -> Hygiene {
+        let (def_crate, local_inner) = match file_id.0 {
             HirFileIdRepr::FileId(_) => (None, false),
             HirFileIdRepr::MacroFile(macro_file) => match macro_file.macro_call_id {
-                MacroCallId::EagerMacro(_id) => (None, false),
                 MacroCallId::LazyMacro(id) => {
                     let loc = db.lookup_intern_macro(id);
                     match loc.def.kind {
@@ -100,68 +36,31 @@ impl HygieneFrames {
                         MacroDefKind::ProcMacro(_) => (None, false),
                     }
                 }
+                MacroCallId::EagerMacro(_id) => (None, false),
             },
         };
-
-        let expansion = file_id.expansion_info(db);
-        let expansion = match expansion {
-            None => {
-                return Some(self.0.alloc(HygieneFrame {
-                    expansion: None,
-                    local_inner,
-                    krate,
-                    call_site: None,
-                    def_site: None,
-                }));
-            }
-            Some(it) => it,
-        };
-
-        let def_site = expansion.def.clone();
-        let call_site = expansion.arg.file_id;
-        let idx = self.0.alloc(HygieneFrame {
-            expansion: Some(expansion),
-            local_inner,
-            krate,
-            call_site: None,
-            def_site: None,
-        });
-
-        self.0[idx].call_site = self.add(db, call_site);
-        self.0[idx].def_site = def_site.and_then(|it| self.add(db, it.file_id));
-
-        Some(idx)
+        Hygiene { def_crate, local_inner }
     }
 
-    fn first(&self) -> Option<&HygieneFrame> {
-        self.0.iter().next().map(|it| it.1)
+    pub fn new_unhygienic() -> Hygiene {
+        Hygiene { def_crate: None, local_inner: false }
     }
 
-    fn root_crate(&self, name_ref: &ast::NameRef) -> Option<CrateId> {
-        let mut token = name_ref.syntax().first_token()?;
-        let first = self.first()?;
-        let mut result = first.krate;
-        let mut current = Some(first);
-
-        while let Some((frame, (mapped, origin))) =
-            current.and_then(|it| Some((it, it.expansion.as_ref()?.map_token_up(&token)?)))
-        {
-            result = frame.krate;
-
-            let site = match origin {
-                Origin::Def => frame.def_site,
-                Origin::Call => frame.call_site,
-            };
-
-            let site = match site {
-                None => break,
-                Some(it) => it,
-            };
-
-            current = Some(&self.0[site]);
-            token = mapped.value;
+    // FIXME: this should just return name
+    pub fn name_ref_to_name(&self, name_ref: ast::NameRef) -> Either<Name, CrateId> {
+        if let Some(def_crate) = self.def_crate {
+            if name_ref.text() == "$crate" {
+                return Either::Right(def_crate);
+            }
         }
+        Either::Left(name_ref.as_name())
+    }
 
-        result
+    pub fn local_inner_macros(&self) -> Option<CrateId> {
+        if self.local_inner {
+            self.def_crate
+        } else {
+            None
+        }
     }
 }
diff --git a/crates/hir_expand/src/lib.rs b/crates/hir_expand/src/lib.rs
index 5b6734a5f4..3fa1b1d776 100644
--- a/crates/hir_expand/src/lib.rs
+++ b/crates/hir_expand/src/lib.rs
@@ -340,8 +340,11 @@ impl ExpansionInfo {
         Some(self.expanded.with_value(token))
     }
 
-    pub fn map_token_up(&self, token: &SyntaxToken) -> Option<(InFile<SyntaxToken>, Origin)> {
-        let token_id = self.exp_map.token_by_range(token.text_range())?;
+    pub fn map_token_up(
+        &self,
+        token: InFile<&SyntaxToken>,
+    ) -> Option<(InFile<SyntaxToken>, Origin)> {
+        let token_id = self.exp_map.token_by_range(token.value.text_range())?;
 
         let (token_id, origin) = self.macro_def.0.map_id_up(token_id);
         let (token_map, tt) = match origin {
@@ -356,7 +359,7 @@ impl ExpansionInfo {
             ),
         };
 
-        let range = token_map.range_by_token(token_id)?.by_kind(token.kind())?;
+        let range = token_map.range_by_token(token_id)?.by_kind(token.value.kind())?;
         let token = algo::find_covering_element(&tt.value, range + tt.value.text_range().start())
             .into_token()?;
         Some((tt.with_value(token), origin))
@@ -492,7 +495,7 @@ fn ascend_call_token(
     expansion: &ExpansionInfo,
     token: InFile<SyntaxToken>,
 ) -> Option<InFile<SyntaxToken>> {
-    let (mapped, origin) = expansion.map_token_up(&token.value)?;
+    let (mapped, origin) = expansion.map_token_up(token.as_ref())?;
     if origin != Origin::Call {
         return None;
     }
diff --git a/crates/mbe/src/mbe_expander/matcher.rs b/crates/mbe/src/mbe_expander/matcher.rs
index 385b466018..ab5f87c487 100644
--- a/crates/mbe/src/mbe_expander/matcher.rs
+++ b/crates/mbe/src/mbe_expander/matcher.rs
@@ -150,7 +150,7 @@ fn match_subtree(
                     res.add_err(err!("leftover tokens"));
                 }
             }
-            Op::Var { name, kind, .. } => {
+            Op::Var { name, kind } => {
                 let kind = match kind {
                     Some(k) => k,
                     None => {
diff --git a/crates/mbe/src/mbe_expander/transcriber.rs b/crates/mbe/src/mbe_expander/transcriber.rs
index 57f3f104dc..7205312371 100644
--- a/crates/mbe/src/mbe_expander/transcriber.rs
+++ b/crates/mbe/src/mbe_expander/transcriber.rs
@@ -100,8 +100,8 @@ fn expand_subtree(
                 err = err.or(e);
                 arena.push(tt.into());
             }
-            Op::Var { name, id, .. } => {
-                let ExpandResult { value: fragment, err: e } = expand_var(ctx, &name, *id);
+            Op::Var { name, .. } => {
+                let ExpandResult { value: fragment, err: e } = expand_var(ctx, &name);
                 err = err.or(e);
                 push_fragment(arena, fragment);
             }
@@ -118,10 +118,12 @@ fn expand_subtree(
     ExpandResult { value: tt::Subtree { delimiter: template.delimiter, token_trees: tts }, err }
 }
 
-fn expand_var(ctx: &mut ExpandCtx, v: &SmolStr, id: tt::TokenId) -> ExpandResult<Fragment> {
+fn expand_var(ctx: &mut ExpandCtx, v: &SmolStr) -> ExpandResult<Fragment> {
     if v == "crate" {
         // We simply produce identifier `$crate` here. And it will be resolved when lowering ast to Path.
-        let tt = tt::Leaf::from(tt::Ident { text: "$crate".into(), id }).into();
+        let tt =
+            tt::Leaf::from(tt::Ident { text: "$crate".into(), id: tt::TokenId::unspecified() })
+                .into();
         ExpandResult::ok(Fragment::Tokens(tt))
     } else if !ctx.bindings.contains(v) {
         // Note that it is possible to have a `$var` inside a macro which is not bound.
@@ -140,8 +142,14 @@ fn expand_var(ctx: &mut ExpandCtx, v: &SmolStr, id: tt::TokenId) -> ExpandResult
         let tt = tt::Subtree {
             delimiter: None,
             token_trees: vec![
-                tt::Leaf::from(tt::Punct { char: '$', spacing: tt::Spacing::Alone, id }).into(),
-                tt::Leaf::from(tt::Ident { text: v.clone(), id }).into(),
+                tt::Leaf::from(tt::Punct {
+                    char: '$',
+                    spacing: tt::Spacing::Alone,
+                    id: tt::TokenId::unspecified(),
+                })
+                .into(),
+                tt::Leaf::from(tt::Ident { text: v.clone(), id: tt::TokenId::unspecified() })
+                    .into(),
             ],
         }
         .into();
diff --git a/crates/mbe/src/parser.rs b/crates/mbe/src/parser.rs
index 77cc739b65..2f3ebc8313 100644
--- a/crates/mbe/src/parser.rs
+++ b/crates/mbe/src/parser.rs
@@ -8,7 +8,7 @@ use crate::{tt_iter::TtIter, ExpandError, MetaTemplate};
 
 #[derive(Clone, Debug, PartialEq, Eq)]
 pub(crate) enum Op {
-    Var { name: SmolStr, kind: Option<SmolStr>, id: tt::TokenId },
+    Var { name: SmolStr, kind: Option<SmolStr> },
     Repeat { subtree: MetaTemplate, kind: RepeatKind, separator: Option<Separator> },
     Leaf(tt::Leaf),
     Subtree(MetaTemplate),
@@ -106,21 +106,18 @@ fn next_op<'a>(first: &tt::TokenTree, src: &mut TtIter<'a>, mode: Mode) -> Resul
                         }
                         let name = UNDERSCORE.clone();
                         let kind = eat_fragment_kind(src, mode)?;
-                        let id = punct.id;
-                        Op::Var { name, kind, id }
+                        Op::Var { name, kind }
                     }
                     tt::Leaf::Ident(ident) => {
                         let name = ident.text.clone();
                         let kind = eat_fragment_kind(src, mode)?;
-                        let id = ident.id;
-                        Op::Var { name, kind, id }
+                        Op::Var { name, kind }
                     }
                     tt::Leaf::Literal(lit) => {
                         if is_boolean_literal(&lit) {
                             let name = lit.text.clone();
                             let kind = eat_fragment_kind(src, mode)?;
-                            let id = lit.id;
-                            Op::Var { name, kind, id }
+                            Op::Var { name, kind }
                         } else {
                             bail!("bad var 2");
                         }


Test patch:
diff --git a/crates/hir_ty/src/tests/macros.rs b/crates/hir_ty/src/tests/macros.rs
index c64f0b5b53..1953da7beb 100644
--- a/crates/hir_ty/src/tests/macros.rs
+++ b/crates/hir_ty/src/tests/macros.rs
@@ -370,37 +370,6 @@ expand!();
     );
 }
 
-#[test]
-fn infer_macro_with_dollar_crate_in_def_site() {
-    check_types(
-        r#"
-//- /main.rs crate:main deps:foo
-use foo::expand;
-
-macro_rules! list {
-    ($($tt:tt)*) => { $($tt)* }
-}
-
-fn test() {
-    let r = expand!();
-    r;
-  //^ u128
-}
-
-//- /lib.rs crate:foo
-#[macro_export]
-macro_rules! expand {
-    () => { list!($crate::m!()) };
-}
-
-#[macro_export]
-macro_rules! m {
-    () => { 0u128 };
-}
-"#,
-    );
-}
-
 #[test]
 fn infer_type_value_non_legacy_macro_use_as() {
     check_infer(