// 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,
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);
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() {
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);
}
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);
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 => {
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 => {
} 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());
}
}
ExprBreak(Some(label)) | ExprAgain(Some(label)) => {
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()))
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);