diff options
| author | Vadim Petrochenkov <vadim.petrochenkov@gmail.com> | 2018-09-02 04:57:56 +0300 |
|---|---|---|
| committer | Vadim Petrochenkov <vadim.petrochenkov@gmail.com> | 2018-09-11 00:30:44 +0300 |
| commit | 730c5de2815f310ee4e71dd48af101c10e46d747 (patch) | |
| tree | bb0003d21981010ddbb0235eaf69c11c6a6746ab | |
| parent | 551244f05b92f90fe327f8f0a6d9a6e674eaab1b (diff) | |
| download | rust-730c5de2815f310ee4e71dd48af101c10e46d747.tar.gz rust-730c5de2815f310ee4e71dd48af101c10e46d747.zip | |
resolve: Support resolving identifier macros without their own ID
Invocation/expansion ID (aka `Mark`) is not really necessary for resolving a macro path. What is really necessary is its parent module, parent expansion and parent legacy scope. This is required for validation resolutions of built-in attributes, which don't get their own `Mark`s
| -rw-r--r-- | src/librustc_resolve/lib.rs | 23 | ||||
| -rw-r--r-- | src/librustc_resolve/macros.rs | 63 | ||||
| -rw-r--r-- | src/libsyntax/ext/base.rs | 9 |
3 files changed, 48 insertions, 47 deletions
diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index bfdf158bbbb..2bf110d2723 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -81,7 +81,7 @@ use std::mem::replace; use rustc_data_structures::sync::Lrc; use resolve_imports::{ImportDirective, ImportDirectiveSubclass, NameResolution, ImportResolver}; -use macros::{InvocationData, LegacyBinding}; +use macros::{InvocationData, LegacyBinding, LegacyScope}; // NB: This module needs to be declared first so diagnostics are // registered before they are used. @@ -1010,7 +1010,7 @@ pub struct ModuleData<'a> { normal_ancestor_id: DefId, resolutions: RefCell<FxHashMap<(Ident, Namespace), &'a RefCell<NameResolution<'a>>>>, - legacy_macro_resolutions: RefCell<Vec<(Mark, Ident, MacroKind, Option<Def>)>>, + legacy_macro_resolutions: RefCell<Vec<(Ident, MacroKind, Mark, LegacyScope<'a>, Option<Def>)>>, macro_resolutions: RefCell<Vec<(Box<[Ident]>, Span)>>, // Macro invocations that can expand into items in this module. @@ -1276,19 +1276,18 @@ impl<'a> NameBinding<'a> { 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. + // Suppose that we resolved macro invocation with `invoc_parent_expansion` to binding `binding` + // at some expansion round `max(invoc, 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. // See more detailed explanation in // https://github.com/rust-lang/rust/pull/53778#issuecomment-419224049 - fn may_appear_after(&self, invoc_id: Mark, binding: &NameBinding) -> bool { - // self > max(invoc_id, binding) => !(self <= invoc_id || self <= binding) + fn may_appear_after(&self, invoc_parent_expansion: Mark, binding: &NameBinding) -> bool { + // self > max(invoc, binding) => !(self <= invoc || self <= binding) // Expansions are partially ordered, so "may appear after" is an inversion of // "certainly appears before or simultaneously" and includes unordered cases. let self_parent_expansion = self.expansion; let other_parent_expansion = binding.expansion; - let invoc_parent_expansion = invoc_id.parent(); let certainly_before_other_or_simultaneously = other_parent_expansion.is_descendant_of(self_parent_expansion); let certainly_before_invoc_or_simultaneously = @@ -3493,16 +3492,16 @@ impl<'a, 'crateloader: 'a> Resolver<'a, 'crateloader> { 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) + self.resolve_path_with_parent_expansion(base_module, path, opt_ns, Mark::root(), + record_used, path_span, crate_lint) } - fn resolve_path_with_invoc_id( + fn resolve_path_with_parent_expansion( &mut self, base_module: Option<ModuleOrUniformRoot<'a>>, path: &[Ident], opt_ns: Option<Namespace>, // `None` indicates a module path - invoc_id: Mark, + parent_expansion: Mark, record_used: bool, path_span: Span, crate_lint: CrateLint, @@ -3595,7 +3594,7 @@ impl<'a, 'crateloader: 'a> Resolver<'a, 'crateloader> { 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, invoc_id, record_used, + self.resolve_lexical_macro_path_segment(ident, ns, parent_expansion, record_used, record_used, false, path_span) .map(|(binding, _)| binding) } else { diff --git a/src/librustc_resolve/macros.rs b/src/librustc_resolve/macros.rs index fe0cb523a15..920d8a6341b 100644 --- a/src/librustc_resolve/macros.rs +++ b/src/librustc_resolve/macros.rs @@ -313,7 +313,7 @@ impl<'a, 'crateloader: 'a> base::Resolver for Resolver<'a, 'crateloader> { None } - fn resolve_macro_invocation(&mut self, invoc: &Invocation, scope: Mark, force: bool) + fn resolve_macro_invocation(&mut self, invoc: &Invocation, invoc_id: Mark, force: bool) -> Result<Option<Lrc<SyntaxExtension>>, Determinacy> { let (path, kind, derives_in_scope) = match invoc.kind { InvocationKind::Attr { attr: None, .. } => @@ -326,7 +326,7 @@ impl<'a, 'crateloader: 'a> base::Resolver for Resolver<'a, 'crateloader> { (path, MacroKind::Derive, &[][..]), }; - let (def, ext) = self.resolve_macro_to_def(path, kind, scope, derives_in_scope, force)?; + let (def, ext) = self.resolve_macro_to_def(path, kind, invoc_id, derives_in_scope, force)?; if let Def::Macro(def_id, _) = def { self.macro_defs.insert(invoc.expansion_data.mark, def_id); @@ -341,10 +341,10 @@ impl<'a, 'crateloader: 'a> base::Resolver for Resolver<'a, 'crateloader> { Ok(Some(ext)) } - fn resolve_macro_path(&mut self, path: &ast::Path, kind: MacroKind, scope: Mark, + fn resolve_macro_path(&mut self, path: &ast::Path, kind: MacroKind, invoc_id: Mark, derives_in_scope: &[ast::Path], force: bool) -> Result<Lrc<SyntaxExtension>, Determinacy> { - Ok(self.resolve_macro_to_def(path, kind, scope, derives_in_scope, force)?.1) + Ok(self.resolve_macro_to_def(path, kind, invoc_id, derives_in_scope, force)?.1) } fn check_unused_macros(&self) { @@ -366,10 +366,10 @@ impl<'a, 'crateloader: 'a> base::Resolver for Resolver<'a, 'crateloader> { } impl<'a, 'cl> Resolver<'a, 'cl> { - fn resolve_macro_to_def(&mut self, path: &ast::Path, kind: MacroKind, scope: Mark, + fn resolve_macro_to_def(&mut self, path: &ast::Path, kind: MacroKind, invoc_id: Mark, derives_in_scope: &[ast::Path], force: bool) -> Result<(Def, Lrc<SyntaxExtension>), Determinacy> { - let def = self.resolve_macro_to_def_inner(path, kind, scope, derives_in_scope, force); + let def = self.resolve_macro_to_def_inner(path, kind, invoc_id, derives_in_scope, force); // Report errors and enforce feature gates for the resolved macro. if def != Err(Determinacy::Undetermined) { @@ -439,8 +439,9 @@ impl<'a, 'cl> Resolver<'a, 'cl> { let ast::Path { ref segments, span } = *path; let mut path: Vec<_> = segments.iter().map(|seg| seg.ident).collect(); let invocation = self.invocations[&invoc_id]; - let module = invocation.module.get(); - self.current_module = if module.is_trait() { module.parent.unwrap() } else { module }; + let parent_expansion = invoc_id.parent(); + let parent_legacy_scope = invocation.parent_legacy_scope.get(); + self.current_module = invocation.module.get().nearest_item_scope(); // Possibly apply the macro helper hack if kind == MacroKind::Bang && path.len() == 1 && @@ -450,8 +451,9 @@ impl<'a, 'cl> Resolver<'a, 'cl> { } if path.len() > 1 { - let def = match self.resolve_path_with_invoc_id(None, &path, Some(MacroNS), invoc_id, - false, span, CrateLint::No) { + let def = match self.resolve_path_with_parent_expansion(None, &path, Some(MacroNS), + parent_expansion, false, span, + CrateLint::No) { PathResult::NonModule(path_res) => match path_res.base_def() { Def::Err => Err(Determinacy::Determined), def @ _ => { @@ -471,19 +473,19 @@ impl<'a, 'cl> Resolver<'a, 'cl> { Err(Determinacy::Determined) }, }; - self.current_module.nearest_item_scope().macro_resolutions.borrow_mut() + self.current_module.macro_resolutions.borrow_mut() .push((path.into_boxed_slice(), span)); return def; } let legacy_resolution = self.resolve_legacy_scope( - path[0], invoc_id, invocation.parent_legacy_scope.get(), false, kind == MacroKind::Attr + path[0], parent_expansion, parent_legacy_scope, false, kind == MacroKind::Attr ); let result = if let Some(legacy_binding) = legacy_resolution { Ok(legacy_binding.def()) } else { - match self.resolve_lexical_macro_path_segment(path[0], MacroNS, invoc_id, false, force, - kind == MacroKind::Attr, span) { + match self.resolve_lexical_macro_path_segment(path[0], MacroNS, parent_expansion, false, + force, kind == MacroKind::Attr, span) { Ok((binding, _)) => Ok(binding.def_ignoring_ambiguity()), Err(Determinacy::Undetermined) => return Err(Determinacy::Undetermined), Err(Determinacy::Determined) => { @@ -493,8 +495,8 @@ impl<'a, 'cl> Resolver<'a, 'cl> { } }; - self.current_module.nearest_item_scope().legacy_macro_resolutions.borrow_mut() - .push((invoc_id, path[0], kind, result.ok())); + self.current_module.legacy_macro_resolutions.borrow_mut() + .push((path[0], kind, parent_expansion, parent_legacy_scope, result.ok())); if let Ok(Def::NonMacroAttr(NonMacroAttrKind::Custom)) = result {} else { return result; @@ -541,7 +543,7 @@ impl<'a, 'cl> Resolver<'a, 'cl> { &mut self, mut ident: Ident, ns: Namespace, - invoc_id: Mark, + parent_expansion: Mark, record_used: bool, force: bool, is_attr: bool, @@ -754,7 +756,7 @@ impl<'a, 'cl> Resolver<'a, 'cl> { // 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.may_appear_after(invoc_id, result.0)) { + innermost_result.0.may_appear_after(parent_expansion, result.0)) { self.ambiguity_errors.push(AmbiguityError { ident, b1: innermost_result.0, @@ -798,8 +800,8 @@ impl<'a, 'cl> Resolver<'a, 'cl> { fn resolve_legacy_scope(&mut self, ident: Ident, - invoc_id: Mark, - invoc_parent_legacy_scope: LegacyScope<'a>, + parent_expansion: Mark, + parent_legacy_scope: LegacyScope<'a>, record_used: bool, is_attr: bool) -> Option<&'a NameBinding<'a>> { @@ -826,7 +828,7 @@ impl<'a, 'cl> Resolver<'a, 'cl> { let mut innermost_result: Option<&NameBinding> = None; // Go through all the scopes and try to resolve the name. - let mut where_to_resolve = invoc_parent_legacy_scope; + let mut where_to_resolve = parent_legacy_scope; loop { let result = match where_to_resolve { LegacyScope::Binding(legacy_binding) if ident == legacy_binding.ident => @@ -854,7 +856,7 @@ impl<'a, 'cl> Resolver<'a, 'cl> { 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.may_appear_after(invoc_id, result) { + innermost_result.may_appear_after(parent_expansion, result) { self.ambiguity_errors.push(AmbiguityError { ident, b1: innermost_result, @@ -891,14 +893,14 @@ impl<'a, 'cl> Resolver<'a, 'cl> { } } - for &(invoc_id, ident, kind, def) in module.legacy_macro_resolutions.borrow().iter() { + for &(ident, kind, parent_expansion, parent_legacy_scope, def) + in module.legacy_macro_resolutions.borrow().iter() { let span = ident.span; - let invocation = self.invocations[&invoc_id]; let legacy_resolution = self.resolve_legacy_scope( - ident, invoc_id, invocation.parent_legacy_scope.get(), true, kind == MacroKind::Attr + ident, parent_expansion, parent_legacy_scope, true, kind == MacroKind::Attr ); let resolution = self.resolve_lexical_macro_path_segment( - ident, MacroNS, invoc_id, true, true, kind == MacroKind::Attr, span + ident, MacroNS, parent_expansion, true, true, kind == MacroKind::Attr, span ); let check_consistency = |this: &Self, new_def: Def| { @@ -932,12 +934,13 @@ impl<'a, 'cl> Resolver<'a, 'cl> { err.emit(); }, (Some(legacy_binding), Ok((binding, FromPrelude(from_prelude)))) - 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, legacy_binding, binding); - } + if legacy_binding.def() != binding.def_ignoring_ambiguity() && + (!from_prelude || + legacy_binding.may_appear_after(parent_expansion, binding)) => { + self.report_ambiguity_error(ident, legacy_binding, binding); }, // OK, non-macro-expanded legacy wins over prelude even if defs are different + // Also, legacy and modern can co-exist if their defs are same (Some(legacy_binding), Ok(_)) | // OK, unambiguous resolution (Some(legacy_binding), Err(_)) => { diff --git a/src/libsyntax/ext/base.rs b/src/libsyntax/ext/base.rs index 1ea71009766..07c3e578e5b 100644 --- a/src/libsyntax/ext/base.rs +++ b/src/libsyntax/ext/base.rs @@ -727,10 +727,9 @@ pub trait Resolver { fn find_legacy_attr_invoc(&mut self, attrs: &mut Vec<Attribute>, allow_derive: bool) -> Option<Attribute>; - fn resolve_macro_invocation(&mut self, invoc: &Invocation, scope: Mark, force: bool) + fn resolve_macro_invocation(&mut self, invoc: &Invocation, invoc_id: Mark, force: bool) -> Result<Option<Lrc<SyntaxExtension>>, Determinacy>; - - fn resolve_macro_path(&mut self, path: &ast::Path, kind: MacroKind, scope: Mark, + fn resolve_macro_path(&mut self, path: &ast::Path, kind: MacroKind, invoc_id: Mark, derives_in_scope: &[ast::Path], force: bool) -> Result<Lrc<SyntaxExtension>, Determinacy>; @@ -764,11 +763,11 @@ impl Resolver for DummyResolver { fn resolve_imports(&mut self) {} fn find_legacy_attr_invoc(&mut self, _attrs: &mut Vec<Attribute>, _allow_derive: bool) -> Option<Attribute> { None } - fn resolve_macro_invocation(&mut self, _invoc: &Invocation, _scope: Mark, _force: bool) + fn resolve_macro_invocation(&mut self, _invoc: &Invocation, _invoc_id: Mark, _force: bool) -> Result<Option<Lrc<SyntaxExtension>>, Determinacy> { Err(Determinacy::Determined) } - fn resolve_macro_path(&mut self, _path: &ast::Path, _kind: MacroKind, _scope: Mark, + fn resolve_macro_path(&mut self, _path: &ast::Path, _kind: MacroKind, _invoc_id: Mark, _derives_in_scope: &[ast::Path], _force: bool) -> Result<Lrc<SyntaxExtension>, Determinacy> { Err(Determinacy::Determined) |
