mirror of
https://github.com/rust-lang/rust.git
synced 2024-12-03 04:04:06 +00:00
Auto merge of #30843 - jseyfried:no_per_ns, r=nikomatsakis
This commit refactors the field `Module::children` from mapping `Name` -> `NameBindings` to mapping `(Name, Namespace)` -> `NameBinding` and refactors the field `Module::import_resolutions` from mapping `Name` -> `ImportResolutionPerNamespace` to mapping `(Name, Namespace)` -> `ImportResolution`. This allows the duplicate checking code to be refactored so that `NameBinding` no longer needs ref-counting or a RefCell (removing the need for `NsDef`). r? @nikomatsakis
This commit is contained in:
commit
b16fbe79ac
@ -16,18 +16,16 @@
|
|||||||
use DefModifiers;
|
use DefModifiers;
|
||||||
use resolve_imports::ImportDirective;
|
use resolve_imports::ImportDirective;
|
||||||
use resolve_imports::ImportDirectiveSubclass::{self, SingleImport, GlobImport};
|
use resolve_imports::ImportDirectiveSubclass::{self, SingleImport, GlobImport};
|
||||||
use resolve_imports::{ImportResolution, ImportResolutionPerNamespace};
|
use resolve_imports::ImportResolution;
|
||||||
use Module;
|
use Module;
|
||||||
use Namespace::{TypeNS, ValueNS};
|
use Namespace::{self, TypeNS, ValueNS};
|
||||||
use NameBindings;
|
use {NameBinding, DefOrModule};
|
||||||
use {names_to_string, module_to_string};
|
use {names_to_string, module_to_string};
|
||||||
use ParentLink::{ModuleParentLink, BlockParentLink};
|
use ParentLink::{ModuleParentLink, BlockParentLink};
|
||||||
use Resolver;
|
use Resolver;
|
||||||
use resolve_imports::Shadowable;
|
use resolve_imports::Shadowable;
|
||||||
use {resolve_error, resolve_struct_error, ResolutionError};
|
use {resolve_error, resolve_struct_error, ResolutionError};
|
||||||
|
|
||||||
use self::DuplicateCheckingMode::*;
|
|
||||||
|
|
||||||
use rustc::middle::cstore::{CrateStore, ChildItem, DlDef, DlField, DlImpl};
|
use rustc::middle::cstore::{CrateStore, ChildItem, DlDef, DlField, DlImpl};
|
||||||
use rustc::middle::def::*;
|
use rustc::middle::def::*;
|
||||||
use rustc::middle::def_id::{CRATE_DEF_INDEX, DefId};
|
use rustc::middle::def_id::{CRATE_DEF_INDEX, DefId};
|
||||||
@ -54,16 +52,6 @@ use rustc_front::intravisit::{self, Visitor};
|
|||||||
use std::mem::replace;
|
use std::mem::replace;
|
||||||
use std::ops::{Deref, DerefMut};
|
use std::ops::{Deref, DerefMut};
|
||||||
|
|
||||||
// Specifies how duplicates should be handled when adding a child item if
|
|
||||||
// another item exists with the same name in some namespace.
|
|
||||||
#[derive(Copy, Clone, PartialEq)]
|
|
||||||
enum DuplicateCheckingMode {
|
|
||||||
ForbidDuplicateTypes,
|
|
||||||
ForbidDuplicateValues,
|
|
||||||
ForbidDuplicateTypesAndValues,
|
|
||||||
OverwriteDuplicates,
|
|
||||||
}
|
|
||||||
|
|
||||||
struct GraphBuilder<'a, 'b: 'a, 'tcx: 'b> {
|
struct GraphBuilder<'a, 'b: 'a, 'tcx: 'b> {
|
||||||
resolver: &'a mut Resolver<'b, 'tcx>,
|
resolver: &'a mut Resolver<'b, 'tcx>,
|
||||||
}
|
}
|
||||||
@ -82,6 +70,23 @@ impl<'a, 'b:'a, 'tcx:'b> DerefMut for GraphBuilder<'a, 'b, 'tcx> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
trait ToNameBinding<'a> {
|
||||||
|
fn to_name_binding(self) -> NameBinding<'a>;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> ToNameBinding<'a> for (Module<'a>, Span) {
|
||||||
|
fn to_name_binding(self) -> NameBinding<'a> {
|
||||||
|
NameBinding::create_from_module(self.0, Some(self.1))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> ToNameBinding<'a> for (Def, Span, DefModifiers) {
|
||||||
|
fn to_name_binding(self) -> NameBinding<'a> {
|
||||||
|
let def = DefOrModule::Def(self.0);
|
||||||
|
NameBinding { modifiers: self.2, def_or_module: def, span: Some(self.1) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<'a, 'b:'a, 'tcx:'b> GraphBuilder<'a, 'b, 'tcx> {
|
impl<'a, 'b:'a, 'tcx:'b> GraphBuilder<'a, 'b, 'tcx> {
|
||||||
/// Constructs the reduced graph for the entire crate.
|
/// Constructs the reduced graph for the entire crate.
|
||||||
fn build_reduced_graph(self, krate: &hir::Crate) {
|
fn build_reduced_graph(self, krate: &hir::Crate) {
|
||||||
@ -92,63 +97,30 @@ impl<'a, 'b:'a, 'tcx:'b> GraphBuilder<'a, 'b, 'tcx> {
|
|||||||
intravisit::walk_crate(&mut visitor, krate);
|
intravisit::walk_crate(&mut visitor, krate);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Adds a new child item to the module definition of the parent node,
|
/// Defines `name` in namespace `ns` of module `parent` to be `def` if it is not yet defined.
|
||||||
/// or if there is already a child, does duplicate checking on the child.
|
fn try_define<T>(&self, parent: Module<'b>, name: Name, ns: Namespace, def: T)
|
||||||
/// Returns the child's corresponding name bindings.
|
where T: ToNameBinding<'b>
|
||||||
fn add_child(&self,
|
{
|
||||||
name: Name,
|
parent.try_define_child(name, ns, def.to_name_binding());
|
||||||
parent: Module<'b>,
|
}
|
||||||
duplicate_checking_mode: DuplicateCheckingMode,
|
|
||||||
// For printing errors
|
|
||||||
sp: Span)
|
|
||||||
-> NameBindings<'b> {
|
|
||||||
self.check_for_conflicts_between_external_crates_and_items(parent, name, sp);
|
|
||||||
|
|
||||||
// Add or reuse the child.
|
/// Defines `name` in namespace `ns` of module `parent` to be `def` if it is not yet defined;
|
||||||
let child = parent.children.borrow().get(&name).cloned();
|
/// otherwise, reports an error.
|
||||||
match child {
|
fn define<T: ToNameBinding<'b>>(&self, parent: Module<'b>, name: Name, ns: Namespace, def: T) {
|
||||||
None => {
|
let name_binding = def.to_name_binding();
|
||||||
let child = NameBindings::new();
|
let span = name_binding.span.unwrap_or(DUMMY_SP);
|
||||||
parent.children.borrow_mut().insert(name, child.clone());
|
self.check_for_conflicts_between_external_crates_and_items(&parent, name, span);
|
||||||
child
|
if !parent.try_define_child(name, ns, name_binding) {
|
||||||
}
|
// Record an error here by looking up the namespace that had the duplicate
|
||||||
Some(child) => {
|
let ns_str = match ns { TypeNS => "type or module", ValueNS => "value" };
|
||||||
// Enforce the duplicate checking mode:
|
let resolution_error = ResolutionError::DuplicateDefinition(ns_str, name);
|
||||||
//
|
let mut err = resolve_struct_error(self, span, resolution_error);
|
||||||
// * If we're requesting duplicate type checking, check that
|
|
||||||
// the name isn't defined in the type namespace.
|
if let Some(sp) = parent.children.borrow().get(&(name, ns)).unwrap().span {
|
||||||
//
|
let note = format!("first definition of {} `{}` here", ns_str, name);
|
||||||
// * If we're requesting duplicate value checking, check that
|
err.span_note(sp, ¬e);
|
||||||
// the name isn't defined in the value namespace.
|
|
||||||
//
|
|
||||||
// * If we're requesting duplicate type and value checking,
|
|
||||||
// check that the name isn't defined in either namespace.
|
|
||||||
//
|
|
||||||
// * If no duplicate checking was requested at all, do
|
|
||||||
// nothing.
|
|
||||||
|
|
||||||
let ns = match duplicate_checking_mode {
|
|
||||||
ForbidDuplicateTypes if child.type_ns.defined() => TypeNS,
|
|
||||||
ForbidDuplicateValues if child.value_ns.defined() => ValueNS,
|
|
||||||
ForbidDuplicateTypesAndValues if child.type_ns.defined() => TypeNS,
|
|
||||||
ForbidDuplicateTypesAndValues if child.value_ns.defined() => ValueNS,
|
|
||||||
_ => return child,
|
|
||||||
};
|
|
||||||
|
|
||||||
// Record an error here by looking up the namespace that had the duplicate
|
|
||||||
let ns_str = match ns { TypeNS => "type or module", ValueNS => "value" };
|
|
||||||
let mut err = resolve_struct_error(self,
|
|
||||||
sp,
|
|
||||||
ResolutionError::DuplicateDefinition(ns_str,
|
|
||||||
name));
|
|
||||||
|
|
||||||
if let Some(sp) = child[ns].span() {
|
|
||||||
let note = format!("first definition of {} `{}` here", ns_str, name);
|
|
||||||
err.span_note(sp, ¬e);
|
|
||||||
}
|
|
||||||
err.emit();
|
|
||||||
child
|
|
||||||
}
|
}
|
||||||
|
err.emit();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -331,12 +303,10 @@ impl<'a, 'b:'a, 'tcx:'b> GraphBuilder<'a, 'b, 'tcx> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ItemMod(..) => {
|
ItemMod(..) => {
|
||||||
let name_bindings = self.add_child(name, parent, ForbidDuplicateTypes, sp);
|
|
||||||
|
|
||||||
let parent_link = ModuleParentLink(parent, name);
|
let parent_link = ModuleParentLink(parent, name);
|
||||||
let def = Def::Mod(self.ast_map.local_def_id(item.id));
|
let def = Def::Mod(self.ast_map.local_def_id(item.id));
|
||||||
let module = self.new_module(parent_link, Some(def), false, is_public);
|
let module = self.new_module(parent_link, Some(def), false, is_public);
|
||||||
name_bindings.define_module(module.clone(), sp);
|
self.define(parent, name, TypeNS, (module, sp));
|
||||||
module
|
module
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -344,51 +314,36 @@ impl<'a, 'b:'a, 'tcx:'b> GraphBuilder<'a, 'b, 'tcx> {
|
|||||||
|
|
||||||
// These items live in the value namespace.
|
// These items live in the value namespace.
|
||||||
ItemStatic(_, m, _) => {
|
ItemStatic(_, m, _) => {
|
||||||
let name_bindings = self.add_child(name, parent, ForbidDuplicateValues, sp);
|
|
||||||
let mutbl = m == hir::MutMutable;
|
let mutbl = m == hir::MutMutable;
|
||||||
|
let def = Def::Static(self.ast_map.local_def_id(item.id), mutbl);
|
||||||
name_bindings.define_value(Def::Static(self.ast_map.local_def_id(item.id), mutbl),
|
self.define(parent, name, ValueNS, (def, sp, modifiers));
|
||||||
sp,
|
|
||||||
modifiers);
|
|
||||||
parent
|
parent
|
||||||
}
|
}
|
||||||
ItemConst(_, _) => {
|
ItemConst(_, _) => {
|
||||||
self.add_child(name, parent, ForbidDuplicateValues, sp)
|
let def = Def::Const(self.ast_map.local_def_id(item.id));
|
||||||
.define_value(Def::Const(self.ast_map.local_def_id(item.id)), sp, modifiers);
|
self.define(parent, name, ValueNS, (def, sp, modifiers));
|
||||||
parent
|
parent
|
||||||
}
|
}
|
||||||
ItemFn(_, _, _, _, _, _) => {
|
ItemFn(_, _, _, _, _, _) => {
|
||||||
let name_bindings = self.add_child(name, parent, ForbidDuplicateValues, sp);
|
|
||||||
|
|
||||||
let def = Def::Fn(self.ast_map.local_def_id(item.id));
|
let def = Def::Fn(self.ast_map.local_def_id(item.id));
|
||||||
name_bindings.define_value(def, sp, modifiers);
|
self.define(parent, name, ValueNS, (def, sp, modifiers));
|
||||||
parent
|
parent
|
||||||
}
|
}
|
||||||
|
|
||||||
// These items live in the type namespace.
|
// These items live in the type namespace.
|
||||||
ItemTy(..) => {
|
ItemTy(..) => {
|
||||||
let name_bindings = self.add_child(name,
|
|
||||||
parent,
|
|
||||||
ForbidDuplicateTypes,
|
|
||||||
sp);
|
|
||||||
|
|
||||||
let parent_link = ModuleParentLink(parent, name);
|
let parent_link = ModuleParentLink(parent, name);
|
||||||
let def = Def::TyAlias(self.ast_map.local_def_id(item.id));
|
let def = Def::TyAlias(self.ast_map.local_def_id(item.id));
|
||||||
let module = self.new_module(parent_link, Some(def), false, is_public);
|
let module = self.new_module(parent_link, Some(def), false, is_public);
|
||||||
name_bindings.define_module(module, sp);
|
self.define(parent, name, TypeNS, (module, sp));
|
||||||
parent
|
parent
|
||||||
}
|
}
|
||||||
|
|
||||||
ItemEnum(ref enum_definition, _) => {
|
ItemEnum(ref enum_definition, _) => {
|
||||||
let name_bindings = self.add_child(name,
|
|
||||||
parent,
|
|
||||||
ForbidDuplicateTypes,
|
|
||||||
sp);
|
|
||||||
|
|
||||||
let parent_link = ModuleParentLink(parent, name);
|
let parent_link = ModuleParentLink(parent, name);
|
||||||
let def = Def::Enum(self.ast_map.local_def_id(item.id));
|
let def = Def::Enum(self.ast_map.local_def_id(item.id));
|
||||||
let module = self.new_module(parent_link, Some(def), false, is_public);
|
let module = self.new_module(parent_link, Some(def), false, is_public);
|
||||||
name_bindings.define_module(module.clone(), sp);
|
self.define(parent, name, TypeNS, (module, sp));
|
||||||
|
|
||||||
let variant_modifiers = if is_public {
|
let variant_modifiers = if is_public {
|
||||||
DefModifiers::empty()
|
DefModifiers::empty()
|
||||||
@ -405,26 +360,15 @@ impl<'a, 'b:'a, 'tcx:'b> GraphBuilder<'a, 'b, 'tcx> {
|
|||||||
|
|
||||||
// These items live in both the type and value namespaces.
|
// These items live in both the type and value namespaces.
|
||||||
ItemStruct(ref struct_def, _) => {
|
ItemStruct(ref struct_def, _) => {
|
||||||
// Adding to both Type and Value namespaces or just Type?
|
|
||||||
let (forbid, ctor_id) = if struct_def.is_struct() {
|
|
||||||
(ForbidDuplicateTypes, None)
|
|
||||||
} else {
|
|
||||||
(ForbidDuplicateTypesAndValues, Some(struct_def.id()))
|
|
||||||
};
|
|
||||||
|
|
||||||
let name_bindings = self.add_child(name, parent, forbid, sp);
|
|
||||||
|
|
||||||
// Define a name in the type namespace.
|
// Define a name in the type namespace.
|
||||||
name_bindings.define_type(Def::Struct(self.ast_map.local_def_id(item.id)),
|
let def = Def::Struct(self.ast_map.local_def_id(item.id));
|
||||||
sp,
|
self.define(parent, name, TypeNS, (def, sp, modifiers));
|
||||||
modifiers);
|
|
||||||
|
|
||||||
// If this is a newtype or unit-like struct, define a name
|
// If this is a newtype or unit-like struct, define a name
|
||||||
// in the value namespace as well
|
// in the value namespace as well
|
||||||
if let Some(cid) = ctor_id {
|
if !struct_def.is_struct() {
|
||||||
name_bindings.define_value(Def::Struct(self.ast_map.local_def_id(cid)),
|
let def = Def::Struct(self.ast_map.local_def_id(struct_def.id()));
|
||||||
sp,
|
self.define(parent, name, ValueNS, (def, sp, modifiers));
|
||||||
modifiers);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Record the def ID and fields of this struct.
|
// Record the def ID and fields of this struct.
|
||||||
@ -447,48 +391,27 @@ impl<'a, 'b:'a, 'tcx:'b> GraphBuilder<'a, 'b, 'tcx> {
|
|||||||
ItemImpl(..) => parent,
|
ItemImpl(..) => parent,
|
||||||
|
|
||||||
ItemTrait(_, _, _, ref items) => {
|
ItemTrait(_, _, _, ref items) => {
|
||||||
let name_bindings = self.add_child(name,
|
|
||||||
parent,
|
|
||||||
ForbidDuplicateTypes,
|
|
||||||
sp);
|
|
||||||
|
|
||||||
let def_id = self.ast_map.local_def_id(item.id);
|
let def_id = self.ast_map.local_def_id(item.id);
|
||||||
|
|
||||||
// Add all the items within to a new module.
|
// Add all the items within to a new module.
|
||||||
let parent_link = ModuleParentLink(parent, name);
|
let parent_link = ModuleParentLink(parent, name);
|
||||||
let def = Def::Trait(def_id);
|
let def = Def::Trait(def_id);
|
||||||
let module_parent = self.new_module(parent_link, Some(def), false, is_public);
|
let module_parent = self.new_module(parent_link, Some(def), false, is_public);
|
||||||
name_bindings.define_module(module_parent.clone(), sp);
|
self.define(parent, name, TypeNS, (module_parent, sp));
|
||||||
|
|
||||||
// Add the names of all the items to the trait info.
|
// Add the names of all the items to the trait info.
|
||||||
for trait_item in items {
|
for item in items {
|
||||||
let name_bindings = self.add_child(trait_item.name,
|
let item_def_id = self.ast_map.local_def_id(item.id);
|
||||||
&module_parent,
|
let (def, ns) = match item.node {
|
||||||
ForbidDuplicateTypesAndValues,
|
hir::ConstTraitItem(..) => (Def::AssociatedConst(item_def_id), ValueNS),
|
||||||
trait_item.span);
|
hir::MethodTraitItem(..) => (Def::Method(item_def_id), ValueNS),
|
||||||
|
hir::TypeTraitItem(..) => (Def::AssociatedTy(def_id, item_def_id), TypeNS),
|
||||||
|
};
|
||||||
|
|
||||||
match trait_item.node {
|
let modifiers = DefModifiers::PUBLIC; // NB: not DefModifiers::IMPORTABLE
|
||||||
hir::ConstTraitItem(..) => {
|
self.define(&module_parent, item.name, ns, (def, item.span, modifiers));
|
||||||
let def = Def::AssociatedConst(self.ast_map.
|
|
||||||
local_def_id(trait_item.id));
|
|
||||||
// NB: not DefModifiers::IMPORTABLE
|
|
||||||
name_bindings.define_value(def, trait_item.span, DefModifiers::PUBLIC);
|
|
||||||
}
|
|
||||||
hir::MethodTraitItem(..) => {
|
|
||||||
let def = Def::Method(self.ast_map.local_def_id(trait_item.id));
|
|
||||||
// NB: not DefModifiers::IMPORTABLE
|
|
||||||
name_bindings.define_value(def, trait_item.span, DefModifiers::PUBLIC);
|
|
||||||
}
|
|
||||||
hir::TypeTraitItem(..) => {
|
|
||||||
let def = Def::AssociatedTy(self.ast_map.local_def_id(item.id),
|
|
||||||
self.ast_map.local_def_id(trait_item.id));
|
|
||||||
// NB: not DefModifiers::IMPORTABLE
|
|
||||||
name_bindings.define_type(def, trait_item.span, DefModifiers::PUBLIC);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let trait_item_def_id = self.ast_map.local_def_id(trait_item.id);
|
self.trait_item_map.insert((item.name, def_id), item_def_id);
|
||||||
self.trait_item_map.insert((trait_item.name, def_id), trait_item_def_id);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
parent
|
parent
|
||||||
@ -512,13 +435,11 @@ impl<'a, 'b:'a, 'tcx:'b> GraphBuilder<'a, 'b, 'tcx> {
|
|||||||
|
|
||||||
// Variants are always treated as importable to allow them to be glob used.
|
// Variants are always treated as importable to allow them to be glob used.
|
||||||
// All variants are defined in both type and value namespaces as future-proofing.
|
// All variants are defined in both type and value namespaces as future-proofing.
|
||||||
let child = self.add_child(name, parent, ForbidDuplicateTypesAndValues, variant.span);
|
let modifiers = DefModifiers::PUBLIC | DefModifiers::IMPORTABLE | variant_modifiers;
|
||||||
child.define_value(Def::Variant(item_id, self.ast_map.local_def_id(variant.node.data.id())),
|
let def = Def::Variant(item_id, self.ast_map.local_def_id(variant.node.data.id()));
|
||||||
variant.span,
|
|
||||||
DefModifiers::PUBLIC | DefModifiers::IMPORTABLE | variant_modifiers);
|
self.define(parent, name, ValueNS, (def, variant.span, modifiers));
|
||||||
child.define_type(Def::Variant(item_id, self.ast_map.local_def_id(variant.node.data.id())),
|
self.define(parent, name, TypeNS, (def, variant.span, modifiers));
|
||||||
variant.span,
|
|
||||||
DefModifiers::PUBLIC | DefModifiers::IMPORTABLE | variant_modifiers);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Constructs the reduced graph for one foreign item.
|
/// Constructs the reduced graph for one foreign item.
|
||||||
@ -532,7 +453,6 @@ impl<'a, 'b:'a, 'tcx:'b> GraphBuilder<'a, 'b, 'tcx> {
|
|||||||
} else {
|
} else {
|
||||||
DefModifiers::empty()
|
DefModifiers::empty()
|
||||||
} | DefModifiers::IMPORTABLE;
|
} | DefModifiers::IMPORTABLE;
|
||||||
let name_bindings = self.add_child(name, parent, ForbidDuplicateValues, foreign_item.span);
|
|
||||||
|
|
||||||
let def = match foreign_item.node {
|
let def = match foreign_item.node {
|
||||||
ForeignItemFn(..) => {
|
ForeignItemFn(..) => {
|
||||||
@ -542,7 +462,7 @@ impl<'a, 'b:'a, 'tcx:'b> GraphBuilder<'a, 'b, 'tcx> {
|
|||||||
Def::Static(self.ast_map.local_def_id(foreign_item.id), m)
|
Def::Static(self.ast_map.local_def_id(foreign_item.id), m)
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
name_bindings.define_value(def, foreign_item.span, modifiers);
|
self.define(parent, name, ValueNS, (def, foreign_item.span, modifiers));
|
||||||
}
|
}
|
||||||
|
|
||||||
fn build_reduced_graph_for_block(&mut self, block: &Block, parent: Module<'b>) -> Module<'b> {
|
fn build_reduced_graph_for_block(&mut self, block: &Block, parent: Module<'b>) -> Module<'b> {
|
||||||
@ -565,7 +485,6 @@ impl<'a, 'b:'a, 'tcx:'b> GraphBuilder<'a, 'b, 'tcx> {
|
|||||||
fn handle_external_def(&mut self,
|
fn handle_external_def(&mut self,
|
||||||
def: Def,
|
def: Def,
|
||||||
vis: Visibility,
|
vis: Visibility,
|
||||||
child_name_bindings: &NameBindings<'b>,
|
|
||||||
final_ident: &str,
|
final_ident: &str,
|
||||||
name: Name,
|
name: Name,
|
||||||
new_parent: Module<'b>) {
|
new_parent: Module<'b>) {
|
||||||
@ -573,11 +492,15 @@ impl<'a, 'b:'a, 'tcx:'b> GraphBuilder<'a, 'b, 'tcx> {
|
|||||||
final_ident,
|
final_ident,
|
||||||
vis);
|
vis);
|
||||||
let is_public = vis == hir::Public;
|
let is_public = vis == hir::Public;
|
||||||
let modifiers = if is_public {
|
|
||||||
DefModifiers::PUBLIC
|
let mut modifiers = DefModifiers::empty();
|
||||||
} else {
|
if is_public {
|
||||||
DefModifiers::empty()
|
modifiers = modifiers | DefModifiers::PUBLIC;
|
||||||
} | DefModifiers::IMPORTABLE;
|
}
|
||||||
|
if new_parent.is_normal() {
|
||||||
|
modifiers = modifiers | DefModifiers::IMPORTABLE;
|
||||||
|
}
|
||||||
|
|
||||||
let is_exported = is_public &&
|
let is_exported = is_public &&
|
||||||
match new_parent.def_id() {
|
match new_parent.def_id() {
|
||||||
None => true,
|
None => true,
|
||||||
@ -586,43 +509,24 @@ impl<'a, 'b:'a, 'tcx:'b> GraphBuilder<'a, 'b, 'tcx> {
|
|||||||
if is_exported {
|
if is_exported {
|
||||||
self.external_exports.insert(def.def_id());
|
self.external_exports.insert(def.def_id());
|
||||||
}
|
}
|
||||||
let is_struct_ctor = if let Def::Struct(def_id) = def {
|
|
||||||
self.session.cstore.tuple_struct_definition_if_ctor(def_id).is_some()
|
|
||||||
} else {
|
|
||||||
false
|
|
||||||
};
|
|
||||||
|
|
||||||
match def {
|
match def {
|
||||||
Def::Mod(_) |
|
Def::Mod(_) | Def::ForeignMod(_) | Def::Enum(..) | Def::TyAlias(..) => {
|
||||||
Def::ForeignMod(_) |
|
debug!("(building reduced graph for external crate) building module {} {}",
|
||||||
Def::Struct(..) |
|
final_ident,
|
||||||
Def::Enum(..) |
|
is_public);
|
||||||
Def::TyAlias(..) if !is_struct_ctor => {
|
let parent_link = ModuleParentLink(new_parent, name);
|
||||||
if let Some(module_def) = child_name_bindings.type_ns.module() {
|
let module = self.new_module(parent_link, Some(def), true, is_public);
|
||||||
debug!("(building reduced graph for external crate) already created module");
|
self.try_define(new_parent, name, TypeNS, (module, DUMMY_SP));
|
||||||
module_def.def.set(Some(def));
|
|
||||||
} else {
|
|
||||||
debug!("(building reduced graph for external crate) building module {} {}",
|
|
||||||
final_ident,
|
|
||||||
is_public);
|
|
||||||
let parent_link = ModuleParentLink(new_parent, name);
|
|
||||||
let module = self.new_module(parent_link, Some(def), true, is_public);
|
|
||||||
child_name_bindings.define_module(module, DUMMY_SP);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
_ => {}
|
|
||||||
}
|
|
||||||
|
|
||||||
match def {
|
|
||||||
Def::Mod(_) | Def::ForeignMod(_) => {}
|
|
||||||
Def::Variant(_, variant_id) => {
|
Def::Variant(_, variant_id) => {
|
||||||
debug!("(building reduced graph for external crate) building variant {}",
|
debug!("(building reduced graph for external crate) building variant {}",
|
||||||
final_ident);
|
final_ident);
|
||||||
// Variants are always treated as importable to allow them to be glob used.
|
// Variants are always treated as importable to allow them to be glob used.
|
||||||
// All variants are defined in both type and value namespaces as future-proofing.
|
// All variants are defined in both type and value namespaces as future-proofing.
|
||||||
let modifiers = DefModifiers::PUBLIC | DefModifiers::IMPORTABLE;
|
let modifiers = DefModifiers::PUBLIC | DefModifiers::IMPORTABLE;
|
||||||
child_name_bindings.define_type(def, DUMMY_SP, modifiers);
|
self.try_define(new_parent, name, TypeNS, (def, DUMMY_SP, modifiers));
|
||||||
child_name_bindings.define_value(def, DUMMY_SP, modifiers);
|
self.try_define(new_parent, name, ValueNS, (def, DUMMY_SP, modifiers));
|
||||||
if self.session.cstore.variant_kind(variant_id) == Some(VariantKind::Struct) {
|
if self.session.cstore.variant_kind(variant_id) == Some(VariantKind::Struct) {
|
||||||
// Not adding fields for variants as they are not accessed with a self receiver
|
// Not adding fields for variants as they are not accessed with a self receiver
|
||||||
self.structs.insert(variant_id, Vec::new());
|
self.structs.insert(variant_id, Vec::new());
|
||||||
@ -635,17 +539,7 @@ impl<'a, 'b:'a, 'tcx:'b> GraphBuilder<'a, 'b, 'tcx> {
|
|||||||
Def::Method(..) => {
|
Def::Method(..) => {
|
||||||
debug!("(building reduced graph for external crate) building value (fn/static) {}",
|
debug!("(building reduced graph for external crate) building value (fn/static) {}",
|
||||||
final_ident);
|
final_ident);
|
||||||
// impl methods have already been defined with the correct importability
|
self.try_define(new_parent, name, ValueNS, (def, DUMMY_SP, modifiers));
|
||||||
// modifier
|
|
||||||
let mut modifiers = match *child_name_bindings.value_ns.borrow() {
|
|
||||||
Some(ref def) => (modifiers & !DefModifiers::IMPORTABLE) |
|
|
||||||
(def.modifiers & DefModifiers::IMPORTABLE),
|
|
||||||
None => modifiers,
|
|
||||||
};
|
|
||||||
if !new_parent.is_normal() {
|
|
||||||
modifiers = modifiers & !DefModifiers::IMPORTABLE;
|
|
||||||
}
|
|
||||||
child_name_bindings.define_value(def, DUMMY_SP, modifiers);
|
|
||||||
}
|
}
|
||||||
Def::Trait(def_id) => {
|
Def::Trait(def_id) => {
|
||||||
debug!("(building reduced graph for external crate) building type {}",
|
debug!("(building reduced graph for external crate) building type {}",
|
||||||
@ -670,45 +564,31 @@ impl<'a, 'b:'a, 'tcx:'b> GraphBuilder<'a, 'b, 'tcx> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Define a module if necessary.
|
|
||||||
let parent_link = ModuleParentLink(new_parent, name);
|
let parent_link = ModuleParentLink(new_parent, name);
|
||||||
let module = self.new_module(parent_link, Some(def), true, is_public);
|
let module = self.new_module(parent_link, Some(def), true, is_public);
|
||||||
child_name_bindings.define_module(module, DUMMY_SP);
|
self.try_define(new_parent, name, TypeNS, (module, DUMMY_SP));
|
||||||
}
|
}
|
||||||
Def::Enum(..) | Def::TyAlias(..) | Def::AssociatedTy(..) => {
|
Def::AssociatedTy(..) => {
|
||||||
debug!("(building reduced graph for external crate) building type {}",
|
debug!("(building reduced graph for external crate) building type {}",
|
||||||
final_ident);
|
final_ident);
|
||||||
|
self.try_define(new_parent, name, TypeNS, (def, DUMMY_SP, modifiers));
|
||||||
let modifiers = match new_parent.is_normal() {
|
|
||||||
true => modifiers,
|
|
||||||
_ => modifiers & !DefModifiers::IMPORTABLE,
|
|
||||||
};
|
|
||||||
|
|
||||||
if let Def::Enum(..) = def {
|
|
||||||
child_name_bindings.type_ns.set_modifiers(modifiers);
|
|
||||||
} else if let Def::TyAlias(..) = def {
|
|
||||||
child_name_bindings.type_ns.set_modifiers(modifiers);
|
|
||||||
} else {
|
|
||||||
child_name_bindings.define_type(def, DUMMY_SP, modifiers);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
Def::Struct(..) if is_struct_ctor => {
|
Def::Struct(def_id)
|
||||||
// Do nothing
|
if self.session.cstore.tuple_struct_definition_if_ctor(def_id).is_none() => {
|
||||||
}
|
|
||||||
Def::Struct(def_id) => {
|
|
||||||
debug!("(building reduced graph for external crate) building type and value for \
|
debug!("(building reduced graph for external crate) building type and value for \
|
||||||
{}",
|
{}",
|
||||||
final_ident);
|
final_ident);
|
||||||
|
self.try_define(new_parent, name, TypeNS, (def, DUMMY_SP, modifiers));
|
||||||
child_name_bindings.define_type(def, DUMMY_SP, modifiers);
|
|
||||||
if let Some(ctor_def_id) = self.session.cstore.struct_ctor_def_id(def_id) {
|
if let Some(ctor_def_id) = self.session.cstore.struct_ctor_def_id(def_id) {
|
||||||
child_name_bindings.define_value(Def::Struct(ctor_def_id), DUMMY_SP, modifiers);
|
let def = Def::Struct(ctor_def_id);
|
||||||
|
self.try_define(new_parent, name, ValueNS, (def, DUMMY_SP, modifiers));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Record the def ID and fields of this struct.
|
// Record the def ID and fields of this struct.
|
||||||
let fields = self.session.cstore.struct_field_names(def_id);
|
let fields = self.session.cstore.struct_field_names(def_id);
|
||||||
self.structs.insert(def_id, fields);
|
self.structs.insert(def_id, fields);
|
||||||
}
|
}
|
||||||
|
Def::Struct(..) => {}
|
||||||
Def::Local(..) |
|
Def::Local(..) |
|
||||||
Def::PrimTy(..) |
|
Def::PrimTy(..) |
|
||||||
Def::TyParam(..) |
|
Def::TyParam(..) |
|
||||||
@ -737,14 +617,8 @@ impl<'a, 'b:'a, 'tcx:'b> GraphBuilder<'a, 'b, 'tcx> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
let child_name_bindings = self.add_child(xcdef.name,
|
|
||||||
root,
|
|
||||||
OverwriteDuplicates,
|
|
||||||
DUMMY_SP);
|
|
||||||
|
|
||||||
self.handle_external_def(def,
|
self.handle_external_def(def,
|
||||||
xcdef.vis,
|
xcdef.vis,
|
||||||
&child_name_bindings,
|
|
||||||
&xcdef.name.as_str(),
|
&xcdef.name.as_str(),
|
||||||
xcdef.name,
|
xcdef.name,
|
||||||
root);
|
root);
|
||||||
@ -827,24 +701,16 @@ impl<'a, 'b:'a, 'tcx:'b> GraphBuilder<'a, 'b, 'tcx> {
|
|||||||
target);
|
target);
|
||||||
|
|
||||||
let mut import_resolutions = module_.import_resolutions.borrow_mut();
|
let mut import_resolutions = module_.import_resolutions.borrow_mut();
|
||||||
match import_resolutions.get_mut(&target) {
|
for &ns in [TypeNS, ValueNS].iter() {
|
||||||
Some(resolution_per_ns) => {
|
let mut resolution = import_resolutions.entry((target, ns)).or_insert(
|
||||||
debug!("(building import directive) bumping reference");
|
ImportResolution::new(id, is_public)
|
||||||
resolution_per_ns.outstanding_references += 1;
|
);
|
||||||
|
|
||||||
// the source of this name is different now
|
resolution.outstanding_references += 1;
|
||||||
let resolution =
|
// the source of this name is different now
|
||||||
ImportResolution { id: id, is_public: is_public, target: None };
|
resolution.id = id;
|
||||||
resolution_per_ns[TypeNS] = resolution.clone();
|
resolution.is_public = is_public;
|
||||||
resolution_per_ns[ValueNS] = resolution;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
None => {}
|
|
||||||
}
|
}
|
||||||
debug!("(building import directive) creating new");
|
|
||||||
let mut import_resolution_per_ns = ImportResolutionPerNamespace::new(id, is_public);
|
|
||||||
import_resolution_per_ns.outstanding_references = 1;
|
|
||||||
import_resolutions.insert(target, import_resolution_per_ns);
|
|
||||||
}
|
}
|
||||||
GlobImport => {
|
GlobImport => {
|
||||||
// Set the glob flag. This tells us that we don't know the
|
// Set the glob flag. This tells us that we don't know the
|
||||||
|
@ -36,7 +36,6 @@ extern crate rustc;
|
|||||||
|
|
||||||
use self::PatternBindingMode::*;
|
use self::PatternBindingMode::*;
|
||||||
use self::Namespace::*;
|
use self::Namespace::*;
|
||||||
use self::NamespaceResult::*;
|
|
||||||
use self::ResolveResult::*;
|
use self::ResolveResult::*;
|
||||||
use self::FallbackSuggestion::*;
|
use self::FallbackSuggestion::*;
|
||||||
use self::TypeParameters::*;
|
use self::TypeParameters::*;
|
||||||
@ -87,13 +86,12 @@ use rustc_front::hir::{TraitRef, Ty, TyBool, TyChar, TyFloat, TyInt};
|
|||||||
use rustc_front::hir::{TyRptr, TyStr, TyUint, TyPath, TyPtr};
|
use rustc_front::hir::{TyRptr, TyStr, TyUint, TyPath, TyPtr};
|
||||||
use rustc_front::util::walk_pat;
|
use rustc_front::util::walk_pat;
|
||||||
|
|
||||||
use std::collections::{HashMap, HashSet};
|
use std::collections::{hash_map, HashMap, HashSet};
|
||||||
use std::cell::{Cell, RefCell};
|
use std::cell::{Cell, RefCell};
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::mem::replace;
|
use std::mem::replace;
|
||||||
use std::rc::Rc;
|
|
||||||
|
|
||||||
use resolve_imports::{Target, ImportDirective, ImportResolutionPerNamespace};
|
use resolve_imports::{Target, ImportDirective, ImportResolution};
|
||||||
use resolve_imports::Shadowable;
|
use resolve_imports::Shadowable;
|
||||||
|
|
||||||
// NB: This module needs to be declared first so diagnostics are
|
// NB: This module needs to be declared first so diagnostics are
|
||||||
@ -357,8 +355,8 @@ fn resolve_struct_error<'b, 'a: 'b, 'tcx: 'a>(resolver: &'b Resolver<'a, 'tcx>,
|
|||||||
if let Some(directive) = resolver.current_module
|
if let Some(directive) = resolver.current_module
|
||||||
.import_resolutions
|
.import_resolutions
|
||||||
.borrow()
|
.borrow()
|
||||||
.get(&name) {
|
.get(&(name, ValueNS)) {
|
||||||
let item = resolver.ast_map.expect_item(directive.value_ns.id);
|
let item = resolver.ast_map.expect_item(directive.id);
|
||||||
err.span_note(item.span, "constant imported here");
|
err.span_note(item.span, "constant imported here");
|
||||||
}
|
}
|
||||||
err
|
err
|
||||||
@ -572,38 +570,6 @@ pub enum Namespace {
|
|||||||
ValueNS,
|
ValueNS,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A NamespaceResult represents the result of resolving an import in
|
|
||||||
/// a particular namespace. The result is either definitely-resolved,
|
|
||||||
/// definitely- unresolved, or unknown.
|
|
||||||
#[derive(Clone)]
|
|
||||||
enum NamespaceResult<'a> {
|
|
||||||
/// Means that resolve hasn't gathered enough information yet to determine
|
|
||||||
/// whether the name is bound in this namespace. (That is, it hasn't
|
|
||||||
/// resolved all `use` directives yet.)
|
|
||||||
UnknownResult,
|
|
||||||
/// Means that resolve has determined that the name is definitely
|
|
||||||
/// not bound in the namespace.
|
|
||||||
UnboundResult,
|
|
||||||
/// Means that resolve has determined that the name is bound in the Module
|
|
||||||
/// argument, and specified by the NameBinding argument.
|
|
||||||
BoundResult(Module<'a>, NameBinding<'a>),
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> NamespaceResult<'a> {
|
|
||||||
fn is_unknown(&self) -> bool {
|
|
||||||
match *self {
|
|
||||||
UnknownResult => true,
|
|
||||||
_ => false,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
fn is_unbound(&self) -> bool {
|
|
||||||
match *self {
|
|
||||||
UnboundResult => true,
|
|
||||||
_ => false,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a, 'v, 'tcx> Visitor<'v> for Resolver<'a, 'tcx> {
|
impl<'a, 'v, 'tcx> Visitor<'v> for Resolver<'a, 'tcx> {
|
||||||
fn visit_nested_item(&mut self, item: hir::ItemId) {
|
fn visit_nested_item(&mut self, item: hir::ItemId) {
|
||||||
self.visit_item(self.ast_map.expect_item(item.id))
|
self.visit_item(self.ast_map.expect_item(item.id))
|
||||||
@ -698,6 +664,7 @@ impl<'a, 'v, 'tcx> Visitor<'v> for Resolver<'a, 'tcx> {
|
|||||||
|
|
||||||
type ErrorMessage = Option<(Span, String)>;
|
type ErrorMessage = Option<(Span, String)>;
|
||||||
|
|
||||||
|
#[derive(Clone, PartialEq, Eq)]
|
||||||
enum ResolveResult<T> {
|
enum ResolveResult<T> {
|
||||||
Failed(ErrorMessage), // Failed to resolve the name, optional helpful error message.
|
Failed(ErrorMessage), // Failed to resolve the name, optional helpful error message.
|
||||||
Indeterminate, // Couldn't determine due to unresolved globs.
|
Indeterminate, // Couldn't determine due to unresolved globs.
|
||||||
@ -835,7 +802,7 @@ pub struct ModuleS<'a> {
|
|||||||
def: Cell<Option<Def>>,
|
def: Cell<Option<Def>>,
|
||||||
is_public: bool,
|
is_public: bool,
|
||||||
|
|
||||||
children: RefCell<HashMap<Name, NameBindings<'a>>>,
|
children: RefCell<HashMap<(Name, Namespace), NameBinding<'a>>>,
|
||||||
imports: RefCell<Vec<ImportDirective>>,
|
imports: RefCell<Vec<ImportDirective>>,
|
||||||
|
|
||||||
// The external module children of this node that were declared with
|
// The external module children of this node that were declared with
|
||||||
@ -859,7 +826,7 @@ pub struct ModuleS<'a> {
|
|||||||
anonymous_children: RefCell<NodeMap<Module<'a>>>,
|
anonymous_children: RefCell<NodeMap<Module<'a>>>,
|
||||||
|
|
||||||
// The status of resolving each import in this module.
|
// The status of resolving each import in this module.
|
||||||
import_resolutions: RefCell<HashMap<Name, ImportResolutionPerNamespace<'a>>>,
|
import_resolutions: RefCell<HashMap<(Name, Namespace), ImportResolution<'a>>>,
|
||||||
|
|
||||||
// The number of unresolved globs that this module exports.
|
// The number of unresolved globs that this module exports.
|
||||||
glob_count: Cell<usize>,
|
glob_count: Cell<usize>,
|
||||||
@ -900,6 +867,17 @@ impl<'a> ModuleS<'a> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn get_child(&self, name: Name, ns: Namespace) -> Option<NameBinding<'a>> {
|
||||||
|
self.children.borrow().get(&(name, ns)).cloned()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn try_define_child(&self, name: Name, ns: Namespace, binding: NameBinding<'a>) -> bool {
|
||||||
|
match self.children.borrow_mut().entry((name, ns)) {
|
||||||
|
hash_map::Entry::Vacant(entry) => { entry.insert(binding); true }
|
||||||
|
hash_map::Entry::Occupied(_) => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn def_id(&self) -> Option<DefId> {
|
fn def_id(&self) -> Option<DefId> {
|
||||||
self.def.get().as_ref().map(Def::def_id)
|
self.def.get().as_ref().map(Def::def_id)
|
||||||
}
|
}
|
||||||
@ -977,20 +955,20 @@ bitflags! {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Records a possibly-private value, type, or module definition.
|
// Records a possibly-private value, type, or module definition.
|
||||||
#[derive(Debug)]
|
#[derive(Clone, Debug)]
|
||||||
struct NsDef<'a> {
|
pub struct NameBinding<'a> {
|
||||||
modifiers: DefModifiers, // see note in ImportResolutionPerNamespace about how to use this
|
modifiers: DefModifiers, // see note in ImportResolution about how to use this
|
||||||
def_or_module: DefOrModule<'a>,
|
def_or_module: DefOrModule<'a>,
|
||||||
span: Option<Span>,
|
span: Option<Span>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Clone, Debug)]
|
||||||
enum DefOrModule<'a> {
|
enum DefOrModule<'a> {
|
||||||
Def(Def),
|
Def(Def),
|
||||||
Module(Module<'a>),
|
Module(Module<'a>),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> NsDef<'a> {
|
impl<'a> NameBinding<'a> {
|
||||||
fn create_from_module(module: Module<'a>, span: Option<Span>) -> Self {
|
fn create_from_module(module: Module<'a>, span: Option<Span>) -> Self {
|
||||||
let modifiers = if module.is_public {
|
let modifiers = if module.is_public {
|
||||||
DefModifiers::PUBLIC
|
DefModifiers::PUBLIC
|
||||||
@ -998,11 +976,7 @@ impl<'a> NsDef<'a> {
|
|||||||
DefModifiers::empty()
|
DefModifiers::empty()
|
||||||
} | DefModifiers::IMPORTABLE;
|
} | DefModifiers::IMPORTABLE;
|
||||||
|
|
||||||
NsDef { modifiers: modifiers, def_or_module: DefOrModule::Module(module), span: span }
|
NameBinding { modifiers: modifiers, def_or_module: DefOrModule::Module(module), span: span }
|
||||||
}
|
|
||||||
|
|
||||||
fn create_from_def(def: Def, modifiers: DefModifiers, span: Option<Span>) -> Self {
|
|
||||||
NsDef { modifiers: modifiers, def_or_module: DefOrModule::Def(def), span: span }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn module(&self) -> Option<Module<'a>> {
|
fn module(&self) -> Option<Module<'a>> {
|
||||||
@ -1018,55 +992,9 @@ impl<'a> NsDef<'a> {
|
|||||||
DefOrModule::Module(ref module) => module.def.get(),
|
DefOrModule::Module(ref module) => module.def.get(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// Records at most one definition that a name in a namespace is bound to
|
|
||||||
#[derive(Clone,Debug)]
|
|
||||||
pub struct NameBinding<'a>(Rc<RefCell<Option<NsDef<'a>>>>);
|
|
||||||
|
|
||||||
impl<'a> NameBinding<'a> {
|
|
||||||
fn new() -> Self {
|
|
||||||
NameBinding(Rc::new(RefCell::new(None)))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn create_from_module(module: Module<'a>) -> Self {
|
|
||||||
NameBinding(Rc::new(RefCell::new(Some(NsDef::create_from_module(module, None)))))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn set(&self, ns_def: NsDef<'a>) {
|
|
||||||
*self.0.borrow_mut() = Some(ns_def);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn set_modifiers(&self, modifiers: DefModifiers) {
|
|
||||||
if let Some(ref mut ns_def) = *self.0.borrow_mut() {
|
|
||||||
ns_def.modifiers = modifiers
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn borrow(&self) -> ::std::cell::Ref<Option<NsDef<'a>>> {
|
|
||||||
self.0.borrow()
|
|
||||||
}
|
|
||||||
|
|
||||||
// Lifted versions of the NsDef methods and fields
|
|
||||||
fn def(&self) -> Option<Def> {
|
|
||||||
self.borrow().as_ref().and_then(NsDef::def)
|
|
||||||
}
|
|
||||||
fn module(&self) -> Option<Module<'a>> {
|
|
||||||
self.borrow().as_ref().and_then(NsDef::module)
|
|
||||||
}
|
|
||||||
fn span(&self) -> Option<Span> {
|
|
||||||
self.borrow().as_ref().and_then(|def| def.span)
|
|
||||||
}
|
|
||||||
fn modifiers(&self) -> Option<DefModifiers> {
|
|
||||||
self.borrow().as_ref().and_then(|def| Some(def.modifiers))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn defined(&self) -> bool {
|
|
||||||
self.borrow().is_some()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn defined_with(&self, modifiers: DefModifiers) -> bool {
|
fn defined_with(&self, modifiers: DefModifiers) -> bool {
|
||||||
self.modifiers().map(|m| m.contains(modifiers)).unwrap_or(false)
|
self.modifiers.contains(modifiers)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_public(&self) -> bool {
|
fn is_public(&self) -> bool {
|
||||||
@ -1079,47 +1007,6 @@ impl<'a> NameBinding<'a> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Records the definitions (at most one for each namespace) that a name is
|
|
||||||
// bound to.
|
|
||||||
#[derive(Clone,Debug)]
|
|
||||||
pub struct NameBindings<'a> {
|
|
||||||
type_ns: NameBinding<'a>, // < Meaning in type namespace.
|
|
||||||
value_ns: NameBinding<'a>, // < Meaning in value namespace.
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> ::std::ops::Index<Namespace> for NameBindings<'a> {
|
|
||||||
type Output = NameBinding<'a>;
|
|
||||||
fn index(&self, namespace: Namespace) -> &NameBinding<'a> {
|
|
||||||
match namespace { TypeNS => &self.type_ns, ValueNS => &self.value_ns }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> NameBindings<'a> {
|
|
||||||
fn new() -> Self {
|
|
||||||
NameBindings {
|
|
||||||
type_ns: NameBinding::new(),
|
|
||||||
value_ns: NameBinding::new(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Creates a new module in this set of name bindings.
|
|
||||||
fn define_module(&self, module: Module<'a>, sp: Span) {
|
|
||||||
self.type_ns.set(NsDef::create_from_module(module, Some(sp)));
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Records a type definition.
|
|
||||||
fn define_type(&self, def: Def, sp: Span, modifiers: DefModifiers) {
|
|
||||||
debug!("defining type for def {:?} with modifiers {:?}", def, modifiers);
|
|
||||||
self.type_ns.set(NsDef::create_from_def(def, modifiers, Some(sp)));
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Records a value definition.
|
|
||||||
fn define_value(&self, def: Def, sp: Span, modifiers: DefModifiers) {
|
|
||||||
debug!("defining value for def {:?} with modifiers {:?}", def, modifiers);
|
|
||||||
self.value_ns.set(NsDef::create_from_def(def, modifiers, Some(sp)));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Interns the names of the primitive types.
|
/// Interns the names of the primitive types.
|
||||||
struct PrimitiveTypeTable {
|
struct PrimitiveTypeTable {
|
||||||
primitive_types: HashMap<Name, PrimTy>,
|
primitive_types: HashMap<Name, PrimTy>,
|
||||||
@ -1333,13 +1220,10 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
|
|||||||
"an external crate named `{}` has already been imported into this module",
|
"an external crate named `{}` has already been imported into this module",
|
||||||
name);
|
name);
|
||||||
}
|
}
|
||||||
match module.children.borrow().get(&name) {
|
if let Some(name_binding) = module.get_child(name, TypeNS) {
|
||||||
Some(name_bindings) if name_bindings.type_ns.defined() => {
|
resolve_error(self,
|
||||||
resolve_error(self,
|
name_binding.span.unwrap_or(codemap::DUMMY_SP),
|
||||||
name_bindings.type_ns.span().unwrap_or(codemap::DUMMY_SP),
|
ResolutionError::NameConflictsWithExternCrate(name));
|
||||||
ResolutionError::NameConflictsWithExternCrate(name));
|
|
||||||
}
|
|
||||||
_ => {},
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1562,25 +1446,18 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
|
|||||||
// its immediate children.
|
// its immediate children.
|
||||||
build_reduced_graph::populate_module_if_necessary(self, &module_);
|
build_reduced_graph::populate_module_if_necessary(self, &module_);
|
||||||
|
|
||||||
match module_.children.borrow().get(&name) {
|
if let Some(binding) = module_.get_child(name, namespace) {
|
||||||
Some(name_bindings) if name_bindings[namespace].defined() => {
|
debug!("top name bindings succeeded");
|
||||||
debug!("top name bindings succeeded");
|
return Success((Target::new(module_, binding, Shadowable::Never), false));
|
||||||
return Success((Target::new(module_,
|
|
||||||
name_bindings[namespace].clone(),
|
|
||||||
Shadowable::Never),
|
|
||||||
false));
|
|
||||||
}
|
|
||||||
Some(_) | None => {
|
|
||||||
// Not found; continue.
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Now check for its import directives. We don't have to have resolved
|
// Now check for its import directives. We don't have to have resolved
|
||||||
// all its imports in the usual way; this is because chains of
|
// all its imports in the usual way; this is because chains of
|
||||||
// adjacent import statements are processed as though they mutated the
|
// adjacent import statements are processed as though they mutated the
|
||||||
// current scope.
|
// current scope.
|
||||||
if let Some(import_resolution) = module_.import_resolutions.borrow().get(&name) {
|
if let Some(import_resolution) =
|
||||||
match import_resolution[namespace].target.clone() {
|
module_.import_resolutions.borrow().get(&(name, namespace)) {
|
||||||
|
match import_resolution.target.clone() {
|
||||||
None => {
|
None => {
|
||||||
// Not found; continue.
|
// Not found; continue.
|
||||||
debug!("(resolving item in lexical scope) found import resolution, but not \
|
debug!("(resolving item in lexical scope) found import resolution, but not \
|
||||||
@ -1590,7 +1467,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
|
|||||||
Some(target) => {
|
Some(target) => {
|
||||||
debug!("(resolving item in lexical scope) using import resolution");
|
debug!("(resolving item in lexical scope) using import resolution");
|
||||||
// track used imports and extern crates as well
|
// track used imports and extern crates as well
|
||||||
let id = import_resolution[namespace].id;
|
let id = import_resolution.id;
|
||||||
if record_used {
|
if record_used {
|
||||||
self.used_imports.insert((id, namespace));
|
self.used_imports.insert((id, namespace));
|
||||||
self.record_import_use(id, name);
|
self.record_import_use(id, name);
|
||||||
@ -1607,7 +1484,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
|
|||||||
if namespace == TypeNS {
|
if namespace == TypeNS {
|
||||||
let children = module_.external_module_children.borrow();
|
let children = module_.external_module_children.borrow();
|
||||||
if let Some(module) = children.get(&name) {
|
if let Some(module) = children.get(&name) {
|
||||||
let name_binding = NameBinding::create_from_module(module);
|
let name_binding = NameBinding::create_from_module(module, None);
|
||||||
debug!("lower name bindings succeeded");
|
debug!("lower name bindings succeeded");
|
||||||
return Success((Target::new(module_, name_binding, Shadowable::Never),
|
return Success((Target::new(module_, name_binding, Shadowable::Never),
|
||||||
false));
|
false));
|
||||||
@ -1774,32 +1651,19 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
|
|||||||
// First, check the direct children of the module.
|
// First, check the direct children of the module.
|
||||||
build_reduced_graph::populate_module_if_necessary(self, &module_);
|
build_reduced_graph::populate_module_if_necessary(self, &module_);
|
||||||
|
|
||||||
let children = module_.children.borrow();
|
if let Some(binding) = module_.get_child(name, namespace) {
|
||||||
match children.get(&name) {
|
debug!("(resolving name in module) found node as child");
|
||||||
Some(name_bindings) if name_bindings[namespace].defined() => {
|
return Success((Target::new(module_, binding, Shadowable::Never), false));
|
||||||
debug!("(resolving name in module) found node as child");
|
|
||||||
return Success((Target::new(module_,
|
|
||||||
name_bindings[namespace].clone(),
|
|
||||||
Shadowable::Never),
|
|
||||||
false));
|
|
||||||
}
|
|
||||||
Some(_) | None => {
|
|
||||||
// Continue.
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check the list of resolved imports.
|
// Check the list of resolved imports.
|
||||||
let children = module_.import_resolutions.borrow();
|
match module_.import_resolutions.borrow().get(&(name, namespace)) {
|
||||||
match children.get(&name) {
|
Some(import_resolution) if allow_private_imports || import_resolution.is_public => {
|
||||||
Some(import_resolution) if allow_private_imports ||
|
if import_resolution.is_public && import_resolution.outstanding_references != 0 {
|
||||||
import_resolution[namespace].is_public => {
|
|
||||||
|
|
||||||
if import_resolution[namespace].is_public &&
|
|
||||||
import_resolution.outstanding_references != 0 {
|
|
||||||
debug!("(resolving name in module) import unresolved; bailing out");
|
debug!("(resolving name in module) import unresolved; bailing out");
|
||||||
return Indeterminate;
|
return Indeterminate;
|
||||||
}
|
}
|
||||||
match import_resolution[namespace].target.clone() {
|
match import_resolution.target.clone() {
|
||||||
None => {
|
None => {
|
||||||
debug!("(resolving name in module) name found, but not in namespace {:?}",
|
debug!("(resolving name in module) name found, but not in namespace {:?}",
|
||||||
namespace);
|
namespace);
|
||||||
@ -1807,7 +1671,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
|
|||||||
Some(target) => {
|
Some(target) => {
|
||||||
debug!("(resolving name in module) resolved to import");
|
debug!("(resolving name in module) resolved to import");
|
||||||
// track used imports and extern crates as well
|
// track used imports and extern crates as well
|
||||||
let id = import_resolution[namespace].id;
|
let id = import_resolution.id;
|
||||||
self.used_imports.insert((id, namespace));
|
self.used_imports.insert((id, namespace));
|
||||||
self.record_import_use(id, name);
|
self.record_import_use(id, name);
|
||||||
if let Some(DefId{krate: kid, ..}) = target.target_module.def_id() {
|
if let Some(DefId{krate: kid, ..}) = target.target_module.def_id() {
|
||||||
@ -1824,7 +1688,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
|
|||||||
if namespace == TypeNS {
|
if namespace == TypeNS {
|
||||||
let children = module_.external_module_children.borrow();
|
let children = module_.external_module_children.borrow();
|
||||||
if let Some(module) = children.get(&name) {
|
if let Some(module) = children.get(&name) {
|
||||||
let name_binding = NameBinding::create_from_module(module);
|
let name_binding = NameBinding::create_from_module(module, None);
|
||||||
return Success((Target::new(module_, name_binding, Shadowable::Never),
|
return Success((Target::new(module_, name_binding, Shadowable::Never),
|
||||||
false));
|
false));
|
||||||
}
|
}
|
||||||
@ -1849,7 +1713,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
|
|||||||
build_reduced_graph::populate_module_if_necessary(self, &module_);
|
build_reduced_graph::populate_module_if_necessary(self, &module_);
|
||||||
|
|
||||||
for (_, child_node) in module_.children.borrow().iter() {
|
for (_, child_node) in module_.children.borrow().iter() {
|
||||||
match child_node.type_ns.module() {
|
match child_node.module() {
|
||||||
None => {
|
None => {
|
||||||
// Continue.
|
// Continue.
|
||||||
}
|
}
|
||||||
@ -1895,14 +1759,14 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
|
|||||||
Some(name) => {
|
Some(name) => {
|
||||||
build_reduced_graph::populate_module_if_necessary(self, &orig_module);
|
build_reduced_graph::populate_module_if_necessary(self, &orig_module);
|
||||||
|
|
||||||
match orig_module.children.borrow().get(&name) {
|
match orig_module.get_child(name, TypeNS) {
|
||||||
None => {
|
None => {
|
||||||
debug!("!!! (with scope) didn't find `{}` in `{}`",
|
debug!("!!! (with scope) didn't find `{}` in `{}`",
|
||||||
name,
|
name,
|
||||||
module_to_string(&*orig_module));
|
module_to_string(&*orig_module));
|
||||||
}
|
}
|
||||||
Some(name_bindings) => {
|
Some(name_binding) => {
|
||||||
match name_bindings.type_ns.module() {
|
match name_binding.module() {
|
||||||
None => {
|
None => {
|
||||||
debug!("!!! (with scope) didn't find module for `{}` in `{}`",
|
debug!("!!! (with scope) didn't find module for `{}` in `{}`",
|
||||||
name,
|
name,
|
||||||
@ -2858,7 +2722,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
|
|||||||
Success((target, _)) => {
|
Success((target, _)) => {
|
||||||
debug!("(resolve bare identifier pattern) succeeded in finding {} at {:?}",
|
debug!("(resolve bare identifier pattern) succeeded in finding {} at {:?}",
|
||||||
name,
|
name,
|
||||||
target.binding.borrow());
|
&target.binding);
|
||||||
match target.binding.def() {
|
match target.binding.def() {
|
||||||
None => {
|
None => {
|
||||||
panic!("resolved name in the value namespace to a set of name bindings \
|
panic!("resolved name in the value namespace to a set of name bindings \
|
||||||
@ -3331,12 +3195,9 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
|
|||||||
if name_path.len() == 1 {
|
if name_path.len() == 1 {
|
||||||
match this.primitive_type_table.primitive_types.get(last_name) {
|
match this.primitive_type_table.primitive_types.get(last_name) {
|
||||||
Some(_) => None,
|
Some(_) => None,
|
||||||
None => {
|
None => this.current_module.get_child(*last_name, TypeNS)
|
||||||
match this.current_module.children.borrow().get(last_name) {
|
.as_ref()
|
||||||
Some(child) => child.type_ns.module(),
|
.and_then(NameBinding::module)
|
||||||
None => None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
match this.resolve_module_path(root, &name_path, UseLexicalScope, span) {
|
match this.resolve_module_path(root, &name_path, UseLexicalScope, span) {
|
||||||
@ -3395,8 +3256,8 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
|
|||||||
|
|
||||||
// Look for a method in the current self type's impl module.
|
// Look for a method in the current self type's impl module.
|
||||||
if let Some(module) = get_module(self, path.span, &name_path) {
|
if let Some(module) = get_module(self, path.span, &name_path) {
|
||||||
if let Some(binding) = module.children.borrow().get(&name) {
|
if let Some(binding) = module.get_child(name, ValueNS) {
|
||||||
if let Some(Def::Method(did)) = binding.value_ns.def() {
|
if let Some(Def::Method(did)) = binding.def() {
|
||||||
if is_static_method(self, did) {
|
if is_static_method(self, did) {
|
||||||
return StaticMethod(path_names_to_string(&path, 0));
|
return StaticMethod(path_names_to_string(&path, 0));
|
||||||
}
|
}
|
||||||
@ -3718,27 +3579,23 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
|
|||||||
// Look for trait children.
|
// Look for trait children.
|
||||||
build_reduced_graph::populate_module_if_necessary(self, &search_module);
|
build_reduced_graph::populate_module_if_necessary(self, &search_module);
|
||||||
|
|
||||||
{
|
for (&(_, ns), name_binding) in search_module.children.borrow().iter() {
|
||||||
for (_, child_names) in search_module.children.borrow().iter() {
|
if ns != TypeNS { continue }
|
||||||
let def = match child_names.type_ns.def() {
|
let trait_def_id = match name_binding.def() {
|
||||||
Some(def) => def,
|
Some(Def::Trait(trait_def_id)) => trait_def_id,
|
||||||
None => continue,
|
Some(..) | None => continue,
|
||||||
};
|
};
|
||||||
let trait_def_id = match def {
|
if self.trait_item_map.contains_key(&(name, trait_def_id)) {
|
||||||
Def::Trait(trait_def_id) => trait_def_id,
|
add_trait_info(&mut found_traits, trait_def_id, name);
|
||||||
_ => continue,
|
|
||||||
};
|
|
||||||
if self.trait_item_map.contains_key(&(name, trait_def_id)) {
|
|
||||||
add_trait_info(&mut found_traits, trait_def_id, name);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Look for imports.
|
// Look for imports.
|
||||||
for (_, import) in search_module.import_resolutions.borrow().iter() {
|
for (&(_, ns), import) in search_module.import_resolutions.borrow().iter() {
|
||||||
let target = match import.type_ns.target {
|
if ns != TypeNS { continue }
|
||||||
None => continue,
|
let target = match import.target {
|
||||||
Some(ref target) => target,
|
Some(ref target) => target,
|
||||||
|
None => continue,
|
||||||
};
|
};
|
||||||
let did = match target.binding.def() {
|
let did = match target.binding.def() {
|
||||||
Some(Def::Trait(trait_def_id)) => trait_def_id,
|
Some(Def::Trait(trait_def_id)) => trait_def_id,
|
||||||
@ -3746,7 +3603,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
|
|||||||
};
|
};
|
||||||
if self.trait_item_map.contains_key(&(name, did)) {
|
if self.trait_item_map.contains_key(&(name, did)) {
|
||||||
add_trait_info(&mut found_traits, did, name);
|
add_trait_info(&mut found_traits, did, name);
|
||||||
let id = import.type_ns.id;
|
let id = import.id;
|
||||||
self.used_imports.insert((id, TypeNS));
|
self.used_imports.insert((id, TypeNS));
|
||||||
let trait_name = self.get_trait_name(did);
|
let trait_name = self.get_trait_name(did);
|
||||||
self.record_import_use(id, trait_name);
|
self.record_import_use(id, trait_name);
|
||||||
@ -3797,52 +3654,6 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
|
||||||
// Diagnostics
|
|
||||||
//
|
|
||||||
// Diagnostics are not particularly efficient, because they're rarely
|
|
||||||
// hit.
|
|
||||||
//
|
|
||||||
|
|
||||||
#[allow(dead_code)] // useful for debugging
|
|
||||||
fn dump_module(&mut self, module_: Module<'a>) {
|
|
||||||
debug!("Dump of module `{}`:", module_to_string(&*module_));
|
|
||||||
|
|
||||||
debug!("Children:");
|
|
||||||
build_reduced_graph::populate_module_if_necessary(self, &module_);
|
|
||||||
for (&name, _) in module_.children.borrow().iter() {
|
|
||||||
debug!("* {}", name);
|
|
||||||
}
|
|
||||||
|
|
||||||
debug!("Import resolutions:");
|
|
||||||
let import_resolutions = module_.import_resolutions.borrow();
|
|
||||||
for (&name, import_resolution) in import_resolutions.iter() {
|
|
||||||
let value_repr;
|
|
||||||
match import_resolution.value_ns.target {
|
|
||||||
None => {
|
|
||||||
value_repr = "".to_string();
|
|
||||||
}
|
|
||||||
Some(_) => {
|
|
||||||
value_repr = " value:?".to_string();
|
|
||||||
// FIXME #4954
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let type_repr;
|
|
||||||
match import_resolution.type_ns.target {
|
|
||||||
None => {
|
|
||||||
type_repr = "".to_string();
|
|
||||||
}
|
|
||||||
Some(_) => {
|
|
||||||
type_repr = " type:?".to_string();
|
|
||||||
// FIXME #4954
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
debug!("* {}:{}{}", name, value_repr, type_repr);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -13,10 +13,9 @@ use self::ImportDirectiveSubclass::*;
|
|||||||
use DefModifiers;
|
use DefModifiers;
|
||||||
use Module;
|
use Module;
|
||||||
use Namespace::{self, TypeNS, ValueNS};
|
use Namespace::{self, TypeNS, ValueNS};
|
||||||
use {NameBindings, NameBinding};
|
use NameBinding;
|
||||||
use NamespaceResult::{BoundResult, UnboundResult, UnknownResult};
|
|
||||||
use NamespaceResult;
|
|
||||||
use ResolveResult;
|
use ResolveResult;
|
||||||
|
use ResolveResult::*;
|
||||||
use Resolver;
|
use Resolver;
|
||||||
use UseLexicalScopeFlag;
|
use UseLexicalScopeFlag;
|
||||||
use {names_to_string, module_to_string};
|
use {names_to_string, module_to_string};
|
||||||
@ -100,26 +99,20 @@ impl<'a> Target<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
/// An ImportResolutionPerNamespace records what we know about an imported name.
|
/// An ImportResolution records what we know about an imported name in a given namespace.
|
||||||
/// More specifically, it records the number of unresolved `use` directives that import the name,
|
/// More specifically, it records the number of unresolved `use` directives that import the name,
|
||||||
/// and for each namespace, it records the `use` directive importing the name in the namespace
|
/// the `use` directive importing the name in the namespace, and the `NameBinding` to which the
|
||||||
/// and the `Target` to which the name in the namespace resolves (if applicable).
|
/// name in the namespace resolves (if applicable).
|
||||||
/// Different `use` directives may import the same name in different namespaces.
|
/// Different `use` directives may import the same name in different namespaces.
|
||||||
pub struct ImportResolutionPerNamespace<'a> {
|
pub struct ImportResolution<'a> {
|
||||||
// When outstanding_references reaches zero, outside modules can count on the targets being
|
// When outstanding_references reaches zero, outside modules can count on the targets being
|
||||||
// correct. Before then, all bets are off; future `use` directives could override the name.
|
// correct. Before then, all bets are off; future `use` directives could override the name.
|
||||||
// Since shadowing is forbidden, the only way outstanding_references > 1 in a legal program
|
// Since shadowing is forbidden, the only way outstanding_references > 1 in a legal program
|
||||||
// is if the name is imported by exactly two `use` directives, one of which resolves to a
|
// is if the name is imported by exactly two `use` directives, one of which resolves to a
|
||||||
// value and the other of which resolves to a type.
|
// value and the other of which resolves to a type.
|
||||||
pub outstanding_references: usize,
|
pub outstanding_references: usize,
|
||||||
pub type_ns: ImportResolution<'a>,
|
|
||||||
pub value_ns: ImportResolution<'a>,
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Records what we know about an imported name in a namespace (see `ImportResolutionPerNamespace`).
|
/// Whether this resolution came from a `use` or a `pub use`.
|
||||||
#[derive(Clone,Debug)]
|
|
||||||
pub struct ImportResolution<'a> {
|
|
||||||
/// Whether the name in the namespace was imported with a `use` or a `pub use`.
|
|
||||||
pub is_public: bool,
|
pub is_public: bool,
|
||||||
|
|
||||||
/// Resolution of the name in the namespace
|
/// Resolution of the name in the namespace
|
||||||
@ -129,29 +122,18 @@ pub struct ImportResolution<'a> {
|
|||||||
pub id: NodeId,
|
pub id: NodeId,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> ::std::ops::Index<Namespace> for ImportResolutionPerNamespace<'a> {
|
impl<'a> ImportResolution<'a> {
|
||||||
type Output = ImportResolution<'a>;
|
|
||||||
fn index(&self, ns: Namespace) -> &ImportResolution<'a> {
|
|
||||||
match ns { TypeNS => &self.type_ns, ValueNS => &self.value_ns }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> ::std::ops::IndexMut<Namespace> for ImportResolutionPerNamespace<'a> {
|
|
||||||
fn index_mut(&mut self, ns: Namespace) -> &mut ImportResolution<'a> {
|
|
||||||
match ns { TypeNS => &mut self.type_ns, ValueNS => &mut self.value_ns }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> ImportResolutionPerNamespace<'a> {
|
|
||||||
pub fn new(id: NodeId, is_public: bool) -> Self {
|
pub fn new(id: NodeId, is_public: bool) -> Self {
|
||||||
let resolution = ImportResolution { id: id, is_public: is_public, target: None };
|
ImportResolution {
|
||||||
ImportResolutionPerNamespace {
|
outstanding_references: 0,
|
||||||
outstanding_references: 0, type_ns: resolution.clone(), value_ns: resolution,
|
id: id,
|
||||||
|
target: None,
|
||||||
|
is_public: is_public,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn shadowable(&self, namespace: Namespace) -> Shadowable {
|
pub fn shadowable(&self) -> Shadowable {
|
||||||
match self[namespace].target {
|
match self.target {
|
||||||
Some(ref target) => target.shadowable,
|
Some(ref target) => target.shadowable,
|
||||||
None => Shadowable::Always,
|
None => Shadowable::Always,
|
||||||
}
|
}
|
||||||
@ -232,7 +214,7 @@ impl<'a, 'b:'a, 'tcx:'b> ImportResolver<'a, 'b, 'tcx> {
|
|||||||
|
|
||||||
build_reduced_graph::populate_module_if_necessary(self.resolver, &module_);
|
build_reduced_graph::populate_module_if_necessary(self.resolver, &module_);
|
||||||
for (_, child_node) in module_.children.borrow().iter() {
|
for (_, child_node) in module_.children.borrow().iter() {
|
||||||
match child_node.type_ns.module() {
|
match child_node.module() {
|
||||||
None => {
|
None => {
|
||||||
// Nothing to do.
|
// Nothing to do.
|
||||||
}
|
}
|
||||||
@ -393,6 +375,80 @@ impl<'a, 'b:'a, 'tcx:'b> ImportResolver<'a, 'b, 'tcx> {
|
|||||||
return resolution_result;
|
return resolution_result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Resolves the name in the namespace of the module because it is being imported by
|
||||||
|
/// importing_module. Returns the module in which the name was defined (as opposed to imported),
|
||||||
|
/// the name bindings defining the name, and whether or not the name was imported into `module`.
|
||||||
|
fn resolve_name_in_module(&mut self,
|
||||||
|
module: Module<'b>, // Module containing the name
|
||||||
|
name: Name,
|
||||||
|
ns: Namespace,
|
||||||
|
importing_module: Module<'b>) // Module importing the name
|
||||||
|
-> (ResolveResult<(Module<'b>, NameBinding<'b>)>, bool) {
|
||||||
|
build_reduced_graph::populate_module_if_necessary(self.resolver, module);
|
||||||
|
if let Some(name_binding) = module.get_child(name, ns) {
|
||||||
|
return (Success((module, name_binding)), false);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ns == TypeNS {
|
||||||
|
if let Some(extern_crate) = module.external_module_children.borrow().get(&name) {
|
||||||
|
// track the extern crate as used.
|
||||||
|
if let Some(DefId{ krate: kid, .. }) = extern_crate.def_id() {
|
||||||
|
self.resolver.used_crates.insert(kid);
|
||||||
|
}
|
||||||
|
let name_binding = NameBinding::create_from_module(extern_crate, None);
|
||||||
|
return (Success((module, name_binding)), false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If there is an unresolved glob at this point in the containing module, bail out.
|
||||||
|
// We don't know enough to be able to resolve the name.
|
||||||
|
if module.pub_glob_count.get() > 0 {
|
||||||
|
return (Indeterminate, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
match module.import_resolutions.borrow().get(&(name, ns)) {
|
||||||
|
// The containing module definitely doesn't have an exported import with the
|
||||||
|
// name in question. We can therefore accurately report that names are unbound.
|
||||||
|
None => (Failed(None), false),
|
||||||
|
|
||||||
|
// The name is an import which has been fully resolved, so we just follow it.
|
||||||
|
Some(resolution) if resolution.outstanding_references == 0 => {
|
||||||
|
// Import resolutions must be declared with "pub" in order to be exported.
|
||||||
|
if !resolution.is_public {
|
||||||
|
return (Failed(None), false);
|
||||||
|
}
|
||||||
|
|
||||||
|
let target = resolution.target.clone();
|
||||||
|
if let Some(Target { target_module, binding, shadowable: _ }) = target {
|
||||||
|
// track used imports and extern crates as well
|
||||||
|
self.resolver.used_imports.insert((resolution.id, ns));
|
||||||
|
self.resolver.record_import_use(resolution.id, name);
|
||||||
|
if let Some(DefId { krate, .. }) = target_module.def_id() {
|
||||||
|
self.resolver.used_crates.insert(krate);
|
||||||
|
}
|
||||||
|
(Success((target_module, binding)), true)
|
||||||
|
} else {
|
||||||
|
(Failed(None), false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If module is the same module whose import we are resolving and
|
||||||
|
// it has an unresolved import with the same name as `name`, then the user
|
||||||
|
// is actually trying to import an item that is declared in the same scope
|
||||||
|
//
|
||||||
|
// e.g
|
||||||
|
// use self::submodule;
|
||||||
|
// pub mod submodule;
|
||||||
|
//
|
||||||
|
// In this case we continue as if we resolved the import and let
|
||||||
|
// check_for_conflicts_between_imports_and_items handle the conflict
|
||||||
|
Some(_) => match (importing_module.def_id(), module.def_id()) {
|
||||||
|
(Some(id1), Some(id2)) if id1 == id2 => (Failed(None), false),
|
||||||
|
_ => (Indeterminate, false)
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn resolve_single_import(&mut self,
|
fn resolve_single_import(&mut self,
|
||||||
module_: Module<'b>,
|
module_: Module<'b>,
|
||||||
target_module: Module<'b>,
|
target_module: Module<'b>,
|
||||||
@ -420,253 +476,86 @@ impl<'a, 'b:'a, 'tcx:'b> ImportResolver<'a, 'b, 'tcx> {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// We need to resolve both namespaces for this to succeed.
|
// We need to resolve both namespaces for this to succeed.
|
||||||
|
let (value_result, value_used_reexport) =
|
||||||
|
self.resolve_name_in_module(&target_module, source, ValueNS, module_);
|
||||||
|
let (type_result, type_used_reexport) =
|
||||||
|
self.resolve_name_in_module(&target_module, source, TypeNS, module_);
|
||||||
|
|
||||||
let mut value_result = UnknownResult;
|
match (&value_result, &type_result) {
|
||||||
let mut type_result = UnknownResult;
|
(&Success((_, ref name_binding)), _) if !value_used_reexport &&
|
||||||
let mut lev_suggestion = "".to_owned();
|
directive.is_public &&
|
||||||
|
!name_binding.is_public() => {
|
||||||
|
let msg = format!("`{}` is private, and cannot be reexported", source);
|
||||||
|
let note_msg = format!("Consider marking `{}` as `pub` in the imported module",
|
||||||
|
source);
|
||||||
|
struct_span_err!(self.resolver.session, directive.span, E0364, "{}", &msg)
|
||||||
|
.span_note(directive.span, ¬e_msg)
|
||||||
|
.emit();
|
||||||
|
}
|
||||||
|
|
||||||
// Search for direct children of the containing module.
|
(_, &Success((_, ref name_binding))) if !type_used_reexport &&
|
||||||
build_reduced_graph::populate_module_if_necessary(self.resolver, &target_module);
|
directive.is_public => {
|
||||||
|
if !name_binding.is_public() {
|
||||||
match target_module.children.borrow().get(&source) {
|
let msg = format!("`{}` is private, and cannot be reexported", source);
|
||||||
None => {
|
let note_msg =
|
||||||
let names = target_module.children.borrow();
|
format!("Consider declaring type or module `{}` with `pub`", source);
|
||||||
if let Some(name) = find_best_match_for_name(names.keys(),
|
struct_span_err!(self.resolver.session, directive.span, E0365, "{}", &msg)
|
||||||
&source.as_str(),
|
.span_note(directive.span, ¬e_msg)
|
||||||
None) {
|
.emit();
|
||||||
lev_suggestion = format!(". Did you mean to use `{}`?", name);
|
} else if name_binding.defined_with(DefModifiers::PRIVATE_VARIANT) {
|
||||||
}
|
let msg = format!("variant `{}` is private, and cannot be reexported \
|
||||||
}
|
(error E0364), consider declaring its enum as `pub`",
|
||||||
Some(ref child_name_bindings) => {
|
source);
|
||||||
// pub_err makes sure we don't give the same error twice.
|
self.resolver.session.add_lint(lint::builtin::PRIVATE_IN_PUBLIC,
|
||||||
let mut pub_err = false;
|
directive.id,
|
||||||
if child_name_bindings.value_ns.defined() {
|
directive.span,
|
||||||
debug!("(resolving single import) found value binding");
|
msg);
|
||||||
value_result = BoundResult(target_module,
|
|
||||||
child_name_bindings.value_ns.clone());
|
|
||||||
if directive.is_public && !child_name_bindings.value_ns.is_public() {
|
|
||||||
let msg = format!("`{}` is private, and cannot be reexported", source);
|
|
||||||
let note_msg = format!("Consider marking `{}` as `pub` in the imported \
|
|
||||||
module",
|
|
||||||
source);
|
|
||||||
struct_span_err!(self.resolver.session, directive.span, E0364, "{}", &msg)
|
|
||||||
.span_note(directive.span, ¬e_msg)
|
|
||||||
.emit();
|
|
||||||
pub_err = true;
|
|
||||||
}
|
|
||||||
if directive.is_public && child_name_bindings.value_ns.
|
|
||||||
defined_with(DefModifiers::PRIVATE_VARIANT) {
|
|
||||||
let msg = format!("variant `{}` is private, and cannot be reexported ( \
|
|
||||||
error E0364), consider declaring its enum as `pub`",
|
|
||||||
source);
|
|
||||||
self.resolver.session.add_lint(lint::builtin::PRIVATE_IN_PUBLIC,
|
|
||||||
directive.id,
|
|
||||||
directive.span,
|
|
||||||
msg);
|
|
||||||
pub_err = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if child_name_bindings.type_ns.defined() {
|
|
||||||
debug!("(resolving single import) found type binding");
|
|
||||||
type_result = BoundResult(target_module,
|
|
||||||
child_name_bindings.type_ns.clone());
|
|
||||||
if !pub_err && directive.is_public &&
|
|
||||||
!child_name_bindings.type_ns.is_public() {
|
|
||||||
let msg = format!("`{}` is private, and cannot be reexported", source);
|
|
||||||
let note_msg = format!("Consider declaring module `{}` as a `pub mod`",
|
|
||||||
source);
|
|
||||||
struct_span_err!(self.resolver.session, directive.span, E0365, "{}", &msg)
|
|
||||||
.span_note(directive.span, ¬e_msg)
|
|
||||||
.emit();
|
|
||||||
}
|
|
||||||
if !pub_err && directive.is_public && child_name_bindings.type_ns.
|
|
||||||
defined_with(DefModifiers::PRIVATE_VARIANT) {
|
|
||||||
let msg = format!("variant `{}` is private, and cannot be reexported ( \
|
|
||||||
error E0365), consider declaring its enum as `pub`",
|
|
||||||
source);
|
|
||||||
self.resolver.session.add_lint(lint::builtin::PRIVATE_IN_PUBLIC,
|
|
||||||
directive.id,
|
|
||||||
directive.span,
|
|
||||||
msg);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_ => {}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Unless we managed to find a result in both namespaces (unlikely),
|
let mut lev_suggestion = "".to_owned();
|
||||||
// search imports as well.
|
match (&value_result, &type_result) {
|
||||||
let mut value_used_reexport = false;
|
(&Indeterminate, _) | (_, &Indeterminate) => return Indeterminate,
|
||||||
let mut type_used_reexport = false;
|
(&Failed(_), &Failed(_)) => {
|
||||||
match (value_result.clone(), type_result.clone()) {
|
let children = target_module.children.borrow();
|
||||||
(BoundResult(..), BoundResult(..)) => {} // Continue.
|
let names = children.keys().map(|&(ref name, _)| name);
|
||||||
_ => {
|
if let Some(name) = find_best_match_for_name(names, &source.as_str(), None) {
|
||||||
// If there is an unresolved glob at this point in the
|
lev_suggestion = format!(". Did you mean to use `{}`?", name);
|
||||||
// containing module, bail out. We don't know enough to be
|
} else {
|
||||||
// able to resolve this import.
|
let resolutions = target_module.import_resolutions.borrow();
|
||||||
|
let names = resolutions.keys().map(|&(ref name, _)| name);
|
||||||
if target_module.pub_glob_count.get() > 0 {
|
if let Some(name) = find_best_match_for_name(names,
|
||||||
debug!("(resolving single import) unresolved pub glob; bailing out");
|
&source.as_str(),
|
||||||
return ResolveResult::Indeterminate;
|
None) {
|
||||||
}
|
lev_suggestion =
|
||||||
|
format!(". Did you mean to use the re-exported import `{}`?", name);
|
||||||
// Now search the exported imports within the containing module.
|
|
||||||
match target_module.import_resolutions.borrow().get(&source) {
|
|
||||||
None => {
|
|
||||||
debug!("(resolving single import) no import");
|
|
||||||
// The containing module definitely doesn't have an
|
|
||||||
// exported import with the name in question. We can
|
|
||||||
// therefore accurately report that the names are
|
|
||||||
// unbound.
|
|
||||||
|
|
||||||
if lev_suggestion.is_empty() { // skip if we already have a suggestion
|
|
||||||
let names = target_module.import_resolutions.borrow();
|
|
||||||
if let Some(name) = find_best_match_for_name(names.keys(),
|
|
||||||
&source.as_str(),
|
|
||||||
None) {
|
|
||||||
lev_suggestion =
|
|
||||||
format!(". Did you mean to use the re-exported import `{}`?",
|
|
||||||
name);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if value_result.is_unknown() {
|
|
||||||
value_result = UnboundResult;
|
|
||||||
}
|
|
||||||
if type_result.is_unknown() {
|
|
||||||
type_result = UnboundResult;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Some(import_resolution) if import_resolution.outstanding_references == 0 => {
|
|
||||||
|
|
||||||
fn get_binding<'a>(this: &mut Resolver,
|
|
||||||
import_resolution: &ImportResolutionPerNamespace<'a>,
|
|
||||||
namespace: Namespace,
|
|
||||||
source: Name)
|
|
||||||
-> NamespaceResult<'a> {
|
|
||||||
|
|
||||||
// Import resolutions must be declared with "pub"
|
|
||||||
// in order to be exported.
|
|
||||||
if !import_resolution[namespace].is_public {
|
|
||||||
return UnboundResult;
|
|
||||||
}
|
|
||||||
|
|
||||||
match import_resolution[namespace].target.clone() {
|
|
||||||
None => {
|
|
||||||
return UnboundResult;
|
|
||||||
}
|
|
||||||
Some(Target {
|
|
||||||
target_module,
|
|
||||||
binding,
|
|
||||||
shadowable: _
|
|
||||||
}) => {
|
|
||||||
debug!("(resolving single import) found import in ns {:?}",
|
|
||||||
namespace);
|
|
||||||
let id = import_resolution[namespace].id;
|
|
||||||
// track used imports and extern crates as well
|
|
||||||
this.used_imports.insert((id, namespace));
|
|
||||||
this.record_import_use(id, source);
|
|
||||||
match target_module.def_id() {
|
|
||||||
Some(DefId{krate: kid, ..}) => {
|
|
||||||
this.used_crates.insert(kid);
|
|
||||||
}
|
|
||||||
_ => {}
|
|
||||||
}
|
|
||||||
return BoundResult(target_module, binding);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// The name is an import which has been fully
|
|
||||||
// resolved. We can, therefore, just follow it.
|
|
||||||
if value_result.is_unknown() {
|
|
||||||
value_result = get_binding(self.resolver,
|
|
||||||
import_resolution,
|
|
||||||
ValueNS,
|
|
||||||
source);
|
|
||||||
value_used_reexport = import_resolution.value_ns.is_public;
|
|
||||||
}
|
|
||||||
if type_result.is_unknown() {
|
|
||||||
type_result = get_binding(self.resolver,
|
|
||||||
import_resolution,
|
|
||||||
TypeNS,
|
|
||||||
source);
|
|
||||||
type_used_reexport = import_resolution.type_ns.is_public;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
Some(_) => {
|
|
||||||
// If target_module is the same module whose import we are resolving
|
|
||||||
// and there it has an unresolved import with the same name as `source`,
|
|
||||||
// then the user is actually trying to import an item that is declared
|
|
||||||
// in the same scope
|
|
||||||
//
|
|
||||||
// e.g
|
|
||||||
// use self::submodule;
|
|
||||||
// pub mod submodule;
|
|
||||||
//
|
|
||||||
// In this case we continue as if we resolved the import and let the
|
|
||||||
// check_for_conflicts_between_imports_and_items call below handle
|
|
||||||
// the conflict
|
|
||||||
match (module_.def_id(), target_module.def_id()) {
|
|
||||||
(Some(id1), Some(id2)) if id1 == id2 => {
|
|
||||||
if value_result.is_unknown() {
|
|
||||||
value_result = UnboundResult;
|
|
||||||
}
|
|
||||||
if type_result.is_unknown() {
|
|
||||||
type_result = UnboundResult;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => {
|
|
||||||
// The import is unresolved. Bail out.
|
|
||||||
debug!("(resolving single import) unresolved import; bailing out");
|
|
||||||
return ResolveResult::Indeterminate;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
_ => (),
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut value_used_public = false;
|
let mut value_used_public = false;
|
||||||
let mut type_used_public = false;
|
let mut type_used_public = false;
|
||||||
|
|
||||||
// If we didn't find a result in the type namespace, search the
|
|
||||||
// external modules.
|
|
||||||
match type_result {
|
|
||||||
BoundResult(..) => {}
|
|
||||||
_ => {
|
|
||||||
match target_module.external_module_children.borrow_mut().get(&source) {
|
|
||||||
None => {} // Continue.
|
|
||||||
Some(module) => {
|
|
||||||
debug!("(resolving single import) found external module");
|
|
||||||
// track the module as used.
|
|
||||||
match module.def_id() {
|
|
||||||
Some(DefId{krate: kid, ..}) => {
|
|
||||||
self.resolver.used_crates.insert(kid);
|
|
||||||
}
|
|
||||||
_ => {}
|
|
||||||
}
|
|
||||||
let name_binding = NameBinding::create_from_module(module);
|
|
||||||
type_result = BoundResult(target_module, name_binding);
|
|
||||||
type_used_public = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// We've successfully resolved the import. Write the results in.
|
// We've successfully resolved the import. Write the results in.
|
||||||
let mut import_resolutions = module_.import_resolutions.borrow_mut();
|
let mut import_resolutions = module_.import_resolutions.borrow_mut();
|
||||||
let import_resolution = import_resolutions.get_mut(&target).unwrap();
|
|
||||||
|
|
||||||
{
|
{
|
||||||
let mut check_and_write_import = |namespace, result: &_, used_public: &mut bool| {
|
let mut check_and_write_import = |namespace, result, used_public: &mut bool| {
|
||||||
|
let result: &ResolveResult<(Module<'b>, NameBinding)> = result;
|
||||||
|
|
||||||
|
let import_resolution = import_resolutions.get_mut(&(target, namespace)).unwrap();
|
||||||
let namespace_name = match namespace {
|
let namespace_name = match namespace {
|
||||||
TypeNS => "type",
|
TypeNS => "type",
|
||||||
ValueNS => "value",
|
ValueNS => "value",
|
||||||
};
|
};
|
||||||
|
|
||||||
match *result {
|
match *result {
|
||||||
BoundResult(ref target_module, ref name_binding) => {
|
Success((ref target_module, ref name_binding)) => {
|
||||||
debug!("(resolving single import) found {:?} target: {:?}",
|
debug!("(resolving single import) found {:?} target: {:?}",
|
||||||
namespace_name,
|
namespace_name,
|
||||||
name_binding.def());
|
name_binding.def());
|
||||||
@ -679,67 +568,68 @@ impl<'a, 'b:'a, 'tcx:'b> ImportResolver<'a, 'b, 'tcx> {
|
|||||||
directive.span,
|
directive.span,
|
||||||
target);
|
target);
|
||||||
|
|
||||||
import_resolution[namespace] = ImportResolution {
|
import_resolution.target = Some(Target::new(target_module,
|
||||||
target: Some(Target::new(target_module,
|
name_binding.clone(),
|
||||||
name_binding.clone(),
|
directive.shadowable));
|
||||||
directive.shadowable)),
|
import_resolution.id = directive.id;
|
||||||
id: directive.id,
|
import_resolution.is_public = directive.is_public;
|
||||||
is_public: directive.is_public
|
|
||||||
};
|
|
||||||
|
|
||||||
self.add_export(module_, target, &import_resolution[namespace]);
|
self.add_export(module_, target, &import_resolution);
|
||||||
*used_public = name_binding.is_public();
|
*used_public = name_binding.is_public();
|
||||||
}
|
}
|
||||||
UnboundResult => {
|
Failed(_) => {
|
||||||
// Continue.
|
// Continue.
|
||||||
}
|
}
|
||||||
UnknownResult => {
|
Indeterminate => {
|
||||||
panic!("{:?} result should be known at this point", namespace_name);
|
panic!("{:?} result should be known at this point", namespace_name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
self.check_for_conflicts_between_imports_and_items(module_,
|
||||||
|
import_resolution,
|
||||||
|
directive.span,
|
||||||
|
(target, namespace));
|
||||||
};
|
};
|
||||||
check_and_write_import(ValueNS, &value_result, &mut value_used_public);
|
check_and_write_import(ValueNS, &value_result, &mut value_used_public);
|
||||||
check_and_write_import(TypeNS, &type_result, &mut type_used_public);
|
check_and_write_import(TypeNS, &type_result, &mut type_used_public);
|
||||||
}
|
}
|
||||||
|
|
||||||
self.check_for_conflicts_between_imports_and_items(module_,
|
if let (&Failed(_), &Failed(_)) = (&value_result, &type_result) {
|
||||||
import_resolution,
|
|
||||||
directive.span,
|
|
||||||
target);
|
|
||||||
|
|
||||||
if value_result.is_unbound() && type_result.is_unbound() {
|
|
||||||
let msg = format!("There is no `{}` in `{}`{}",
|
let msg = format!("There is no `{}` in `{}`{}",
|
||||||
source,
|
source,
|
||||||
module_to_string(&target_module), lev_suggestion);
|
module_to_string(&target_module), lev_suggestion);
|
||||||
return ResolveResult::Failed(Some((directive.span, msg)));
|
return Failed(Some((directive.span, msg)));
|
||||||
}
|
}
|
||||||
|
|
||||||
let value_used_public = value_used_reexport || value_used_public;
|
let value_used_public = value_used_reexport || value_used_public;
|
||||||
let type_used_public = type_used_reexport || type_used_public;
|
let type_used_public = type_used_reexport || type_used_public;
|
||||||
|
|
||||||
assert!(import_resolution.outstanding_references >= 1);
|
let value_def_and_priv = {
|
||||||
import_resolution.outstanding_references -= 1;
|
let import_resolution_value = import_resolutions.get_mut(&(target, ValueNS)).unwrap();
|
||||||
|
assert!(import_resolution_value.outstanding_references >= 1);
|
||||||
|
import_resolution_value.outstanding_references -= 1;
|
||||||
|
|
||||||
// Record what this import resolves to for later uses in documentation,
|
// Record what this import resolves to for later uses in documentation,
|
||||||
// this may resolve to either a value or a type, but for 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.
|
// purposes it's good enough to just favor one over the other.
|
||||||
let value_def_and_priv = import_resolution.value_ns.target.as_ref().map(|target| {
|
import_resolution_value.target.as_ref().map(|target| {
|
||||||
let def = target.binding.def().unwrap();
|
let def = target.binding.def().unwrap();
|
||||||
(def,
|
let last_private = if value_used_public { lp } else { DependsOn(def.def_id()) };
|
||||||
if value_used_public {
|
(def, last_private)
|
||||||
lp
|
|
||||||
} else {
|
|
||||||
DependsOn(def.def_id())
|
|
||||||
})
|
})
|
||||||
});
|
};
|
||||||
let type_def_and_priv = import_resolution.type_ns.target.as_ref().map(|target| {
|
|
||||||
let def = target.binding.def().unwrap();
|
let type_def_and_priv = {
|
||||||
(def,
|
let import_resolution_type = import_resolutions.get_mut(&(target, TypeNS)).unwrap();
|
||||||
if type_used_public {
|
assert!(import_resolution_type.outstanding_references >= 1);
|
||||||
lp
|
import_resolution_type.outstanding_references -= 1;
|
||||||
} else {
|
|
||||||
DependsOn(def.def_id())
|
import_resolution_type.target.as_ref().map(|target| {
|
||||||
|
let def = target.binding.def().unwrap();
|
||||||
|
let last_private = if type_used_public { lp } else { DependsOn(def.def_id()) };
|
||||||
|
(def, last_private)
|
||||||
})
|
})
|
||||||
});
|
};
|
||||||
|
|
||||||
let import_lp = LastImport {
|
let import_lp = LastImport {
|
||||||
value_priv: value_def_and_priv.map(|(_, p)| p),
|
value_priv: value_def_and_priv.map(|(_, p)| p),
|
||||||
@ -766,7 +656,7 @@ impl<'a, 'b:'a, 'tcx:'b> ImportResolver<'a, 'b, 'tcx> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
debug!("(resolving single import) successfully resolved import");
|
debug!("(resolving single import) successfully resolved import");
|
||||||
return ResolveResult::Success(());
|
return Success(());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Resolves a glob import. Note that this function cannot fail; it either
|
// Resolves a glob import. Note that this function cannot fail; it either
|
||||||
@ -806,44 +696,41 @@ impl<'a, 'b:'a, 'tcx:'b> ImportResolver<'a, 'b, 'tcx> {
|
|||||||
"Cannot glob-import a module into itself.".into())));
|
"Cannot glob-import a module into itself.".into())));
|
||||||
}
|
}
|
||||||
|
|
||||||
for (name, target_import_resolution) in import_resolutions.iter() {
|
for (&(name, ns), target_import_resolution) in import_resolutions.iter() {
|
||||||
debug!("(resolving glob import) writing module resolution {} into `{}`",
|
debug!("(resolving glob import) writing module resolution {} into `{}`",
|
||||||
*name,
|
name,
|
||||||
module_to_string(module_));
|
module_to_string(module_));
|
||||||
|
|
||||||
// Here we merge two import resolutions.
|
// Here we merge two import resolutions.
|
||||||
let mut import_resolutions = module_.import_resolutions.borrow_mut();
|
let mut import_resolutions = module_.import_resolutions.borrow_mut();
|
||||||
let mut dest_import_resolution = import_resolutions.entry(*name).or_insert_with(|| {
|
let mut dest_import_resolution =
|
||||||
ImportResolutionPerNamespace::new(id, is_public)
|
import_resolutions.entry((name, ns))
|
||||||
});
|
.or_insert_with(|| ImportResolution::new(id, is_public));
|
||||||
|
|
||||||
for &ns in [TypeNS, ValueNS].iter() {
|
match target_import_resolution.target {
|
||||||
match target_import_resolution[ns].target {
|
Some(ref target) if target_import_resolution.is_public => {
|
||||||
Some(ref target) if target_import_resolution[ns].is_public => {
|
self.check_for_conflicting_import(&dest_import_resolution,
|
||||||
self.check_for_conflicting_import(&dest_import_resolution,
|
import_directive.span,
|
||||||
import_directive.span,
|
name,
|
||||||
*name,
|
ns);
|
||||||
ns);
|
dest_import_resolution.id = id;
|
||||||
dest_import_resolution[ns] = ImportResolution {
|
dest_import_resolution.is_public = is_public;
|
||||||
id: id, is_public: is_public, target: Some(target.clone())
|
dest_import_resolution.target = Some(target.clone());
|
||||||
};
|
self.add_export(module_, name, &dest_import_resolution);
|
||||||
self.add_export(module_, *name, &dest_import_resolution[ns]);
|
|
||||||
}
|
|
||||||
_ => {}
|
|
||||||
}
|
}
|
||||||
|
_ => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add all children from the containing module.
|
// Add all children from the containing module.
|
||||||
build_reduced_graph::populate_module_if_necessary(self.resolver, &target_module);
|
build_reduced_graph::populate_module_if_necessary(self.resolver, &target_module);
|
||||||
|
|
||||||
for (&name, name_bindings) in target_module.children.borrow().iter() {
|
for (&name, name_binding) in target_module.children.borrow().iter() {
|
||||||
self.merge_import_resolution(module_,
|
self.merge_import_resolution(module_,
|
||||||
target_module,
|
target_module,
|
||||||
import_directive,
|
import_directive,
|
||||||
name,
|
name,
|
||||||
name_bindings.clone());
|
name_binding.clone());
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Record the destination of this import
|
// Record the destination of this import
|
||||||
@ -864,14 +751,14 @@ impl<'a, 'b:'a, 'tcx:'b> ImportResolver<'a, 'b, 'tcx> {
|
|||||||
module_: Module<'b>,
|
module_: Module<'b>,
|
||||||
containing_module: Module<'b>,
|
containing_module: Module<'b>,
|
||||||
import_directive: &ImportDirective,
|
import_directive: &ImportDirective,
|
||||||
name: Name,
|
(name, ns): (Name, Namespace),
|
||||||
name_bindings: NameBindings<'b>) {
|
name_binding: NameBinding<'b>) {
|
||||||
let id = import_directive.id;
|
let id = import_directive.id;
|
||||||
let is_public = import_directive.is_public;
|
let is_public = import_directive.is_public;
|
||||||
|
|
||||||
let mut import_resolutions = module_.import_resolutions.borrow_mut();
|
let mut import_resolutions = module_.import_resolutions.borrow_mut();
|
||||||
let dest_import_resolution = import_resolutions.entry(name).or_insert_with(|| {
|
let dest_import_resolution = import_resolutions.entry((name, ns)).or_insert_with(|| {
|
||||||
ImportResolutionPerNamespace::new(id, is_public)
|
ImportResolution::new(id, is_public)
|
||||||
});
|
});
|
||||||
|
|
||||||
debug!("(resolving glob import) writing resolution `{}` in `{}` to `{}`",
|
debug!("(resolving glob import) writing resolution `{}` in `{}` to `{}`",
|
||||||
@ -880,61 +767,46 @@ impl<'a, 'b:'a, 'tcx:'b> ImportResolver<'a, 'b, 'tcx> {
|
|||||||
module_to_string(module_));
|
module_to_string(module_));
|
||||||
|
|
||||||
// Merge the child item into the import resolution.
|
// Merge the child item into the import resolution.
|
||||||
// pub_err makes sure we don't give the same error twice.
|
let modifier = DefModifiers::IMPORTABLE | DefModifiers::PUBLIC;
|
||||||
let mut pub_err = false;
|
|
||||||
{
|
|
||||||
let mut merge_child_item = |namespace| {
|
|
||||||
if !pub_err && is_public &&
|
|
||||||
name_bindings[namespace].defined_with(DefModifiers::PRIVATE_VARIANT) {
|
|
||||||
let msg = format!("variant `{}` is private, and cannot be reexported (error \
|
|
||||||
E0364), consider declaring its enum as `pub`", name);
|
|
||||||
self.resolver.session.add_lint(lint::builtin::PRIVATE_IN_PUBLIC,
|
|
||||||
import_directive.id,
|
|
||||||
import_directive.span,
|
|
||||||
msg);
|
|
||||||
pub_err = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
let modifier = DefModifiers::IMPORTABLE | DefModifiers::PUBLIC;
|
if ns == TypeNS && is_public && name_binding.defined_with(DefModifiers::PRIVATE_VARIANT) {
|
||||||
if name_bindings[namespace].defined_with(modifier) {
|
let msg = format!("variant `{}` is private, and cannot be reexported (error \
|
||||||
let namespace_name = match namespace {
|
E0364), consider declaring its enum as `pub`", name);
|
||||||
TypeNS => "type",
|
self.resolver.session.add_lint(lint::builtin::PRIVATE_IN_PUBLIC,
|
||||||
ValueNS => "value",
|
import_directive.id,
|
||||||
};
|
import_directive.span,
|
||||||
debug!("(resolving glob import) ... for {} target", namespace_name);
|
msg);
|
||||||
if dest_import_resolution.shadowable(namespace) == Shadowable::Never {
|
}
|
||||||
let msg = format!("a {} named `{}` has already been imported in this \
|
|
||||||
module",
|
if name_binding.defined_with(modifier) {
|
||||||
namespace_name,
|
let namespace_name = match ns {
|
||||||
name);
|
TypeNS => "type",
|
||||||
span_err!(self.resolver.session,
|
ValueNS => "value",
|
||||||
import_directive.span,
|
|
||||||
E0251,
|
|
||||||
"{}",
|
|
||||||
msg);
|
|
||||||
} else {
|
|
||||||
dest_import_resolution[namespace] = ImportResolution {
|
|
||||||
target: Some(Target::new(containing_module,
|
|
||||||
name_bindings[namespace].clone(),
|
|
||||||
import_directive.shadowable)),
|
|
||||||
id: id,
|
|
||||||
is_public: is_public
|
|
||||||
};
|
|
||||||
self.add_export(module_, name, &dest_import_resolution[namespace]);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// FIXME #30159: This is required for backwards compatability.
|
|
||||||
dest_import_resolution[namespace].is_public |= is_public;
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
merge_child_item(ValueNS);
|
debug!("(resolving glob import) ... for {} target", namespace_name);
|
||||||
merge_child_item(TypeNS);
|
if dest_import_resolution.shadowable() == Shadowable::Never {
|
||||||
|
let msg = format!("a {} named `{}` has already been imported in this module",
|
||||||
|
namespace_name,
|
||||||
|
name);
|
||||||
|
span_err!(self.resolver.session, import_directive.span, E0251, "{}", msg);
|
||||||
|
} else {
|
||||||
|
let target = Target::new(containing_module,
|
||||||
|
name_binding.clone(),
|
||||||
|
import_directive.shadowable);
|
||||||
|
dest_import_resolution.target = Some(target);
|
||||||
|
dest_import_resolution.id = id;
|
||||||
|
dest_import_resolution.is_public = is_public;
|
||||||
|
self.add_export(module_, name, &dest_import_resolution);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// FIXME #30159: This is required for backwards compatability.
|
||||||
|
dest_import_resolution.is_public |= is_public;
|
||||||
}
|
}
|
||||||
|
|
||||||
self.check_for_conflicts_between_imports_and_items(module_,
|
self.check_for_conflicts_between_imports_and_items(module_,
|
||||||
dest_import_resolution,
|
dest_import_resolution,
|
||||||
import_directive.span,
|
import_directive.span,
|
||||||
name);
|
(name, ns));
|
||||||
}
|
}
|
||||||
|
|
||||||
fn add_export(&mut self, module: Module<'b>, name: Name, resolution: &ImportResolution<'b>) {
|
fn add_export(&mut self, module: Module<'b>, name: Name, resolution: &ImportResolution<'b>) {
|
||||||
@ -952,11 +824,11 @@ impl<'a, 'b:'a, 'tcx:'b> ImportResolver<'a, 'b, 'tcx> {
|
|||||||
|
|
||||||
/// Checks that imported names and items don't have the same name.
|
/// Checks that imported names and items don't have the same name.
|
||||||
fn check_for_conflicting_import(&mut self,
|
fn check_for_conflicting_import(&mut self,
|
||||||
import_resolution: &ImportResolutionPerNamespace,
|
import_resolution: &ImportResolution,
|
||||||
import_span: Span,
|
import_span: Span,
|
||||||
name: Name,
|
name: Name,
|
||||||
namespace: Namespace) {
|
namespace: Namespace) {
|
||||||
let target = &import_resolution[namespace].target;
|
let target = &import_resolution.target;
|
||||||
debug!("check_for_conflicting_import: {}; target exists: {}",
|
debug!("check_for_conflicting_import: {}; target exists: {}",
|
||||||
name,
|
name,
|
||||||
target.is_some());
|
target.is_some());
|
||||||
@ -973,7 +845,7 @@ impl<'a, 'b:'a, 'tcx:'b> ImportResolver<'a, 'b, 'tcx> {
|
|||||||
}
|
}
|
||||||
ValueNS => "value",
|
ValueNS => "value",
|
||||||
};
|
};
|
||||||
let use_id = import_resolution[namespace].id;
|
let use_id = import_resolution.id;
|
||||||
let item = self.resolver.ast_map.expect_item(use_id);
|
let item = self.resolver.ast_map.expect_item(use_id);
|
||||||
let mut err = struct_span_err!(self.resolver.session,
|
let mut err = struct_span_err!(self.resolver.session,
|
||||||
import_span,
|
import_span,
|
||||||
@ -1006,55 +878,53 @@ impl<'a, 'b:'a, 'tcx:'b> ImportResolver<'a, 'b, 'tcx> {
|
|||||||
/// Checks that imported names and items don't have the same name.
|
/// Checks that imported names and items don't have the same name.
|
||||||
fn check_for_conflicts_between_imports_and_items(&mut self,
|
fn check_for_conflicts_between_imports_and_items(&mut self,
|
||||||
module: Module<'b>,
|
module: Module<'b>,
|
||||||
import: &ImportResolutionPerNamespace<'b>,
|
import: &ImportResolution<'b>,
|
||||||
import_span: Span,
|
import_span: Span,
|
||||||
name: Name) {
|
(name, ns): (Name, Namespace)) {
|
||||||
// First, check for conflicts between imports and `extern crate`s.
|
// First, check for conflicts between imports and `extern crate`s.
|
||||||
if module.external_module_children
|
if ns == TypeNS {
|
||||||
.borrow()
|
if module.external_module_children.borrow().contains_key(&name) {
|
||||||
.contains_key(&name) {
|
match import.target {
|
||||||
match import.type_ns.target {
|
Some(ref target) if target.shadowable != Shadowable::Always => {
|
||||||
Some(ref target) if target.shadowable != Shadowable::Always => {
|
let msg = format!("import `{0}` conflicts with imported crate \
|
||||||
let msg = format!("import `{0}` conflicts with imported crate in this module \
|
in this module (maybe you meant `use {0}::*`?)",
|
||||||
(maybe you meant `use {0}::*`?)",
|
name);
|
||||||
name);
|
span_err!(self.resolver.session, import_span, E0254, "{}", &msg[..]);
|
||||||
span_err!(self.resolver.session, import_span, E0254, "{}", &msg[..]);
|
}
|
||||||
|
Some(_) | None => {}
|
||||||
}
|
}
|
||||||
Some(_) | None => {}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check for item conflicts.
|
// Check for item conflicts.
|
||||||
let name_bindings = match module.children.borrow().get(&name) {
|
let name_binding = match module.get_child(name, ns) {
|
||||||
None => {
|
None => {
|
||||||
// There can't be any conflicts.
|
// There can't be any conflicts.
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
Some(ref name_bindings) => (*name_bindings).clone(),
|
Some(name_binding) => name_binding,
|
||||||
};
|
};
|
||||||
|
|
||||||
match import.value_ns.target {
|
if ns == ValueNS {
|
||||||
Some(ref target) if target.shadowable != Shadowable::Always => {
|
match import.target {
|
||||||
if let Some(ref value) = *name_bindings.value_ns.borrow() {
|
Some(ref target) if target.shadowable != Shadowable::Always => {
|
||||||
let mut err = struct_span_err!(self.resolver.session,
|
let mut err = struct_span_err!(self.resolver.session,
|
||||||
import_span,
|
import_span,
|
||||||
E0255,
|
E0255,
|
||||||
"import `{}` conflicts with \
|
"import `{}` conflicts with \
|
||||||
value in this module",
|
value in this module",
|
||||||
name);
|
name);
|
||||||
if let Some(span) = value.span {
|
if let Some(span) = name_binding.span {
|
||||||
err.span_note(span, "conflicting value here");
|
err.span_note(span, "conflicting value here");
|
||||||
}
|
}
|
||||||
err.emit();
|
err.emit();
|
||||||
}
|
}
|
||||||
|
Some(_) | None => {}
|
||||||
}
|
}
|
||||||
Some(_) | None => {}
|
} else {
|
||||||
}
|
match import.target {
|
||||||
|
Some(ref target) if target.shadowable != Shadowable::Always => {
|
||||||
match import.type_ns.target {
|
let (what, note) = match name_binding.module() {
|
||||||
Some(ref target) if target.shadowable != Shadowable::Always => {
|
|
||||||
if let Some(ref ty) = *name_bindings.type_ns.borrow() {
|
|
||||||
let (what, note) = match ty.module() {
|
|
||||||
Some(ref module) if module.is_normal() =>
|
Some(ref module) if module.is_normal() =>
|
||||||
("existing submodule", "note conflicting module here"),
|
("existing submodule", "note conflicting module here"),
|
||||||
Some(ref module) if module.is_trait() =>
|
Some(ref module) if module.is_trait() =>
|
||||||
@ -1067,13 +937,13 @@ impl<'a, 'b:'a, 'tcx:'b> ImportResolver<'a, 'b, 'tcx> {
|
|||||||
"import `{}` conflicts with {}",
|
"import `{}` conflicts with {}",
|
||||||
name,
|
name,
|
||||||
what);
|
what);
|
||||||
if let Some(span) = ty.span {
|
if let Some(span) = name_binding.span {
|
||||||
err.span_note(span, note);
|
err.span_note(span, note);
|
||||||
}
|
}
|
||||||
err.emit();
|
err.emit();
|
||||||
}
|
}
|
||||||
|
Some(_) | None => {}
|
||||||
}
|
}
|
||||||
Some(_) | None => {}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user