// except according to those terms.
use {AmbiguityError, AmbiguityKind, AmbiguityErrorMisc};
-use {CrateLint, Resolver, ResolutionError, is_known_tool, resolve_error};
+use {CrateLint, DeterminacyExt, Resolver, ResolutionError, is_known_tool, resolve_error};
use {Module, ModuleKind, NameBinding, NameBindingKind, PathResult, ToNameBinding};
use ModuleOrUniformRoot;
use Namespace::{self, *};
crate parent_legacy_scope: Cell<LegacyScope<'a>>,
/// Legacy scope *produced* by expanding this macro invocation,
/// includes all the macro_rules items, other invocations, etc generated by it.
- /// Set to the parent scope if the macro is not expanded yet (as if the macro produced nothing).
- crate output_legacy_scope: Cell<LegacyScope<'a>>,
+ /// `None` if the macro is not expanded yet.
+ crate output_legacy_scope: Cell<Option<LegacyScope<'a>>>,
}
impl<'a> InvocationData<'a> {
module: Cell::new(graph_root),
def_index: CRATE_DEF_INDEX,
parent_legacy_scope: Cell::new(LegacyScope::Empty),
- output_legacy_scope: Cell::new(LegacyScope::Empty),
+ output_legacy_scope: Cell::new(Some(LegacyScope::Empty)),
}
}
}
// Macro namespace is separated into two sub-namespaces, one for bang macros and
// one for attribute-like macros (attributes, derives).
// We ignore resolutions from one sub-namespace when searching names in scope for another.
-fn sub_namespace_mismatch(requirement: Option<MacroKind>, candidate: Option<MacroKind>) -> bool {
+fn sub_namespace_match(candidate: Option<MacroKind>, requirement: Option<MacroKind>) -> bool {
#[derive(PartialEq)]
enum SubNS { Bang, AttrLike }
let sub_ns = |kind| match kind {
let requirement = requirement.and_then(|kind| sub_ns(kind));
let candidate = candidate.and_then(|kind| sub_ns(kind));
// "No specific sub-namespace" means "matches anything" for both requirements and candidates.
- candidate.is_some() && requirement.is_some() && candidate != requirement
+ candidate.is_none() || requirement.is_none() || candidate == requirement
}
impl<'a, 'crateloader: 'a> base::Resolver for Resolver<'a, 'crateloader> {
module: Cell::new(module),
def_index: module.def_id().unwrap().index,
parent_legacy_scope: Cell::new(LegacyScope::Empty),
- output_legacy_scope: Cell::new(LegacyScope::Empty),
+ output_legacy_scope: Cell::new(Some(LegacyScope::Empty)),
}));
mark
}
expansion: mark,
};
fragment.visit_with(&mut visitor);
- invocation.output_legacy_scope.set(visitor.current_legacy_scope);
+ invocation.output_legacy_scope.set(Some(visitor.current_legacy_scope));
}
fn add_builtin(&mut self, ident: ast::Ident, ext: Lrc<SyntaxExtension>) {
let mut innermost_result: Option<(&NameBinding, Flags)> = None;
// Go through all the scopes and try to resolve the name.
- let mut where_to_resolve = WhereToResolve::DeriveHelpers;
+ let mut where_to_resolve = if ns == MacroNS {
+ WhereToResolve::DeriveHelpers
+ } else {
+ WhereToResolve::Module(parent_scope.module)
+ };
let mut use_prelude = !parent_scope.module.no_implicit_prelude;
+ let mut determinacy = Determinacy::Determined;
loop {
let result = match where_to_resolve {
WhereToResolve::DeriveHelpers => {
let mut result = Err(Determinacy::Determined);
for derive in &parent_scope.derives {
let parent_scope = ParentScope { derives: Vec::new(), ..*parent_scope };
- if let Ok((_, ext)) = self.resolve_macro_to_def(derive, MacroKind::Derive,
- &parent_scope, force) {
- if let SyntaxExtension::ProcMacroDerive(_, helper_attrs, _) = &*ext {
- if helper_attrs.contains(&ident.name) {
- let binding =
- (Def::NonMacroAttr(NonMacroAttrKind::DeriveHelper),
- ty::Visibility::Public, derive.span, Mark::root())
- .to_name_binding(self.arenas);
- result = Ok((binding, Flags::empty()));
- break;
+ match self.resolve_macro_to_def(derive, MacroKind::Derive,
+ &parent_scope, force) {
+ Ok((_, ext)) => {
+ if let SyntaxExtension::ProcMacroDerive(_, helpers, _) = &*ext {
+ if helpers.contains(&ident.name) {
+ let binding =
+ (Def::NonMacroAttr(NonMacroAttrKind::DeriveHelper),
+ ty::Visibility::Public, derive.span, Mark::root())
+ .to_name_binding(self.arenas);
+ result = Ok((binding, Flags::empty()));
+ break;
+ }
}
}
+ Err(Determinacy::Determined) => {}
+ Err(Determinacy::Undetermined) =>
+ result = Err(Determinacy::Undetermined),
}
}
result
WhereToResolve::MacroRules(legacy_scope) => match legacy_scope {
LegacyScope::Binding(legacy_binding) if ident == legacy_binding.ident =>
Ok((legacy_binding.binding, Flags::MACRO_RULES)),
+ LegacyScope::Invocation(invoc) if invoc.output_legacy_scope.get().is_none() =>
+ Err(Determinacy::Undetermined),
_ => Err(Determinacy::Determined),
}
WhereToResolve::Module(module) => {
let orig_current_module = mem::replace(&mut self.current_module, module);
- let binding = self.resolve_ident_in_module_unadjusted(
+ let binding = self.resolve_ident_in_module_unadjusted_ext(
ModuleOrUniformRoot::Module(module),
ident,
ns,
path_span,
);
self.current_module = orig_current_module;
- let misc_flags = if module.is_normal() {
- Flags::MISC_SUGGEST_SELF
- } else {
- Flags::empty()
- };
- binding.map(|binding| (binding, Flags::MODULE | misc_flags))
+ match binding {
+ Ok(binding) => {
+ let misc_flags = if module.is_normal() {
+ Flags::MISC_SUGGEST_SELF
+ } else {
+ Flags::empty()
+ };
+ Ok((binding, Flags::MODULE | misc_flags))
+ }
+ Err(DeterminacyExt::Undetermined) =>
+ return Err(Determinacy::determined(force)),
+ Err(DeterminacyExt::WeakUndetermined) => Err(Determinacy::Undetermined),
+ Err(DeterminacyExt::Determined) => Err(Determinacy::Determined),
+ }
}
WhereToResolve::MacroUsePrelude => {
- let mut result = Err(Determinacy::Determined);
if use_prelude || self.session.rust_2015() {
- if let Some(binding) = self.macro_use_prelude.get(&ident.name).cloned() {
- result = Ok((binding, Flags::PRELUDE | Flags::MISC_FROM_PRELUDE));
+ match self.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()
+ ))
}
+ } else {
+ Err(Determinacy::Determined)
}
- result
}
WhereToResolve::BuiltinMacros => {
match self.builtin_macros.get(&ident.name).cloned() {
}
}
WhereToResolve::ExternPrelude => {
- let mut result = Err(Determinacy::Determined);
if use_prelude {
- if let Some(binding) = self.extern_prelude_get(ident, !record_used,
- innermost_result.is_some()) {
- result = Ok((binding, Flags::PRELUDE));
+ match self.extern_prelude_get(ident, !record_used,
+ innermost_result.is_some()) {
+ Some(binding) => Ok((binding, Flags::PRELUDE)),
+ None => Err(Determinacy::determined(
+ self.graph_root.unresolved_invocations.borrow().is_empty()
+ )),
}
+ } else {
+ Err(Determinacy::Determined)
}
- result
}
WhereToResolve::ToolPrelude => {
if use_prelude && is_known_tool(ident.name) {
ident,
ns,
false,
- false,
path_span,
) {
result = Ok((binding, Flags::PRELUDE | Flags::MISC_FROM_PRELUDE));
}
};
- macro_rules! continue_search { () => {
- where_to_resolve = match where_to_resolve {
- WhereToResolve::DeriveHelpers =>
- WhereToResolve::MacroRules(parent_scope.legacy),
- WhereToResolve::MacroRules(legacy_scope) => match legacy_scope {
- LegacyScope::Binding(binding) =>
- WhereToResolve::MacroRules(binding.parent_legacy_scope),
- LegacyScope::Invocation(invocation) =>
- WhereToResolve::MacroRules(invocation.output_legacy_scope.get()),
- LegacyScope::Empty => WhereToResolve::Module(parent_scope.module),
- LegacyScope::Uninitialized => unreachable!(),
- }
- WhereToResolve::Module(module) => {
- match self.hygienic_lexical_parent(module, &mut ident.span) {
- Some(parent_module) => WhereToResolve::Module(parent_module),
- None => {
- use_prelude = !module.no_implicit_prelude;
- match ns {
- TypeNS => WhereToResolve::ExternPrelude,
- ValueNS => WhereToResolve::StdLibPrelude,
- MacroNS => WhereToResolve::MacroUsePrelude,
- }
- }
- }
- }
- WhereToResolve::MacroUsePrelude => WhereToResolve::BuiltinMacros,
- WhereToResolve::BuiltinMacros => WhereToResolve::BuiltinAttrs,
- WhereToResolve::BuiltinAttrs => WhereToResolve::LegacyPluginHelpers,
- WhereToResolve::LegacyPluginHelpers => break, // nowhere else to search
- WhereToResolve::ExternPrelude => WhereToResolve::ToolPrelude,
- WhereToResolve::ToolPrelude => WhereToResolve::StdLibPrelude,
- WhereToResolve::StdLibPrelude => match ns {
- TypeNS => WhereToResolve::BuiltinTypes,
- ValueNS => break, // nowhere else to search
- MacroNS => unreachable!(),
- }
- WhereToResolve::BuiltinTypes => break, // nowhere else to search
- };
-
- continue;
- }}
-
match result {
- Ok((binding, flags)) => {
- if sub_namespace_mismatch(macro_kind, binding.macro_kind()) {
- continue_search!();
- }
-
+ Ok((binding, flags)) if sub_namespace_match(binding.macro_kind(), macro_kind) => {
if !record_used {
return Ok(binding);
}
// Found the first solution.
innermost_result = Some((binding, flags));
}
-
- continue_search!();
- },
- Err(Determinacy::Determined) => {
- continue_search!();
}
- Err(Determinacy::Undetermined) => return Err(Determinacy::determined(force)),
+ Ok(..) | Err(Determinacy::Determined) => {}
+ Err(Determinacy::Undetermined) => determinacy = Determinacy::Undetermined
}
+
+ where_to_resolve = match where_to_resolve {
+ WhereToResolve::DeriveHelpers =>
+ WhereToResolve::MacroRules(parent_scope.legacy),
+ WhereToResolve::MacroRules(legacy_scope) => match legacy_scope {
+ LegacyScope::Binding(binding) => WhereToResolve::MacroRules(
+ binding.parent_legacy_scope
+ ),
+ LegacyScope::Invocation(invoc) => WhereToResolve::MacroRules(
+ invoc.output_legacy_scope.get().unwrap_or(invoc.parent_legacy_scope.get())
+ ),
+ LegacyScope::Empty => WhereToResolve::Module(parent_scope.module),
+ LegacyScope::Uninitialized => unreachable!(),
+ }
+ WhereToResolve::Module(module) => {
+ match self.hygienic_lexical_parent(module, &mut ident.span) {
+ Some(parent_module) => WhereToResolve::Module(parent_module),
+ None => {
+ use_prelude = !module.no_implicit_prelude;
+ match ns {
+ TypeNS => WhereToResolve::ExternPrelude,
+ ValueNS => WhereToResolve::StdLibPrelude,
+ MacroNS => WhereToResolve::MacroUsePrelude,
+ }
+ }
+ }
+ }
+ WhereToResolve::MacroUsePrelude => WhereToResolve::BuiltinMacros,
+ WhereToResolve::BuiltinMacros => WhereToResolve::BuiltinAttrs,
+ WhereToResolve::BuiltinAttrs => WhereToResolve::LegacyPluginHelpers,
+ WhereToResolve::LegacyPluginHelpers => break, // nowhere else to search
+ WhereToResolve::ExternPrelude => WhereToResolve::ToolPrelude,
+ WhereToResolve::ToolPrelude => WhereToResolve::StdLibPrelude,
+ WhereToResolve::StdLibPrelude => match ns {
+ TypeNS => WhereToResolve::BuiltinTypes,
+ ValueNS => break, // nowhere else to search
+ MacroNS => unreachable!(),
+ }
+ WhereToResolve::BuiltinTypes => break, // nowhere else to search
+ };
+
+ continue;
}
// The first found solution was the only one, return it.
return Ok(binding);
}
- let determinacy = Determinacy::determined(force);
+ let determinacy = Determinacy::determined(determinacy == Determinacy::Determined || force);
if determinacy == Determinacy::Determined && macro_kind == Some(MacroKind::Attr) {
// For single-segment attributes interpret determinate "no resolution" as a custom
// attribute. (Lexical resolution implies the first segment and attr kind should imply
def_index: invoc.def_index,
module: Cell::new(graph_root),
parent_legacy_scope: Cell::new(LegacyScope::Uninitialized),
- output_legacy_scope: Cell::new(LegacyScope::Uninitialized),
+ output_legacy_scope: Cell::new(None),
})
});
};
use self::ImportDirectiveSubclass::*;
use {AmbiguityError, AmbiguityKind, AmbiguityErrorMisc};
-use {CrateLint, Module, ModuleOrUniformRoot, PerNS};
+use {CrateLint, DeterminacyExt, Module, ModuleOrUniformRoot, PerNS};
use Namespace::{self, TypeNS, MacroNS};
use {NameBinding, NameBindingKind, ToNameBinding, PathResult, PrivacyError};
use {Resolver, Segment};
.or_insert_with(|| self.arenas.alloc_name_resolution())
}
+ crate fn resolve_ident_in_module_unadjusted(
+ &mut self,
+ module: ModuleOrUniformRoot<'a>,
+ ident: Ident,
+ ns: Namespace,
+ record_used: bool,
+ path_span: Span,
+ ) -> Result<&'a NameBinding<'a>, Determinacy> {
+ self.resolve_ident_in_module_unadjusted_ext(
+ module, ident, ns, false, record_used, path_span
+ ).map_err(|determinacy_ext| match determinacy_ext {
+ DeterminacyExt::Determined => Determined,
+ DeterminacyExt::Undetermined | DeterminacyExt::WeakUndetermined => Undetermined,
+ })
+ }
+
/// Attempts to resolve `ident` in namespaces `ns` of `module`.
/// Invariant: if `record_used` is `Some`, expansion and import resolution must be complete.
- pub fn resolve_ident_in_module_unadjusted(&mut self,
- module: ModuleOrUniformRoot<'a>,
- ident: Ident,
- ns: Namespace,
- restricted_shadowing: bool,
- record_used: bool,
- path_span: Span)
- -> Result<&'a NameBinding<'a>, Determinacy> {
+ crate fn resolve_ident_in_module_unadjusted_ext(
+ &mut self,
+ module: ModuleOrUniformRoot<'a>,
+ ident: Ident,
+ ns: Namespace,
+ restricted_shadowing: bool,
+ record_used: bool,
+ path_span: Span,
+ ) -> Result<&'a NameBinding<'a>, DeterminacyExt> {
let module = match module {
ModuleOrUniformRoot::Module(module) => module,
ModuleOrUniformRoot::UniformRoot(root) => {
let mut ctxt = ident.span.ctxt().modern();
let self_module = self.resolve_self(&mut ctxt, self.current_module);
- let binding = self.resolve_ident_in_module_unadjusted(
+ let binding = self.resolve_ident_in_module_unadjusted_ext(
ModuleOrUniformRoot::Module(self_module),
ident,
ns,
return Ok(binding);
} else if !self.graph_root.unresolved_invocations.borrow().is_empty() {
// Macro-expanded `extern crate`items still can add names to extern prelude.
- return Err(Undetermined);
+ return Err(DeterminacyExt::Undetermined);
} else {
- return Err(Determined);
+ return Err(DeterminacyExt::Determined);
}
} else {
- return Err(Determined);
+ return Err(DeterminacyExt::Determined);
};
self.populate_module_if_necessary(crate_root);
let binding = (crate_root, ty::Visibility::Public,
let resolution = self.resolution(module, ident, ns)
.try_borrow_mut()
- .map_err(|_| Determined)?; // This happens when there is a cycle of imports
+ // This happens when there is a cycle of imports.
+ .map_err(|_| DeterminacyExt::Determined)?;
if let Some(binding) = resolution.binding {
if !restricted_shadowing && binding.expansion != Mark::root() {
}
}
- return resolution.binding.ok_or(Determined);
+ return resolution.binding.ok_or(DeterminacyExt::Determined);
}
let check_usable = |this: &mut Self, binding: &'a NameBinding<'a>| {
// `extern crate` are always usable for backwards compatibility, see issue #37020.
let usable = this.is_accessible(binding.vis) || binding.is_extern_crate();
- if usable { Ok(binding) } else { Err(Determined) }
+ if usable { Ok(binding) } else { Err(DeterminacyExt::Determined) }
};
// Items and single imports are not shadowable, if we have one, then it's determined.
if !self.is_accessible(single_import.vis.get()) {
continue;
}
- let module = unwrap_or!(single_import.imported_module.get(), return Err(Undetermined));
+ let module = unwrap_or!(single_import.imported_module.get(),
+ return Err(DeterminacyExt::Undetermined));
let ident = match single_import.subclass {
SingleImport { source, .. } => source,
_ => unreachable!(),
Ok(binding) if !self.is_accessible_from(
binding.vis, single_import.parent_scope.module
) => continue,
- Ok(_) | Err(Undetermined) => return Err(Undetermined),
+ Ok(_) | Err(Undetermined) => return Err(DeterminacyExt::Undetermined),
}
}
if !unexpanded_macros || ns == MacroNS || restricted_shadowing {
return check_usable(self, binding);
} else {
- return Err(Undetermined);
+ return Err(DeterminacyExt::Undetermined);
}
}
// Now we are in situation when new item/import can appear only from a glob or a macro
// expansion. With restricted shadowing names from globs and macro expansions cannot
// shadow names from outer scopes, so we can freely fallback from module search to search
- // in outer scopes. To continue search in outer scopes we have to lie a bit and return
- // `Determined` to `early_resolve_ident_in_lexical_scope` even if the correct answer
- // for in-module resolution could be `Undetermined`.
- if restricted_shadowing {
- return Err(Determined);
- }
+ // in outer scopes. For `early_resolve_ident_in_lexical_scope` to continue search in outer
+ // scopes we return `WeakUndetermined` instead of full `Undetermined`.
// Check if one of unexpanded macros can still define the name,
// if it can then our "no resolution" result is not determined and can be invalidated.
if unexpanded_macros {
- return Err(Undetermined);
+ return Err(DeterminacyExt::WeakUndetermined);
}
// Check if one of glob imports can still define the name,
let module = match glob_import.imported_module.get() {
Some(ModuleOrUniformRoot::Module(module)) => module,
Some(ModuleOrUniformRoot::UniformRoot(_)) => continue,
- None => return Err(Undetermined),
+ None => return Err(DeterminacyExt::WeakUndetermined),
};
let (orig_current_module, mut ident) = (self.current_module, ident.modern());
match ident.span.glob_adjust(module.expansion, glob_import.span.ctxt().modern()) {
ident,
ns,
false,
- false,
path_span,
);
self.current_module = orig_current_module;
Ok(binding) if !self.is_accessible_from(
binding.vis, glob_import.parent_scope.module
) => continue,
- Ok(_) | Err(Undetermined) => return Err(Undetermined),
+ Ok(_) | Err(Undetermined) => return Err(DeterminacyExt::WeakUndetermined),
}
}
// No resolution and no one else can define the name - determinate error.
- Err(Determined)
+ Err(DeterminacyExt::Determined)
}
// Add an import directive to the current module.