// option. This file may not be copied, modified, or distributed
// except according to those terms.
-// Do not remove on snapshot creation. Needed for bootstrap. (Issue #22364)
-#![cfg_attr(stage0, feature(custom_attribute))]
#![crate_name = "rustc_resolve"]
#![unstable(feature = "rustc_private", issue = "27812")]
-#![cfg_attr(stage0, staged_api)]
#![crate_type = "dylib"]
#![crate_type = "rlib"]
#![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
use rustc::middle::cstore::{CrateStore, DefLike, DlDef};
use rustc::middle::def::*;
use rustc::middle::def_id::DefId;
-use rustc::middle::pat_util::pat_bindings_hygienic;
+use rustc::middle::pat_util::pat_bindings;
use rustc::middle::privacy::*;
use rustc::middle::subst::{ParamSpace, FnSpace, TypeSpace};
use rustc::middle::ty::{Freevar, FreevarMap, TraitMap, GlobMap};
use rustc::util::nodemap::{NodeMap, DefIdSet, FnvHashMap};
use syntax::ast;
-use syntax::ast::{CRATE_NODE_ID, Ident, Name, NodeId, CrateNum, TyIs, TyI8, TyI16, TyI32, TyI64};
+use syntax::ast::{CRATE_NODE_ID, Name, NodeId, CrateNum, TyIs, TyI8, TyI16, TyI32, TyI64};
use syntax::ast::{TyUs, TyU8, TyU16, TyU32, TyU64, TyF64, TyF32};
use syntax::attr::AttrMetaMethods;
-use syntax::ext::mtwt;
use syntax::parse::token::{self, special_names, special_idents};
-use syntax::ptr::P;
use syntax::codemap::{self, Span, Pos};
use syntax::util::lev_distance::{lev_distance, max_suggestion_distance};
use std::rc::{Rc, Weak};
use std::usize;
-use resolve_imports::{Target, ImportDirective, ImportResolution};
+use resolve_imports::{Target, ImportDirective, ImportResolutionPerNamespace};
use resolve_imports::Shadowable;
// NB: This module needs to be declared first so diagnostics are
/// error E0424: `self` is not available in a static method
SelfNotAvailableInStaticMethod,
/// error E0425: unresolved name
- UnresolvedName(&'a str, &'a str),
+ UnresolvedName(&'a str, &'a str, UnresolvedNameContext),
/// error E0426: use of undeclared label
UndeclaredLabel(&'a str),
/// error E0427: cannot use `ref` binding mode with ...
AttemptToUseNonConstantValueInConstant,
}
+/// Context of where `ResolutionError::UnresolvedName` arose.
+#[derive(Clone, PartialEq, Eq, Debug)]
+pub 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
+ /// the erroneous path expression.
+ PathIsMod(ast::NodeId),
+
+ /// `Other` means we have no extra information about the context
+ /// of the unresolved name error. (Maybe we could eliminate all
+ /// such cases; but for now, this is an information-free default.)
+ Other,
+}
+
fn resolve_error<'b, 'a: 'b, 'tcx: 'a>(resolver: &'b Resolver<'a, 'tcx>,
span: syntax::codemap::Span,
resolution_error: ResolutionError<'b>) {
.import_resolutions
.borrow()
.get(&name) {
- let item = resolver.ast_map.expect_item(directive.value_id);
+ let item = resolver.ast_map.expect_item(directive.value_ns.id);
resolver.session.span_note(item.span, "constant imported here");
}
}
"`self` is not available in a static method. Maybe a `self` argument is \
missing?");
}
- ResolutionError::UnresolvedName(path, name) => {
+ ResolutionError::UnresolvedName(path, msg, context) => {
span_err!(resolver.session,
span,
E0425,
"unresolved name `{}`{}",
path,
- name);
+ msg);
+
+ match context {
+ UnresolvedNameContext::Other => {} // no help available
+ UnresolvedNameContext::PathIsMod(id) => {
+ let mut help_msg = String::new();
+ let parent_id = resolver.ast_map.get_parent_node(id);
+ if let Some(hir_map::Node::NodeExpr(e)) = resolver.ast_map.find(parent_id) {
+ match e.node {
+ ExprField(_, ident) => {
+ help_msg = format!("To reference an item from the \
+ `{module}` module, use \
+ `{module}::{ident}`",
+ module = &*path,
+ ident = ident.node);
+ }
+
+ ExprMethodCall(ident, _, _) => {
+ help_msg = format!("To call a function from the \
+ `{module}` module, use \
+ `{module}::{ident}(..)`",
+ module = &*path,
+ ident = ident.node);
+ }
+
+ _ => {} // no help available
+ }
+ }
+
+ if !help_msg.is_empty() {
+ resolver.session.fileline_help(span, &help_msg);
+ }
+ }
+ }
}
ResolutionError::UndeclaredLabel(name) => {
span_err!(resolver.session,
Ok(def) => self.record_def(tref.trait_ref.ref_id, def),
Err(_) => {
// error already reported
+ self.record_def(tref.trait_ref.ref_id, err_path_resolution())
}
}
intravisit::walk_poly_trait_ref(self, tref, m);
anonymous_children: RefCell<NodeMap<Rc<Module>>>,
// The status of resolving each import in this module.
- import_resolutions: RefCell<HashMap<Name, ImportResolution>>,
+ import_resolutions: RefCell<HashMap<Name, ImportResolutionPerNamespace>>,
// The number of unresolved globs that this module exports.
glob_count: Cell<usize>,
bitflags! {
#[derive(Debug)]
flags DefModifiers: u8 {
+ // Enum variants are always considered `PUBLIC`, this is needed for `use Enum::Variant`
+ // or `use Enum::*` to work on private enums.
const PUBLIC = 1 << 0,
const IMPORTABLE = 1 << 1,
+ // Variants are considered `PUBLIC`, but some of them live in private enums.
+ // We need to track them to prohibit reexports like `pub use PrivEnum::Variant`.
+ const PRIVATE_VARIANT = 1 << 2,
}
}
// Records a possibly-private value, type, or module definition.
#[derive(Debug)]
struct NsDef {
- modifiers: DefModifiers, // see note in ImportResolution about how to use this
+ modifiers: DefModifiers, // see note in ImportResolutionPerNamespace about how to use this
def_or_module: DefOrModule,
span: Option<Span>,
}
fn resolve_item_in_lexical_scope(&mut self,
module_: Rc<Module>,
name: Name,
- namespace: Namespace)
+ namespace: Namespace,
+ record_used: bool)
-> ResolveResult<(Target, bool)> {
debug!("(resolving item in lexical scope) resolving `{}` in namespace {:?} in `{}`",
name,
// adjacent import statements are processed as though they mutated the
// current scope.
if let Some(import_resolution) = module_.import_resolutions.borrow().get(&name) {
- match (*import_resolution).target_for_namespace(namespace) {
+ match import_resolution[namespace].target.clone() {
None => {
// Not found; continue.
debug!("(resolving item in lexical scope) found import resolution, but not \
Some(target) => {
debug!("(resolving item in lexical scope) using import resolution");
// track used imports and extern crates as well
- let id = import_resolution.id(namespace);
- self.used_imports.insert((id, namespace));
- self.record_import_use(id, name);
- if let Some(DefId{krate: kid, ..}) = target.target_module.def_id() {
- self.used_crates.insert(kid);
+ let id = import_resolution[namespace].id;
+ if record_used {
+ self.used_imports.insert((id, namespace));
+ self.record_import_use(id, name);
+ if let Some(DefId{krate: kid, ..}) = target.target_module.def_id() {
+ self.used_crates.insert(kid);
+ }
}
return Success((target, false));
}
-> ResolveResult<Rc<Module>> {
// If this module is an anonymous module, resolve the item in the
// lexical scope. Otherwise, resolve the item from the crate root.
- let resolve_result = self.resolve_item_in_lexical_scope(module_, name, TypeNS);
+ let resolve_result = self.resolve_item_in_lexical_scope(module_, name, TypeNS, true);
match resolve_result {
Success((target, _)) => {
if let Some(module_def) = target.binding.module() {
// Check the list of resolved imports.
match module_.import_resolutions.borrow().get(&name) {
- Some(import_resolution) if allow_private_imports || import_resolution.is_public => {
+ Some(import_resolution) if allow_private_imports ||
+ import_resolution[namespace].is_public => {
- if import_resolution.is_public && import_resolution.outstanding_references != 0 {
+ if import_resolution[namespace].is_public &&
+ import_resolution.outstanding_references != 0 {
debug!("(resolving name in module) import unresolved; bailing out");
return Indeterminate;
}
- match import_resolution.target_for_namespace(namespace) {
+ match import_resolution[namespace].target.clone() {
None => {
debug!("(resolving name in module) name found, but not in namespace {:?}",
namespace);
Some(target) => {
debug!("(resolving name in module) resolved to import");
// track used imports and extern crates as well
- let id = import_resolution.id(namespace);
+ let id = import_resolution[namespace].id;
self.used_imports.insert((id, namespace));
self.record_import_use(id, name);
if let Some(DefId{krate: kid, ..}) = target.target_module.def_id() {
opt_trait_ref,
&**self_type,
item.id,
- &impl_items[..]);
+ impl_items);
}
ItemTrait(_, ref generics, ref bounds, ref trait_items) => {
prefix.span,
ResolutionError::FailedToResolve(
&path_names_to_string(prefix, 0)));
+ self.record_def(item.id, err_path_resolution());
}
}
}
resolve_error(self,
eq_pred.span,
ResolutionError::UndeclaredAssociatedType);
+ self.record_def(eq_pred.id, err_path_resolution());
}
}
}
self.record_def(trait_ref.ref_id, path_res);
new_val = Some((path_res.base_def.def_id(), trait_ref.clone()));
new_id = Some(path_res.base_def.def_id());
+ } else {
+ self.record_def(trait_ref.ref_id, err_path_resolution());
}
intravisit::walk_trait_ref(self, trait_ref);
}
opt_trait_reference: &Option<TraitRef>,
self_type: &Ty,
item_id: NodeId,
- impl_items: &[P<ImplItem>]) {
+ impl_items: &[ImplItem]) {
// If applicable, create a rib for the type parameters.
self.with_type_parameter_rib(HasTypeParameters(generics,
TypeSpace,
// user and one 'x' came from the macro.
fn binding_mode_map(&mut self, pat: &Pat) -> BindingMap {
let mut result = HashMap::new();
- pat_bindings_hygienic(&self.def_map, pat, |binding_mode, _id, sp, path1| {
- let name = mtwt::resolve(path1.node);
+ pat_bindings(&self.def_map, pat, |binding_mode, _id, sp, path1| {
+ let name = path1.node;
result.insert(name,
BindingInfo {
span: sp,
self.record_def(ty.id, def);
}
None => {
+ self.record_def(ty.id, err_path_resolution());
+
// Keep reporting some errors even if they're ignored above.
self.resolve_path(ty.id, path, 0, TypeNS, true);
let const_ok = mode == RefutableMode && at_rhs.is_none();
let ident = path1.node;
- let renamed = mtwt::resolve(ident);
+ let renamed = ident.name;
- match self.resolve_bare_identifier_pattern(ident.name, pattern.span) {
+ match self.resolve_bare_identifier_pattern(ident.unhygienic_name,
+ pattern.span) {
FoundStructOrEnumVariant(def, lp) if const_ok => {
debug!("(resolving pattern) resolving `{}` to struct or enum variant",
renamed);
ResolutionError::DeclarationShadowsEnumVariantOrUnitLikeStruct(
renamed)
);
+ self.record_def(pattern.id, err_path_resolution());
}
FoundConst(def, lp, _) if const_ok => {
debug!("(resolving pattern) resolving `{}` to constant", renamed);
ResolutionError::OnlyIrrefutablePatternsAllowedHere(def.def_id(),
name)
);
+ self.record_def(pattern.id, err_path_resolution());
}
BareIdentifierPatternUnresolved => {
debug!("(resolving pattern) binding `{}`", renamed);
resolve_error(&self,
path.span,
ResolutionError::StaticVariableReference);
+ self.record_def(pattern.id, err_path_resolution());
}
_ => {
// If anything ends up here entirely resolved,
.name
.as_str())
);
+ self.record_def(pattern.id, err_path_resolution());
} else {
let const_name = path.segments
.last()
ResolutionError::UnresolvedEnumVariantStructOrConst(
&path.segments.last().unwrap().identifier.name.as_str())
);
+ self.record_def(pattern.id, err_path_resolution());
}
intravisit::walk_path(self, path);
}
&path.segments.last().unwrap().identifier.name.as_str()
)
);
+ self.record_def(pattern.id, err_path_resolution());
}
}
} else {
.identifier
.name
.as_str()));
+ self.record_def(pattern.id, err_path_resolution());
}
intravisit::walk_pat(self, pattern);
}
ResolutionError::DoesNotNameAStruct(
&*path_names_to_string(path, 0))
);
+ self.record_def(pattern.id, err_path_resolution());
}
}
intravisit::walk_path(self, path);
span: Span)
-> BareIdentifierPatternResolution {
let module = self.current_module.clone();
- match self.resolve_item_in_lexical_scope(module, name, ValueNS) {
+ match self.resolve_item_in_lexical_scope(module, name, ValueNS, true) {
Success((target, _)) => {
debug!("(resolve bare identifier pattern) succeeded in finding {} at {:?}",
name,
}
// Try to find a path to an item in a module.
- let unqualified_def = self.resolve_identifier(segments.last().unwrap().identifier,
- namespace,
- check_ribs);
-
+ let last_ident = segments.last().unwrap().identifier;
if segments.len() <= 1 {
+ let unqualified_def = self.resolve_identifier(last_ident, namespace, check_ribs, true);
return unqualified_def.and_then(|def| self.adjust_local_def(def, span))
.map(|def| {
PathResolution::new(def, LastMod(AllPublic), path_depth)
});
}
+ let unqualified_def = self.resolve_identifier(last_ident, namespace, check_ribs, false);
let def = self.resolve_module_relative_path(span, segments, namespace);
match (def, unqualified_def) {
(Some((ref d, _)), Some(ref ud)) if *d == ud.def => {
// Resolve a single identifier
fn resolve_identifier(&mut self,
- identifier: Ident,
+ identifier: hir::Ident,
namespace: Namespace,
- check_ribs: bool)
+ check_ribs: bool,
+ record_used: bool)
-> Option<LocalDef> {
// First, check to see whether the name is a primitive type.
if namespace == TypeNS {
if let Some(&prim_ty) = self.primitive_type_table
.primitive_types
- .get(&identifier.name) {
+ .get(&identifier.unhygienic_name) {
return Some(LocalDef::from_def(DefPrimTy(prim_ty)));
}
}
}
}
- self.resolve_item_by_name_in_lexical_scope(identifier.name, namespace)
+ let name = identifier.unhygienic_name;
+ self.resolve_item_by_name_in_lexical_scope(name, namespace, record_used)
.map(LocalDef::from_def)
}
}
fn resolve_identifier_in_local_ribs(&mut self,
- ident: Ident,
+ ident: hir::Ident,
namespace: Namespace)
-> Option<LocalDef> {
// Check the local set of ribs.
let (name, ribs) = match namespace {
- ValueNS => (mtwt::resolve(ident), &self.value_ribs),
- TypeNS => (ident.name, &self.type_ribs),
+ ValueNS => (ident.name, &self.value_ribs),
+ TypeNS => (ident.unhygienic_name, &self.type_ribs),
};
for (i, rib) in ribs.iter().enumerate().rev() {
fn resolve_item_by_name_in_lexical_scope(&mut self,
name: Name,
- namespace: Namespace)
+ namespace: Namespace,
+ record_used: bool)
-> Option<Def> {
// Check the items.
let module = self.current_module.clone();
- match self.resolve_item_in_lexical_scope(module, name, namespace) {
+ match self.resolve_item_in_lexical_scope(module, name, namespace, record_used) {
Success((target, _)) => {
match target.binding.def() {
None => {
} else {
self.session.span_help(expr.span, &msg);
}
+ self.record_def(expr.id, err_path_resolution());
} else {
// Write the result into the def map.
debug!("(resolving expr) resolved `{}`",
let type_res = self.with_no_errors(|this| {
this.resolve_path(expr.id, path, 0, TypeNS, false)
});
+
+ self.record_def(expr.id, err_path_resolution());
match type_res.map(|r| r.base_def) {
Some(DefTy(struct_id, _)) if self.structs.contains_key(&struct_id) => {
resolve_error(
format!("to call `{}::{}`", path_str, path_name),
};
+ let mut context = UnresolvedNameContext::Other;
if !msg.is_empty() {
- msg = format!(". Did you mean {}?", msg)
+ msg = format!(". Did you mean {}?", msg);
+ } else {
+ // we check if this a module and if so, we display a help
+ // message
+ let name_path = path.segments.iter()
+ .map(|seg| seg.identifier.name)
+ .collect::<Vec<_>>();
+ let current_module = self.current_module.clone();
+
+ match self.resolve_module_path(current_module,
+ &name_path[..],
+ UseLexicalScope,
+ expr.span,
+ PathSearch) {
+ Success(_) => {
+ context = UnresolvedNameContext::PathIsMod(expr.id);
+ },
+ _ => {},
+ };
}
resolve_error(self,
expr.span,
- ResolutionError::UnresolvedName(&*path_name, &*msg));
+ ResolutionError::UnresolvedName(
+ &*path_name, &*msg, context));
}
}
}
ResolutionError::DoesNotNameAStruct(
&*path_names_to_string(path, 0))
);
+ self.record_def(expr.id, err_path_resolution());
}
}
{
let rib = this.label_ribs.last_mut().unwrap();
- let renamed = mtwt::resolve(label);
- rib.bindings.insert(renamed, def_like);
+ rib.bindings.insert(label.name, def_like);
}
intravisit::walk_expr(this, expr);
}
ExprBreak(Some(label)) | ExprAgain(Some(label)) => {
- let renamed = mtwt::resolve(label.node);
- match self.search_label(renamed) {
+ match self.search_label(label.node.name) {
None => {
+ self.record_def(expr.id, err_path_resolution());
resolve_error(self,
label.span,
ResolutionError::UndeclaredLabel(&label.node.name.as_str()))
// Look for imports.
for (_, import) in search_module.import_resolutions.borrow().iter() {
- let target = match import.target_for_namespace(TypeNS) {
+ let target = match import.type_ns.target {
None => continue,
- Some(target) => target,
+ Some(ref target) => target,
};
let did = match target.binding.def() {
Some(DefTrait(trait_def_id)) => trait_def_id,
};
if self.trait_item_map.contains_key(&(name, did)) {
add_trait_info(&mut found_traits, did, name);
- let id = import.type_id;
+ let id = import.type_ns.id;
self.used_imports.insert((id, TypeNS));
let trait_name = self.get_trait_name(did);
self.record_import_use(id, trait_name);
let import_resolutions = module_.import_resolutions.borrow();
for (&name, import_resolution) in import_resolutions.iter() {
let value_repr;
- match import_resolution.target_for_namespace(ValueNS) {
+ match import_resolution.value_ns.target {
None => {
value_repr = "".to_string();
}
}
let type_repr;
- match import_resolution.target_for_namespace(TypeNS) {
+ match import_resolution.type_ns.target {
None => {
type_repr = "".to_string();
}
names_to_string(&names.into_iter().rev().collect::<Vec<ast::Name>>())
}
+fn err_path_resolution() -> PathResolution {
+ PathResolution {
+ base_def: DefErr,
+ last_private: LastMod(AllPublic),
+ depth: 0,
+ }
+}
+
pub struct CrateMap {
pub def_map: RefCell<DefMap>,
let mut resolver = create_resolver(session, ast_map, krate, make_glob_map, None);
resolver.resolve_crate(krate);
- session.abort_if_errors();
check_unused::check_crate(&mut resolver, krate);