// 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::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::parse::token::{self, special_names, special_idents};
/// 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>) {
"`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,
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,
}
}
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,
debug!("(resolving item in lexical scope) using import resolution");
// track used imports and extern crates as well
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() {
- self.used_crates.insert(kid);
+ 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() {
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 => {
fn resolve_identifier(&mut self,
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 {
}
}
- self.resolve_item_by_name_in_lexical_scope(identifier.unhygienic_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_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 => {
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));
}
}
}