]> git.lizzy.rs Git - rust.git/commitdiff
resolve: Introduce "may appear after" abstraction for macro path resolutions
authorVadim Petrochenkov <vadim.petrochenkov@gmail.com>
Tue, 28 Aug 2018 01:07:31 +0000 (04:07 +0300)
committerVadim Petrochenkov <vadim.petrochenkov@gmail.com>
Sat, 8 Sep 2018 11:15:11 +0000 (14:15 +0300)
src/librustc_resolve/lib.rs
src/librustc_resolve/macros.rs
src/libsyntax_pos/hygiene.rs

index 26756e2992600f86f48ec7ae1a36b2c3ab106468..e1f532232f5599da8c5ab326a87fb7ee19724718 100644 (file)
@@ -1269,6 +1269,15 @@ fn is_macro_def(&self) -> bool {
     fn descr(&self) -> &'static str {
         if self.is_extern_crate() { "extern crate" } else { self.def().kind_name() }
     }
+
+    // Suppose that we resolved macro invocation with `invoc_id` to binding `binding` at some
+    // expansion round `max(invoc_id, binding)` when they both emerged from macros.
+    // Then this function returns `true` if `self` may emerge from a macro *after* that
+    // in some later round and screw up our previously found resolution.
+    fn may_appear_after(&self, _invoc_id: Mark, _binding: &NameBinding) -> bool {
+        // FIXME: This is a very conservative estimation.
+        self.expansion != Mark::root()
+    }
 }
 
 /// Interns the names of the primitive types.
@@ -3466,6 +3475,20 @@ fn resolve_path(
         record_used: bool,
         path_span: Span,
         crate_lint: CrateLint,
+    ) -> PathResult<'a> {
+        self.resolve_path_with_invoc_id(base_module, path, opt_ns, Mark::root(),
+                                        record_used, path_span, crate_lint)
+    }
+
+    fn resolve_path_with_invoc_id(
+        &mut self,
+        base_module: Option<ModuleOrUniformRoot<'a>>,
+        path: &[Ident],
+        opt_ns: Option<Namespace>, // `None` indicates a module path
+        invoc_id: Mark,
+        record_used: bool,
+        path_span: Span,
+        crate_lint: CrateLint,
     ) -> PathResult<'a> {
         let mut module = base_module;
         let mut allow_super = true;
@@ -3555,8 +3578,9 @@ fn resolve_path(
                 self.resolve_ident_in_module(module, ident, ns, record_used, path_span)
             } else if opt_ns == Some(MacroNS) {
                 assert!(ns == TypeNS);
-                self.resolve_lexical_macro_path_segment(ident, ns, record_used, record_used,
-                                                        false, path_span).map(|(b, _)| b)
+                self.resolve_lexical_macro_path_segment(ident, ns, invoc_id, record_used,
+                                                        record_used, false, path_span)
+                                                        .map(|(binding, _)| binding)
             } else {
                 let record_used_id =
                     if record_used { crate_lint.node_id().or(Some(CRATE_NODE_ID)) } else { None };
index 26499551af686cce1b33ec3692629ded05e85355..af9959c808435ad8c167b97ca0b7e1c3d13fe553 100644 (file)
@@ -431,12 +431,12 @@ fn resolve_macro_to_def(&mut self, path: &ast::Path, kind: MacroKind, scope: Mar
         Ok((def, self.get_macro(def)))
     }
 
-    pub fn resolve_macro_to_def_inner(&mut self, path: &ast::Path, kind: MacroKind, scope: Mark,
+    pub fn resolve_macro_to_def_inner(&mut self, path: &ast::Path, kind: MacroKind, invoc_id: Mark,
                                       derives_in_scope: &[ast::Path], force: bool)
                                       -> Result<Def, Determinacy> {
         let ast::Path { ref segments, span } = *path;
         let mut path: Vec<_> = segments.iter().map(|seg| seg.ident).collect();
-        let invocation = self.invocations[&scope];
+        let invocation = self.invocations[&invoc_id];
         let module = invocation.module.get();
         self.current_module = if module.is_trait() { module.parent.unwrap() } else { module };
 
@@ -448,8 +448,8 @@ pub fn resolve_macro_to_def_inner(&mut self, path: &ast::Path, kind: MacroKind,
         }
 
         if path.len() > 1 {
-            let res = self.resolve_path(None, &path, Some(MacroNS), false, span, CrateLint::No);
-            let def = match res {
+            let def = match self.resolve_path_with_invoc_id(None, &path, Some(MacroNS), invoc_id,
+                                                            false, span, CrateLint::No) {
                 PathResult::NonModule(path_res) => match path_res.base_def() {
                     Def::Err => Err(Determinacy::Determined),
                     def @ _ => {
@@ -480,11 +480,12 @@ pub fn resolve_macro_to_def_inner(&mut self, path: &ast::Path, kind: MacroKind,
             }
         }
 
-        let legacy_resolution = self.resolve_legacy_scope(&invocation.legacy_scope, path[0], false);
+        let legacy_resolution =
+            self.resolve_legacy_scope(path[0], invoc_id, &invocation.legacy_scope, false);
         let result = if let Some(legacy_binding) = legacy_resolution {
             Ok(legacy_binding.def())
         } else {
-            match self.resolve_lexical_macro_path_segment(path[0], MacroNS, false, force,
+            match self.resolve_lexical_macro_path_segment(path[0], MacroNS, invoc_id, false, force,
                                                           kind == MacroKind::Attr, span) {
                 Ok((binding, _)) => Ok(binding.def_ignoring_ambiguity()),
                 Err(Determinacy::Undetermined) => return Err(Determinacy::Undetermined),
@@ -496,7 +497,7 @@ pub fn resolve_macro_to_def_inner(&mut self, path: &ast::Path, kind: MacroKind,
         };
 
         self.current_module.nearest_item_scope().legacy_macro_resolutions.borrow_mut()
-            .push((scope, path[0], kind, result.ok()));
+            .push((invoc_id, path[0], kind, result.ok()));
 
         if let Ok(Def::NonMacroAttr(NonMacroAttrKind::Custom)) = result {} else {
             return result;
@@ -515,7 +516,7 @@ pub fn resolve_macro_to_def_inner(&mut self, path: &ast::Path, kind: MacroKind,
         enum ConvertToDeriveHelper { Yes, No, DontKnow }
         let mut convert_to_derive_helper = ConvertToDeriveHelper::No;
         for derive in derives_in_scope {
-            match self.resolve_macro_path(derive, MacroKind::Derive, scope, &[], force) {
+            match self.resolve_macro_path(derive, MacroKind::Derive, invoc_id, &[], force) {
                 Ok(ext) => if let SyntaxExtension::ProcMacroDerive(_, ref inert_attrs, _) = *ext {
                     if inert_attrs.contains(&path[0].name) {
                         convert_to_derive_helper = ConvertToDeriveHelper::Yes;
@@ -543,10 +544,11 @@ enum ConvertToDeriveHelper { Yes, No, DontKnow }
         &mut self,
         mut ident: Ident,
         ns: Namespace,
+        invoc_id: Mark,
         record_used: bool,
         force: bool,
         is_attr: bool,
-        path_span: Span
+        path_span: Span,
     ) -> Result<(&'a NameBinding<'a>, FromPrelude), Determinacy> {
         // General principles:
         // 1. Not controlled (user-defined) names should have higher priority than controlled names
@@ -737,7 +739,7 @@ macro_rules! continue_search { () => {
                         // Found another solution, if the first one was "weak", report an error.
                         if result.0.def() != innermost_result.0.def() &&
                            (innermost_result.0.is_glob_import() ||
-                            innermost_result.0.expansion != Mark::root()) {
+                            innermost_result.0.may_appear_after(invoc_id, result.0)) {
                             self.ambiguity_errors.push(AmbiguityError {
                                 span: path_span,
                                 name: ident.name,
@@ -781,8 +783,9 @@ macro_rules! continue_search { () => {
     }
 
     fn resolve_legacy_scope(&mut self,
-                            invocation_legacy_scope: &'a Cell<LegacyScope<'a>>,
                             ident: Ident,
+                            invoc_id: Mark,
+                            invoc_parent_legacy_scope: &'a Cell<LegacyScope<'a>>,
                             record_used: bool)
                             -> Option<&'a NameBinding<'a>> {
         let ident = ident.modern();
@@ -801,7 +804,7 @@ fn resolve_legacy_scope(&mut self,
         let mut innermost_result: Option<&NameBinding> = None;
 
         // Go through all the scopes and try to resolve the name.
-        let mut where_to_resolve = invocation_legacy_scope;
+        let mut where_to_resolve = invoc_parent_legacy_scope;
         loop {
             let result = match where_to_resolve.get() {
                 LegacyScope::Binding(legacy_binding) if ident == legacy_binding.ident =>
@@ -837,7 +840,7 @@ macro_rules! continue_search { () => {
                     if let Some(innermost_result) = innermost_result {
                         // Found another solution, if the first one was "weak", report an error.
                         if result.def() != innermost_result.def() &&
-                           innermost_result.expansion != Mark::root() {
+                           innermost_result.may_appear_after(invoc_id, result) {
                             self.ambiguity_errors.push(AmbiguityError {
                                 span: ident.span,
                                 name: ident.name,
@@ -875,12 +878,13 @@ pub fn finalize_current_module_macro_resolutions(&mut self) {
             }
         }
 
-        for &(mark, ident, kind, def) in module.legacy_macro_resolutions.borrow().iter() {
+        for &(invoc_id, ident, kind, def) in module.legacy_macro_resolutions.borrow().iter() {
             let span = ident.span;
-            let legacy_scope = &self.invocations[&mark].legacy_scope;
-            let legacy_resolution = self.resolve_legacy_scope(legacy_scope, ident, true);
-            let resolution = self.resolve_lexical_macro_path_segment(ident, MacroNS, true, true,
-                                                                     kind == MacroKind::Attr, span);
+            let legacy_scope = &self.invocations[&invoc_id].legacy_scope;
+            let legacy_resolution = self.resolve_legacy_scope(ident, invoc_id, legacy_scope, true);
+            let resolution = self.resolve_lexical_macro_path_segment(
+                ident, MacroNS, invoc_id, true, true, kind == MacroKind::Attr, span
+            );
 
             let check_consistency = |this: &Self, new_def: Def| {
                 if let Some(def) = def {
@@ -913,7 +917,7 @@ pub fn finalize_current_module_macro_resolutions(&mut self) {
                     err.emit();
                 },
                 (Some(legacy_binding), Ok((binding, FromPrelude(from_prelude))))
-                        if !from_prelude || legacy_binding.expansion != Mark::root() => {
+                        if !from_prelude || legacy_binding.may_appear_after(invoc_id, binding) => {
                     if legacy_binding.def_ignoring_ambiguity() != binding.def_ignoring_ambiguity() {
                         self.report_ambiguity_error(ident.name, span, legacy_binding, binding);
                     }
index 7e985cf52f550d1aa1f8c95cd5ba9fbdd0dad2b6..f053cb10d0649b893c41a014434097444d6bdff6 100644 (file)
@@ -100,6 +100,11 @@ pub fn from_u32(raw: u32) -> Mark {
         Mark(raw)
     }
 
+    #[inline]
+    pub fn parent(self) -> Mark {
+        HygieneData::with(|data| data.marks[self.0 as usize].parent)
+    }
+
     #[inline]
     pub fn expn_info(self) -> Option<ExpnInfo> {
         HygieneData::with(|data| data.marks[self.0 as usize].expn_info.clone())