Auto merge of #32240 - jseyfried:cleanup_resolve, r=nikomatsakis

Cleanup resolve

This is a collection of small refactorings and improvements in `resolve`, most of which could stand alone.
r? @nikomatsakis
This commit is contained in:
bors 2016-03-26 12:40:53 -07:00
commit 13bfd5c0b7
4 changed files with 221 additions and 407 deletions

View File

@ -19,12 +19,11 @@ use resolve_imports::ImportDirectiveSubclass::{self, SingleImport, GlobImport};
use Module;
use Namespace::{self, TypeNS, ValueNS};
use {NameBinding, NameBindingKind};
use module_to_string;
use ParentLink::{ModuleParentLink, BlockParentLink};
use Resolver;
use {resolve_error, resolve_struct_error, ResolutionError};
use rustc::middle::cstore::{CrateStore, ChildItem, DlDef, DlField, DlImpl};
use rustc::middle::cstore::{CrateStore, ChildItem, DlDef};
use rustc::middle::def::*;
use rustc::middle::def_id::{CRATE_DEF_INDEX, DefId};
use rustc::middle::ty::VariantKind;
@ -42,30 +41,8 @@ use rustc_front::hir::{ItemForeignMod, ItemImpl, ItemMod, ItemStatic, ItemDefaul
use rustc_front::hir::{ItemStruct, ItemTrait, ItemTy, ItemUse};
use rustc_front::hir::{PathListIdent, PathListMod, StmtDecl};
use rustc_front::hir::{Variant, ViewPathGlob, ViewPathList, ViewPathSimple};
use rustc_front::hir::Visibility;
use rustc_front::intravisit::{self, Visitor};
use std::mem::replace;
use std::ops::{Deref, DerefMut};
struct GraphBuilder<'a, 'b: 'a, 'tcx: 'b> {
resolver: &'a mut Resolver<'b, 'tcx>,
}
impl<'a, 'b:'a, 'tcx:'b> Deref for GraphBuilder<'a, 'b, 'tcx> {
type Target = Resolver<'b, 'tcx>;
fn deref(&self) -> &Resolver<'b, 'tcx> {
&*self.resolver
}
}
impl<'a, 'b:'a, 'tcx:'b> DerefMut for GraphBuilder<'a, 'b, 'tcx> {
fn deref_mut(&mut self) -> &mut Resolver<'b, 'tcx> {
&mut *self.resolver
}
}
trait ToNameBinding<'a> {
fn to_name_binding(self) -> NameBinding<'a>;
}
@ -83,12 +60,12 @@ impl<'a> ToNameBinding<'a> for (Def, Span, DefModifiers) {
}
}
impl<'a, 'b:'a, 'tcx:'b> GraphBuilder<'a, 'b, 'tcx> {
impl<'b, 'tcx:'b> Resolver<'b, 'tcx> {
/// Constructs the reduced graph for the entire crate.
fn build_reduced_graph(self, krate: &hir::Crate) {
pub fn build_reduced_graph(&mut self, krate: &hir::Crate) {
let mut visitor = BuildReducedGraphVisitor {
parent: self.graph_root,
builder: self,
resolver: self,
};
intravisit::walk_crate(&mut visitor, krate);
}
@ -124,7 +101,8 @@ impl<'a, 'b:'a, 'tcx:'b> GraphBuilder<'a, 'b, 'tcx> {
}
/// Constructs the reduced graph for one item.
fn build_reduced_graph_for_item(&mut self, item: &Item, parent: Module<'b>) -> Module<'b> {
fn build_reduced_graph_for_item(&mut self, item: &Item, parent_ref: &mut Module<'b>) {
let parent = *parent_ref;
let name = item.name;
let sp = item.span;
let is_public = item.vis == hir::Public;
@ -244,7 +222,6 @@ impl<'a, 'b:'a, 'tcx:'b> GraphBuilder<'a, 'b, 'tcx> {
is_prelude);
}
}
parent
}
ItemExternCrate(_) => {
@ -262,7 +239,6 @@ impl<'a, 'b:'a, 'tcx:'b> GraphBuilder<'a, 'b, 'tcx> {
self.build_reduced_graph_for_external_crate(module);
}
parent
}
ItemMod(..) => {
@ -271,34 +247,30 @@ impl<'a, 'b:'a, 'tcx:'b> GraphBuilder<'a, 'b, 'tcx> {
let module = self.new_module(parent_link, Some(def), false, is_public);
self.define(parent, name, TypeNS, (module, sp));
parent.module_children.borrow_mut().insert(item.id, module);
module
*parent_ref = module;
}
ItemForeignMod(..) => parent,
ItemForeignMod(..) => {}
// These items live in the value namespace.
ItemStatic(_, m, _) => {
let mutbl = m == hir::MutMutable;
let def = Def::Static(self.ast_map.local_def_id(item.id), mutbl);
self.define(parent, name, ValueNS, (def, sp, modifiers));
parent
}
ItemConst(_, _) => {
let def = Def::Const(self.ast_map.local_def_id(item.id));
self.define(parent, name, ValueNS, (def, sp, modifiers));
parent
}
ItemFn(_, _, _, _, _, _) => {
let def = Def::Fn(self.ast_map.local_def_id(item.id));
self.define(parent, name, ValueNS, (def, sp, modifiers));
parent
}
// These items live in the type namespace.
ItemTy(..) => {
let def = Def::TyAlias(self.ast_map.local_def_id(item.id));
self.define(parent, name, TypeNS, (def, sp, modifiers));
parent
}
ItemEnum(ref enum_definition, _) => {
@ -317,7 +289,6 @@ impl<'a, 'b:'a, 'tcx:'b> GraphBuilder<'a, 'b, 'tcx> {
self.build_reduced_graph_for_variant(variant, item_def_id,
module, variant_modifiers);
}
parent
}
// These items live in both the type and value namespaces.
@ -340,12 +311,9 @@ impl<'a, 'b:'a, 'tcx:'b> GraphBuilder<'a, 'b, 'tcx> {
.collect();
let item_def_id = self.ast_map.local_def_id(item.id);
self.structs.insert(item_def_id, field_names);
parent
}
ItemDefaultImpl(_, _) |
ItemImpl(..) => parent,
ItemDefaultImpl(_, _) | ItemImpl(..) => {}
ItemTrait(_, _, _, ref items) => {
let def_id = self.ast_map.local_def_id(item.id);
@ -370,8 +338,6 @@ impl<'a, 'b:'a, 'tcx:'b> GraphBuilder<'a, 'b, 'tcx> {
self.trait_item_map.insert((item.name, def_id), item_def_id);
}
parent
}
}
}
@ -422,7 +388,7 @@ impl<'a, 'b:'a, 'tcx:'b> GraphBuilder<'a, 'b, 'tcx> {
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: &mut Module<'b>) {
if self.block_needs_anonymous_module(block) {
let block_id = block.id;
@ -433,48 +399,52 @@ impl<'a, 'b:'a, 'tcx:'b> GraphBuilder<'a, 'b, 'tcx> {
let parent_link = BlockParentLink(parent, block_id);
let new_module = self.new_module(parent_link, None, false, false);
parent.module_children.borrow_mut().insert(block_id, new_module);
new_module
} else {
parent
*parent = new_module;
}
}
fn handle_external_def(&mut self,
def: Def,
vis: Visibility,
final_ident: &str,
name: Name,
new_parent: Module<'b>) {
debug!("(building reduced graph for external crate) building external def {}, priv {:?}",
final_ident,
vis);
let is_public = vis == hir::Public || new_parent.is_trait();
/// Builds the reduced graph for a single item in an external crate.
fn build_reduced_graph_for_external_crate_def(&mut self, parent: Module<'b>, xcdef: ChildItem) {
let def = match xcdef.def {
DlDef(def) => def,
_ => return,
};
if let Def::ForeignMod(def_id) = def {
// Foreign modules have no names. Recur and populate eagerly.
for child in self.session.cstore.item_children(def_id) {
self.build_reduced_graph_for_external_crate_def(parent, child);
}
return;
}
let name = xcdef.name;
let is_public = xcdef.vis == hir::Public || parent.is_trait();
let mut modifiers = DefModifiers::empty();
if is_public {
modifiers = modifiers | DefModifiers::PUBLIC;
}
if new_parent.is_normal() {
if parent.is_normal() {
modifiers = modifiers | DefModifiers::IMPORTABLE;
}
match def {
Def::Mod(_) | Def::ForeignMod(_) | Def::Enum(..) => {
debug!("(building reduced graph for external crate) building module {} {}",
final_ident,
name,
is_public);
let parent_link = ModuleParentLink(new_parent, name);
let parent_link = ModuleParentLink(parent, name);
let module = self.new_module(parent_link, Some(def), true, is_public);
self.try_define(new_parent, name, TypeNS, (module, DUMMY_SP));
self.try_define(parent, name, TypeNS, (module, DUMMY_SP));
}
Def::Variant(_, variant_id) => {
debug!("(building reduced graph for external crate) building variant {}",
final_ident);
debug!("(building reduced graph for external crate) building variant {}", name);
// 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.
let modifiers = DefModifiers::PUBLIC | DefModifiers::IMPORTABLE;
self.try_define(new_parent, name, TypeNS, (def, DUMMY_SP, modifiers));
self.try_define(new_parent, name, ValueNS, (def, DUMMY_SP, modifiers));
self.try_define(parent, name, TypeNS, (def, DUMMY_SP, modifiers));
self.try_define(parent, name, ValueNS, (def, DUMMY_SP, modifiers));
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
self.structs.insert(variant_id, Vec::new());
@ -486,12 +456,11 @@ impl<'a, 'b:'a, 'tcx:'b> GraphBuilder<'a, 'b, 'tcx> {
Def::AssociatedConst(..) |
Def::Method(..) => {
debug!("(building reduced graph for external crate) building value (fn/static) {}",
final_ident);
self.try_define(new_parent, name, ValueNS, (def, DUMMY_SP, modifiers));
name);
self.try_define(parent, name, ValueNS, (def, DUMMY_SP, modifiers));
}
Def::Trait(def_id) => {
debug!("(building reduced graph for external crate) building type {}",
final_ident);
debug!("(building reduced graph for external crate) building type {}", name);
// If this is a trait, add all the trait item names to the trait
// info.
@ -508,24 +477,22 @@ impl<'a, 'b:'a, 'tcx:'b> GraphBuilder<'a, 'b, 'tcx> {
self.trait_item_map.insert((trait_item_name, def_id), trait_item_def.def_id());
}
let parent_link = ModuleParentLink(new_parent, name);
let parent_link = ModuleParentLink(parent, name);
let module = self.new_module(parent_link, Some(def), true, is_public);
self.try_define(new_parent, name, TypeNS, (module, DUMMY_SP));
self.try_define(parent, name, TypeNS, (module, DUMMY_SP));
}
Def::TyAlias(..) | Def::AssociatedTy(..) => {
debug!("(building reduced graph for external crate) building type {}",
final_ident);
self.try_define(new_parent, name, TypeNS, (def, DUMMY_SP, modifiers));
debug!("(building reduced graph for external crate) building type {}", name);
self.try_define(parent, name, TypeNS, (def, DUMMY_SP, modifiers));
}
Def::Struct(def_id)
if self.session.cstore.tuple_struct_definition_if_ctor(def_id).is_none() => {
debug!("(building reduced graph for external crate) building type and value for \
{}",
final_ident);
self.try_define(new_parent, name, TypeNS, (def, DUMMY_SP, modifiers));
debug!("(building reduced graph for external crate) building type and value for {}",
name);
self.try_define(parent, name, TypeNS, (def, DUMMY_SP, modifiers));
if let Some(ctor_def_id) = self.session.cstore.struct_ctor_def_id(def_id) {
let def = Def::Struct(ctor_def_id);
self.try_define(new_parent, name, ValueNS, (def, DUMMY_SP, modifiers));
self.try_define(parent, name, ValueNS, (def, DUMMY_SP, modifiers));
}
// Record the def ID and fields of this struct.
@ -545,69 +512,6 @@ impl<'a, 'b:'a, 'tcx:'b> GraphBuilder<'a, 'b, 'tcx> {
}
}
/// Builds the reduced graph for a single item in an external crate.
fn build_reduced_graph_for_external_crate_def(&mut self,
root: Module<'b>,
xcdef: ChildItem) {
match xcdef.def {
DlDef(def) => {
// Add the new child item, if necessary.
match def {
Def::ForeignMod(def_id) => {
// Foreign modules have no names. Recur and populate
// eagerly.
for child in self.session.cstore.item_children(def_id) {
self.build_reduced_graph_for_external_crate_def(root, child)
}
}
_ => {
self.handle_external_def(def,
xcdef.vis,
&xcdef.name.as_str(),
xcdef.name,
root);
}
}
}
DlImpl(_) => {
debug!("(building reduced graph for external crate) ignoring impl");
}
DlField => {
debug!("(building reduced graph for external crate) ignoring field");
}
}
}
/// Builds the reduced graph rooted at the given external module.
fn populate_external_module(&mut self, module: Module<'b>) {
debug!("(populating external module) attempting to populate {}",
module_to_string(module));
let def_id = match module.def_id() {
None => {
debug!("(populating external module) ... no def ID!");
return;
}
Some(def_id) => def_id,
};
for child in self.session.cstore.item_children(def_id) {
debug!("(populating external module) ... found ident: {}",
child.name);
self.build_reduced_graph_for_external_crate_def(module, child);
}
module.populated.set(true)
}
/// Ensures that the reduced graph rooted at the given external module
/// is built, building it if it is not.
fn populate_module_if_necessary(&mut self, module: Module<'b>) {
if !module.populated.get() {
self.populate_external_module(module)
}
assert!(module.populated.get())
}
/// Builds the reduced graph rooted at the 'use' directive for an external
/// crate.
fn build_reduced_graph_for_external_crate(&mut self, root: Module<'b>) {
@ -649,42 +553,43 @@ impl<'a, 'b:'a, 'tcx:'b> GraphBuilder<'a, 'b, 'tcx> {
module_.add_import_directive(directive);
self.unresolved_imports += 1;
}
/// Ensures that the reduced graph rooted at the given external module
/// is built, building it if it is not.
pub fn populate_module_if_necessary(&mut self, module: Module<'b>) {
if module.populated.get() { return }
for child in self.session.cstore.item_children(module.def_id().unwrap()) {
self.build_reduced_graph_for_external_crate_def(module, child);
}
module.populated.set(true)
}
}
struct BuildReducedGraphVisitor<'a, 'b: 'a, 'tcx: 'b> {
builder: GraphBuilder<'a, 'b, 'tcx>,
resolver: &'a mut Resolver<'b, 'tcx>,
parent: Module<'b>,
}
impl<'a, 'b, 'v, 'tcx> Visitor<'v> for BuildReducedGraphVisitor<'a, 'b, 'tcx> {
fn visit_nested_item(&mut self, item: hir::ItemId) {
self.visit_item(self.builder.resolver.ast_map.expect_item(item.id))
self.visit_item(self.resolver.ast_map.expect_item(item.id))
}
fn visit_item(&mut self, item: &Item) {
let p = self.builder.build_reduced_graph_for_item(item, &self.parent);
let old_parent = replace(&mut self.parent, p);
let old_parent = self.parent;
self.resolver.build_reduced_graph_for_item(item, &mut self.parent);
intravisit::walk_item(self, item);
self.parent = old_parent;
}
fn visit_foreign_item(&mut self, foreign_item: &ForeignItem) {
self.builder.build_reduced_graph_for_foreign_item(foreign_item, &self.parent);
self.resolver.build_reduced_graph_for_foreign_item(foreign_item, &self.parent);
}
fn visit_block(&mut self, block: &Block) {
let np = self.builder.build_reduced_graph_for_block(block, &self.parent);
let old_parent = replace(&mut self.parent, np);
let old_parent = self.parent;
self.resolver.build_reduced_graph_for_block(block, &mut self.parent);
intravisit::walk_block(self, block);
self.parent = old_parent;
}
}
pub fn build_reduced_graph(resolver: &mut Resolver, krate: &hir::Crate) {
GraphBuilder { resolver: resolver }.build_reduced_graph(krate);
}
pub fn populate_module_if_necessary<'a, 'tcx>(resolver: &mut Resolver<'a, 'tcx>,
module: Module<'a>) {
GraphBuilder { resolver: resolver }.populate_module_if_necessary(module);
}

View File

@ -51,7 +51,7 @@ use rustc::dep_graph::DepNode;
use rustc::front::map as hir_map;
use rustc::session::Session;
use rustc::lint;
use rustc::middle::cstore::{CrateStore, DefLike, DlDef};
use rustc::middle::cstore::CrateStore;
use rustc::middle::def::*;
use rustc::middle::def_id::DefId;
use rustc::middle::pat_util::pat_bindings;
@ -95,7 +95,7 @@ use resolve_imports::{ImportDirective, NameResolution};
// NB: This module needs to be declared first so diagnostics are
// registered before they are used.
pub mod diagnostics;
mod diagnostics;
mod check_unused;
mod build_reduced_graph;
@ -119,12 +119,12 @@ enum SuggestionType {
}
/// Candidates for a name resolution failure
pub struct SuggestedCandidates {
struct SuggestedCandidates {
name: String,
candidates: Vec<Path>,
}
pub enum ResolutionError<'a> {
enum ResolutionError<'a> {
/// error E0401: can't use type parameters from outer function
TypeParametersFromOuterFunction,
/// error E0402: cannot use an outer type parameter in this context
@ -201,7 +201,7 @@ pub enum ResolutionError<'a> {
/// Context of where `ResolutionError::UnresolvedName` arose.
#[derive(Clone, PartialEq, Eq, Debug)]
pub enum UnresolvedNameContext {
enum UnresolvedNameContext {
/// `PathIsMod(id)` indicates that a given path, used in
/// expression context, actually resolved to a module rather than
/// a value. The `id` attached to the variant is the node id of
@ -756,7 +756,7 @@ enum BareIdentifierPatternResolution {
/// One local scope.
#[derive(Debug)]
struct Rib<'a> {
bindings: HashMap<Name, DefLike>,
bindings: HashMap<Name, Def>,
kind: RibKind<'a>,
}
@ -784,6 +784,31 @@ impl LocalDef {
}
}
enum LexicalScopeBinding<'a> {
Item(&'a NameBinding<'a>),
LocalDef(LocalDef),
}
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()),
}
}
fn def(self) -> Def {
self.local_def().def
}
fn module(self) -> Option<Module<'a>> {
match self {
LexicalScopeBinding::Item(binding) => binding.module(),
_ => None,
}
}
}
/// The link from a module up to its nearest parent node.
#[derive(Clone,Debug)]
enum ParentLink<'a> {
@ -1106,7 +1131,7 @@ pub struct Resolver<'a, 'tcx: 'a> {
arenas: &'a ResolverArenas<'a>,
}
pub struct ResolverArenas<'a> {
struct ResolverArenas<'a> {
modules: arena::TypedArena<ModuleS<'a>>,
name_bindings: arena::TypedArena<NameBinding<'a>>,
import_directives: arena::TypedArena<ImportDirective>,
@ -1340,9 +1365,6 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
/// Attempts to resolve the module part of an import directive or path
/// rooted at the given module.
///
/// On success, returns the resolved module, and the closest *private*
/// module found to the destination when resolving this path.
fn resolve_module_path(&mut self,
module_path: &[Name],
use_lexical_scope: UseLexicalScopeFlag,
@ -1357,28 +1379,11 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
module_to_string(self.current_module));
// Resolve the module prefix, if any.
let module_prefix_result = self.resolve_module_prefix(module_path);
let module_prefix_result = self.resolve_module_prefix(module_path, span);
let search_module;
let start_index;
match module_prefix_result {
Failed(None) => {
let mpath = names_to_string(module_path);
let mpath = &mpath[..];
match mpath.rfind(':') {
Some(idx) => {
let msg = format!("Could not find `{}` in `{}`",
// idx +- 1 to account for the
// colons on either side
&mpath[idx + 1..],
&mpath[..idx - 1]);
return Failed(Some((span, msg)));
}
None => {
return Failed(None);
}
}
}
Failed(err) => return Failed(err),
Indeterminate => {
debug!("(resolving module path for import) indeterminate; bailing");
@ -1399,20 +1404,13 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
// This is not a crate-relative path. We resolve the
// first component of the path in the current lexical
// scope and then proceed to resolve below that.
match self.resolve_item_in_lexical_scope(module_path[0],
TypeNS,
true) {
Failed(err) => return Failed(err),
Indeterminate => {
debug!("(resolving module path for import) indeterminate; bailing");
return Indeterminate;
}
Success(binding) => match binding.module() {
Some(containing_module) => {
search_module = containing_module;
start_index = 1;
}
None => return Failed(None),
let ident = hir::Ident::from_name(module_path[0]);
match self.resolve_ident_in_lexical_scope(ident, TypeNS, true)
.and_then(LexicalScopeBinding::module) {
None => return Failed(None),
Some(containing_module) => {
search_module = containing_module;
start_index = 1;
}
}
}
@ -1430,40 +1428,54 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
span)
}
/// This function resolves `name` in `namespace` in the current lexical scope, returning
/// Success(binding) if `name` resolves to an item, or Failed(None) if `name` does not resolve
/// or resolves to a type parameter or local variable.
/// n.b. `resolve_identifier_in_local_ribs` also resolves names in the current lexical scope.
/// This resolves the identifier `ident` in the namespace `ns` in the current lexical scope.
/// More specifically, we proceed up the hierarchy of scopes and return the binding for
/// `ident` in the first scope that defines it (or None if no scopes define it).
///
/// A block's items are above its local variables in the scope hierarchy, regardless of where
/// the items are defined in the block. For example,
/// ```rust
/// fn f() {
/// g(); // Since there are no local variables in scope yet, this resolves to the item.
/// let g = || {};
/// fn g() {}
/// g(); // This resolves to the local variable `g` since it shadows the item.
/// }
/// ```
///
/// Invariant: This must only be called during main resolution, not during
/// import resolution.
fn resolve_item_in_lexical_scope(&mut self,
name: Name,
namespace: Namespace,
record_used: bool)
-> ResolveResult<&'a NameBinding<'a>> {
fn resolve_ident_in_lexical_scope(&mut self,
ident: hir::Ident,
ns: Namespace,
record_used: bool)
-> Option<LexicalScopeBinding<'a>> {
let name = match ns { ValueNS => ident.name, TypeNS => ident.unhygienic_name };
// Walk backwards up the ribs in scope.
for i in (0 .. self.get_ribs(namespace).len()).rev() {
if let Some(_) = self.get_ribs(namespace)[i].bindings.get(&name).cloned() {
// The name resolves to a type parameter or local variable, so return Failed(None).
return Failed(None);
for i in (0 .. self.get_ribs(ns).len()).rev() {
if let Some(def) = self.get_ribs(ns)[i].bindings.get(&name).cloned() {
// The ident resolves to a type parameter or local variable.
return Some(LexicalScopeBinding::LocalDef(LocalDef {
ribs: Some((ns, i)),
def: def,
}));
}
if let ModuleRibKind(module) = self.get_ribs(namespace)[i].kind {
if let Success(binding) = self.resolve_name_in_module(module,
name,
namespace,
true,
record_used) {
// The name resolves to an item.
return Success(binding);
if let ModuleRibKind(module) = self.get_ribs(ns)[i].kind {
let name = ident.unhygienic_name;
let item = self.resolve_name_in_module(module, name, ns, true, record_used);
if let Success(binding) = item {
// The ident resolves to an item.
return Some(LexicalScopeBinding::Item(binding));
}
// We can only see through anonymous modules
if module.def.is_some() { return Failed(None); }
if module.def.is_some() { return None; }
}
}
Failed(None)
None
}
/// Returns the nearest normal module parent of the given module.
@ -1499,7 +1511,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
/// 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) *
fn resolve_module_prefix(&mut self, module_path: &[Name])
fn resolve_module_prefix(&mut self, module_path: &[Name], span: Span)
-> ResolveResult<ModulePrefixResult<'a>> {
// Start at the current module if we see `self` or `super`, or at the
// top of the crate otherwise.
@ -1516,7 +1528,10 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
debug!("(resolving module prefix) resolving `super` at {}",
module_to_string(&containing_module));
match self.get_nearest_normal_module_parent(containing_module) {
None => return Failed(None),
None => {
let msg = "There are too many initial `super`s.".into();
return Failed(Some((span, msg)));
}
Some(new_module) => {
containing_module = new_module;
i += 1;
@ -1542,7 +1557,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
-> ResolveResult<&'a NameBinding<'a>> {
debug!("(resolving name in module) resolving `{}` in `{}`", name, module_to_string(module));
build_reduced_graph::populate_module_if_necessary(self, module);
self.populate_module_if_necessary(module);
match use_lexical_scope {
true => module.resolve_name_in_lexical_scope(name, namespace)
.map(Success).unwrap_or(Failed(None)),
@ -1594,7 +1609,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
/// Searches the current set of local scopes for labels.
/// Stops after meeting a closure.
fn search_label(&self, name: Name) -> Option<DefLike> {
fn search_label(&self, name: Name) -> Option<Def> {
for rib in self.label_ribs.iter().rev() {
match rib.kind {
NormalRibKind => {
@ -1753,13 +1768,9 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
seen_bindings.insert(name);
// plain insert (no renaming)
function_type_rib.bindings
.insert(name,
DlDef(Def::TyParam(space,
index as u32,
self.ast_map
.local_def_id(type_parameter.id),
name)));
let def_id = self.ast_map.local_def_id(type_parameter.id);
let def = Def::TyParam(space, index as u32, def_id, name);
function_type_rib.bindings.insert(name, def);
}
self.type_ribs.push(function_type_rib);
}
@ -1948,7 +1959,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
// plain insert (no renaming, types are not currently hygienic....)
let name = special_names::type_self;
self_type_rib.bindings.insert(name, DlDef(self_def));
self_type_rib.bindings.insert(name, self_def);
self.type_ribs.push(self_type_rib);
f(self);
if !self.resolved {
@ -2261,8 +2272,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
let ident = path1.node;
let renamed = ident.name;
match self.resolve_bare_identifier_pattern(ident.unhygienic_name,
pattern.span) {
match self.resolve_bare_identifier_pattern(ident, pattern.span) {
FoundStructOrEnumVariant(def) if const_ok => {
debug!("(resolving pattern) resolving `{}` to struct or enum variant",
renamed);
@ -2328,7 +2338,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
if !bindings_list.contains_key(&renamed) {
let this = &mut *self;
let last_rib = this.value_ribs.last_mut().unwrap();
last_rib.bindings.insert(renamed, DlDef(def));
last_rib.bindings.insert(renamed, def);
bindings_list.insert(renamed, pat_id);
} else if mode == ArgumentIrrefutableMode &&
bindings_list.contains_key(&renamed) {
@ -2513,49 +2523,21 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
});
}
fn resolve_bare_identifier_pattern(&mut self,
name: Name,
span: Span)
fn resolve_bare_identifier_pattern(&mut self, ident: hir::Ident, span: Span)
-> BareIdentifierPatternResolution {
match self.resolve_item_in_lexical_scope(name, ValueNS, true) {
Success(binding) => {
debug!("(resolve bare identifier pattern) succeeded in finding {} at {:?}",
name,
binding);
match binding.def() {
None => {
panic!("resolved name in the value namespace to a set of name bindings \
with no def?!");
}
// For the two success cases, this lookup can be
// considered as not having a private component because
// the lookup happened only within the current module.
Some(def @ Def::Variant(..)) | Some(def @ Def::Struct(..)) => {
return FoundStructOrEnumVariant(def);
}
Some(def @ Def::Const(..)) | Some(def @ Def::AssociatedConst(..)) => {
return FoundConst(def, name);
}
Some(Def::Static(..)) => {
resolve_error(self, span, ResolutionError::StaticVariableReference);
return BareIdentifierPatternUnresolved;
}
_ => return BareIdentifierPatternUnresolved
}
match self.resolve_ident_in_lexical_scope(ident, ValueNS, true)
.map(LexicalScopeBinding::def) {
Some(def @ Def::Variant(..)) | Some(def @ Def::Struct(..)) => {
FoundStructOrEnumVariant(def)
}
Indeterminate => return BareIdentifierPatternUnresolved,
Failed(err) => {
match err {
Some((span, msg)) => {
resolve_error(self, span, ResolutionError::FailedToResolve(&msg));
}
None => (),
}
debug!("(resolve bare identifier pattern) failed to find {}", name);
return BareIdentifierPatternUnresolved;
Some(def @ Def::Const(..)) | Some(def @ Def::AssociatedConst(..)) => {
FoundConst(def, ident.unhygienic_name)
}
Some(Def::Static(..)) => {
resolve_error(self, span, ResolutionError::StaticVariableReference);
BareIdentifierPatternUnresolved
}
_ => BareIdentifierPatternUnresolved,
}
}
@ -2602,12 +2584,8 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
/// Skips `path_depth` trailing segments, which is also reflected in the
/// returned value. See `middle::def::PathResolution` for more info.
pub fn resolve_path(&mut self,
id: NodeId,
path: &Path,
path_depth: usize,
namespace: Namespace)
-> Option<PathResolution> {
fn resolve_path(&mut self, id: NodeId, path: &Path, path_depth: usize, namespace: Namespace)
-> Option<PathResolution> {
let span = path.span;
let segments = &path.segments[..path.segments.len() - path_depth];
@ -2676,7 +2654,8 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
return Some(LocalDef::from_def(Def::Err));
}
self.resolve_identifier_in_local_ribs(identifier, namespace, record_used)
self.resolve_ident_in_lexical_scope(identifier, namespace, record_used)
.map(LexicalScopeBinding::local_def)
}
// Resolve a local definition, potentially adjusting for closures.
@ -2860,54 +2839,6 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
})
}
fn resolve_identifier_in_local_ribs(&mut self,
ident: hir::Ident,
namespace: Namespace,
record_used: bool)
-> Option<LocalDef> {
// Check the local set of ribs.
let name = match namespace { ValueNS => ident.name, TypeNS => ident.unhygienic_name };
for i in (0 .. self.get_ribs(namespace).len()).rev() {
if let Some(def_like) = self.get_ribs(namespace)[i].bindings.get(&name).cloned() {
match def_like {
DlDef(def) => {
debug!("(resolving path in local ribs) resolved `{}` to {:?} at {}",
name,
def,
i);
return Some(LocalDef {
ribs: Some((namespace, i)),
def: def,
});
}
def_like => {
debug!("(resolving path in local ribs) resolved `{}` to pseudo-def {:?}",
name,
def_like);
return None;
}
}
}
if let ModuleRibKind(module) = self.get_ribs(namespace)[i].kind {
if let Success(binding) = self.resolve_name_in_module(module,
ident.unhygienic_name,
namespace,
true,
record_used) {
if let Some(def) = binding.def() {
return Some(LocalDef::from_def(def));
}
}
// We can only see through anonymous modules
if module.def.is_some() { return None; }
}
}
None
}
fn with_no_errors<T, F>(&mut self, f: F) -> T
where F: FnOnce(&mut Resolver) -> T
{
@ -3230,11 +3161,11 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
ExprLoop(_, Some(label)) | ExprWhile(_, _, Some(label)) => {
self.with_label_rib(|this| {
let def_like = DlDef(Def::Label(expr.id));
let def = Def::Label(expr.id);
{
let rib = this.label_ribs.last_mut().unwrap();
rib.bindings.insert(label.name, def_like);
rib.bindings.insert(label.name, def);
}
intravisit::walk_expr(this, expr);
@ -3249,7 +3180,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
label.span,
ResolutionError::UndeclaredLabel(&label.node.name.as_str()))
}
Some(DlDef(def @ Def::Label(_))) => {
Some(def @ Def::Label(_)) => {
// Since this def is a label, it is never read.
self.record_def(expr.id,
PathResolution {
@ -3302,18 +3233,15 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
}
let mut found_traits = Vec::new();
// Look for the current trait.
if let Some((trait_def_id, _)) = self.current_trait_ref {
if self.trait_item_map.contains_key(&(name, trait_def_id)) {
add_trait_info(&mut found_traits, trait_def_id, name);
}
}
let mut search_module = self.current_module;
loop {
// Look for the current trait.
match self.current_trait_ref {
Some((trait_def_id, _)) => {
if self.trait_item_map.contains_key(&(name, trait_def_id)) {
add_trait_info(&mut found_traits, trait_def_id, name);
}
}
None => {} // Nothing to do.
}
// Look for trait children.
let mut search_in_module = |module: Module<'a>| module.for_each_child(|_, ns, binding| {
if ns != TypeNS { return }
@ -3363,7 +3291,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
while let Some((in_module,
path_segments,
in_module_is_extern)) = worklist.pop() {
build_reduced_graph::populate_module_if_necessary(self, &in_module);
self.populate_module_if_necessary(in_module);
in_module.for_each_child(|name, ns, name_binding| {
@ -3723,18 +3651,18 @@ pub fn resolve_crate<'a, 'tcx>(session: &'a Session,
/// preserving the ribs + current module. This allows resolve_path
/// calls to be made with the correct scope info. The node in the
/// callback corresponds to the current node in the walk.
pub fn create_resolver<'a, 'tcx>(session: &'a Session,
ast_map: &'a hir_map::Map<'tcx>,
krate: &'a Crate,
make_glob_map: MakeGlobMap,
arenas: &'a ResolverArenas<'a>,
callback: Option<Box<Fn(hir_map::Node, &mut bool) -> bool>>)
-> Resolver<'a, 'tcx> {
fn create_resolver<'a, 'tcx>(session: &'a Session,
ast_map: &'a hir_map::Map<'tcx>,
krate: &'a Crate,
make_glob_map: MakeGlobMap,
arenas: &'a ResolverArenas<'a>,
callback: Option<Box<Fn(hir_map::Node, &mut bool) -> bool>>)
-> Resolver<'a, 'tcx> {
let mut resolver = Resolver::new(session, ast_map, make_glob_map, arenas);
resolver.callback = callback;
build_reduced_graph::build_reduced_graph(&mut resolver, krate);
resolver.build_reduced_graph(krate);
resolve_imports::resolve_imports(&mut resolver);

View File

@ -17,12 +17,10 @@ use {NameBinding, NameBindingKind, PrivacyError};
use ResolveResult;
use ResolveResult::*;
use Resolver;
use UseLexicalScopeFlag;
use UseLexicalScopeFlag::DontUseLexicalScope;
use {names_to_string, module_to_string};
use {resolve_error, ResolutionError};
use build_reduced_graph;
use rustc::lint;
use rustc::middle::def::*;
@ -60,12 +58,12 @@ impl ImportDirectiveSubclass {
/// One import directive.
#[derive(Debug,Clone)]
pub struct ImportDirective {
pub module_path: Vec<Name>,
pub subclass: ImportDirectiveSubclass,
pub span: Span,
pub id: NodeId,
pub is_public: bool, // see note in ImportResolutionPerNamespace about how to use this
pub is_prelude: bool,
module_path: Vec<Name>,
subclass: ImportDirectiveSubclass,
span: Span,
id: NodeId,
is_public: bool, // see note in ImportResolutionPerNamespace about how to use this
is_prelude: bool,
}
impl ImportDirective {
@ -285,7 +283,6 @@ impl<'a> ::ModuleS<'a> {
fn define_in_glob_importers(&self, name: Name, ns: Namespace, binding: &'a NameBinding<'a>) {
if !binding.defined_with(DefModifiers::PUBLIC | DefModifiers::IMPORTABLE) { return }
if binding.is_extern_crate() { return }
for &(importer, directive) in self.glob_importers.borrow_mut().iter() {
let _ = importer.try_define_child(name, ns, directive.import(binding, None));
}
@ -384,7 +381,7 @@ impl<'a, 'b:'a, 'tcx:'b> ImportResolver<'a, 'b, 'tcx> {
debug!("(resolving imports for module subtree) resolving {}",
module_to_string(&module_));
let orig_module = replace(&mut self.resolver.current_module, module_);
self.resolve_imports_for_module(module_, errors);
self.resolve_imports_in_current_module(errors);
self.resolver.current_module = orig_module;
for (_, child_module) in module_.module_children.borrow().iter() {
@ -393,29 +390,31 @@ impl<'a, 'b:'a, 'tcx:'b> ImportResolver<'a, 'b, 'tcx> {
}
/// Attempts to resolve imports for the given module only.
fn resolve_imports_for_module(&mut self,
module: Module<'b>,
errors: &mut Vec<ImportResolvingError<'b>>) {
fn resolve_imports_in_current_module(&mut self, errors: &mut Vec<ImportResolvingError<'b>>) {
let mut imports = Vec::new();
let mut unresolved_imports = module.unresolved_imports.borrow_mut();
let mut unresolved_imports = self.resolver.current_module.unresolved_imports.borrow_mut();
::std::mem::swap(&mut imports, &mut unresolved_imports);
for import_directive in imports {
match self.resolve_import_for_module(module, &import_directive) {
match self.resolve_import(&import_directive) {
Failed(err) => {
let (span, help) = match err {
Some((span, msg)) => (span, format!(". {}", msg)),
None => (import_directive.span, String::new()),
};
errors.push(ImportResolvingError {
source_module: module,
source_module: self.resolver.current_module,
import_directive: import_directive,
span: span,
help: help,
});
}
Indeterminate => unresolved_imports.push(import_directive),
Success(()) => {}
Success(()) => {
// Decrement the count of unresolved imports.
assert!(self.resolver.unresolved_imports >= 1);
self.resolver.unresolved_imports -= 1;
}
}
}
}
@ -425,43 +424,27 @@ impl<'a, 'b:'a, 'tcx:'b> ImportResolver<'a, 'b, 'tcx> {
/// don't know whether the name exists at the moment due to other
/// currently-unresolved imports, or success if we know the name exists.
/// If successful, the resolved bindings are written into the module.
fn resolve_import_for_module(&mut self,
module_: Module<'b>,
import_directive: &'b ImportDirective)
-> ResolveResult<()> {
fn resolve_import(&mut self, directive: &'b ImportDirective) -> ResolveResult<()> {
debug!("(resolving import for module) resolving import `{}::...` in `{}`",
names_to_string(&import_directive.module_path),
module_to_string(&module_));
names_to_string(&directive.module_path),
module_to_string(self.resolver.current_module));
self.resolver
.resolve_module_path(&import_directive.module_path,
UseLexicalScopeFlag::DontUseLexicalScope,
import_directive.span)
.and_then(|containing_module| {
// We found the module that the target is contained
// within. Attempt to resolve the import within it.
self.resolve_import(module_, containing_module, import_directive)
})
.and_then(|()| {
// Decrement the count of unresolved imports.
assert!(self.resolver.unresolved_imports >= 1);
self.resolver.unresolved_imports -= 1;
Success(())
})
}
let target_module = match self.resolver.resolve_module_path(&directive.module_path,
DontUseLexicalScope,
directive.span) {
Success(module) => module,
Indeterminate => return Indeterminate,
Failed(err) => return Failed(err),
};
fn resolve_import(&mut self,
module_: Module<'b>,
target_module: Module<'b>,
directive: &'b ImportDirective)
-> ResolveResult<()> {
let (source, target, value_determined, type_determined) = match directive.subclass {
SingleImport { source, target, ref value_determined, ref type_determined } =>
(source, target, value_determined, type_determined),
GlobImport => return self.resolve_glob_import(module_, target_module, directive),
GlobImport => return self.resolve_glob_import(target_module, directive),
};
// We need to resolve both namespaces for this to succeed.
let module_ = self.resolver.current_module;
let (value_result, type_result) = {
let mut resolve_in_ns = |ns, determined: bool| {
// Temporarily count the directive as determined so that the resolution fails
@ -596,21 +579,19 @@ impl<'a, 'b:'a, 'tcx:'b> ImportResolver<'a, 'b, 'tcx> {
// succeeds or bails out (as importing * from an empty module or a module
// that exports nothing is valid). target_module is the module we are
// actually importing, i.e., `foo` in `use foo::*`.
fn resolve_glob_import(&mut self,
module_: Module<'b>,
target_module: Module<'b>,
directive: &'b ImportDirective)
fn resolve_glob_import(&mut self, target_module: Module<'b>, directive: &'b ImportDirective)
-> ResolveResult<()> {
if let Some(Def::Trait(_)) = target_module.def {
self.resolver.session.span_err(directive.span, "items in traits are not importable.");
}
let module_ = self.resolver.current_module;
if module_.def_id() == target_module.def_id() {
// This means we are trying to glob import a module into itself, and it is a no-go
let msg = "Cannot glob-import a module into itself.".into();
return Failed(Some((directive.span, msg)));
}
build_reduced_graph::populate_module_if_necessary(self.resolver, target_module);
self.resolver.populate_module_if_necessary(target_module);
if directive.is_prelude {
*module_.prelude.borrow_mut() = Some(target_module);

View File

@ -8,7 +8,7 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use super::f; //~ ERROR unresolved import `super::f`
use super::f; //~ ERROR unresolved import `super::f`. There are too many initial `super`s.
fn main() {
}