// option. This file may not be copied, modified, or distributed
// except according to those terms.
-use self::Determinacy::*;
use self::ImportDirectiveSubclass::*;
-use Module;
-use Namespace::{self, TypeNS, ValueNS};
-use {NameBinding, NameBindingKind, PrivacyError, ToNameBinding};
-use ResolveResult;
-use ResolveResult::*;
+use {AmbiguityError, Module, PerNS};
+use Namespace::{self, TypeNS, MacroNS};
+use {NameBinding, NameBindingKind, PathResult, PrivacyError};
use Resolver;
-use UseLexicalScopeFlag::DontUseLexicalScope;
use {names_to_string, module_to_string};
use {resolve_error, ResolutionError};
use rustc::ty;
use rustc::lint::builtin::PRIVATE_IN_PUBLIC;
+use rustc::hir::def_id::DefId;
use rustc::hir::def::*;
+use rustc::util::nodemap::FxHashSet;
-use syntax::ast::{NodeId, Name};
+use syntax::ast::{Ident, NodeId};
+use syntax::ext::base::Determinacy::{self, Determined, Undetermined};
+use syntax::ext::hygiene::Mark;
+use syntax::parse::token;
+use syntax::symbol::keywords;
use syntax::util::lev_distance::find_best_match_for_name;
use syntax_pos::Span;
use std::cell::{Cell, RefCell};
-
-impl<'a> Resolver<'a> {
- pub fn resolve_imports(&mut self) {
- ImportResolver { resolver: self }.resolve_imports();
- }
-}
-
-#[derive(Copy, Clone, Debug)]
-pub enum Determinacy {
- Determined,
- Undetermined,
-}
+use std::mem;
/// Contains data for specific types of import directives.
#[derive(Clone, Debug)]
pub enum ImportDirectiveSubclass<'a> {
SingleImport {
- target: Name,
- source: Name,
- value_result: Cell<Result<&'a NameBinding<'a>, Determinacy>>,
- type_result: Cell<Result<&'a NameBinding<'a>, Determinacy>>,
+ target: Ident,
+ source: Ident,
+ result: PerNS<Cell<Result<&'a NameBinding<'a>, Determinacy>>>,
+ type_ns_only: bool,
},
GlobImport {
is_prelude: bool,
max_vis: Cell<ty::Visibility>, // The visibility of the greatest reexport.
// n.b. `max_vis` is only used in `finalize_import` to check for reexport errors.
},
-}
-
-impl<'a> ImportDirectiveSubclass<'a> {
- pub fn single(target: Name, source: Name) -> Self {
- SingleImport {
- target: target,
- source: source,
- type_result: Cell::new(Err(Undetermined)),
- value_result: Cell::new(Err(Undetermined)),
- }
- }
+ ExternCrate,
+ MacroUse,
}
/// One import directive.
#[derive(Debug,Clone)]
pub struct ImportDirective<'a> {
pub id: NodeId,
- parent: Module<'a>,
- module_path: Vec<Name>,
- imported_module: Cell<Option<Module<'a>>>, // the resolution of `module_path`
- subclass: ImportDirectiveSubclass<'a>,
- span: Span,
- vis: Cell<ty::Visibility>,
+ pub parent: Module<'a>,
+ pub module_path: Vec<Ident>,
+ pub imported_module: Cell<Option<Module<'a>>>, // the resolution of `module_path`
+ pub subclass: ImportDirectiveSubclass<'a>,
+ pub span: Span,
+ pub vis: Cell<ty::Visibility>,
+ pub expansion: Mark,
+ pub used: Cell<bool>,
}
impl<'a> ImportDirective<'a> {
single_imports: SingleImports<'a>,
/// The least shadowable known binding for this name, or None if there are no known bindings.
pub binding: Option<&'a NameBinding<'a>>,
- duplicate_globs: Vec<&'a NameBinding<'a>>,
+ shadows_glob: Option<&'a NameBinding<'a>>,
}
#[derive(Clone, Debug)]
}
impl<'a> Resolver<'a> {
- fn resolution(&self, module: Module<'a>, name: Name, ns: Namespace)
+ fn resolution(&self, module: Module<'a>, ident: Ident, ns: Namespace)
-> &'a RefCell<NameResolution<'a>> {
- *module.resolutions.borrow_mut().entry((name, ns))
+ let ident = ident.unhygienize();
+ *module.resolutions.borrow_mut().entry((ident, ns))
.or_insert_with(|| self.arenas.alloc_name_resolution())
}
- /// Attempts to resolve the supplied name in the given module for the given namespace.
- /// If successful, returns the binding corresponding to the name.
+ /// Attempts to resolve `ident` in namespaces `ns` of `module`.
/// Invariant: if `record_used` is `Some`, import resolution must be complete.
- pub fn resolve_name_in_module(&mut self,
- module: Module<'a>,
- name: Name,
- ns: Namespace,
- allow_private_imports: bool,
- record_used: Option<Span>)
- -> ResolveResult<&'a NameBinding<'a>> {
+ pub fn resolve_ident_in_module(&mut self,
+ module: Module<'a>,
+ ident: Ident,
+ ns: Namespace,
+ ignore_unresolved_invocations: bool,
+ record_used: Option<Span>)
+ -> Result<&'a NameBinding<'a>, Determinacy> {
self.populate_module_if_necessary(module);
- let resolution = self.resolution(module, name, ns);
- let resolution = match resolution.borrow_state() {
- ::std::cell::BorrowState::Unused => resolution.borrow_mut(),
- _ => return Failed(None), // This happens when there is a cycle of imports
- };
-
- let new_import_semantics = self.new_import_semantics;
- let is_disallowed_private_import = |binding: &NameBinding| {
- !new_import_semantics && !allow_private_imports && // disallowed
- binding.vis != ty::Visibility::Public && binding.is_import() // non-`pub` import
- };
+ let resolution = self.resolution(module, ident, ns)
+ .try_borrow_mut()
+ .map_err(|_| Determined)?; // This happens when there is a cycle of imports
if let Some(span) = record_used {
if let Some(binding) = resolution.binding {
- if is_disallowed_private_import(binding) {
- return Failed(None);
+ if let Some(shadowed_glob) = resolution.shadows_glob {
+ let name = ident.name;
+ // If we ignore unresolved invocations, we must forbid
+ // expanded shadowing to avoid time travel.
+ if ignore_unresolved_invocations &&
+ binding.expansion != Mark::root() &&
+ ns != MacroNS && // In MacroNS, `try_define` always forbids this shadowing
+ binding.def() != shadowed_glob.def() {
+ self.ambiguity_errors.push(AmbiguityError {
+ span: span, name: name, lexical: false, b1: binding, b2: shadowed_glob,
+ legacy: false,
+ });
+ }
}
- if self.record_use(name, ns, binding, span) {
- return Success(self.dummy_binding);
+ if self.record_use(ident, ns, binding, span) {
+ return Ok(self.dummy_binding);
}
if !self.is_accessible(binding.vis) {
- self.privacy_errors.push(PrivacyError(span, name, binding));
+ self.privacy_errors.push(PrivacyError(span, ident.name, binding));
}
}
- return resolution.binding.map(Success).unwrap_or(Failed(None));
+ return resolution.binding.ok_or(Determined);
}
- // If the resolution doesn't depend on glob definability, check privacy and return.
- if let Some(result) = self.try_result(&resolution, ns) {
- return result.and_then(|binding| {
- if self.is_accessible(binding.vis) && !is_disallowed_private_import(binding) ||
- binding.is_extern_crate() { // c.f. issue #37020
- Success(binding)
- } else {
- Failed(None)
- }
- });
- }
+ let check_usable = |this: &mut Self, binding: &'a NameBinding<'a>| {
+ // `extern crate` are always usable for backwards compatability, see issue #37020.
+ let usable = this.is_accessible(binding.vis) || binding.is_extern_crate();
+ if usable { Ok(binding) } else { Err(Determined) }
+ };
- // Check if the globs are determined
- for directive in module.globs.borrow().iter() {
- if self.is_accessible(directive.vis.get()) {
- if let Some(module) = directive.imported_module.get() {
- let result = self.resolve_name_in_module(module, name, ns, true, None);
- if let Indeterminate = result {
- return Indeterminate;
- }
- } else {
- return Indeterminate;
- }
+ // Items and single imports are not shadowable.
+ if let Some(binding) = resolution.binding {
+ if !binding.is_glob_import() {
+ return check_usable(self, binding);
}
}
- Failed(None)
- }
-
- // Returns Some(the resolution of the name), or None if the resolution depends
- // on whether more globs can define the name.
- fn try_result(&mut self, resolution: &NameResolution<'a>, ns: Namespace)
- -> Option<ResolveResult<&'a NameBinding<'a>>> {
- match resolution.binding {
- Some(binding) if !binding.is_glob_import() =>
- return Some(Success(binding)), // Items and single imports are not shadowable.
- _ => {}
- };
-
// Check if a single import can still define the name.
match resolution.single_imports {
- SingleImports::AtLeastOne => return Some(Indeterminate),
+ SingleImports::AtLeastOne => return Err(Undetermined),
SingleImports::MaybeOne(directive) if self.is_accessible(directive.vis.get()) => {
let module = match directive.imported_module.get() {
Some(module) => module,
- None => return Some(Indeterminate),
+ None => return Err(Undetermined),
};
- let name = match directive.subclass {
+ let ident = match directive.subclass {
SingleImport { source, .. } => source,
- GlobImport { .. } => unreachable!(),
+ _ => unreachable!(),
};
- match self.resolve_name_in_module(module, name, ns, true, None) {
- Failed(_) => {}
- _ => return Some(Indeterminate),
+ match self.resolve_ident_in_module(module, ident, ns, false, None) {
+ Err(Determined) => {}
+ _ => return Err(Undetermined),
}
}
SingleImports::MaybeOne(_) | SingleImports::None => {},
}
- resolution.binding.map(Success)
+ let no_unresolved_invocations =
+ ignore_unresolved_invocations || module.unresolved_invocations.borrow().is_empty();
+ match resolution.binding {
+ // In `MacroNS`, expanded bindings do not shadow (enforced in `try_define`).
+ Some(binding) if no_unresolved_invocations || ns == MacroNS =>
+ return check_usable(self, binding),
+ None if no_unresolved_invocations => {}
+ _ => return Err(Undetermined),
+ }
+
+ // Check if the globs are determined
+ for directive in module.globs.borrow().iter() {
+ if self.is_accessible(directive.vis.get()) {
+ if let Some(module) = directive.imported_module.get() {
+ let result = self.resolve_ident_in_module(module, ident, ns, false, None);
+ if let Err(Undetermined) = result {
+ return Err(Undetermined);
+ }
+ } else {
+ return Err(Undetermined);
+ }
+ }
+ }
+
+ Err(Determined)
}
// Add an import directive to the current module.
pub fn add_import_directive(&mut self,
- module_path: Vec<Name>,
+ module_path: Vec<Ident>,
subclass: ImportDirectiveSubclass<'a>,
span: Span,
id: NodeId,
- vis: ty::Visibility) {
+ vis: ty::Visibility,
+ expansion: Mark) {
let current_module = self.current_module;
let directive = self.arenas.alloc_import_directive(ImportDirective {
parent: current_module,
span: span,
id: id,
vis: Cell::new(vis),
+ expansion: expansion,
+ used: Cell::new(false),
});
self.indeterminate_imports.push(directive);
match directive.subclass {
SingleImport { target, .. } => {
- for &ns in &[ValueNS, TypeNS] {
- let mut resolution = self.resolution(current_module, target, ns).borrow_mut();
+ self.per_ns(|this, ns| {
+ let mut resolution = this.resolution(current_module, target, ns).borrow_mut();
resolution.single_imports.add_directive(directive);
- }
+ });
}
// We don't add prelude imports to the globs since they only affect lexical scopes,
// which are not relevant to import resolution.
GlobImport { is_prelude: true, .. } => {}
GlobImport { .. } => self.current_module.globs.borrow_mut().push(directive),
+ _ => unreachable!(),
}
}
// Given a binding and an import directive that resolves to it,
// return the corresponding binding defined by the import directive.
- fn import(&mut self, binding: &'a NameBinding<'a>, directive: &'a ImportDirective<'a>)
- -> NameBinding<'a> {
+ pub fn import(&self, binding: &'a NameBinding<'a>, directive: &'a ImportDirective<'a>)
+ -> &'a NameBinding<'a> {
let vis = if binding.pseudo_vis().is_at_least(directive.vis.get(), self) ||
!directive.is_glob() && binding.is_extern_crate() { // c.f. `PRIVATE_IN_PUBLIC`
directive.vis.get()
}
}
- NameBinding {
+ self.arenas.alloc_name_binding(NameBinding {
kind: NameBindingKind::Import {
binding: binding,
directive: directive,
used: Cell::new(false),
+ legacy_self_import: false,
},
span: directive.span,
vis: vis,
- }
+ expansion: directive.expansion,
+ })
}
// Define the name or return the existing binding if there is a collision.
- pub fn try_define<T>(&mut self, module: Module<'a>, name: Name, ns: Namespace, binding: T)
- -> Result<(), &'a NameBinding<'a>>
- where T: ToNameBinding<'a>
- {
- let binding = self.arenas.alloc_name_binding(binding.to_name_binding());
- self.update_resolution(module, name, ns, |this, resolution| {
+ pub fn try_define(&mut self,
+ module: Module<'a>,
+ ident: Ident,
+ ns: Namespace,
+ binding: &'a NameBinding<'a>)
+ -> Result<(), &'a NameBinding<'a>> {
+ self.update_resolution(module, ident, ns, |this, resolution| {
if let Some(old_binding) = resolution.binding {
if binding.is_glob_import() {
- if !this.new_import_semantics || !old_binding.is_glob_import() {
- resolution.duplicate_globs.push(binding);
+ if !old_binding.is_glob_import() &&
+ !(ns == MacroNS && old_binding.expansion != Mark::root()) {
+ resolution.shadows_glob = Some(binding);
} else if binding.def() != old_binding.def() {
- resolution.binding = Some(this.arenas.alloc_name_binding(NameBinding {
- kind: NameBindingKind::Ambiguity {
- b1: old_binding,
- b2: binding,
- },
- vis: if old_binding.vis.is_at_least(binding.vis, this) {
- old_binding.vis
- } else {
- binding.vis
- },
- span: old_binding.span,
- }));
- } else if !old_binding.vis.is_at_least(binding.vis, this) {
+ resolution.binding = Some(this.ambiguity(old_binding, binding));
+ } else if !old_binding.vis.is_at_least(binding.vis, &*this) {
// We are glob-importing the same item but with greater visibility.
resolution.binding = Some(binding);
}
} else if old_binding.is_glob_import() {
- resolution.duplicate_globs.push(old_binding);
- resolution.binding = Some(binding);
+ if ns == MacroNS && binding.expansion != Mark::root() &&
+ binding.def() != old_binding.def() {
+ resolution.binding = Some(this.ambiguity(binding, old_binding));
+ } else {
+ resolution.binding = Some(binding);
+ resolution.shadows_glob = Some(old_binding);
+ }
} else {
return Err(old_binding);
}
})
}
+ pub fn ambiguity(&self, b1: &'a NameBinding<'a>, b2: &'a NameBinding<'a>)
+ -> &'a NameBinding<'a> {
+ self.arenas.alloc_name_binding(NameBinding {
+ kind: NameBindingKind::Ambiguity { b1: b1, b2: b2, legacy: false },
+ vis: if b1.vis.is_at_least(b2.vis, self) { b1.vis } else { b2.vis },
+ span: b1.span,
+ expansion: Mark::root(),
+ })
+ }
+
// Use `f` to mutate the resolution of the name in the module.
// If the resolution becomes a success, define it in the module's glob importers.
- fn update_resolution<T, F>(&mut self, module: Module<'a>, name: Name, ns: Namespace, f: F) -> T
+ fn update_resolution<T, F>(&mut self, module: Module<'a>, ident: Ident, ns: Namespace, f: F)
+ -> T
where F: FnOnce(&mut Resolver<'a>, &mut NameResolution<'a>) -> T
{
// Ensure that `resolution` isn't borrowed when defining in the module's glob importers,
// during which the resolution might end up getting re-defined via a glob cycle.
let (binding, t) = {
- let mut resolution = &mut *self.resolution(module, name, ns).borrow_mut();
+ let mut resolution = &mut *self.resolution(module, ident, ns).borrow_mut();
let old_binding = resolution.binding();
let t = f(self, resolution);
match resolution.binding() {
- _ if !self.new_import_semantics && old_binding.is_some() => return t,
+ _ if old_binding.is_some() => return t,
None => return t,
Some(binding) => match old_binding {
Some(old_binding) if old_binding as *const _ == binding as *const _ => return t,
// Define `binding` in `module`s glob importers.
for directive in module.glob_importers.borrow_mut().iter() {
- if match self.new_import_semantics {
- true => self.is_accessible_from(binding.vis, directive.parent),
- false => binding.vis == ty::Visibility::Public,
- } {
+ if self.is_accessible_from(binding.vis, directive.parent) {
let imported_binding = self.import(binding, directive);
- let _ = self.try_define(directive.parent, name, ns, imported_binding);
+ let _ = self.try_define(directive.parent, ident, ns, imported_binding);
}
}
t
}
+
+ // Define a "dummy" resolution containing a Def::Err as a placeholder for a
+ // failed resolution
+ fn import_dummy_binding(&mut self, directive: &'a ImportDirective<'a>) {
+ if let SingleImport { target, .. } = directive.subclass {
+ let dummy_binding = self.dummy_binding;
+ let dummy_binding = self.import(dummy_binding, directive);
+ self.per_ns(|this, ns| {
+ let _ = this.try_define(directive.parent, target, ns, dummy_binding);
+ });
+ }
+ }
}
-struct ImportResolver<'a, 'b: 'a> {
- resolver: &'a mut Resolver<'b>,
+pub struct ImportResolver<'a, 'b: 'a> {
+ pub resolver: &'a mut Resolver<'b>,
}
impl<'a, 'b: 'a> ::std::ops::Deref for ImportResolver<'a, 'b> {
}
}
-impl<'a, 'b: 'a> ty::NodeIdTree for ImportResolver<'a, 'b> {
- fn is_descendant_of(&self, node: NodeId, ancestor: NodeId) -> bool {
- self.resolver.is_descendant_of(node, ancestor)
+impl<'a, 'b: 'a> ty::DefIdTree for &'a ImportResolver<'a, 'b> {
+ fn parent(self, id: DefId) -> Option<DefId> {
+ self.resolver.parent(id)
}
}
/// Resolves all imports for the crate. This method performs the fixed-
/// point iteration.
- fn resolve_imports(&mut self) {
- let mut i = 0;
+ pub fn resolve_imports(&mut self) {
let mut prev_num_indeterminates = self.indeterminate_imports.len() + 1;
-
while self.indeterminate_imports.len() < prev_num_indeterminates {
prev_num_indeterminates = self.indeterminate_imports.len();
- debug!("(resolving imports) iteration {}, {} imports left", i, prev_num_indeterminates);
-
- let mut imports = Vec::new();
- ::std::mem::swap(&mut imports, &mut self.indeterminate_imports);
-
- for import in imports {
+ for import in mem::replace(&mut self.indeterminate_imports, Vec::new()) {
match self.resolve_import(&import) {
- Failed(_) => self.determined_imports.push(import),
- Indeterminate => self.indeterminate_imports.push(import),
- Success(()) => self.determined_imports.push(import),
+ true => self.determined_imports.push(import),
+ false => self.indeterminate_imports.push(import),
}
}
-
- i += 1;
}
+ }
+ pub fn finalize_imports(&mut self) {
for module in self.arenas.local_modules().iter() {
self.finalize_resolutions_in(module);
}
let mut errors = false;
for i in 0 .. self.determined_imports.len() {
let import = self.determined_imports[i];
- if let Failed(err) = self.finalize_import(import) {
+ if let Some(err) = self.finalize_import(import) {
errors = true;
- let (span, help) = match err {
- Some((span, msg)) => (span, msg),
- None => continue,
- };
// If the error is a single failed import then create a "fake" import
// resolution for it so that later resolve stages won't complain.
self.import_dummy_binding(import);
let path = import_path_to_string(&import.module_path, &import.subclass);
- let error = ResolutionError::UnresolvedImport(Some((&path, &help)));
- resolve_error(self.resolver, span, error);
+ let error = ResolutionError::UnresolvedImport(Some((&path, &err)));
+ resolve_error(self.resolver, import.span, error);
}
}
}
}
- // Define a "dummy" resolution containing a Def::Err as a placeholder for a
- // failed resolution
- fn import_dummy_binding(&mut self, directive: &'b ImportDirective<'b>) {
- if let SingleImport { target, .. } = directive.subclass {
- let dummy_binding = self.dummy_binding;
- let dummy_binding = self.import(dummy_binding, directive);
- let _ = self.try_define(directive.parent, target, ValueNS, dummy_binding.clone());
- let _ = self.try_define(directive.parent, target, TypeNS, dummy_binding);
- }
- }
-
- /// Attempts to resolve the given import. The return value indicates
- /// failure if we're certain the name does not exist, indeterminate if we
- /// don't know whether the name exists at the moment due to other
- /// currently-unresolved imports, or success if we know the name exists.
+ /// Attempts to resolve the given import, returning true if its resolution is determined.
/// If successful, the resolved bindings are written into the module.
- fn resolve_import(&mut self, directive: &'b ImportDirective<'b>) -> ResolveResult<()> {
+ fn resolve_import(&mut self, directive: &'b ImportDirective<'b>) -> bool {
debug!("(resolving import for module) resolving import `{}::...` in `{}`",
names_to_string(&directive.module_path),
module_to_string(self.current_module));
let vis = directive.vis.get();
// For better failure detection, pretend that the import will not define any names
// while resolving its module path.
- directive.vis.set(ty::Visibility::PrivateExternal);
- let result =
- self.resolve_module_path(&directive.module_path, DontUseLexicalScope, None);
+ directive.vis.set(ty::Visibility::Invisible);
+ let result = self.resolve_path(&directive.module_path, None, None);
directive.vis.set(vis);
match result {
- Success(module) => module,
- Indeterminate => return Indeterminate,
- Failed(err) => return Failed(err),
+ PathResult::Module(module) => module,
+ PathResult::Indeterminate => return false,
+ _ => return true,
}
};
directive.imported_module.set(Some(module));
- let (source, target, value_result, type_result) = match directive.subclass {
- SingleImport { source, target, ref value_result, ref type_result } =>
- (source, target, value_result, type_result),
+ let (source, target, result, type_ns_only) = match directive.subclass {
+ SingleImport { source, target, ref result, type_ns_only } =>
+ (source, target, result, type_ns_only),
GlobImport { .. } => {
self.resolve_glob_import(directive);
- return Success(());
+ return true;
}
+ _ => unreachable!(),
};
let mut indeterminate = false;
- for &(ns, result) in &[(ValueNS, value_result), (TypeNS, type_result)] {
- if let Err(Undetermined) = result.get() {
- result.set({
- match self.resolve_name_in_module(module, source, ns, false, None) {
- Success(binding) => Ok(binding),
- Indeterminate => Err(Undetermined),
- Failed(_) => Err(Determined),
- }
- });
+ self.per_ns(|this, ns| if !type_ns_only || ns == TypeNS {
+ if let Err(Undetermined) = result[ns].get() {
+ result[ns].set(this.resolve_ident_in_module(module, source, ns, false, None));
} else {
- continue
+ return
};
- match result.get() {
+ let parent = directive.parent;
+ match result[ns].get() {
Err(Undetermined) => indeterminate = true,
Err(Determined) => {
- self.update_resolution(directive.parent, target, ns, |_, resolution| {
+ this.update_resolution(parent, target, ns, |_, resolution| {
resolution.single_imports.directive_failed()
});
}
Ok(binding) if !binding.is_importable() => {
let msg = format!("`{}` is not directly importable", target);
- struct_span_err!(self.session, directive.span, E0253, "{}", &msg)
+ struct_span_err!(this.session, directive.span, E0253, "{}", &msg)
.span_label(directive.span, &format!("cannot be imported directly"))
.emit();
// Do not import this illegal binding. Import a dummy binding and pretend
// everything is fine
- self.import_dummy_binding(directive);
- return Success(());
+ this.import_dummy_binding(directive);
}
Ok(binding) => {
- let imported_binding = self.import(binding, directive);
- let conflict = self.try_define(directive.parent, target, ns, imported_binding);
+ let imported_binding = this.import(binding, directive);
+ let conflict = this.try_define(parent, target, ns, imported_binding);
if let Err(old_binding) = conflict {
- let binding = &self.import(binding, directive);
- self.report_conflict(directive.parent, target, ns, binding, old_binding);
+ this.report_conflict(parent, target, ns, imported_binding, old_binding);
}
}
}
- }
+ });
- if indeterminate { Indeterminate } else { Success(()) }
+ !indeterminate
}
- fn finalize_import(&mut self, directive: &'b ImportDirective<'b>) -> ResolveResult<()> {
+ // If appropriate, returns an error to report.
+ fn finalize_import(&mut self, directive: &'b ImportDirective<'b>) -> Option<String> {
self.current_module = directive.parent;
let ImportDirective { ref module_path, span, .. } = *directive;
- let module_result = self.resolve_module_path(&module_path, DontUseLexicalScope, Some(span));
+ let module_result = self.resolve_path(&module_path, None, Some(span));
let module = match module_result {
- Success(module) => module,
- Indeterminate => return Indeterminate,
- Failed(err) => {
- let self_module = self.module_map[&self.current_module.normal_ancestor_id.unwrap()];
-
- let resolve_from_self_result = self.resolve_module_path_from_root(
- &self_module, &module_path, 0, Some(span));
-
- return if let Success(_) = resolve_from_self_result {
- let msg = format!("Did you mean `self::{}`?", &names_to_string(module_path));
- Failed(Some((span, msg)))
+ PathResult::Module(module) => module,
+ PathResult::Failed(msg, _) => {
+ let (mut self_path, mut self_result) = (module_path.clone(), None);
+ if !self_path.is_empty() && !token::Ident(self_path[0]).is_path_segment_keyword() {
+ self_path[0].name = keywords::SelfValue.name();
+ self_result = Some(self.resolve_path(&self_path, None, None));
+ }
+ return if let Some(PathResult::Module(..)) = self_result {
+ Some(format!("Did you mean `{}`?", names_to_string(&self_path)))
} else {
- Failed(err)
+ Some(msg)
};
},
+ _ => return None,
};
- let (name, value_result, type_result) = match directive.subclass {
- SingleImport { source, ref value_result, ref type_result, .. } =>
- (source, value_result.get(), type_result.get()),
+ let (ident, result, type_ns_only) = match directive.subclass {
+ SingleImport { source, ref result, type_ns_only, .. } => (source, result, type_ns_only),
GlobImport { .. } if module.def_id() == directive.parent.def_id() => {
// Importing a module into itself is not allowed.
- let msg = "Cannot glob-import a module into itself.".into();
- return Failed(Some((directive.span, msg)));
+ return Some("Cannot glob-import a module into itself.".to_string());
}
GlobImport { is_prelude, ref max_vis } => {
if !is_prelude &&
- max_vis.get() != ty::Visibility::PrivateExternal && // Allow empty globs.
- !max_vis.get().is_at_least(directive.vis.get(), self) {
+ max_vis.get() != ty::Visibility::Invisible && // Allow empty globs.
+ !max_vis.get().is_at_least(directive.vis.get(), &*self) {
let msg = "A non-empty glob must import something with the glob's visibility";
self.session.span_err(directive.span, msg);
}
- return Success(());
+ return None;
}
+ _ => unreachable!(),
};
- for &(ns, result) in &[(ValueNS, value_result), (TypeNS, type_result)] {
- if let Ok(binding) = result {
- if self.record_use(name, ns, binding, directive.span) {
- self.resolution(module, name, ns).borrow_mut().binding =
- Some(self.dummy_binding);
+ let mut all_ns_err = true;
+ let mut legacy_self_import = None;
+ self.per_ns(|this, ns| if !type_ns_only || ns == TypeNS {
+ if let Ok(binding) = result[ns].get() {
+ all_ns_err = false;
+ if this.record_use(ident, ns, binding, directive.span) {
+ this.resolution(module, ident, ns).borrow_mut().binding =
+ Some(this.dummy_binding);
}
}
- }
+ } else if let Ok(binding) = this.resolve_ident_in_module(module, ident, ns, false, None) {
+ legacy_self_import = Some(directive);
+ let binding = this.arenas.alloc_name_binding(NameBinding {
+ kind: NameBindingKind::Import {
+ binding: binding,
+ directive: directive,
+ used: Cell::new(false),
+ legacy_self_import: true,
+ },
+ ..*binding
+ });
+ let _ = this.try_define(directive.parent, ident, ns, binding);
+ });
- if value_result.is_err() && type_result.is_err() {
- let (value_result, type_result);
- value_result = self.resolve_name_in_module(module, name, ValueNS, false, Some(span));
- type_result = self.resolve_name_in_module(module, name, TypeNS, false, Some(span));
+ if all_ns_err {
+ if let Some(directive) = legacy_self_import {
+ self.warn_legacy_self_import(directive);
+ return None;
+ }
+ let mut all_ns_failed = true;
+ self.per_ns(|this, ns| if !type_ns_only || ns == TypeNS {
+ match this.resolve_ident_in_module(module, ident, ns, false, Some(span)) {
+ Ok(_) => all_ns_failed = false,
+ _ => {}
+ }
+ });
- return if let (Failed(_), Failed(_)) = (value_result, type_result) {
+ return if all_ns_failed {
let resolutions = module.resolutions.borrow();
- let names = resolutions.iter().filter_map(|(&(ref n, _), resolution)| {
- if *n == name { return None; } // Never suggest the same name
+ let names = resolutions.iter().filter_map(|(&(ref i, _), resolution)| {
+ if *i == ident { return None; } // Never suggest the same name
match *resolution.borrow() {
- NameResolution { binding: Some(_), .. } => Some(n),
+ NameResolution { binding: Some(name_binding), .. } => {
+ match name_binding.kind {
+ NameBindingKind::Import { binding, .. } => {
+ match binding.kind {
+ // Never suggest the name that has binding error
+ // i.e. the name that cannot be previously resolved
+ NameBindingKind::Def(Def::Err) => return None,
+ _ => Some(&i.name),
+ }
+ },
+ _ => Some(&i.name),
+ }
+ },
NameResolution { single_imports: SingleImports::None, .. } => None,
- _ => Some(n),
+ _ => Some(&i.name),
}
});
- let lev_suggestion = match find_best_match_for_name(names, &name.as_str(), None) {
- Some(name) => format!(". Did you mean to use `{}`?", name),
- None => "".to_owned(),
- };
+ let lev_suggestion =
+ match find_best_match_for_name(names, &ident.name.as_str(), None) {
+ Some(name) => format!(". Did you mean to use `{}`?", name),
+ None => "".to_owned(),
+ };
let module_str = module_to_string(module);
let msg = if &module_str == "???" {
- format!("no `{}` in the root{}", name, lev_suggestion)
+ format!("no `{}` in the root{}", ident, lev_suggestion)
} else {
- format!("no `{}` in `{}`{}", name, module_str, lev_suggestion)
+ format!("no `{}` in `{}`{}", ident, module_str, lev_suggestion)
};
- Failed(Some((directive.span, msg)))
+ Some(msg)
} else {
- // `resolve_name_in_module` reported a privacy error.
+ // `resolve_ident_in_module` reported a privacy error.
self.import_dummy_binding(directive);
- Success(())
+ None
}
}
- let session = self.session;
- let reexport_error = || {
- let msg = format!("`{}` is private, and cannot be reexported", name);
- let note_msg =
- format!("consider marking `{}` as `pub` in the imported module", name);
- struct_span_err!(session, directive.span, E0364, "{}", &msg)
- .span_note(directive.span, ¬e_msg)
- .emit();
- };
-
- let extern_crate_lint = || {
- let msg = format!("extern crate `{}` is private, and cannot be reexported \
- (error E0364), consider declaring with `pub`",
- name);
- session.add_lint(PRIVATE_IN_PUBLIC, directive.id, directive.span, msg);
- };
-
- match (value_result, type_result) {
- // With `#![feature(item_like_imports)]`, all namespaces
- // must be re-exported with extra visibility for an error to occur.
- (Ok(value_binding), Ok(type_binding)) if self.new_import_semantics => {
+ let mut reexport_error = None;
+ let mut any_successful_reexport = false;
+ self.per_ns(|this, ns| {
+ if let Ok(binding) = result[ns].get() {
let vis = directive.vis.get();
- if !value_binding.pseudo_vis().is_at_least(vis, self) &&
- !type_binding.pseudo_vis().is_at_least(vis, self) {
- reexport_error();
- } else if type_binding.is_extern_crate() &&
- !type_binding.vis.is_at_least(vis, self) {
- extern_crate_lint();
- }
- }
-
- (Ok(binding), _) if !binding.pseudo_vis().is_at_least(directive.vis.get(), self) => {
- reexport_error();
- }
-
- (_, Ok(binding)) if !binding.pseudo_vis().is_at_least(directive.vis.get(), self) => {
- if binding.is_extern_crate() {
- extern_crate_lint();
+ if !binding.pseudo_vis().is_at_least(vis, &*this) {
+ reexport_error = Some((ns, binding));
} else {
- struct_span_err!(self.session, directive.span, E0365,
- "`{}` is private, and cannot be reexported", name)
- .span_label(directive.span, &format!("reexport of private `{}`", name))
- .note(&format!("consider declaring type or module `{}` with `pub`", name))
- .emit();
+ any_successful_reexport = true;
}
}
+ });
- _ => {}
+ // All namespaces must be re-exported with extra visibility for an error to occur.
+ if !any_successful_reexport {
+ let (ns, binding) = reexport_error.unwrap();
+ if ns == TypeNS && binding.is_extern_crate() {
+ let msg = format!("extern crate `{}` is private, and cannot be reexported \
+ (error E0364), consider declaring with `pub`",
+ ident);
+ self.session.add_lint(PRIVATE_IN_PUBLIC, directive.id, directive.span, msg);
+ } else if ns == TypeNS {
+ struct_span_err!(self.session, directive.span, E0365,
+ "`{}` is private, and cannot be reexported", ident)
+ .span_label(directive.span, &format!("reexport of private `{}`", ident))
+ .note(&format!("consider declaring type or module `{}` with `pub`", ident))
+ .emit();
+ } else {
+ let msg = format!("`{}` is private, and cannot be reexported", ident);
+ let note_msg =
+ format!("consider marking `{}` as `pub` in the imported module", ident);
+ struct_span_err!(self.session, directive.span, E0364, "{}", &msg)
+ .span_note(directive.span, ¬e_msg)
+ .emit();
+ }
}
// Record what this import resolves to for later uses in documentation,
// this may resolve to either a value or a type, but for documentation
// purposes it's good enough to just favor one over the other.
- let def = match type_result.ok().map(NameBinding::def) {
- Some(def) => def,
- None => value_result.ok().map(NameBinding::def).unwrap(),
- };
- let path_resolution = PathResolution::new(def);
- self.def_map.insert(directive.id, path_resolution);
+ self.per_ns(|this, ns| if let Some(binding) = result[ns].get().ok() {
+ this.def_map.entry(directive.id).or_insert(PathResolution::new(binding.def()));
+ });
debug!("(resolving single import) successfully resolved import");
- return Success(());
+ None
}
fn resolve_glob_import(&mut self, directive: &'b ImportDirective<'b>) {
// Ensure that `resolutions` isn't borrowed during `try_define`,
// since it might get updated via a glob cycle.
- let bindings = module.resolutions.borrow().iter().filter_map(|(name, resolution)| {
- resolution.borrow().binding().map(|binding| (*name, binding))
+ let bindings = module.resolutions.borrow().iter().filter_map(|(&ident, resolution)| {
+ resolution.borrow().binding().map(|binding| (ident, binding))
}).collect::<Vec<_>>();
- for ((name, ns), binding) in bindings {
- if binding.pseudo_vis() == ty::Visibility::Public ||
- self.new_import_semantics && self.is_accessible(binding.vis) {
+ for ((ident, ns), binding) in bindings {
+ if binding.pseudo_vis() == ty::Visibility::Public || self.is_accessible(binding.vis) {
let imported_binding = self.import(binding, directive);
- let _ = self.try_define(directive.parent, name, ns, imported_binding);
+ let _ = self.try_define(directive.parent, ident, ns, imported_binding);
}
}
// Record the destination of this import
- if let Some(did) = module.def_id() {
- let resolution = PathResolution::new(Def::Mod(did));
- self.def_map.insert(directive.id, resolution);
- }
+ self.record_def(directive.id, PathResolution::new(module.def().unwrap()));
}
// Miscellaneous post-processing, including recording reexports, reporting conflicts,
*module.globs.borrow_mut() = Vec::new();
let mut reexports = Vec::new();
- for (&(name, ns), resolution) in module.resolutions.borrow().iter() {
- let resolution = resolution.borrow();
+ if module as *const _ == self.graph_root as *const _ {
+ let mut exported_macro_names = FxHashSet();
+ for export in mem::replace(&mut self.macro_exports, Vec::new()).into_iter().rev() {
+ if exported_macro_names.insert(export.name) {
+ reexports.push(export);
+ }
+ }
+ }
+
+ for (&(ident, ns), resolution) in module.resolutions.borrow().iter() {
+ let resolution = &mut *resolution.borrow_mut();
let binding = match resolution.binding {
Some(binding) => binding,
None => continue,
};
- // Report conflicts
- if !self.new_import_semantics {
- for duplicate_glob in resolution.duplicate_globs.iter() {
- // FIXME #31337: We currently allow items to shadow glob-imported re-exports.
- if !binding.is_import() {
- if let NameBindingKind::Import { binding, .. } = duplicate_glob.kind {
- if binding.is_import() { continue }
- }
- }
-
- self.report_conflict(module, name, ns, duplicate_glob, binding);
- }
- }
-
if binding.vis == ty::Visibility::Public &&
(binding.is_import() || binding.is_extern_crate()) {
let def = binding.def();
if def != Def::Err {
- reexports.push(Export { name: name, def_id: def.def_id() });
+ if !def.def_id().is_local() {
+ self.session.cstore.export_macros(def.def_id().krate);
+ }
+ reexports.push(Export { name: ident.name, def: def });
}
}
- if let NameBindingKind::Import { binding: orig_binding, directive, .. } = binding.kind {
- if ns == TypeNS && orig_binding.is_variant() &&
- !orig_binding.vis.is_at_least(binding.vis, self) {
- let msg = format!("variant `{}` is private, and cannot be reexported \
- (error E0364), consider declaring its enum as `pub`",
- name);
- self.session.add_lint(PRIVATE_IN_PUBLIC, directive.id, binding.span, msg);
+ match binding.kind {
+ NameBindingKind::Import { binding: orig_binding, directive, .. } => {
+ if ns == TypeNS && orig_binding.is_variant() &&
+ !orig_binding.vis.is_at_least(binding.vis, &*self) {
+ let msg = format!("variant `{}` is private, and cannot be reexported \
+ (error E0364), consider declaring its enum as `pub`",
+ ident);
+ self.session.add_lint(PRIVATE_IN_PUBLIC, directive.id, binding.span, msg);
+ }
+ }
+ NameBindingKind::Ambiguity { b1, b2, .. }
+ if b1.is_glob_import() && b2.is_glob_import() => {
+ let (orig_b1, orig_b2) = match (&b1.kind, &b2.kind) {
+ (&NameBindingKind::Import { binding: b1, .. },
+ &NameBindingKind::Import { binding: b2, .. }) => (b1, b2),
+ _ => continue,
+ };
+ let (b1, b2) = match (orig_b1.vis, orig_b2.vis) {
+ (ty::Visibility::Public, ty::Visibility::Public) => continue,
+ (ty::Visibility::Public, _) => (b1, b2),
+ (_, ty::Visibility::Public) => (b2, b1),
+ _ => continue,
+ };
+ resolution.binding = Some(self.arenas.alloc_name_binding(NameBinding {
+ kind: NameBindingKind::Ambiguity { b1: b1, b2: b2, legacy: true }, ..*b1
+ }));
}
+ _ => {}
}
}
}
}
-fn import_path_to_string(names: &[Name], subclass: &ImportDirectiveSubclass) -> String {
+fn import_path_to_string(names: &[Ident], subclass: &ImportDirectiveSubclass) -> String {
+ let global = !names.is_empty() && names[0].name == keywords::CrateRoot.name();
+ let names = if global { &names[1..] } else { names };
if names.is_empty() {
import_directive_subclass_to_string(subclass)
} else {
match *subclass {
SingleImport { source, .. } => source.to_string(),
GlobImport { .. } => "*".to_string(),
+ ExternCrate => "<extern crate>".to_string(),
+ MacroUse => "#[macro_use]".to_string(),
}
}