/// A specific scope in which a name can be looked up.
/// This enum is currently used only for early resolution (imports and macros),
/// but not for late resolution yet.
+#[derive(Clone, Copy)]
enum Scope<'a> {
DeriveHelpers,
MacroRules(LegacyScope<'a>),
}
}
+ /// A generic scope visitor.
+ /// Visits scopes in order to resolve some identifier in them or perform other actions.
+ /// If the callback returns `Some` result, we stop visiting scopes and return it.
+ fn visit_scopes<T>(
+ &mut self,
+ scope_set: ScopeSet,
+ parent_scope: &ParentScope<'a>,
+ mut ident: Ident,
+ mut visitor: impl FnMut(&mut Self, Scope<'a>, Ident) -> Option<T>,
+ ) -> Option<T> {
+ // General principles:
+ // 1. Not controlled (user-defined) names should have higher priority than controlled names
+ // built into the language or standard library. This way we can add new names into the
+ // language or standard library without breaking user code.
+ // 2. "Closed set" below means new names cannot appear after the current resolution attempt.
+ // Places to search (in order of decreasing priority):
+ // (Type NS)
+ // 1. FIXME: Ribs (type parameters), there's no necessary infrastructure yet
+ // (open set, not controlled).
+ // 2. Names in modules (both normal `mod`ules and blocks), loop through hygienic parents
+ // (open, not controlled).
+ // 3. Extern prelude (open, the open part is from macro expansions, not controlled).
+ // 4. Tool modules (closed, controlled right now, but not in the future).
+ // 5. Standard library prelude (de-facto closed, controlled).
+ // 6. Language prelude (closed, controlled).
+ // (Value NS)
+ // 1. FIXME: Ribs (local variables), there's no necessary infrastructure yet
+ // (open set, not controlled).
+ // 2. Names in modules (both normal `mod`ules and blocks), loop through hygienic parents
+ // (open, not controlled).
+ // 3. Standard library prelude (de-facto closed, controlled).
+ // (Macro NS)
+ // 1-3. Derive helpers (open, not controlled). All ambiguities with other names
+ // are currently reported as errors. They should be higher in priority than preludes
+ // and probably even names in modules according to the "general principles" above. They
+ // also should be subject to restricted shadowing because are effectively produced by
+ // derives (you need to resolve the derive first to add helpers into scope), but they
+ // should be available before the derive is expanded for compatibility.
+ // It's mess in general, so we are being conservative for now.
+ // 1-3. `macro_rules` (open, not controlled), loop through legacy scopes. Have higher
+ // priority than prelude macros, but create ambiguities with macros in modules.
+ // 1-3. Names in modules (both normal `mod`ules and blocks), loop through hygienic parents
+ // (open, not controlled). Have higher priority than prelude macros, but create
+ // ambiguities with `macro_rules`.
+ // 4. `macro_use` prelude (open, the open part is from macro expansions, not controlled).
+ // 4a. User-defined prelude from macro-use
+ // (open, the open part is from macro expansions, not controlled).
+ // 4b. Standard library prelude is currently implemented as `macro-use` (closed, controlled)
+ // 5. Language prelude: builtin macros (closed, controlled, except for legacy plugins).
+ // 6. Language prelude: builtin attributes (closed, controlled).
+ // 4-6. Legacy plugin helpers (open, not controlled). Similar to derive helpers,
+ // but introduced by legacy plugins using `register_attribute`. Priority is somewhere
+ // in prelude, not sure where exactly (creates ambiguities with any other prelude names).
+
+ let (ns, is_absolute_path) = match scope_set {
+ ScopeSet::Import(ns) => (ns, false),
+ ScopeSet::AbsolutePath(ns) => (ns, true),
+ ScopeSet::Macro(_) => (MacroNS, false),
+ ScopeSet::Module => (TypeNS, false),
+ };
+ let mut scope = match ns {
+ _ if is_absolute_path => Scope::CrateRoot,
+ TypeNS | ValueNS => Scope::Module(parent_scope.module),
+ MacroNS => Scope::DeriveHelpers,
+ };
+
+ loop {
+ if let break_result @ Some(..) = visitor(self, scope, ident) {
+ return break_result;
+ }
+
+ scope = match scope {
+ Scope::DeriveHelpers =>
+ Scope::MacroRules(parent_scope.legacy),
+ Scope::MacroRules(legacy_scope) => match legacy_scope {
+ LegacyScope::Binding(binding) => Scope::MacroRules(
+ binding.parent_legacy_scope
+ ),
+ LegacyScope::Invocation(invoc) => Scope::MacroRules(
+ invoc.output_legacy_scope.get().unwrap_or(invoc.parent_legacy_scope)
+ ),
+ LegacyScope::Empty => Scope::Module(parent_scope.module),
+ }
+ Scope::CrateRoot => match ns {
+ TypeNS => {
+ ident.span.adjust(Mark::root());
+ Scope::ExternPrelude
+ }
+ ValueNS | MacroNS => break,
+ }
+ Scope::Module(module) => {
+ match self.hygienic_lexical_parent(module, &mut ident.span) {
+ Some(parent_module) => Scope::Module(parent_module),
+ None => {
+ ident.span.adjust(Mark::root());
+ match ns {
+ TypeNS => Scope::ExternPrelude,
+ ValueNS => Scope::StdLibPrelude,
+ MacroNS => Scope::MacroUsePrelude,
+ }
+ }
+ }
+ }
+ Scope::MacroUsePrelude => Scope::StdLibPrelude,
+ Scope::BuiltinMacros => Scope::BuiltinAttrs,
+ Scope::BuiltinAttrs => Scope::LegacyPluginHelpers,
+ Scope::LegacyPluginHelpers => break, // nowhere else to search
+ Scope::ExternPrelude if is_absolute_path => break,
+ Scope::ExternPrelude => Scope::ToolPrelude,
+ Scope::ToolPrelude => Scope::StdLibPrelude,
+ Scope::StdLibPrelude => match ns {
+ TypeNS => Scope::BuiltinTypes,
+ ValueNS => break, // nowhere else to search
+ MacroNS => Scope::BuiltinMacros,
+ }
+ Scope::BuiltinTypes => break, // nowhere else to search
+ };
+ }
+
+ None
+ }
+
/// This resolves the identifier `ident` in the namespace `ns` in the current lexical scope.
/// More specifically, we proceed up the hierarchy of scopes and return the binding for
/// `ident` in the first scope that defines it (or None if no scopes define it).
pub struct LegacyBinding<'a> {
binding: &'a NameBinding<'a>,
/// Legacy scope into which the `macro_rules` item was planted.
- parent_legacy_scope: LegacyScope<'a>,
+ crate parent_legacy_scope: LegacyScope<'a>,
ident: Ident,
}
force: bool,
path_span: Span,
) -> Result<&'a NameBinding<'a>, Determinacy> {
- // General principles:
- // 1. Not controlled (user-defined) names should have higher priority than controlled names
- // built into the language or standard library. This way we can add new names into the
- // language or standard library without breaking user code.
- // 2. "Closed set" below means new names cannot appear after the current resolution attempt.
- // Places to search (in order of decreasing priority):
- // (Type NS)
- // 1. FIXME: Ribs (type parameters), there's no necessary infrastructure yet
- // (open set, not controlled).
- // 2. Names in modules (both normal `mod`ules and blocks), loop through hygienic parents
- // (open, not controlled).
- // 3. Extern prelude (closed, not controlled).
- // 4. Tool modules (closed, controlled right now, but not in the future).
- // 5. Standard library prelude (de-facto closed, controlled).
- // 6. Language prelude (closed, controlled).
- // (Value NS)
- // 1. FIXME: Ribs (local variables), there's no necessary infrastructure yet
- // (open set, not controlled).
- // 2. Names in modules (both normal `mod`ules and blocks), loop through hygienic parents
- // (open, not controlled).
- // 3. Standard library prelude (de-facto closed, controlled).
- // (Macro NS)
- // 1-3. Derive helpers (open, not controlled). All ambiguities with other names
- // are currently reported as errors. They should be higher in priority than preludes
- // and probably even names in modules according to the "general principles" above. They
- // also should be subject to restricted shadowing because are effectively produced by
- // derives (you need to resolve the derive first to add helpers into scope), but they
- // should be available before the derive is expanded for compatibility.
- // It's mess in general, so we are being conservative for now.
- // 1-3. `macro_rules` (open, not controlled), loop through legacy scopes. Have higher
- // priority than prelude macros, but create ambiguities with macros in modules.
- // 1-3. Names in modules (both normal `mod`ules and blocks), loop through hygienic parents
- // (open, not controlled). Have higher priority than prelude macros, but create
- // ambiguities with `macro_rules`.
- // 4. `macro_use` prelude (open, the open part is from macro expansions, not controlled).
- // 4a. User-defined prelude from macro-use
- // (open, the open part is from macro expansions, not controlled).
- // 4b. Standard library prelude is currently implemented as `macro-use` (closed, controlled)
- // 5. Language prelude: builtin macros (closed, controlled, except for legacy plugins).
- // 6. Language prelude: builtin attributes (closed, controlled).
- // 4-6. Legacy plugin helpers (open, not controlled). Similar to derive helpers,
- // but introduced by legacy plugins using `register_attribute`. Priority is somewhere
- // in prelude, not sure where exactly (creates ambiguities with any other prelude names).
-
bitflags::bitflags! {
struct Flags: u8 {
const MACRO_RULES = 1 << 0;
}
assert!(force || !record_used); // `record_used` implies `force`
- let mut ident = orig_ident.modern();
+ let ident = orig_ident.modern();
// Make sure `self`, `super` etc produce an error when passed to here.
if ident.is_path_segment_keyword() {
return Err(Determinacy::Determined);
}
+ let rust_2015 = orig_ident.span.rust_2015();
+ let (ns, macro_kind, is_import, is_absolute_path) = match scope_set {
+ ScopeSet::Import(ns) => (ns, None, true, false),
+ ScopeSet::AbsolutePath(ns) => (ns, None, false, true),
+ ScopeSet::Macro(macro_kind) => (MacroNS, Some(macro_kind), false, false),
+ ScopeSet::Module => (TypeNS, None, false, false),
+ };
+
// This is *the* result, resolution from the scope closest to the resolved identifier.
// However, sometimes this result is "weak" because it comes from a glob import or
// a macro expansion, and in this case it cannot shadow names from outer scopes, e.g.
// So we have to save the innermost solution and continue searching in outer scopes
// to detect potential ambiguities.
let mut innermost_result: Option<(&NameBinding<'_>, Flags)> = None;
-
- // Go through all the scopes and try to resolve the name.
- let rust_2015 = orig_ident.span.rust_2015();
- let (ns, macro_kind, is_import, is_absolute_path) = match scope_set {
- ScopeSet::Import(ns) => (ns, None, true, false),
- ScopeSet::AbsolutePath(ns) => (ns, None, false, true),
- ScopeSet::Macro(macro_kind) => (MacroNS, Some(macro_kind), false, false),
- ScopeSet::Module => (TypeNS, None, false, false),
- };
- let mut where_to_resolve = match ns {
- _ if is_absolute_path => Scope::CrateRoot,
- TypeNS | ValueNS => Scope::Module(parent_scope.module),
- MacroNS => Scope::DeriveHelpers,
- };
let mut use_prelude = !parent_scope.module.no_implicit_prelude;
let mut determinacy = Determinacy::Determined;
- loop {
- let result = match where_to_resolve {
+
+ // Go through all the scopes and try to resolve the name.
+ let break_result = self.visit_scopes(scope_set, parent_scope, ident, |this, scope, ident| {
+ let result = match scope {
Scope::DeriveHelpers => {
let mut result = Err(Determinacy::Determined);
for derive in &parent_scope.derives {
let parent_scope = ParentScope { derives: Vec::new(), ..*parent_scope };
- match self.resolve_macro_path(derive, MacroKind::Derive,
+ match this.resolve_macro_path(derive, MacroKind::Derive,
&parent_scope, true, force) {
Ok((Some(ext), _)) => if ext.helper_attrs.contains(&ident.name) {
let binding = (Res::NonMacroAttr(NonMacroAttrKind::DeriveHelper),
ty::Visibility::Public, derive.span, Mark::root())
- .to_name_binding(self.arenas);
+ .to_name_binding(this.arenas);
result = Ok((binding, Flags::empty()));
break;
}
}
Scope::CrateRoot => {
let root_ident = Ident::new(kw::PathRoot, orig_ident.span);
- let root_module = self.resolve_crate_root(root_ident);
- let binding = self.resolve_ident_in_module_ext(
+ let root_module = this.resolve_crate_root(root_ident);
+ let binding = this.resolve_ident_in_module_ext(
ModuleOrUniformRoot::Module(root_module),
orig_ident,
ns,
match binding {
Ok(binding) => Ok((binding, Flags::MODULE | Flags::MISC_SUGGEST_CRATE)),
Err((Determinacy::Undetermined, Weak::No)) =>
- return Err(Determinacy::determined(force)),
+ return Some(Err(Determinacy::determined(force))),
Err((Determinacy::Undetermined, Weak::Yes)) =>
Err(Determinacy::Undetermined),
Err((Determinacy::Determined, _)) => Err(Determinacy::Determined),
}
}
Scope::Module(module) => {
- let orig_current_module = mem::replace(&mut self.current_module, module);
- let binding = self.resolve_ident_in_module_unadjusted_ext(
+ use_prelude = !module.no_implicit_prelude;
+ let orig_current_module = mem::replace(&mut this.current_module, module);
+ let binding = this.resolve_ident_in_module_unadjusted_ext(
ModuleOrUniformRoot::Module(module),
ident,
ns,
record_used,
path_span,
);
- self.current_module = orig_current_module;
+ this.current_module = orig_current_module;
match binding {
Ok(binding) => {
- let misc_flags = if ptr::eq(module, self.graph_root) {
+ let misc_flags = if ptr::eq(module, this.graph_root) {
Flags::MISC_SUGGEST_CRATE
} else if module.is_normal() {
Flags::MISC_SUGGEST_SELF
Ok((binding, Flags::MODULE | misc_flags))
}
Err((Determinacy::Undetermined, Weak::No)) =>
- return Err(Determinacy::determined(force)),
+ return Some(Err(Determinacy::determined(force))),
Err((Determinacy::Undetermined, Weak::Yes)) =>
Err(Determinacy::Undetermined),
Err((Determinacy::Determined, _)) => Err(Determinacy::Determined),
}
Scope::MacroUsePrelude => {
if use_prelude || rust_2015 {
- match self.macro_use_prelude.get(&ident.name).cloned() {
+ match this.macro_use_prelude.get(&ident.name).cloned() {
Some(binding) =>
Ok((binding, Flags::PRELUDE | Flags::MISC_FROM_PRELUDE)),
None => Err(Determinacy::determined(
- self.graph_root.unresolved_invocations.borrow().is_empty()
+ this.graph_root.unresolved_invocations.borrow().is_empty()
))
}
} else {
}
}
Scope::BuiltinMacros => {
- match self.builtin_macros.get(&ident.name).cloned() {
+ match this.builtin_macros.get(&ident.name).cloned() {
Some(binding) => Ok((binding, Flags::PRELUDE)),
None => Err(Determinacy::Determined),
}
if is_builtin_attr_name(ident.name) {
let binding = (Res::NonMacroAttr(NonMacroAttrKind::Builtin),
ty::Visibility::Public, DUMMY_SP, Mark::root())
- .to_name_binding(self.arenas);
+ .to_name_binding(this.arenas);
Ok((binding, Flags::PRELUDE))
} else {
Err(Determinacy::Determined)
}
Scope::LegacyPluginHelpers => {
if (use_prelude || rust_2015) &&
- self.session.plugin_attributes.borrow().iter()
+ this.session.plugin_attributes.borrow().iter()
.any(|(name, _)| ident.name == *name) {
let binding = (Res::NonMacroAttr(NonMacroAttrKind::LegacyPluginHelper),
ty::Visibility::Public, DUMMY_SP, Mark::root())
- .to_name_binding(self.arenas);
+ .to_name_binding(this.arenas);
Ok((binding, Flags::PRELUDE))
} else {
Err(Determinacy::Determined)
}
Scope::ExternPrelude => {
if use_prelude || is_absolute_path {
- match self.extern_prelude_get(ident, !record_used) {
+ match this.extern_prelude_get(ident, !record_used) {
Some(binding) => Ok((binding, Flags::PRELUDE)),
None => Err(Determinacy::determined(
- self.graph_root.unresolved_invocations.borrow().is_empty()
+ this.graph_root.unresolved_invocations.borrow().is_empty()
)),
}
} else {
Scope::ToolPrelude => {
if use_prelude && is_known_tool(ident.name) {
let binding = (Res::ToolMod, ty::Visibility::Public,
- DUMMY_SP, Mark::root()).to_name_binding(self.arenas);
+ DUMMY_SP, Mark::root()).to_name_binding(this.arenas);
Ok((binding, Flags::PRELUDE))
} else {
Err(Determinacy::Determined)
Scope::StdLibPrelude => {
let mut result = Err(Determinacy::Determined);
if use_prelude {
- if let Some(prelude) = self.prelude {
- if let Ok(binding) = self.resolve_ident_in_module_unadjusted(
+ if let Some(prelude) = this.prelude {
+ if let Ok(binding) = this.resolve_ident_in_module_unadjusted(
ModuleOrUniformRoot::Module(prelude),
ident,
ns,
result
}
Scope::BuiltinTypes => {
- match self.primitive_type_table.primitive_types.get(&ident.name).cloned() {
+ match this.primitive_type_table.primitive_types.get(&ident.name).cloned() {
Some(prim_ty) => {
let binding = (Res::PrimTy(prim_ty), ty::Visibility::Public,
- DUMMY_SP, Mark::root()).to_name_binding(self.arenas);
+ DUMMY_SP, Mark::root()).to_name_binding(this.arenas);
Ok((binding, Flags::PRELUDE))
}
None => Err(Determinacy::Determined)
match result {
Ok((binding, flags)) if sub_namespace_match(binding.macro_kind(), macro_kind) => {
if !record_used {
- return Ok(binding);
+ return Some(Ok(binding));
}
if let Some((innermost_binding, innermost_flags)) = innermost_result {
Some(AmbiguityKind::LegacyHelperVsPrelude)
} else if innermost_flags.contains(Flags::MACRO_RULES) &&
flags.contains(Flags::MODULE) &&
- !self.disambiguate_legacy_vs_modern(innermost_binding,
+ !this.disambiguate_legacy_vs_modern(innermost_binding,
binding) ||
flags.contains(Flags::MACRO_RULES) &&
innermost_flags.contains(Flags::MODULE) &&
- !self.disambiguate_legacy_vs_modern(binding,
+ !this.disambiguate_legacy_vs_modern(binding,
innermost_binding) {
Some(AmbiguityKind::LegacyVsModern)
} else if innermost_binding.is_glob_import() {
} else {
AmbiguityErrorMisc::None
};
- self.ambiguity_errors.push(AmbiguityError {
+ this.ambiguity_errors.push(AmbiguityError {
kind,
ident: orig_ident,
b1: innermost_binding,
misc1: misc(innermost_flags),
misc2: misc(flags),
});
- return Ok(innermost_binding);
+ return Some(Ok(innermost_binding));
}
}
} else {
Err(Determinacy::Undetermined) => determinacy = Determinacy::Undetermined
}
- where_to_resolve = match where_to_resolve {
- Scope::DeriveHelpers =>
- Scope::MacroRules(parent_scope.legacy),
- Scope::MacroRules(legacy_scope) => match legacy_scope {
- LegacyScope::Binding(binding) => Scope::MacroRules(
- binding.parent_legacy_scope
- ),
- LegacyScope::Invocation(invoc) => Scope::MacroRules(
- invoc.output_legacy_scope.get().unwrap_or(invoc.parent_legacy_scope)
- ),
- LegacyScope::Empty => Scope::Module(parent_scope.module),
- }
- Scope::CrateRoot => match ns {
- TypeNS => {
- ident.span.adjust(Mark::root());
- Scope::ExternPrelude
- }
- ValueNS | MacroNS => break,
- }
- Scope::Module(module) => {
- match self.hygienic_lexical_parent(module, &mut ident.span) {
- Some(parent_module) => Scope::Module(parent_module),
- None => {
- ident.span.adjust(Mark::root());
- use_prelude = !module.no_implicit_prelude;
- match ns {
- TypeNS => Scope::ExternPrelude,
- ValueNS => Scope::StdLibPrelude,
- MacroNS => Scope::MacroUsePrelude,
- }
- }
- }
- }
- Scope::MacroUsePrelude => Scope::StdLibPrelude,
- Scope::BuiltinMacros => Scope::BuiltinAttrs,
- Scope::BuiltinAttrs => Scope::LegacyPluginHelpers,
- Scope::LegacyPluginHelpers => break, // nowhere else to search
- Scope::ExternPrelude if is_absolute_path => break,
- Scope::ExternPrelude => Scope::ToolPrelude,
- Scope::ToolPrelude => Scope::StdLibPrelude,
- Scope::StdLibPrelude => match ns {
- TypeNS => Scope::BuiltinTypes,
- ValueNS => break, // nowhere else to search
- MacroNS => Scope::BuiltinMacros,
- }
- Scope::BuiltinTypes => break, // nowhere else to search
- };
+ None
+ });
- continue;
+ if let Some(break_result) = break_result {
+ return break_result;
}
// The first found solution was the only one, return it.