Auto merge of #35894 - jseyfried:new_import_semantics, r=nrc
Implement RFC 1560 behind `#![feature(item_like_imports)]` This implements https://github.com/rust-lang/rfcs/pull/1560 (cc #35120) behind the `item_like_imports` feature gate. The [RFC text](https://github.com/rust-lang/rfcs/blob/master/text/1560-name-resolution.md#changes-to-name-resolution-rules) describes the changes to name resolution enabled by `#![feature(item_like_imports)` in detail. To summarize, - Items and named imports shadow glob imports. - Multiple globs can import the same name if the name is unused or the imports are shadowed. - Multiple globs can import the same name if the imports are of the same item (following re-exports). - The visibility of such a name is the maximum visibility of the imports. - Equivalently, adding a glob import will never reduce the visibility of a name, nor will removing one increase it. - Non-prelude private imports can be used wherever we currently allow private items to be used. - Prelude-imported names are unaffected, i.e. they continue to be usable only in lexical scopes. - Globs import all visible names, not just public names. - Equivalently, glob importing from an ancestor module imports all of the ancestor's names, and glob importing from other modules is unchanged. r? @nrc
This commit is contained in:
commit
8aeb15acc7
@ -26,6 +26,8 @@ use rustc::hir::def::*;
|
||||
use rustc::hir::def_id::{CRATE_DEF_INDEX, DefId};
|
||||
use rustc::ty::{self, VariantKind};
|
||||
|
||||
use std::cell::Cell;
|
||||
|
||||
use syntax::ast::Name;
|
||||
use syntax::attr;
|
||||
use syntax::parse::token;
|
||||
@ -81,7 +83,6 @@ impl<'b> Resolver<'b> {
|
||||
/// Constructs the reduced graph for one item.
|
||||
fn build_reduced_graph_for_item(&mut self, item: &Item) {
|
||||
let parent = self.current_module;
|
||||
let parent_vis = self.current_vis;
|
||||
let name = item.ident.name;
|
||||
let sp = item.span;
|
||||
let vis = self.resolve_visibility(&item.vis);
|
||||
@ -177,7 +178,10 @@ impl<'b> Resolver<'b> {
|
||||
}
|
||||
}
|
||||
ViewPathGlob(_) => {
|
||||
let subclass = GlobImport { is_prelude: is_prelude };
|
||||
let subclass = GlobImport {
|
||||
is_prelude: is_prelude,
|
||||
max_vis: Cell::new(ty::Visibility::PrivateExternal),
|
||||
};
|
||||
let span = view_path.span;
|
||||
self.add_import_directive(module_path, subclass, span, item.id, vis);
|
||||
}
|
||||
@ -204,7 +208,7 @@ impl<'b> Resolver<'b> {
|
||||
ItemKind::Mod(..) => {
|
||||
let parent_link = ModuleParentLink(parent, name);
|
||||
let def = Def::Mod(self.definitions.local_def_id(item.id));
|
||||
let module = self.new_module(parent_link, Some(def), false);
|
||||
let module = self.new_module(parent_link, Some(def), Some(item.id));
|
||||
module.no_implicit_prelude.set({
|
||||
parent.no_implicit_prelude.get() ||
|
||||
attr::contains_name(&item.attrs, "no_implicit_prelude")
|
||||
@ -214,7 +218,6 @@ impl<'b> Resolver<'b> {
|
||||
|
||||
// Descend into the module.
|
||||
self.current_module = module;
|
||||
self.current_vis = ty::Visibility::Restricted(item.id);
|
||||
}
|
||||
|
||||
ItemKind::ForeignMod(..) => {}
|
||||
@ -243,7 +246,7 @@ impl<'b> Resolver<'b> {
|
||||
ItemKind::Enum(ref enum_definition, _) => {
|
||||
let parent_link = ModuleParentLink(parent, name);
|
||||
let def = Def::Enum(self.definitions.local_def_id(item.id));
|
||||
let module = self.new_module(parent_link, Some(def), false);
|
||||
let module = self.new_module(parent_link, Some(def), parent.normal_ancestor_id);
|
||||
self.define(parent, name, TypeNS, (module, sp, vis));
|
||||
|
||||
for variant in &(*enum_definition).variants {
|
||||
@ -285,7 +288,8 @@ impl<'b> Resolver<'b> {
|
||||
// Add all the items within to a new module.
|
||||
let parent_link = ModuleParentLink(parent, name);
|
||||
let def = Def::Trait(def_id);
|
||||
let module_parent = self.new_module(parent_link, Some(def), false);
|
||||
let module_parent =
|
||||
self.new_module(parent_link, Some(def), parent.normal_ancestor_id);
|
||||
self.define(parent, name, TypeNS, (module_parent, sp, vis));
|
||||
|
||||
// Add the names of all the items to the trait info.
|
||||
@ -312,7 +316,6 @@ impl<'b> Resolver<'b> {
|
||||
|
||||
visit::walk_item(&mut BuildReducedGraphVisitor { resolver: self }, item);
|
||||
self.current_module = parent;
|
||||
self.current_vis = parent_vis;
|
||||
}
|
||||
|
||||
// Constructs the reduced graph for one variant. Variants exist in the
|
||||
@ -363,7 +366,7 @@ impl<'b> Resolver<'b> {
|
||||
block_id);
|
||||
|
||||
let parent_link = BlockParentLink(parent, block_id);
|
||||
let new_module = self.new_module(parent_link, None, false);
|
||||
let new_module = self.new_module(parent_link, None, parent.normal_ancestor_id);
|
||||
self.module_map.insert(block_id, new_module);
|
||||
self.current_module = new_module; // Descend into the block.
|
||||
}
|
||||
@ -395,7 +398,7 @@ impl<'b> Resolver<'b> {
|
||||
debug!("(building reduced graph for external crate) building module {} {:?}",
|
||||
name, vis);
|
||||
let parent_link = ModuleParentLink(parent, name);
|
||||
let module = self.new_module(parent_link, Some(def), true);
|
||||
let module = self.new_module(parent_link, Some(def), None);
|
||||
let _ = self.try_define(parent, name, TypeNS, (module, DUMMY_SP, vis));
|
||||
}
|
||||
Def::Variant(_, variant_id) => {
|
||||
@ -437,7 +440,7 @@ impl<'b> Resolver<'b> {
|
||||
}
|
||||
|
||||
let parent_link = ModuleParentLink(parent, name);
|
||||
let module = self.new_module(parent_link, Some(def), true);
|
||||
let module = self.new_module(parent_link, Some(def), None);
|
||||
let _ = self.try_define(parent, name, TypeNS, (module, DUMMY_SP, vis));
|
||||
}
|
||||
Def::TyAlias(..) | Def::AssociatedTy(..) => {
|
||||
|
@ -65,7 +65,7 @@ use syntax::ast::{Item, ItemKind, ImplItem, ImplItemKind};
|
||||
use syntax::ast::{Local, Mutability, Pat, PatKind, Path};
|
||||
use syntax::ast::{PathSegment, PathParameters, QSelf, TraitItemKind, TraitRef, Ty, TyKind};
|
||||
|
||||
use syntax_pos::Span;
|
||||
use syntax_pos::{Span, DUMMY_SP};
|
||||
use errors::DiagnosticBuilder;
|
||||
|
||||
use std::cell::{Cell, RefCell};
|
||||
@ -459,7 +459,7 @@ fn resolve_struct_error<'b, 'a: 'b, 'c>(resolver: &'b Resolver<'a>,
|
||||
err
|
||||
}
|
||||
ResolutionError::BindingShadowsSomethingUnacceptable(what_binding, name, binding) => {
|
||||
let shadows_what = PathResolution::new(binding.def().unwrap()).kind_name();
|
||||
let shadows_what = PathResolution::new(binding.def()).kind_name();
|
||||
let mut err = struct_span_err!(resolver.session,
|
||||
span,
|
||||
E0530,
|
||||
@ -739,7 +739,7 @@ impl<'a> LexicalScopeBinding<'a> {
|
||||
fn local_def(self) -> LocalDef {
|
||||
match self {
|
||||
LexicalScopeBinding::LocalDef(local_def) => local_def,
|
||||
LexicalScopeBinding::Item(binding) => LocalDef::from_def(binding.def().unwrap()),
|
||||
LexicalScopeBinding::Item(binding) => LocalDef::from_def(binding.def()),
|
||||
}
|
||||
}
|
||||
|
||||
@ -749,10 +749,6 @@ impl<'a> LexicalScopeBinding<'a> {
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
fn module(self) -> Option<Module<'a>> {
|
||||
self.item().and_then(NameBinding::module)
|
||||
}
|
||||
}
|
||||
|
||||
/// The link from a module up to its nearest parent node.
|
||||
@ -768,6 +764,9 @@ pub struct ModuleS<'a> {
|
||||
parent_link: ParentLink<'a>,
|
||||
def: Option<Def>,
|
||||
|
||||
// The node id of the closest normal module (`mod`) ancestor (including this module).
|
||||
normal_ancestor_id: Option<NodeId>,
|
||||
|
||||
// If the module is an extern crate, `def` is root of the external crate and `extern_crate_id`
|
||||
// is the NodeId of the local `extern crate` item (otherwise, `extern_crate_id` is None).
|
||||
extern_crate_id: Option<NodeId>,
|
||||
@ -791,17 +790,19 @@ pub struct ModuleS<'a> {
|
||||
pub type Module<'a> = &'a ModuleS<'a>;
|
||||
|
||||
impl<'a> ModuleS<'a> {
|
||||
fn new(parent_link: ParentLink<'a>, def: Option<Def>, external: bool) -> Self {
|
||||
fn new(parent_link: ParentLink<'a>, def: Option<Def>, normal_ancestor_id: Option<NodeId>)
|
||||
-> Self {
|
||||
ModuleS {
|
||||
parent_link: parent_link,
|
||||
def: def,
|
||||
normal_ancestor_id: normal_ancestor_id,
|
||||
extern_crate_id: None,
|
||||
resolutions: RefCell::new(FnvHashMap()),
|
||||
no_implicit_prelude: Cell::new(false),
|
||||
glob_importers: RefCell::new(Vec::new()),
|
||||
globs: RefCell::new((Vec::new())),
|
||||
traits: RefCell::new(None),
|
||||
populated: Cell::new(!external),
|
||||
populated: Cell::new(normal_ancestor_id.is_some()),
|
||||
}
|
||||
}
|
||||
|
||||
@ -829,6 +830,13 @@ impl<'a> ModuleS<'a> {
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
fn parent(&self) -> Option<&'a Self> {
|
||||
match self.parent_link {
|
||||
ModuleParentLink(parent, _) | BlockParentLink(parent, _) => Some(parent),
|
||||
NoParentLink => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> fmt::Debug for ModuleS<'a> {
|
||||
@ -863,32 +871,35 @@ enum NameBindingKind<'a> {
|
||||
binding: &'a NameBinding<'a>,
|
||||
directive: &'a ImportDirective<'a>,
|
||||
},
|
||||
Ambiguity {
|
||||
b1: &'a NameBinding<'a>,
|
||||
b2: &'a NameBinding<'a>,
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
struct PrivacyError<'a>(Span, Name, &'a NameBinding<'a>);
|
||||
|
||||
impl<'a> NameBinding<'a> {
|
||||
fn module(&self) -> Option<Module<'a>> {
|
||||
fn module(&self) -> Result<Module<'a>, bool /* true if an error has already been reported */> {
|
||||
match self.kind {
|
||||
NameBindingKind::Module(module) => Some(module),
|
||||
NameBindingKind::Def(_) => None,
|
||||
NameBindingKind::Module(module) => Ok(module),
|
||||
NameBindingKind::Import { binding, .. } => binding.module(),
|
||||
NameBindingKind::Def(Def::Err) => Err(true),
|
||||
NameBindingKind::Def(_) => Err(false),
|
||||
NameBindingKind::Ambiguity { .. } => Err(false),
|
||||
}
|
||||
}
|
||||
|
||||
fn def(&self) -> Option<Def> {
|
||||
fn def(&self) -> Def {
|
||||
match self.kind {
|
||||
NameBindingKind::Def(def) => Some(def),
|
||||
NameBindingKind::Module(module) => module.def,
|
||||
NameBindingKind::Def(def) => def,
|
||||
NameBindingKind::Module(module) => module.def.unwrap(),
|
||||
NameBindingKind::Import { binding, .. } => binding.def(),
|
||||
NameBindingKind::Ambiguity { .. } => Def::Err,
|
||||
}
|
||||
}
|
||||
|
||||
fn is_pseudo_public(&self) -> bool {
|
||||
self.pseudo_vis() == ty::Visibility::Public
|
||||
}
|
||||
|
||||
// We sometimes need to treat variants as `pub` for backwards compatibility
|
||||
fn pseudo_vis(&self) -> ty::Visibility {
|
||||
if self.is_variant() { ty::Visibility::Public } else { self.vis }
|
||||
@ -902,7 +913,7 @@ impl<'a> NameBinding<'a> {
|
||||
}
|
||||
|
||||
fn is_extern_crate(&self) -> bool {
|
||||
self.module().and_then(|module| module.extern_crate_id).is_some()
|
||||
self.module().ok().and_then(|module| module.extern_crate_id).is_some()
|
||||
}
|
||||
|
||||
fn is_import(&self) -> bool {
|
||||
@ -915,16 +926,25 @@ impl<'a> NameBinding<'a> {
|
||||
fn is_glob_import(&self) -> bool {
|
||||
match self.kind {
|
||||
NameBindingKind::Import { directive, .. } => directive.is_glob(),
|
||||
NameBindingKind::Ambiguity { .. } => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
fn is_importable(&self) -> bool {
|
||||
match self.def().unwrap() {
|
||||
match self.def() {
|
||||
Def::AssociatedConst(..) | Def::Method(..) | Def::AssociatedTy(..) => false,
|
||||
_ => true,
|
||||
}
|
||||
}
|
||||
|
||||
fn ambiguity(&self) -> Option<(&'a NameBinding<'a>, &'a NameBinding<'a>)> {
|
||||
match self.kind {
|
||||
NameBindingKind::Ambiguity { b1, b2 } => Some((b1, b2)),
|
||||
NameBindingKind::Import { binding, .. } => binding.ambiguity(),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Interns the names of the primitive types.
|
||||
@ -987,10 +1007,6 @@ pub struct Resolver<'a> {
|
||||
// The module that represents the current item scope.
|
||||
current_module: Module<'a>,
|
||||
|
||||
// The visibility of `pub(self)` items in the current scope.
|
||||
// Equivalently, the visibility required for an item to be accessible from the current scope.
|
||||
current_vis: ty::Visibility,
|
||||
|
||||
// The current set of local scopes, for values.
|
||||
// FIXME #4948: Reuse ribs to avoid allocation.
|
||||
value_ribs: Vec<Rib<'a>>,
|
||||
@ -1047,8 +1063,11 @@ pub struct Resolver<'a> {
|
||||
pub maybe_unused_trait_imports: NodeSet,
|
||||
|
||||
privacy_errors: Vec<PrivacyError<'a>>,
|
||||
ambiguity_errors: Vec<(Span, Name, &'a NameBinding<'a>)>,
|
||||
|
||||
arenas: &'a ResolverArenas<'a>,
|
||||
dummy_binding: &'a NameBinding<'a>,
|
||||
new_import_semantics: bool, // true if `#![feature(item_like_imports)]`
|
||||
}
|
||||
|
||||
pub struct ResolverArenas<'a> {
|
||||
@ -1083,15 +1102,12 @@ impl<'a> ResolverArenas<'a> {
|
||||
}
|
||||
|
||||
impl<'a> ty::NodeIdTree for Resolver<'a> {
|
||||
fn is_descendant_of(&self, node: NodeId, ancestor: NodeId) -> bool {
|
||||
let ancestor = self.definitions.local_def_id(ancestor);
|
||||
let mut module = *self.module_map.get(&node).unwrap();
|
||||
while module.def_id() != Some(ancestor) {
|
||||
let module_parent = match self.get_nearest_normal_module_parent(module) {
|
||||
Some(parent) => parent,
|
||||
fn is_descendant_of(&self, mut node: NodeId, ancestor: NodeId) -> bool {
|
||||
while node != ancestor {
|
||||
node = match self.module_map[&node].parent() {
|
||||
Some(parent) => parent.normal_ancestor_id.unwrap(),
|
||||
None => return false,
|
||||
};
|
||||
module = module_parent;
|
||||
}
|
||||
}
|
||||
true
|
||||
}
|
||||
@ -1101,7 +1117,7 @@ impl<'a> hir::lowering::Resolver for Resolver<'a> {
|
||||
fn resolve_generated_global_path(&mut self, path: &hir::Path, is_value: bool) -> Def {
|
||||
let namespace = if is_value { ValueNS } else { TypeNS };
|
||||
match self.resolve_crate_relative_path(path.span, &path.segments, namespace) {
|
||||
Ok(binding) => binding.def().unwrap(),
|
||||
Ok(binding) => binding.def(),
|
||||
Err(true) => Def::Err,
|
||||
Err(false) => {
|
||||
let path_name = &format!("{}", path);
|
||||
@ -1154,7 +1170,7 @@ impl<'a> Resolver<'a> {
|
||||
-> Resolver<'a> {
|
||||
let root_def_id = DefId::local(CRATE_DEF_INDEX);
|
||||
let graph_root =
|
||||
ModuleS::new(NoParentLink, Some(Def::Mod(root_def_id)), false);
|
||||
ModuleS::new(NoParentLink, Some(Def::Mod(root_def_id)), Some(CRATE_NODE_ID));
|
||||
let graph_root = arenas.alloc_module(graph_root);
|
||||
let mut module_map = NodeMap();
|
||||
module_map.insert(CRATE_NODE_ID, graph_root);
|
||||
@ -1177,7 +1193,6 @@ impl<'a> Resolver<'a> {
|
||||
indeterminate_imports: Vec::new(),
|
||||
|
||||
current_module: graph_root,
|
||||
current_vis: ty::Visibility::Restricted(ast::CRATE_NODE_ID),
|
||||
value_ribs: vec![Rib::new(ModuleRibKind(graph_root))],
|
||||
type_ribs: vec![Rib::new(ModuleRibKind(graph_root))],
|
||||
label_ribs: Vec::new(),
|
||||
@ -1203,8 +1218,15 @@ impl<'a> Resolver<'a> {
|
||||
maybe_unused_trait_imports: NodeSet(),
|
||||
|
||||
privacy_errors: Vec::new(),
|
||||
ambiguity_errors: Vec::new(),
|
||||
|
||||
arenas: arenas,
|
||||
dummy_binding: arenas.alloc_name_binding(NameBinding {
|
||||
kind: NameBindingKind::Def(Def::Err),
|
||||
span: DUMMY_SP,
|
||||
vis: ty::Visibility::Public,
|
||||
}),
|
||||
new_import_semantics: session.features.borrow().item_like_imports,
|
||||
}
|
||||
}
|
||||
|
||||
@ -1221,21 +1243,23 @@ impl<'a> Resolver<'a> {
|
||||
/// Entry point to crate resolution.
|
||||
pub fn resolve_crate(&mut self, krate: &Crate) {
|
||||
self.current_module = self.graph_root;
|
||||
self.current_vis = ty::Visibility::Restricted(ast::CRATE_NODE_ID);
|
||||
visit::walk_crate(self, krate);
|
||||
|
||||
check_unused::check_crate(self, krate);
|
||||
self.report_privacy_errors();
|
||||
self.report_errors();
|
||||
}
|
||||
|
||||
fn new_module(&self, parent_link: ParentLink<'a>, def: Option<Def>, external: bool)
|
||||
fn new_module(&self,
|
||||
parent_link: ParentLink<'a>,
|
||||
def: Option<Def>,
|
||||
normal_ancestor_id: Option<NodeId>)
|
||||
-> Module<'a> {
|
||||
self.arenas.alloc_module(ModuleS::new(parent_link, def, external))
|
||||
self.arenas.alloc_module(ModuleS::new(parent_link, def, normal_ancestor_id))
|
||||
}
|
||||
|
||||
fn new_extern_crate_module(&self, parent_link: ParentLink<'a>, def: Def, local_node_id: NodeId)
|
||||
-> Module<'a> {
|
||||
let mut module = ModuleS::new(parent_link, Some(def), false);
|
||||
let mut module = ModuleS::new(parent_link, Some(def), Some(local_node_id));
|
||||
module.extern_crate_id = Some(local_node_id);
|
||||
self.arenas.modules.alloc(module)
|
||||
}
|
||||
@ -1244,9 +1268,10 @@ impl<'a> Resolver<'a> {
|
||||
match ns { ValueNS => &mut self.value_ribs, TypeNS => &mut self.type_ribs }
|
||||
}
|
||||
|
||||
fn record_use(&mut self, name: Name, ns: Namespace, binding: &'a NameBinding<'a>) {
|
||||
fn record_use(&mut self, name: Name, ns: Namespace, binding: &'a NameBinding<'a>, span: Span)
|
||||
-> bool /* true if an error was reported */ {
|
||||
// track extern crates for unused_extern_crate lint
|
||||
if let Some(DefId { krate, .. }) = binding.module().and_then(ModuleS::def_id) {
|
||||
if let Some(DefId { krate, .. }) = binding.module().ok().and_then(ModuleS::def_id) {
|
||||
self.used_crates.insert(krate);
|
||||
}
|
||||
|
||||
@ -1254,6 +1279,13 @@ impl<'a> Resolver<'a> {
|
||||
self.used_imports.insert((directive.id, ns));
|
||||
self.add_to_glob_map(directive.id, name);
|
||||
}
|
||||
|
||||
if binding.ambiguity().is_some() {
|
||||
self.ambiguity_errors.push((span, name, binding));
|
||||
return true;
|
||||
}
|
||||
|
||||
false
|
||||
}
|
||||
|
||||
fn add_to_glob_map(&mut self, id: NodeId, name: Name) {
|
||||
@ -1262,6 +1294,18 @@ impl<'a> Resolver<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
fn expect_module(&mut self, name: Name, binding: &'a NameBinding<'a>, span: Option<Span>)
|
||||
-> ResolveResult<Module<'a>> {
|
||||
match binding.module() {
|
||||
Ok(module) => Success(module),
|
||||
Err(true) => Failed(None),
|
||||
Err(false) => {
|
||||
let msg = format!("Not a module `{}`", name);
|
||||
Failed(span.map(|span| (span, msg)))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Resolves the given module path from the given root `search_module`.
|
||||
fn resolve_module_path_from_root(&mut self,
|
||||
mut search_module: Module<'a>,
|
||||
@ -1291,7 +1335,7 @@ impl<'a> Resolver<'a> {
|
||||
while index < module_path_len {
|
||||
let name = module_path[index];
|
||||
match self.resolve_name_in_module(search_module, name, TypeNS, false, span) {
|
||||
Failed(None) => {
|
||||
Failed(_) => {
|
||||
let segment_name = name.as_str();
|
||||
let module_name = module_to_string(search_module);
|
||||
let msg = if "???" == &module_name {
|
||||
@ -1318,7 +1362,6 @@ impl<'a> Resolver<'a> {
|
||||
|
||||
return Failed(span.map(|span| (span, msg)));
|
||||
}
|
||||
Failed(err) => return Failed(err),
|
||||
Indeterminate => {
|
||||
debug!("(resolving module path for import) module resolution is \
|
||||
indeterminate: {}",
|
||||
@ -1328,11 +1371,9 @@ impl<'a> Resolver<'a> {
|
||||
Success(binding) => {
|
||||
// Check to see whether there are type bindings, and, if
|
||||
// so, whether there is a module within.
|
||||
if let Some(module_def) = binding.module() {
|
||||
search_module = module_def;
|
||||
} else {
|
||||
let msg = format!("Not a module `{}`", name);
|
||||
return Failed(span.map(|span| (span, msg)));
|
||||
match self.expect_module(name, binding, span) {
|
||||
Success(module) => search_module = module,
|
||||
result @ _ => return result,
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1385,13 +1426,20 @@ impl<'a> Resolver<'a> {
|
||||
// first component of the path in the current lexical
|
||||
// scope and then proceed to resolve below that.
|
||||
let ident = ast::Ident::with_empty_ctxt(module_path[0]);
|
||||
match self.resolve_ident_in_lexical_scope(ident, TypeNS, span)
|
||||
.and_then(LexicalScopeBinding::module) {
|
||||
None => return Failed(None),
|
||||
Some(containing_module) => {
|
||||
search_module = containing_module;
|
||||
start_index = 1;
|
||||
let lexical_binding =
|
||||
self.resolve_ident_in_lexical_scope(ident, TypeNS, span);
|
||||
if let Some(binding) = lexical_binding.and_then(LexicalScopeBinding::item) {
|
||||
match self.expect_module(ident.name, binding, span) {
|
||||
Success(containing_module) => {
|
||||
search_module = containing_module;
|
||||
start_index = 1;
|
||||
}
|
||||
result @ _ => return result,
|
||||
}
|
||||
} else {
|
||||
let msg =
|
||||
format!("Use of undeclared type or module `{}`", ident.name);
|
||||
return Failed(span.map(|span| (span, msg)));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1474,35 +1522,6 @@ impl<'a> Resolver<'a> {
|
||||
None
|
||||
}
|
||||
|
||||
/// Returns the nearest normal module parent of the given module.
|
||||
fn get_nearest_normal_module_parent(&self, mut module: Module<'a>) -> Option<Module<'a>> {
|
||||
loop {
|
||||
match module.parent_link {
|
||||
NoParentLink => return None,
|
||||
ModuleParentLink(new_module, _) |
|
||||
BlockParentLink(new_module, _) => {
|
||||
let new_module = new_module;
|
||||
if new_module.is_normal() {
|
||||
return Some(new_module);
|
||||
}
|
||||
module = new_module;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the nearest normal module parent of the given module, or the
|
||||
/// module itself if it is a normal module.
|
||||
fn get_nearest_normal_module_parent_or_self(&self, module: Module<'a>) -> Module<'a> {
|
||||
if module.is_normal() {
|
||||
return module;
|
||||
}
|
||||
match self.get_nearest_normal_module_parent(module) {
|
||||
None => module,
|
||||
Some(new_module) => new_module,
|
||||
}
|
||||
}
|
||||
|
||||
/// Resolves a "module prefix". A module prefix is one or both of (a) `self::`;
|
||||
/// (b) some chain of `super::`.
|
||||
/// grammar: (SELF MOD_SEP ) ? (SUPER MOD_SEP) *
|
||||
@ -1515,22 +1534,20 @@ impl<'a> Resolver<'a> {
|
||||
"super" => 0,
|
||||
_ => return Success(NoPrefixFound),
|
||||
};
|
||||
|
||||
let mut containing_module =
|
||||
self.get_nearest_normal_module_parent_or_self(self.current_module);
|
||||
self.module_map[&self.current_module.normal_ancestor_id.unwrap()];
|
||||
|
||||
// Now loop through all the `super`s we find.
|
||||
while i < module_path.len() && "super" == module_path[i].as_str() {
|
||||
debug!("(resolving module prefix) resolving `super` at {}",
|
||||
module_to_string(&containing_module));
|
||||
match self.get_nearest_normal_module_parent(containing_module) {
|
||||
None => {
|
||||
let msg = "There are too many initial `super`s.".into();
|
||||
return Failed(span.map(|span| (span, msg)));
|
||||
}
|
||||
Some(new_module) => {
|
||||
containing_module = new_module;
|
||||
i += 1;
|
||||
}
|
||||
if let Some(parent) = containing_module.parent() {
|
||||
containing_module = self.module_map[&parent.normal_ancestor_id.unwrap()];
|
||||
i += 1;
|
||||
} else {
|
||||
let msg = "There are too many initial `super`s.".into();
|
||||
return Failed(span.map(|span| (span, msg)));
|
||||
}
|
||||
}
|
||||
|
||||
@ -1565,14 +1582,12 @@ impl<'a> Resolver<'a> {
|
||||
if let Some(module) = module {
|
||||
// Move down in the graph.
|
||||
let orig_module = replace(&mut self.current_module, module);
|
||||
let orig_vis = replace(&mut self.current_vis, ty::Visibility::Restricted(id));
|
||||
self.value_ribs.push(Rib::new(ModuleRibKind(module)));
|
||||
self.type_ribs.push(Rib::new(ModuleRibKind(module)));
|
||||
|
||||
f(self);
|
||||
|
||||
self.current_module = orig_module;
|
||||
self.current_vis = orig_vis;
|
||||
self.value_ribs.pop();
|
||||
self.type_ribs.pop();
|
||||
} else {
|
||||
@ -1697,7 +1712,7 @@ impl<'a> Resolver<'a> {
|
||||
&prefix.segments,
|
||||
TypeNS) {
|
||||
Ok(binding) => {
|
||||
let def = binding.def().unwrap();
|
||||
let def = binding.def();
|
||||
self.record_def(item.id, PathResolution::new(def));
|
||||
}
|
||||
Err(true) => self.record_def(item.id, err_path_resolution()),
|
||||
@ -2313,14 +2328,15 @@ impl<'a> Resolver<'a> {
|
||||
// entity, then fall back to a fresh binding.
|
||||
let binding = self.resolve_ident_in_lexical_scope(ident.node, ValueNS, None)
|
||||
.and_then(LexicalScopeBinding::item);
|
||||
let resolution = binding.and_then(NameBinding::def).and_then(|def| {
|
||||
let resolution = binding.map(NameBinding::def).and_then(|def| {
|
||||
let always_binding = !pat_src.is_refutable() || opt_pat.is_some() ||
|
||||
bmode != BindingMode::ByValue(Mutability::Immutable);
|
||||
match def {
|
||||
Def::Struct(..) | Def::Variant(..) |
|
||||
Def::Const(..) | Def::AssociatedConst(..) if !always_binding => {
|
||||
// A constant, unit variant, etc pattern.
|
||||
self.record_use(ident.node.name, ValueNS, binding.unwrap());
|
||||
let name = ident.node.name;
|
||||
self.record_use(name, ValueNS, binding.unwrap(), ident.span);
|
||||
Some(PathResolution::new(def))
|
||||
}
|
||||
Def::Struct(..) | Def::Variant(..) |
|
||||
@ -2447,7 +2463,7 @@ impl<'a> Resolver<'a> {
|
||||
|
||||
if path.global {
|
||||
let binding = self.resolve_crate_relative_path(span, segments, namespace);
|
||||
return binding.map(|binding| mk_res(binding.def().unwrap()));
|
||||
return binding.map(|binding| mk_res(binding.def()));
|
||||
}
|
||||
|
||||
// Try to find a path to an item in a module.
|
||||
@ -2485,7 +2501,7 @@ impl<'a> Resolver<'a> {
|
||||
let unqualified_def = resolve_identifier_with_fallback(self, None);
|
||||
let qualified_binding = self.resolve_module_relative_path(span, segments, namespace);
|
||||
match (qualified_binding, unqualified_def) {
|
||||
(Ok(binding), Some(ref ud)) if binding.def().unwrap() == ud.def => {
|
||||
(Ok(binding), Some(ref ud)) if binding.def() == ud.def => {
|
||||
self.session
|
||||
.add_lint(lint::builtin::UNUSED_QUALIFICATIONS,
|
||||
id,
|
||||
@ -2495,7 +2511,7 @@ impl<'a> Resolver<'a> {
|
||||
_ => {}
|
||||
}
|
||||
|
||||
qualified_binding.map(|binding| mk_res(binding.def().unwrap()))
|
||||
qualified_binding.map(|binding| mk_res(binding.def()))
|
||||
}
|
||||
|
||||
// Resolve a single identifier
|
||||
@ -2618,16 +2634,9 @@ impl<'a> Resolver<'a> {
|
||||
let containing_module;
|
||||
match self.resolve_module_path(&module_path, UseLexicalScope, Some(span)) {
|
||||
Failed(err) => {
|
||||
let (span, msg) = match err {
|
||||
Some((span, msg)) => (span, msg),
|
||||
None => {
|
||||
let msg = format!("Use of undeclared type or module `{}`",
|
||||
names_to_string(&module_path));
|
||||
(span, msg)
|
||||
}
|
||||
};
|
||||
|
||||
resolve_error(self, span, ResolutionError::FailedToResolve(&msg));
|
||||
if let Some((span, msg)) = err {
|
||||
resolve_error(self, span, ResolutionError::FailedToResolve(&msg));
|
||||
}
|
||||
return Err(true);
|
||||
}
|
||||
Indeterminate => return Err(false),
|
||||
@ -2655,16 +2664,9 @@ impl<'a> Resolver<'a> {
|
||||
let containing_module;
|
||||
match self.resolve_module_path_from_root(root_module, &module_path, 0, Some(span)) {
|
||||
Failed(err) => {
|
||||
let (span, msg) = match err {
|
||||
Some((span, msg)) => (span, msg),
|
||||
None => {
|
||||
let msg = format!("Use of undeclared module `::{}`",
|
||||
names_to_string(&module_path));
|
||||
(span, msg)
|
||||
}
|
||||
};
|
||||
|
||||
resolve_error(self, span, ResolutionError::FailedToResolve(&msg));
|
||||
if let Some((span, msg)) = err {
|
||||
resolve_error(self, span, ResolutionError::FailedToResolve(&msg));
|
||||
}
|
||||
return Err(true);
|
||||
}
|
||||
|
||||
@ -3118,7 +3120,7 @@ impl<'a> Resolver<'a> {
|
||||
let mut collected_traits = Vec::new();
|
||||
module.for_each_child(|name, ns, binding| {
|
||||
if ns != TypeNS { return }
|
||||
if let Some(Def::Trait(_)) = binding.def() {
|
||||
if let Def::Trait(_) = binding.def() {
|
||||
collected_traits.push((name, binding));
|
||||
}
|
||||
});
|
||||
@ -3126,7 +3128,7 @@ impl<'a> Resolver<'a> {
|
||||
}
|
||||
|
||||
for &(trait_name, binding) in traits.as_ref().unwrap().iter() {
|
||||
let trait_def_id = binding.def().unwrap().def_id();
|
||||
let trait_def_id = binding.def().def_id();
|
||||
if this.trait_item_map.contains_key(&(name, trait_def_id)) {
|
||||
let mut import_id = None;
|
||||
if let NameBindingKind::Import { directive, .. } = binding.kind {
|
||||
@ -3185,8 +3187,8 @@ impl<'a> Resolver<'a> {
|
||||
if name_binding.is_import() { return; }
|
||||
|
||||
// collect results based on the filter function
|
||||
if let Some(def) = name_binding.def() {
|
||||
if name == lookup_name && ns == namespace && filter_fn(def) {
|
||||
if name == lookup_name && ns == namespace {
|
||||
if filter_fn(name_binding.def()) {
|
||||
// create the path
|
||||
let ident = ast::Ident::with_empty_ctxt(name);
|
||||
let params = PathParameters::none();
|
||||
@ -3216,7 +3218,7 @@ impl<'a> Resolver<'a> {
|
||||
}
|
||||
|
||||
// collect submodules to explore
|
||||
if let Some(module) = name_binding.module() {
|
||||
if let Ok(module) = name_binding.module() {
|
||||
// form the path
|
||||
let path_segments = match module.parent_link {
|
||||
NoParentLink => path_segments.clone(),
|
||||
@ -3263,23 +3265,23 @@ impl<'a> Resolver<'a> {
|
||||
ast::Visibility::Public => return ty::Visibility::Public,
|
||||
ast::Visibility::Crate(_) => return ty::Visibility::Restricted(ast::CRATE_NODE_ID),
|
||||
ast::Visibility::Restricted { ref path, id } => (path, id),
|
||||
ast::Visibility::Inherited => return self.current_vis,
|
||||
ast::Visibility::Inherited => {
|
||||
return ty::Visibility::Restricted(self.current_module.normal_ancestor_id.unwrap());
|
||||
}
|
||||
};
|
||||
|
||||
let segments: Vec<_> = path.segments.iter().map(|seg| seg.identifier.name).collect();
|
||||
let mut path_resolution = err_path_resolution();
|
||||
let vis = match self.resolve_module_path(&segments, DontUseLexicalScope, Some(path.span)) {
|
||||
Success(module) => {
|
||||
let def = module.def.unwrap();
|
||||
path_resolution = PathResolution::new(def);
|
||||
ty::Visibility::Restricted(self.definitions.as_local_node_id(def.def_id()).unwrap())
|
||||
path_resolution = PathResolution::new(module.def.unwrap());
|
||||
ty::Visibility::Restricted(module.normal_ancestor_id.unwrap())
|
||||
}
|
||||
Failed(Some((span, msg))) => {
|
||||
self.session.span_err(span, &format!("failed to resolve module path. {}", msg));
|
||||
ty::Visibility::Public
|
||||
}
|
||||
_ => {
|
||||
self.session.span_err(path.span, "unresolved module path");
|
||||
Indeterminate => unreachable!(),
|
||||
Failed(err) => {
|
||||
if let Some((span, msg)) = err {
|
||||
self.session.span_err(span, &format!("failed to resolve module path. {}", msg));
|
||||
}
|
||||
ty::Visibility::Public
|
||||
}
|
||||
};
|
||||
@ -3292,12 +3294,28 @@ impl<'a> Resolver<'a> {
|
||||
}
|
||||
|
||||
fn is_accessible(&self, vis: ty::Visibility) -> bool {
|
||||
vis.is_at_least(self.current_vis, self)
|
||||
vis.is_accessible_from(self.current_module.normal_ancestor_id.unwrap(), self)
|
||||
}
|
||||
|
||||
fn report_privacy_errors(&self) {
|
||||
if self.privacy_errors.len() == 0 { return }
|
||||
fn is_accessible_from(&self, vis: ty::Visibility, module: Module<'a>) -> bool {
|
||||
vis.is_accessible_from(module.normal_ancestor_id.unwrap(), self)
|
||||
}
|
||||
|
||||
fn report_errors(&self) {
|
||||
let mut reported_spans = FnvHashSet();
|
||||
|
||||
for &(span, name, binding) in &self.ambiguity_errors {
|
||||
if !reported_spans.insert(span) { continue }
|
||||
let (b1, b2) = binding.ambiguity().unwrap();
|
||||
let msg1 = format!("`{}` could resolve to the name imported here", name);
|
||||
let msg2 = format!("`{}` could also resolve to the name imported here", name);
|
||||
self.session.struct_span_err(span, &format!("`{}` is ambiguous", name))
|
||||
.span_note(b1.span, &msg1)
|
||||
.span_note(b2.span, &msg2)
|
||||
.note(&format!("Consider adding an explicit import of `{}` to disambiguate", name))
|
||||
.emit();
|
||||
}
|
||||
|
||||
for &PrivacyError(span, name, binding) in &self.privacy_errors {
|
||||
if !reported_spans.insert(span) { continue }
|
||||
if binding.is_extern_crate() {
|
||||
@ -3306,7 +3324,7 @@ impl<'a> Resolver<'a> {
|
||||
let msg = format!("extern crate `{}` is private", name);
|
||||
self.session.add_lint(lint::builtin::INACCESSIBLE_EXTERN_CRATE, node_id, span, msg);
|
||||
} else {
|
||||
let def = binding.def().unwrap();
|
||||
let def = binding.def();
|
||||
self.session.span_err(span, &format!("{} `{}` is private", def.kind_name(), name));
|
||||
}
|
||||
}
|
||||
@ -3339,9 +3357,9 @@ impl<'a> Resolver<'a> {
|
||||
let msg = {
|
||||
let kind = match (ns, old_binding.module()) {
|
||||
(ValueNS, _) => "a value",
|
||||
(TypeNS, Some(module)) if module.extern_crate_id.is_some() => "an extern crate",
|
||||
(TypeNS, Some(module)) if module.is_normal() => "a module",
|
||||
(TypeNS, Some(module)) if module.is_trait() => "a trait",
|
||||
(TypeNS, Ok(module)) if module.extern_crate_id.is_some() => "an extern crate",
|
||||
(TypeNS, Ok(module)) if module.is_normal() => "a module",
|
||||
(TypeNS, Ok(module)) if module.is_trait() => "a trait",
|
||||
(TypeNS, _) => "a type",
|
||||
};
|
||||
format!("{} named `{}` has already been {} in this {}",
|
||||
|
@ -27,7 +27,7 @@ use rustc::hir::def::*;
|
||||
|
||||
use syntax::ast::{NodeId, Name};
|
||||
use syntax::util::lev_distance::find_best_match_for_name;
|
||||
use syntax_pos::{Span, DUMMY_SP};
|
||||
use syntax_pos::Span;
|
||||
|
||||
use std::cell::{Cell, RefCell};
|
||||
|
||||
@ -52,7 +52,11 @@ pub enum ImportDirectiveSubclass<'a> {
|
||||
value_result: Cell<Result<&'a NameBinding<'a>, Determinacy>>,
|
||||
type_result: Cell<Result<&'a NameBinding<'a>, Determinacy>>,
|
||||
},
|
||||
GlobImport { is_prelude: bool },
|
||||
GlobImport {
|
||||
is_prelude: bool,
|
||||
max_vis: Cell<ty::Visibility>, // The visibility of the greatest reexport.
|
||||
// n.b. `max_vis` is only used in `finalize_import` to check for reexport errors.
|
||||
},
|
||||
}
|
||||
|
||||
impl<'a> ImportDirectiveSubclass<'a> {
|
||||
@ -167,8 +171,10 @@ impl<'a> Resolver<'a> {
|
||||
_ => return Failed(None), // This happens when there is a cycle of imports
|
||||
};
|
||||
|
||||
let new_import_semantics = self.new_import_semantics;
|
||||
let is_disallowed_private_import = |binding: &NameBinding| {
|
||||
!allow_private_imports && !binding.is_pseudo_public() && binding.is_import()
|
||||
!new_import_semantics && !allow_private_imports && // disallowed
|
||||
binding.vis != ty::Visibility::Public && binding.is_import() // non-`pub` import
|
||||
};
|
||||
|
||||
if let Some(span) = record_used {
|
||||
@ -176,7 +182,9 @@ impl<'a> Resolver<'a> {
|
||||
if is_disallowed_private_import(binding) {
|
||||
return Failed(None);
|
||||
}
|
||||
self.record_use(name, ns, binding);
|
||||
if self.record_use(name, ns, binding, span) {
|
||||
return Success(self.dummy_binding);
|
||||
}
|
||||
if !self.is_accessible(binding.vis) {
|
||||
self.privacy_errors.push(PrivacyError(span, name, binding));
|
||||
}
|
||||
@ -274,7 +282,7 @@ impl<'a> Resolver<'a> {
|
||||
}
|
||||
// We don't add prelude imports to the globs since they only affect lexical scopes,
|
||||
// which are not relevant to import resolution.
|
||||
GlobImport { is_prelude: true } => {}
|
||||
GlobImport { is_prelude: true, .. } => {}
|
||||
GlobImport { .. } => self.current_module.globs.borrow_mut().push(directive),
|
||||
}
|
||||
}
|
||||
@ -283,13 +291,26 @@ impl<'a> Resolver<'a> {
|
||||
// return the corresponding binding defined by the import directive.
|
||||
fn import(&mut self, binding: &'a NameBinding<'a>, directive: &'a ImportDirective<'a>)
|
||||
-> NameBinding<'a> {
|
||||
let vis = if binding.pseudo_vis().is_at_least(directive.vis.get(), self) ||
|
||||
!directive.is_glob() && binding.is_extern_crate() { // c.f. `PRIVATE_IN_PUBLIC`
|
||||
directive.vis.get()
|
||||
} else {
|
||||
binding.pseudo_vis()
|
||||
};
|
||||
|
||||
if let GlobImport { ref max_vis, .. } = directive.subclass {
|
||||
if vis == directive.vis.get() || vis.is_at_least(max_vis.get(), self) {
|
||||
max_vis.set(vis)
|
||||
}
|
||||
}
|
||||
|
||||
NameBinding {
|
||||
kind: NameBindingKind::Import {
|
||||
binding: binding,
|
||||
directive: directive,
|
||||
},
|
||||
span: directive.span,
|
||||
vis: directive.vis.get(),
|
||||
vis: vis,
|
||||
}
|
||||
}
|
||||
|
||||
@ -299,10 +320,28 @@ impl<'a> Resolver<'a> {
|
||||
where T: ToNameBinding<'a>
|
||||
{
|
||||
let binding = self.arenas.alloc_name_binding(binding.to_name_binding());
|
||||
self.update_resolution(module, name, ns, |_, resolution| {
|
||||
self.update_resolution(module, name, ns, |this, resolution| {
|
||||
if let Some(old_binding) = resolution.binding {
|
||||
if binding.is_glob_import() {
|
||||
resolution.duplicate_globs.push(binding);
|
||||
if !this.new_import_semantics || !old_binding.is_glob_import() {
|
||||
resolution.duplicate_globs.push(binding);
|
||||
} else if binding.def() != old_binding.def() {
|
||||
resolution.binding = Some(this.arenas.alloc_name_binding(NameBinding {
|
||||
kind: NameBindingKind::Ambiguity {
|
||||
b1: old_binding,
|
||||
b2: binding,
|
||||
},
|
||||
vis: if old_binding.vis.is_at_least(binding.vis, this) {
|
||||
old_binding.vis
|
||||
} else {
|
||||
binding.vis
|
||||
},
|
||||
span: old_binding.span,
|
||||
}));
|
||||
} else if !old_binding.vis.is_at_least(binding.vis, this) {
|
||||
// We are glob-importing the same item but with greater visibility.
|
||||
resolution.binding = Some(binding);
|
||||
}
|
||||
} else if old_binding.is_glob_import() {
|
||||
resolution.duplicate_globs.push(old_binding);
|
||||
resolution.binding = Some(binding);
|
||||
@ -324,23 +363,29 @@ impl<'a> Resolver<'a> {
|
||||
{
|
||||
// Ensure that `resolution` isn't borrowed when defining in the module's glob importers,
|
||||
// during which the resolution might end up getting re-defined via a glob cycle.
|
||||
let (new_binding, t) = {
|
||||
let (binding, t) = {
|
||||
let mut resolution = &mut *self.resolution(module, name, ns).borrow_mut();
|
||||
let was_known = resolution.binding().is_some();
|
||||
let old_binding = resolution.binding();
|
||||
|
||||
let t = f(self, resolution);
|
||||
|
||||
if was_known { return t; }
|
||||
match resolution.binding() {
|
||||
Some(binding) => (binding, t),
|
||||
_ if !self.new_import_semantics && old_binding.is_some() => return t,
|
||||
None => return t,
|
||||
Some(binding) => match old_binding {
|
||||
Some(old_binding) if old_binding as *const _ == binding as *const _ => return t,
|
||||
_ => (binding, t),
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// Define `new_binding` in `module`s glob importers.
|
||||
if new_binding.is_importable() && new_binding.is_pseudo_public() {
|
||||
for directive in module.glob_importers.borrow_mut().iter() {
|
||||
let imported_binding = self.import(new_binding, directive);
|
||||
// Define `binding` in `module`s glob importers.
|
||||
for directive in module.glob_importers.borrow_mut().iter() {
|
||||
if match self.new_import_semantics {
|
||||
true => self.is_accessible_from(binding.vis, directive.parent),
|
||||
false => binding.vis == ty::Visibility::Public,
|
||||
} {
|
||||
let imported_binding = self.import(binding, directive);
|
||||
let _ = self.try_define(directive.parent, name, ns, imported_binding);
|
||||
}
|
||||
}
|
||||
@ -381,14 +426,6 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> {
|
||||
// remain or unsuccessfully when no forward progress in resolving imports
|
||||
// is made.
|
||||
|
||||
fn set_current_module(&mut self, module: Module<'b>) {
|
||||
self.current_module = module;
|
||||
self.current_vis = ty::Visibility::Restricted({
|
||||
let normal_module = self.get_nearest_normal_module_parent_or_self(module);
|
||||
self.definitions.as_local_node_id(normal_module.def_id().unwrap()).unwrap()
|
||||
});
|
||||
}
|
||||
|
||||
/// Resolves all imports for the crate. This method performs the fixed-
|
||||
/// point iteration.
|
||||
fn resolve_imports(&mut self) {
|
||||
@ -424,7 +461,7 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> {
|
||||
errors = true;
|
||||
let (span, help) = match err {
|
||||
Some((span, msg)) => (span, msg),
|
||||
None => (import.span, String::new()),
|
||||
None => continue,
|
||||
};
|
||||
|
||||
// If the error is a single failed import then create a "fake" import
|
||||
@ -450,13 +487,8 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> {
|
||||
// failed resolution
|
||||
fn import_dummy_binding(&mut self, directive: &'b ImportDirective<'b>) {
|
||||
if let SingleImport { target, .. } = directive.subclass {
|
||||
let dummy_binding = self.arenas.alloc_name_binding(NameBinding {
|
||||
kind: NameBindingKind::Def(Def::Err),
|
||||
span: DUMMY_SP,
|
||||
vis: ty::Visibility::Public,
|
||||
});
|
||||
let dummy_binding = self.dummy_binding;
|
||||
let dummy_binding = self.import(dummy_binding, directive);
|
||||
|
||||
let _ = self.try_define(directive.parent, target, ValueNS, dummy_binding.clone());
|
||||
let _ = self.try_define(directive.parent, target, TypeNS, dummy_binding);
|
||||
}
|
||||
@ -472,7 +504,7 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> {
|
||||
names_to_string(&directive.module_path),
|
||||
module_to_string(self.current_module));
|
||||
|
||||
self.set_current_module(directive.parent);
|
||||
self.current_module = directive.parent;
|
||||
|
||||
let module = if let Some(module) = directive.imported_module.get() {
|
||||
module
|
||||
@ -548,7 +580,7 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> {
|
||||
}
|
||||
|
||||
fn finalize_import(&mut self, directive: &'b ImportDirective<'b>) -> ResolveResult<()> {
|
||||
self.set_current_module(directive.parent);
|
||||
self.current_module = directive.parent;
|
||||
|
||||
let ImportDirective { ref module_path, span, .. } = *directive;
|
||||
let module_result = self.resolve_module_path(&module_path, DontUseLexicalScope, Some(span));
|
||||
@ -566,12 +598,23 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> {
|
||||
let msg = "Cannot glob-import a module into itself.".into();
|
||||
return Failed(Some((directive.span, msg)));
|
||||
}
|
||||
GlobImport { .. } => return Success(()),
|
||||
GlobImport { is_prelude, ref max_vis } => {
|
||||
if !is_prelude &&
|
||||
max_vis.get() != ty::Visibility::PrivateExternal && // Allow empty globs.
|
||||
!max_vis.get().is_at_least(directive.vis.get(), self) {
|
||||
let msg = "A non-empty glob must import something with the glob's visibility";
|
||||
self.session.span_err(directive.span, msg);
|
||||
}
|
||||
return Success(());
|
||||
}
|
||||
};
|
||||
|
||||
for &(ns, result) in &[(ValueNS, value_result), (TypeNS, type_result)] {
|
||||
if let Ok(binding) = result {
|
||||
self.record_use(name, ns, binding);
|
||||
if self.record_use(name, ns, binding, directive.span) {
|
||||
self.resolution(module, name, ns).borrow_mut().binding =
|
||||
Some(self.dummy_binding);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -608,22 +651,44 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> {
|
||||
}
|
||||
}
|
||||
|
||||
let session = self.session;
|
||||
let reexport_error = || {
|
||||
let msg = format!("`{}` is private, and cannot be reexported", name);
|
||||
let note_msg =
|
||||
format!("consider marking `{}` as `pub` in the imported module", name);
|
||||
struct_span_err!(session, directive.span, E0364, "{}", &msg)
|
||||
.span_note(directive.span, ¬e_msg)
|
||||
.emit();
|
||||
};
|
||||
|
||||
let extern_crate_lint = || {
|
||||
let msg = format!("extern crate `{}` is private, and cannot be reexported \
|
||||
(error E0364), consider declaring with `pub`",
|
||||
name);
|
||||
session.add_lint(PRIVATE_IN_PUBLIC, directive.id, directive.span, msg);
|
||||
};
|
||||
|
||||
match (value_result, type_result) {
|
||||
// With `#![feature(item_like_imports)]`, all namespaces
|
||||
// must be re-exported with extra visibility for an error to occur.
|
||||
(Ok(value_binding), Ok(type_binding)) if self.new_import_semantics => {
|
||||
let vis = directive.vis.get();
|
||||
if !value_binding.pseudo_vis().is_at_least(vis, self) &&
|
||||
!type_binding.pseudo_vis().is_at_least(vis, self) {
|
||||
reexport_error();
|
||||
} else if type_binding.is_extern_crate() &&
|
||||
!type_binding.vis.is_at_least(vis, self) {
|
||||
extern_crate_lint();
|
||||
}
|
||||
}
|
||||
|
||||
(Ok(binding), _) if !binding.pseudo_vis().is_at_least(directive.vis.get(), self) => {
|
||||
let msg = format!("`{}` is private, and cannot be reexported", name);
|
||||
let note_msg =
|
||||
format!("consider marking `{}` as `pub` in the imported module", name);
|
||||
struct_span_err!(self.session, directive.span, E0364, "{}", &msg)
|
||||
.span_note(directive.span, ¬e_msg)
|
||||
.emit();
|
||||
reexport_error();
|
||||
}
|
||||
|
||||
(_, Ok(binding)) if !binding.pseudo_vis().is_at_least(directive.vis.get(), self) => {
|
||||
if binding.is_extern_crate() {
|
||||
let msg = format!("extern crate `{}` is private, and cannot be reexported \
|
||||
(error E0364), consider declaring with `pub`",
|
||||
name);
|
||||
self.session.add_lint(PRIVATE_IN_PUBLIC, directive.id, directive.span, msg);
|
||||
extern_crate_lint();
|
||||
} else {
|
||||
struct_span_err!(self.session, directive.span, E0365,
|
||||
"`{}` is private, and cannot be reexported", name)
|
||||
@ -639,9 +704,9 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> {
|
||||
// Record what this import resolves to for later uses in documentation,
|
||||
// this may resolve to either a value or a type, but for documentation
|
||||
// purposes it's good enough to just favor one over the other.
|
||||
let def = match type_result.ok().and_then(NameBinding::def) {
|
||||
let def = match type_result.ok().map(NameBinding::def) {
|
||||
Some(def) => def,
|
||||
None => value_result.ok().and_then(NameBinding::def).unwrap(),
|
||||
None => value_result.ok().map(NameBinding::def).unwrap(),
|
||||
};
|
||||
let path_resolution = PathResolution::new(def);
|
||||
self.def_map.insert(directive.id, path_resolution);
|
||||
@ -656,11 +721,10 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> {
|
||||
|
||||
if let Some(Def::Trait(_)) = module.def {
|
||||
self.session.span_err(directive.span, "items in traits are not importable.");
|
||||
}
|
||||
|
||||
if module.def_id() == directive.parent.def_id() {
|
||||
return;
|
||||
} else if let GlobImport { is_prelude: true } = directive.subclass {
|
||||
} else if module.def_id() == directive.parent.def_id() {
|
||||
return;
|
||||
} else if let GlobImport { is_prelude: true, .. } = directive.subclass {
|
||||
self.prelude = Some(module);
|
||||
return;
|
||||
}
|
||||
@ -674,7 +738,8 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> {
|
||||
resolution.borrow().binding().map(|binding| (*name, binding))
|
||||
}).collect::<Vec<_>>();
|
||||
for ((name, ns), binding) in bindings {
|
||||
if binding.is_importable() && binding.is_pseudo_public() {
|
||||
if binding.pseudo_vis() == ty::Visibility::Public ||
|
||||
self.new_import_semantics && self.is_accessible(binding.vis) {
|
||||
let imported_binding = self.import(binding, directive);
|
||||
let _ = self.try_define(directive.parent, name, ns, imported_binding);
|
||||
}
|
||||
@ -702,20 +767,23 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> {
|
||||
};
|
||||
|
||||
// Report conflicts
|
||||
for duplicate_glob in resolution.duplicate_globs.iter() {
|
||||
// FIXME #31337: We currently allow items to shadow glob-imported re-exports.
|
||||
if !binding.is_import() {
|
||||
if let NameBindingKind::Import { binding, .. } = duplicate_glob.kind {
|
||||
if binding.is_import() { continue }
|
||||
if !self.new_import_semantics {
|
||||
for duplicate_glob in resolution.duplicate_globs.iter() {
|
||||
// FIXME #31337: We currently allow items to shadow glob-imported re-exports.
|
||||
if !binding.is_import() {
|
||||
if let NameBindingKind::Import { binding, .. } = duplicate_glob.kind {
|
||||
if binding.is_import() { continue }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
self.report_conflict(module, name, ns, duplicate_glob, binding);
|
||||
self.report_conflict(module, name, ns, duplicate_glob, binding);
|
||||
}
|
||||
}
|
||||
|
||||
if binding.vis == ty::Visibility::Public &&
|
||||
(binding.is_import() || binding.is_extern_crate()) {
|
||||
if let Some(def) = binding.def() {
|
||||
let def = binding.def();
|
||||
if def != Def::Err {
|
||||
reexports.push(Export { name: name, def_id: def.def_id() });
|
||||
}
|
||||
}
|
||||
|
@ -285,7 +285,10 @@ declare_features! (
|
||||
|
||||
// Allows the sysV64 ABI to be specified on all platforms
|
||||
// instead of just the platforms on which it is the C ABI
|
||||
(active, abi_sysv64, "1.13.0", Some(36167))
|
||||
(active, abi_sysv64, "1.13.0", Some(36167)),
|
||||
|
||||
// Use the import semantics from RFC 1560.
|
||||
(active, item_like_imports, "1.13.0", Some(35120))
|
||||
);
|
||||
|
||||
declare_features! (
|
||||
|
@ -8,6 +8,10 @@
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// error-pattern: failed to resolve. Use of undeclared type or module `thing`
|
||||
fn main() {
|
||||
let foo = thing::len(Vec::new());
|
||||
//~^ ERROR failed to resolve. Use of undeclared type or module `thing`
|
||||
|
||||
fn main() { let foo = thing::len(Vec::new()); }
|
||||
let foo = foo::bar::baz();
|
||||
//~^ ERROR failed to resolve. Use of undeclared type or module `foo`
|
||||
}
|
||||
|
70
src/test/compile-fail/imports/duplicate.rs
Normal file
70
src/test/compile-fail/imports/duplicate.rs
Normal file
@ -0,0 +1,70 @@
|
||||
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
#![feature(item_like_imports)]
|
||||
|
||||
mod a {
|
||||
pub fn foo() {}
|
||||
}
|
||||
|
||||
mod b {
|
||||
pub fn foo() {}
|
||||
}
|
||||
|
||||
mod c {
|
||||
pub use a::foo;
|
||||
}
|
||||
|
||||
mod d {
|
||||
use a::foo; //~ NOTE previous import
|
||||
use a::foo; //~ ERROR `foo` has already been imported
|
||||
//~| NOTE already imported
|
||||
}
|
||||
|
||||
mod e {
|
||||
pub use a::*;
|
||||
pub use c::*; // ok
|
||||
}
|
||||
|
||||
mod f {
|
||||
pub use a::*; //~ NOTE `foo` could resolve to the name imported here
|
||||
pub use b::*; //~ NOTE `foo` could also resolve to the name imported here
|
||||
}
|
||||
|
||||
mod g {
|
||||
pub use a::*; //~ NOTE `foo` could resolve to the name imported here
|
||||
pub use f::*; //~ NOTE `foo` could also resolve to the name imported here
|
||||
}
|
||||
|
||||
fn main() {
|
||||
e::foo();
|
||||
f::foo(); //~ ERROR `foo` is ambiguous
|
||||
//~| NOTE Consider adding an explicit import of `foo` to disambiguate
|
||||
g::foo(); //~ ERROR `foo` is ambiguous
|
||||
//~| NOTE Consider adding an explicit import of `foo` to disambiguate
|
||||
}
|
||||
|
||||
mod ambiguous_module_errors {
|
||||
pub mod m1 { pub use super::m1 as foo; }
|
||||
pub mod m2 { pub use super::m2 as foo; }
|
||||
|
||||
use self::m1::*; //~ NOTE
|
||||
//~| NOTE
|
||||
use self::m2::*; //~ NOTE
|
||||
//~| NOTE
|
||||
|
||||
use self::foo::bar; //~ ERROR `foo` is ambiguous
|
||||
//~| NOTE
|
||||
|
||||
fn f() {
|
||||
foo::bar(); //~ ERROR `foo` is ambiguous
|
||||
//~| NOTE
|
||||
}
|
||||
}
|
44
src/test/compile-fail/imports/reexports.rs
Normal file
44
src/test/compile-fail/imports/reexports.rs
Normal file
@ -0,0 +1,44 @@
|
||||
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
#![feature(item_like_imports)]
|
||||
|
||||
mod a {
|
||||
fn foo() {}
|
||||
mod foo {}
|
||||
|
||||
mod a {
|
||||
pub use super::foo; //~ ERROR cannot be reexported
|
||||
pub use super::*; //~ ERROR must import something with the glob's visibility
|
||||
}
|
||||
}
|
||||
|
||||
mod b {
|
||||
pub fn foo() {}
|
||||
mod foo { pub struct S; }
|
||||
|
||||
pub mod a {
|
||||
pub use super::foo; // This is OK since the value `foo` is visible enough.
|
||||
fn f(_: foo::S) {} // `foo` is imported in the type namespace (but not `pub` reexported).
|
||||
}
|
||||
|
||||
pub mod b {
|
||||
pub use super::*; // This is also OK since the value `foo` is visible enough.
|
||||
fn f(_: foo::S) {} // Again, the module `foo` is imported (but not `pub` reexported).
|
||||
}
|
||||
}
|
||||
|
||||
mod c {
|
||||
// Test that `foo` is not reexported.
|
||||
use b::a::foo::S; //~ ERROR `foo`
|
||||
use b::b::foo::S as T; //~ ERROR `foo`
|
||||
}
|
||||
|
||||
fn main() {}
|
@ -10,10 +10,10 @@
|
||||
|
||||
// ensure that the ThreadRng isn't/doesn't become accidentally sendable.
|
||||
|
||||
use std::rand; //~ ERROR: module `rand` is private
|
||||
use std::__rand::ThreadRng;
|
||||
|
||||
fn test_send<S: Send>() {}
|
||||
|
||||
pub fn main() {
|
||||
test_send::<rand::ThreadRng>();
|
||||
test_send::<ThreadRng>(); //~ ERROR std::marker::Send` is not satisfied
|
||||
}
|
||||
|
78
src/test/run-pass/imports.rs
Normal file
78
src/test/run-pass/imports.rs
Normal file
@ -0,0 +1,78 @@
|
||||
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// ignore-pretty : (#23623) problems when ending with // comments
|
||||
|
||||
#![feature(item_like_imports)]
|
||||
#![allow(unused)]
|
||||
|
||||
// Like other items, private imports can be imported and used non-lexically in paths.
|
||||
mod a {
|
||||
use a as foo;
|
||||
use self::foo::foo as bar;
|
||||
|
||||
mod b {
|
||||
use super::bar;
|
||||
}
|
||||
}
|
||||
|
||||
mod foo { pub fn f() {} }
|
||||
mod bar { pub fn f() {} }
|
||||
|
||||
pub fn f() -> bool { true }
|
||||
|
||||
// Items and explicit imports shadow globs.
|
||||
fn g() {
|
||||
use foo::*;
|
||||
use bar::*;
|
||||
fn f() -> bool { true }
|
||||
let _: bool = f();
|
||||
}
|
||||
|
||||
fn h() {
|
||||
use foo::*;
|
||||
use bar::*;
|
||||
use f;
|
||||
let _: bool = f();
|
||||
}
|
||||
|
||||
// Here, there appears to be shadowing but isn't because of namespaces.
|
||||
mod b {
|
||||
use foo::*; // This imports `f` in the value namespace.
|
||||
use super::b as f; // This imports `f` only in the type namespace,
|
||||
fn test() { self::f(); } // so the glob isn't shadowed.
|
||||
}
|
||||
|
||||
// Here, there is shadowing in one namespace, but not the other.
|
||||
mod c {
|
||||
mod test {
|
||||
pub fn f() {}
|
||||
pub mod f {}
|
||||
}
|
||||
use self::test::*; // This glob-imports `f` in both namespaces.
|
||||
mod f { pub fn f() {} } // This shadows the glob only in the value namespace.
|
||||
|
||||
fn test() {
|
||||
self::f(); // Check that the glob-imported value isn't shadowed.
|
||||
self::f::f(); // Check that the glob-imported module is shadowed.
|
||||
}
|
||||
}
|
||||
|
||||
// Unused names can be ambiguous.
|
||||
mod d {
|
||||
pub use foo::*; // This imports `f` in the value namespace.
|
||||
pub use bar::*; // This also imports `f` in the value namespace.
|
||||
}
|
||||
|
||||
mod e {
|
||||
pub use d::*; // n.b. Since `e::f` is not used, this is not considered to be a use of `d::f`.
|
||||
}
|
||||
|
||||
fn main() {}
|
Loading…
Reference in New Issue
Block a user