use rustc::hir::{Freevar, FreevarMap, TraitCandidate, TraitMap, GlobMap};
use rustc::util::nodemap::{NodeMap, NodeSet, FxHashMap, FxHashSet, DefIdMap};
+use syntax::codemap::{dummy_spanned, respan};
use syntax::ext::hygiene::{Mark, SyntaxContext};
use syntax::ast::{self, Name, NodeId, Ident, SpannedIdent, FloatTy, IntTy, UintTy};
use syntax::ext::base::SyntaxExtension;
/// error E0431: `self` import can only appear in an import list with a non-empty prefix
SelfImportOnlyInImportListWithNonEmptyPrefix,
/// error E0432: unresolved import
- UnresolvedImport(Option<(&'a str, &'a str)>),
+ UnresolvedImport(Option<(Span, &'a str, &'a str)>),
/// error E0433: failed to resolve
FailedToResolve(&'a str),
/// error E0434: can't capture dynamic environment in a fn item
non-empty prefix")
}
ResolutionError::UnresolvedImport(name) => {
- let msg = match name {
- Some((n, _)) => format!("unresolved import `{}`", n),
- None => "unresolved import".to_owned(),
+ let (span, msg) = match name {
+ Some((sp, n, _)) => (sp, format!("unresolved import `{}`", n)),
+ None => (span, "unresolved import".to_owned()),
};
let mut err = struct_span_err!(resolver.session, span, E0432, "{}", msg);
- if let Some((_, p)) = name {
+ if let Some((_, _, p)) = name {
err.span_label(span, p);
}
err
Module(Module<'a>),
NonModule(PathResolution),
Indeterminate,
- Failed(String, bool /* is the error from the last segment? */),
+ Failed(Span, String, bool /* is the error from the last segment? */),
}
enum ModuleKind {
fn resolve_hir_path(&mut self, path: &mut hir::Path, is_value: bool) {
let namespace = if is_value { ValueNS } else { TypeNS };
let hir::Path { ref segments, span, ref mut def } = *path;
- let path: Vec<_> = segments.iter().map(|seg| Ident::with_empty_ctxt(seg.name)).collect();
+ let path: Vec<SpannedIdent> = segments.iter()
+ .map(|seg| respan(span, Ident::with_empty_ctxt(seg.name)))
+ .collect();
match self.resolve_path(&path, Some(namespace), true, span) {
PathResult::Module(module) => *def = module.def().unwrap(),
PathResult::NonModule(path_res) if path_res.unresolved_segments() == 0 =>
*def = path_res.base_def(),
PathResult::NonModule(..) => match self.resolve_path(&path, None, true, span) {
- PathResult::Failed(msg, _) => {
+ PathResult::Failed(span, msg, _) => {
resolve_error(self, span, ResolutionError::FailedToResolve(&msg));
}
_ => {}
},
PathResult::Indeterminate => unreachable!(),
- PathResult::Failed(msg, _) => {
+ PathResult::Failed(span, msg, _) => {
resolve_error(self, span, ResolutionError::FailedToResolve(&msg));
}
}
let mut new_val = None;
let mut new_id = None;
if let Some(trait_ref) = opt_trait_ref {
- let path: Vec<_> = trait_ref.path.segments.iter().map(|seg| seg.identifier).collect();
+ let path: Vec<_> = trait_ref.path.segments.iter()
+ .map(|seg| respan(seg.span, seg.identifier))
+ .collect();
let def = self.smart_resolve_path_fragment(trait_ref.ref_id,
None,
&path,
path: &Path,
source: PathSource)
-> PathResolution {
- let segments = &path.segments.iter().map(|seg| seg.identifier).collect::<Vec<_>>();
+ let segments = &path.segments.iter()
+ .map(|seg| respan(seg.span, seg.identifier))
+ .collect::<Vec<_>>();
let ident_span = path.segments.last().map_or(path.span, |seg| seg.span);
self.smart_resolve_path_fragment(id, qself, segments, path.span, ident_span, source)
}
fn smart_resolve_path_fragment(&mut self,
id: NodeId,
qself: Option<&QSelf>,
- path: &[Ident],
+ path: &[SpannedIdent],
span: Span,
ident_span: Span,
source: PathSource)
(format!("expected {}, found {} `{}`", expected, def.kind_name(), path_str),
format!("not a {}", expected), span)
} else {
- let item_str = path[path.len() - 1];
+ let item_str = path[path.len() - 1].node;
+ let item_span = path[path.len() - 1].span;
let (mod_prefix, mod_str) = if path.len() == 1 {
(format!(""), format!("this scope"))
- } else if path.len() == 2 && path[0].name == keywords::CrateRoot.name() {
+ } else if path.len() == 2 && path[0].node.name == keywords::CrateRoot.name() {
(format!(""), format!("the crate root"))
} else {
let mod_path = &path[..path.len() - 1];
(mod_prefix, format!("`{}`", names_to_string(mod_path)))
};
(format!("cannot find {} `{}` in {}{}", expected, item_str, mod_prefix, mod_str),
- format!("not found in {}", mod_str), ident_span)
+ format!("not found in {}", mod_str), item_span)
};
let mut err = this.session.struct_span_err_with_code(base_span, &base_msg, code);
// Try to lookup the name in more relaxed fashion for better error reporting.
let ident = *path.last().unwrap();
- let candidates = this.lookup_import_candidates(ident.name, ns, is_expected);
+ let candidates = this.lookup_import_candidates(ident.node.name, ns, is_expected);
if !candidates.is_empty() {
let mut module_span = this.current_module.span;
module_span.hi = module_span.lo;
show_candidates(&mut err, module_span, &candidates, def.is_some());
} else if is_expected(Def::Enum(DefId::local(CRATE_DEF_INDEX))) {
let enum_candidates =
- this.lookup_import_candidates(ident.name, ns, is_enum_variant);
+ this.lookup_import_candidates(ident.node.name, ns, is_enum_variant);
let mut enum_candidates = enum_candidates.iter()
.map(|suggestion| import_candidate_to_paths(&suggestion)).collect::<Vec<_>>();
enum_candidates.sort();
}
}
if path.len() == 1 && this.self_type_is_available(span) {
- if let Some(candidate) = this.lookup_assoc_candidate(ident, ns, is_expected) {
- let self_is_available = this.self_value_is_available(path[0].ctxt, span);
+ if let Some(candidate) = this.lookup_assoc_candidate(ident.node, ns, is_expected) {
+ let self_is_available = this.self_value_is_available(path[0].node.ctxt, span);
match candidate {
AssocSuggestion::Field => {
err.span_suggestion(span, "try",
// or `<T>::A::B`. If `B` should be resolved in value namespace then
// it needs to be added to the trait map.
if ns == ValueNS {
- let item_name = *path.last().unwrap();
+ let item_name = path.last().unwrap().node;
let traits = self.get_traits_containing_item(item_name, ns);
self.trait_map.insert(id, traits);
}
fn resolve_qpath_anywhere(&mut self,
id: NodeId,
qself: Option<&QSelf>,
- path: &[Ident],
+ path: &[SpannedIdent],
primary_ns: Namespace,
span: Span,
defer_to_typeck: bool,
};
}
}
- let is_global = self.global_macros.get(&path[0].name).cloned()
+ let is_global = self.global_macros.get(&path[0].node.name).cloned()
.map(|binding| binding.get_macro(self).kind() == MacroKind::Bang).unwrap_or(false);
- if primary_ns != MacroNS && (is_global || self.macro_names.contains(&path[0].modern())) {
+ if primary_ns != MacroNS && (is_global ||
+ self.macro_names.contains(&path[0].node.modern())) {
// Return some dummy definition, it's enough for error reporting.
return Some(
PathResolution::new(Def::Macro(DefId::local(CRATE_DEF_INDEX), MacroKind::Bang))
fn resolve_qpath(&mut self,
id: NodeId,
qself: Option<&QSelf>,
- path: &[Ident],
+ path: &[SpannedIdent],
ns: Namespace,
span: Span,
global_by_default: bool)
// The same fallback is used when `a` resolves to nothing.
PathResult::Module(..) | PathResult::Failed(..)
if (ns == TypeNS || path.len() > 1) &&
- self.primitive_type_table.primitive_types.contains_key(&path[0].name) => {
- let prim = self.primitive_type_table.primitive_types[&path[0].name];
+ self.primitive_type_table.primitive_types
+ .contains_key(&path[0].node.name) => {
+ let prim = self.primitive_type_table.primitive_types[&path[0].node.name];
match prim {
TyUint(UintTy::U128) | TyInt(IntTy::I128) => {
if !self.session.features.borrow().i128_type {
PathResolution::with_unresolved_segments(Def::PrimTy(prim), path.len() - 1)
}
PathResult::Module(module) => PathResolution::new(module.def().unwrap()),
- PathResult::Failed(msg, false) => {
+ PathResult::Failed(span, msg, false) => {
resolve_error(self, span, ResolutionError::FailedToResolve(&msg));
err_path_resolution()
}
};
if path.len() > 1 && !global_by_default && result.base_def() != Def::Err &&
- path[0].name != keywords::CrateRoot.name() &&
- path[0].name != keywords::DollarCrate.name() {
+ path[0].node.name != keywords::CrateRoot.name() &&
+ path[0].node.name != keywords::DollarCrate.name() {
let unqualified_result = {
match self.resolve_path(&[*path.last().unwrap()], Some(ns), false, span) {
PathResult::NonModule(path_res) => path_res.base_def(),
}
fn resolve_path(&mut self,
- path: &[Ident],
+ path: &[SpannedIdent],
opt_ns: Option<Namespace>, // `None` indicates a module path
record_used: bool,
path_span: Span)
let mut allow_super = true;
for (i, &ident) in path.iter().enumerate() {
+ debug!("resolve_path ident {} {:?}", i, ident);
let is_last = i == path.len() - 1;
let ns = if is_last { opt_ns.unwrap_or(TypeNS) } else { TypeNS };
- if i == 0 && ns == TypeNS && ident.name == keywords::SelfValue.name() {
- let mut ctxt = ident.ctxt.modern();
+ if i == 0 && ns == TypeNS && ident.node.name == keywords::SelfValue.name() {
+ let mut ctxt = ident.node.ctxt.modern();
module = Some(self.resolve_self(&mut ctxt, self.current_module));
continue
- } else if allow_super && ns == TypeNS && ident.name == keywords::Super.name() {
- let mut ctxt = ident.ctxt.modern();
+ } else if allow_super && ns == TypeNS && ident.node.name == keywords::Super.name() {
+ let mut ctxt = ident.node.ctxt.modern();
let self_module = match i {
0 => self.resolve_self(&mut ctxt, self.current_module),
_ => module.unwrap(),
continue
} else {
let msg = "There are too many initial `super`s.".to_string();
- return PathResult::Failed(msg, false);
+ return PathResult::Failed(ident.span, msg, false);
}
}
allow_super = false;
- if i == 0 && ns == TypeNS && ident.name == keywords::CrateRoot.name() {
- module = Some(self.resolve_crate_root(ident.ctxt.modern()));
+ if i == 0 && ns == TypeNS && ident.node.name == keywords::CrateRoot.name() {
+ module = Some(self.resolve_crate_root(ident.node.ctxt.modern()));
continue
- } else if i == 0 && ns == TypeNS && ident.name == keywords::DollarCrate.name() {
- module = Some(self.resolve_crate_root(ident.ctxt));
+ } else if i == 0 && ns == TypeNS && ident.node.name == keywords::DollarCrate.name() {
+ module = Some(self.resolve_crate_root(ident.node.ctxt));
continue
}
let binding = if let Some(module) = module {
- self.resolve_ident_in_module(module, ident, ns, false, record_used, path_span)
+ self.resolve_ident_in_module(module, ident.node, ns, false, record_used, path_span)
} else if opt_ns == Some(MacroNS) {
- self.resolve_lexical_macro_path_segment(ident, ns, record_used, path_span)
+ self.resolve_lexical_macro_path_segment(ident.node, ns, record_used, path_span)
.map(MacroBinding::binding)
} else {
- match self.resolve_ident_in_lexical_scope(ident, ns, record_used, path_span) {
+ match self.resolve_ident_in_lexical_scope(ident.node, ns, record_used, path_span) {
Some(LexicalScopeBinding::Item(binding)) => Ok(binding),
Some(LexicalScopeBinding::Def(def))
if opt_ns == Some(TypeNS) || opt_ns == Some(ValueNS) => {
def, path.len() - i - 1
));
} else {
- return PathResult::Failed(format!("Not a module `{}`", ident), is_last);
+ return PathResult::Failed(ident.span,
+ format!("Not a module `{}`", ident.node),
+ is_last);
}
}
Err(Undetermined) => return PathResult::Indeterminate,
let msg = if module.and_then(ModuleData::def) == self.graph_root.def() {
let is_mod = |def| match def { Def::Mod(..) => true, _ => false };
let mut candidates =
- self.lookup_import_candidates(ident.name, TypeNS, is_mod);
+ self.lookup_import_candidates(ident.node.name, TypeNS, is_mod);
candidates.sort_by_key(|c| (c.path.segments.len(), c.path.to_string()));
if let Some(candidate) = candidates.get(0) {
format!("Did you mean `{}`?", candidate.path)
} else {
- format!("Maybe a missing `extern crate {};`?", ident)
+ format!("Maybe a missing `extern crate {};`?", ident.node)
}
} else if i == 0 {
- format!("Use of undeclared type or module `{}`", ident)
+ format!("Use of undeclared type or module `{}`", ident.node)
} else {
- format!("Could not find `{}` in `{}`", ident, path[i - 1])
+ format!("Could not find `{}` in `{}`", ident.node, path[i - 1].node)
};
- return PathResult::Failed(msg, is_last);
+ return PathResult::Failed(ident.span, msg, is_last);
}
}
}
// An invalid forward use of a type parameter from a previous default.
if let ForwardTyParamBanRibKind = self.ribs[ns][rib_index].kind {
if record_used {
- resolve_error(self, span,
- ResolutionError::ForwardDeclaredTyParam);
+ resolve_error(self, span, ResolutionError::ForwardDeclaredTyParam);
}
assert_eq!(def, Def::Err);
return Def::Err;
}
fn lookup_typo_candidate<FilterFn>(&mut self,
- path: &[Ident],
+ path: &[SpannedIdent],
ns: Namespace,
filter_fn: FilterFn,
span: Span)
}
}
- let name = path[path.len() - 1].name;
+ let name = path[path.len() - 1].node.name;
// Make sure error reporting is deterministic.
names.sort_by_key(|name| name.as_str());
match find_best_match_for_name(names.iter(), &name.as_str(), None) {
}
}
-fn is_self_type(path: &[Ident], namespace: Namespace) -> bool {
- namespace == TypeNS && path.len() == 1 && path[0].name == keywords::SelfType.name()
+fn is_self_type(path: &[SpannedIdent], namespace: Namespace) -> bool {
+ namespace == TypeNS && path.len() == 1 && path[0].node.name == keywords::SelfType.name()
}
-fn is_self_value(path: &[Ident], namespace: Namespace) -> bool {
- namespace == ValueNS && path.len() == 1 && path[0].name == keywords::SelfValue.name()
+fn is_self_value(path: &[SpannedIdent], namespace: Namespace) -> bool {
+ namespace == ValueNS && path.len() == 1 && path[0].node.name == keywords::SelfValue.name()
}
-fn names_to_string(idents: &[Ident]) -> String {
+fn names_to_string(idents: &[SpannedIdent]) -> String {
let mut result = String::new();
- for (i, ident) in idents.iter().filter(|i| i.name != keywords::CrateRoot.name()).enumerate() {
+ for (i, ident) in idents.iter()
+ .filter(|i| i.node.name != keywords::CrateRoot.name())
+ .enumerate() {
if i > 0 {
result.push_str("::");
}
- result.push_str(&ident.name.as_str());
+ result.push_str(&ident.node.name.as_str());
}
result
}
fn path_names_to_string(path: &Path) -> String {
- names_to_string(&path.segments.iter().map(|seg| seg.identifier).collect::<Vec<_>>())
+ names_to_string(&path.segments.iter()
+ .map(|seg| respan(seg.span, seg.identifier))
+ .collect::<Vec<_>>())
}
/// Get the path for an enum and the variant from an `ImportSuggestion` for an enum variant.
if names.is_empty() {
return "???".to_string();
}
- names_to_string(&names.into_iter().rev().collect::<Vec<_>>())
+ names_to_string(&names.into_iter()
+ .rev()
+ .map(|n| dummy_spanned(n))
+ .collect::<Vec<_>>())
}
fn err_path_resolution() -> PathResolution {
use rustc::lint::builtin::PUB_USE_OF_PRIVATE_EXTERN_CRATE;
use rustc::hir::def_id::DefId;
use rustc::hir::def::*;
-use rustc::util::nodemap::FxHashMap;
+use rustc::util::nodemap::{FxHashMap, FxHashSet};
-use syntax::ast::{Ident, NodeId};
+use syntax::ast::{Ident, SpannedIdent, NodeId};
use syntax::ext::base::Determinacy::{self, Determined, Undetermined};
use syntax::ext::hygiene::Mark;
use syntax::parse::token;
pub struct ImportDirective<'a> {
pub id: NodeId,
pub parent: Module<'a>,
- pub module_path: Vec<Ident>,
+ pub module_path: Vec<SpannedIdent>,
pub imported_module: Cell<Option<Module<'a>>>, // the resolution of `module_path`
pub subclass: ImportDirectiveSubclass<'a>,
pub span: Span,
// Add an import directive to the current module.
pub fn add_import_directive(&mut self,
- module_path: Vec<Ident>,
+ module_path: Vec<SpannedIdent>,
subclass: ImportDirectiveSubclass<'a>,
span: Span,
id: NodeId,
}
let mut errors = false;
+ let mut seen_spans = FxHashSet();
for i in 0 .. self.determined_imports.len() {
let import = self.determined_imports[i];
- if let Some(err) = self.finalize_import(import) {
+ if let Some((span, err)) = self.finalize_import(import) {
errors = true;
if let SingleImport { source, ref result, .. } = import.subclass {
// If the error is a single failed import then create a "fake" import
// resolution for it so that later resolve stages won't complain.
self.import_dummy_binding(import);
- let path = import_path_to_string(&import.module_path, &import.subclass);
- let error = ResolutionError::UnresolvedImport(Some((&path, &err)));
- resolve_error(self.resolver, import.span, error);
+ if !seen_spans.contains(&span) {
+ let path = import_path_to_string(&import.module_path[..],
+ &import.subclass,
+ span);
+ let error = ResolutionError::UnresolvedImport(Some((span, &path, &err)));
+ resolve_error(self.resolver, span, error);
+ seen_spans.insert(span);
+ }
}
}
/// If successful, the resolved bindings are written into the module.
fn resolve_import(&mut self, directive: &'b ImportDirective<'b>) -> bool {
debug!("(resolving import for module) resolving import `{}::...` in `{}`",
- names_to_string(&directive.module_path),
+ names_to_string(&directive.module_path[..]),
module_to_string(self.current_module));
self.current_module = directive.parent;
// For better failure detection, pretend that the import will not define any names
// while resolving its module path.
directive.vis.set(ty::Visibility::Invisible);
- let result = self.resolve_path(&directive.module_path, None, false, directive.span);
+ let result = self.resolve_path(&directive.module_path[..], None, false, directive.span);
directive.vis.set(vis);
match result {
}
// If appropriate, returns an error to report.
- fn finalize_import(&mut self, directive: &'b ImportDirective<'b>) -> Option<String> {
+ fn finalize_import(&mut self, directive: &'b ImportDirective<'b>) -> Option<(Span, String)> {
self.current_module = directive.parent;
let ImportDirective { ref module_path, span, .. } = *directive;
let module_result = self.resolve_path(&module_path, None, true, span);
let module = match module_result {
PathResult::Module(module) => module,
- PathResult::Failed(msg, _) => {
+ PathResult::Failed(span, msg, _) => {
let (mut self_path, mut self_result) = (module_path.clone(), None);
- if !self_path.is_empty() && !token::Ident(self_path[0]).is_path_segment_keyword() {
- self_path[0].name = keywords::SelfValue.name();
+ if !self_path.is_empty() &&
+ !token::Ident(self_path[0].node).is_path_segment_keyword()
+ {
+ self_path[0].node.name = keywords::SelfValue.name();
self_result = Some(self.resolve_path(&self_path, None, false, span));
}
return if let Some(PathResult::Module(..)) = self_result {
- Some(format!("Did you mean `{}`?", names_to_string(&self_path)))
+ Some((span, format!("Did you mean `{}`?", names_to_string(&self_path[..]))))
} else {
- Some(msg)
+ Some((span, msg))
};
},
_ => return None,
SingleImport { source, ref result, type_ns_only, .. } => (source, result, type_ns_only),
GlobImport { .. } if module.def_id() == directive.parent.def_id() => {
// Importing a module into itself is not allowed.
- return Some("Cannot glob-import a module into itself.".to_string());
+ return Some((directive.span,
+ "Cannot glob-import a module into itself.".to_string()));
}
GlobImport { is_prelude, ref max_vis } => {
if !is_prelude &&
} else {
format!("no `{}` in `{}`{}", ident, module_str, lev_suggestion)
};
- Some(msg)
+ Some((span, msg))
} else {
// `resolve_ident_in_module` reported a privacy error.
self.import_dummy_binding(directive);
}
}
-fn import_path_to_string(names: &[Ident], subclass: &ImportDirectiveSubclass) -> String {
- let global = !names.is_empty() && names[0].name == keywords::CrateRoot.name();
- let names = if global { &names[1..] } else { names };
- if names.is_empty() {
- import_directive_subclass_to_string(subclass)
+fn import_path_to_string(names: &[SpannedIdent],
+ subclass: &ImportDirectiveSubclass,
+ span: Span) -> String {
+ let pos = names.iter()
+ .position(|p| span == p.span && p.node.name != keywords::CrateRoot.name());
+ let global = !names.is_empty() && names[0].node.name == keywords::CrateRoot.name();
+ if let Some(pos) = pos {
+ let names = if global { &names[1..pos + 1] } else { &names[..pos + 1] };
+ names_to_string(names)
} else {
- (format!("{}::{}",
- names_to_string(names),
- import_directive_subclass_to_string(subclass)))
- .to_string()
+ let names = if global { &names[1..] } else { names };
+ if names.is_empty() {
+ import_directive_subclass_to_string(subclass)
+ } else {
+ (format!("{}::{}",
+ names_to_string(names),
+ import_directive_subclass_to_string(subclass)))
+ }
}
}