Point at path segment on module not found
Point at the correct path segment on a import statement where a module doesn't exist. New output: ```rust error[E0432]: unresolved import `std::bar` --> <anon>:1:10 | 1 | use std::bar::{foo1, foo2}; | ^^^ Could not find `bar` in `std` ``` instead of: ```rust error[E0432]: unresolved import `std::bar::foo1` --> <anon>:1:16 | 1 | use std::bar::{foo1, foo2}; | ^^^^ Could not find `bar` in `std` error[E0432]: unresolved import `std::bar::foo2` --> <anon>:1:22 | 1 | use std::bar::{foo1, foo2}; | ^^^^ Could not find `bar` in `std` ```
This commit is contained in:
parent
6c949655de
commit
552ff07758
@ -35,6 +35,7 @@ use syntax::attr;
|
||||
use syntax::ast::{self, Block, ForeignItem, ForeignItemKind, Item, ItemKind};
|
||||
use syntax::ast::{Mutability, StmtKind, TraitItem, TraitItemKind};
|
||||
use syntax::ast::{Variant, ViewPathGlob, ViewPathList, ViewPathSimple};
|
||||
use syntax::codemap::respan;
|
||||
use syntax::ext::base::SyntaxExtension;
|
||||
use syntax::ext::base::Determinacy::Undetermined;
|
||||
use syntax::ext::hygiene::Mark;
|
||||
@ -119,7 +120,7 @@ impl<'a> Resolver<'a> {
|
||||
.unwrap()
|
||||
.1
|
||||
.iter()
|
||||
.map(|seg| seg.identifier)
|
||||
.map(|seg| respan(seg.span, seg.identifier))
|
||||
.collect()
|
||||
}
|
||||
|
||||
@ -127,14 +128,16 @@ impl<'a> Resolver<'a> {
|
||||
ViewPathList(ref module_ident_path, _) => {
|
||||
module_ident_path.segments
|
||||
.iter()
|
||||
.map(|seg| seg.identifier)
|
||||
.map(|seg| respan(seg.span, seg.identifier))
|
||||
.collect()
|
||||
}
|
||||
};
|
||||
|
||||
// This can be removed once warning cycle #36888 is complete.
|
||||
if module_path.len() >= 2 && module_path[0].name == keywords::CrateRoot.name() &&
|
||||
token::Ident(module_path[1]).is_path_segment_keyword() {
|
||||
if module_path.len() >= 2 &&
|
||||
module_path[0].node.name == keywords::CrateRoot.name() &&
|
||||
token::Ident(module_path[1].node).is_path_segment_keyword()
|
||||
{
|
||||
module_path.remove(0);
|
||||
}
|
||||
|
||||
@ -202,10 +205,13 @@ impl<'a> Resolver<'a> {
|
||||
let (module_path, ident, rename, type_ns_only) = {
|
||||
if node.name.name != keywords::SelfValue.name() {
|
||||
let rename = node.rename.unwrap_or(node.name);
|
||||
(module_path.clone(), node.name, rename, false)
|
||||
(module_path.clone(),
|
||||
respan(source_item.span, node.name),
|
||||
rename,
|
||||
false)
|
||||
} else {
|
||||
let ident = *module_path.last().unwrap();
|
||||
if ident.name == keywords::CrateRoot.name() {
|
||||
if ident.node.name == keywords::CrateRoot.name() {
|
||||
resolve_error(
|
||||
self,
|
||||
source_item.span,
|
||||
@ -215,13 +221,13 @@ impl<'a> Resolver<'a> {
|
||||
continue;
|
||||
}
|
||||
let module_path = module_path.split_last().unwrap().1;
|
||||
let rename = node.rename.unwrap_or(ident);
|
||||
let rename = node.rename.unwrap_or(ident.node);
|
||||
(module_path.to_vec(), ident, rename, true)
|
||||
}
|
||||
};
|
||||
let subclass = SingleImport {
|
||||
target: rename,
|
||||
source: ident,
|
||||
source: ident.node,
|
||||
result: self.per_ns(|_, _| Cell::new(Err(Undetermined))),
|
||||
type_ns_only: type_ns_only,
|
||||
};
|
||||
|
@ -45,6 +45,7 @@ use rustc::ty;
|
||||
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;
|
||||
@ -149,7 +150,7 @@ enum ResolutionError<'a> {
|
||||
/// 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
|
||||
@ -297,12 +298,12 @@ fn resolve_struct_error<'sess, 'a>(resolver: &'sess Resolver,
|
||||
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
|
||||
@ -820,7 +821,7 @@ enum PathResult<'a> {
|
||||
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 {
|
||||
@ -1276,19 +1277,21 @@ impl<'a> hir::lowering::Resolver for Resolver<'a> {
|
||||
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));
|
||||
}
|
||||
}
|
||||
@ -1909,7 +1912,9 @@ impl<'a> Resolver<'a> {
|
||||
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,
|
||||
@ -2334,7 +2339,9 @@ impl<'a> Resolver<'a> {
|
||||
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)
|
||||
}
|
||||
@ -2342,7 +2349,7 @@ impl<'a> Resolver<'a> {
|
||||
fn smart_resolve_path_fragment(&mut self,
|
||||
id: NodeId,
|
||||
qself: Option<&QSelf>,
|
||||
path: &[Ident],
|
||||
path: &[SpannedIdent],
|
||||
span: Span,
|
||||
ident_span: Span,
|
||||
source: PathSource)
|
||||
@ -2361,10 +2368,11 @@ impl<'a> Resolver<'a> {
|
||||
(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];
|
||||
@ -2375,7 +2383,7 @@ impl<'a> Resolver<'a> {
|
||||
(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);
|
||||
|
||||
@ -2396,7 +2404,7 @@ impl<'a> Resolver<'a> {
|
||||
|
||||
// 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;
|
||||
@ -2404,7 +2412,7 @@ impl<'a> Resolver<'a> {
|
||||
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();
|
||||
@ -2422,8 +2430,8 @@ impl<'a> Resolver<'a> {
|
||||
}
|
||||
}
|
||||
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",
|
||||
@ -2538,7 +2546,7 @@ impl<'a> Resolver<'a> {
|
||||
// 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);
|
||||
}
|
||||
@ -2570,7 +2578,7 @@ impl<'a> Resolver<'a> {
|
||||
fn resolve_qpath_anywhere(&mut self,
|
||||
id: NodeId,
|
||||
qself: Option<&QSelf>,
|
||||
path: &[Ident],
|
||||
path: &[SpannedIdent],
|
||||
primary_ns: Namespace,
|
||||
span: Span,
|
||||
defer_to_typeck: bool,
|
||||
@ -2590,9 +2598,10 @@ impl<'a> Resolver<'a> {
|
||||
};
|
||||
}
|
||||
}
|
||||
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))
|
||||
@ -2605,7 +2614,7 @@ impl<'a> Resolver<'a> {
|
||||
fn resolve_qpath(&mut self,
|
||||
id: NodeId,
|
||||
qself: Option<&QSelf>,
|
||||
path: &[Ident],
|
||||
path: &[SpannedIdent],
|
||||
ns: Namespace,
|
||||
span: Span,
|
||||
global_by_default: bool)
|
||||
@ -2645,8 +2654,9 @@ impl<'a> Resolver<'a> {
|
||||
// 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 {
|
||||
@ -2661,7 +2671,7 @@ impl<'a> Resolver<'a> {
|
||||
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()
|
||||
}
|
||||
@ -2670,8 +2680,8 @@ impl<'a> Resolver<'a> {
|
||||
};
|
||||
|
||||
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(),
|
||||
@ -2689,7 +2699,7 @@ impl<'a> Resolver<'a> {
|
||||
}
|
||||
|
||||
fn resolve_path(&mut self,
|
||||
path: &[Ident],
|
||||
path: &[SpannedIdent],
|
||||
opt_ns: Option<Namespace>, // `None` indicates a module path
|
||||
record_used: bool,
|
||||
path_span: Span)
|
||||
@ -2698,15 +2708,16 @@ impl<'a> Resolver<'a> {
|
||||
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(),
|
||||
@ -2716,26 +2727,26 @@ impl<'a> Resolver<'a> {
|
||||
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) => {
|
||||
@ -2760,7 +2771,9 @@ impl<'a> Resolver<'a> {
|
||||
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,
|
||||
@ -2775,19 +2788,19 @@ impl<'a> Resolver<'a> {
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -2807,8 +2820,7 @@ impl<'a> Resolver<'a> {
|
||||
// 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;
|
||||
@ -2978,7 +2990,7 @@ impl<'a> Resolver<'a> {
|
||||
}
|
||||
|
||||
fn lookup_typo_candidate<FilterFn>(&mut self,
|
||||
path: &[Ident],
|
||||
path: &[SpannedIdent],
|
||||
ns: Namespace,
|
||||
filter_fn: FilterFn,
|
||||
span: Span)
|
||||
@ -3039,7 +3051,7 @@ impl<'a> Resolver<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
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) {
|
||||
@ -3573,27 +3585,31 @@ fn is_struct_like(def: Def) -> bool {
|
||||
}
|
||||
}
|
||||
|
||||
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.
|
||||
@ -3661,7 +3677,10 @@ fn module_to_string(module: Module) -> String {
|
||||
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 {
|
||||
|
@ -19,6 +19,7 @@ use rustc::hir::map::{self, DefCollector};
|
||||
use rustc::{ty, lint};
|
||||
use syntax::ast::{self, Name, Ident};
|
||||
use syntax::attr::{self, HasAttrs};
|
||||
use syntax::codemap::respan;
|
||||
use syntax::errors::DiagnosticBuilder;
|
||||
use syntax::ext::base::{self, Annotatable, Determinacy, MultiModifier, MultiDecorator};
|
||||
use syntax::ext::base::{MacroKind, SyntaxExtension, Resolver as SyntaxResolver};
|
||||
@ -393,7 +394,7 @@ impl<'a> Resolver<'a> {
|
||||
return Err(Determinacy::Determined);
|
||||
}
|
||||
|
||||
let path: Vec<_> = segments.iter().map(|seg| seg.identifier).collect();
|
||||
let path: Vec<_> = segments.iter().map(|seg| respan(seg.span, seg.identifier)).collect();
|
||||
let invocation = self.invocations[&scope];
|
||||
self.current_module = invocation.module.get();
|
||||
|
||||
@ -418,16 +419,19 @@ impl<'a> Resolver<'a> {
|
||||
Err(Determinacy::Determined)
|
||||
},
|
||||
};
|
||||
let path = path.iter().map(|p| p.node).collect::<Vec<_>>();
|
||||
self.current_module.nearest_item_scope().macro_resolutions.borrow_mut()
|
||||
.push((path.into_boxed_slice(), span));
|
||||
return def;
|
||||
}
|
||||
|
||||
let legacy_resolution = self.resolve_legacy_scope(&invocation.legacy_scope, path[0], false);
|
||||
let legacy_resolution = self.resolve_legacy_scope(&invocation.legacy_scope,
|
||||
path[0].node,
|
||||
false);
|
||||
let result = if let Some(MacroBinding::Legacy(binding)) = legacy_resolution {
|
||||
Ok(Def::Macro(binding.def_id, MacroKind::Bang))
|
||||
} else {
|
||||
match self.resolve_lexical_macro_path_segment(path[0], MacroNS, false, span) {
|
||||
match self.resolve_lexical_macro_path_segment(path[0].node, MacroNS, false, span) {
|
||||
Ok(binding) => Ok(binding.binding().def_ignoring_ambiguity()),
|
||||
Err(Determinacy::Undetermined) if !force => return Err(Determinacy::Undetermined),
|
||||
Err(_) => {
|
||||
@ -438,7 +442,7 @@ impl<'a> Resolver<'a> {
|
||||
};
|
||||
|
||||
self.current_module.nearest_item_scope().legacy_macro_resolutions.borrow_mut()
|
||||
.push((scope, path[0], span, kind));
|
||||
.push((scope, path[0].node, span, kind));
|
||||
|
||||
result
|
||||
}
|
||||
@ -576,9 +580,10 @@ impl<'a> Resolver<'a> {
|
||||
pub fn finalize_current_module_macro_resolutions(&mut self) {
|
||||
let module = self.current_module;
|
||||
for &(ref path, span) in module.macro_resolutions.borrow().iter() {
|
||||
match self.resolve_path(path, Some(MacroNS), true, span) {
|
||||
let path = path.iter().map(|p| respan(span, *p)).collect::<Vec<_>>();
|
||||
match self.resolve_path(&path, Some(MacroNS), true, span) {
|
||||
PathResult::NonModule(_) => {},
|
||||
PathResult::Failed(msg, _) => {
|
||||
PathResult::Failed(span, msg, _) => {
|
||||
resolve_error(self, span, ResolutionError::FailedToResolve(&msg));
|
||||
}
|
||||
_ => unreachable!(),
|
||||
@ -652,7 +657,7 @@ impl<'a> Resolver<'a> {
|
||||
}
|
||||
};
|
||||
let ident = Ident::from_str(name);
|
||||
self.lookup_typo_candidate(&vec![ident], MacroNS, is_macro, span)
|
||||
self.lookup_typo_candidate(&vec![respan(span, ident)], MacroNS, is_macro, span)
|
||||
});
|
||||
|
||||
if let Some(suggestion) = suggestion {
|
||||
|
@ -21,9 +21,9 @@ use rustc::ty;
|
||||
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;
|
||||
@ -57,7 +57,7 @@ pub enum ImportDirectiveSubclass<'a> {
|
||||
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,
|
||||
@ -256,7 +256,7 @@ impl<'a> Resolver<'a> {
|
||||
|
||||
// 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,
|
||||
@ -478,9 +478,10 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> {
|
||||
}
|
||||
|
||||
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 {
|
||||
@ -496,9 +497,14 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> {
|
||||
// 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -516,7 +522,7 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> {
|
||||
/// 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;
|
||||
@ -528,7 +534,7 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> {
|
||||
// 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 {
|
||||
@ -593,23 +599,25 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> {
|
||||
}
|
||||
|
||||
// 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,
|
||||
@ -619,7 +627,8 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> {
|
||||
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 &&
|
||||
@ -708,7 +717,7 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> {
|
||||
} 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);
|
||||
@ -888,16 +897,24 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> {
|
||||
}
|
||||
}
|
||||
|
||||
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)))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -13,7 +13,7 @@ mod a {}
|
||||
macro_rules! m {
|
||||
() => {
|
||||
use a::$crate; //~ ERROR unresolved import `a::$crate`
|
||||
use a::$crate::b; //~ ERROR unresolved import `a::$crate::b`
|
||||
use a::$crate::b; //~ ERROR unresolved import `a::$crate`
|
||||
type A = a::$crate; //~ ERROR cannot find type `$crate` in module `a`
|
||||
}
|
||||
}
|
||||
|
@ -8,7 +8,7 @@
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
use baz::zed::bar; //~ ERROR unresolved import `baz::zed::bar` [E0432]
|
||||
use baz::zed::bar; //~ ERROR unresolved import `baz::zed` [E0432]
|
||||
//~^ Could not find `zed` in `baz`
|
||||
|
||||
mod baz {}
|
||||
|
@ -10,7 +10,7 @@
|
||||
|
||||
// Testing that we don't fail abnormally after hitting the errors
|
||||
|
||||
use unresolved::*; //~ ERROR unresolved import `unresolved::*` [E0432]
|
||||
use unresolved::*; //~ ERROR unresolved import `unresolved` [E0432]
|
||||
//~^ Maybe a missing `extern crate unresolved;`?
|
||||
|
||||
fn main() {}
|
||||
|
@ -10,10 +10,10 @@
|
||||
|
||||
type Alias = ();
|
||||
use Alias::*;
|
||||
//~^ ERROR unresolved import `Alias::*` [E0432]
|
||||
//~^ ERROR unresolved import `Alias` [E0432]
|
||||
//~| Not a module `Alias`
|
||||
use std::io::Result::*;
|
||||
//~^ ERROR unresolved import `std::io::Result::*` [E0432]
|
||||
//~^ ERROR unresolved import `std::io::Result` [E0432]
|
||||
//~| Not a module `Result`
|
||||
|
||||
trait T {}
|
||||
|
@ -11,13 +11,10 @@
|
||||
// Make sure that the spans of import errors are correct.
|
||||
|
||||
use abc::one_el;
|
||||
//~^ ERROR 13:5: 13:16
|
||||
//~^ ERROR 13:5: 13:8
|
||||
use abc::{a, bbb, cccccc};
|
||||
//~^ ERROR 15:11: 15:12
|
||||
//~^^ ERROR 15:14: 15:17
|
||||
//~^^^ ERROR 15:19: 15:25
|
||||
//~^ ERROR 15:5: 15:8
|
||||
use a_very_long_name::{el, el2};
|
||||
//~^ ERROR 19:24: 19:26
|
||||
//~^^ ERROR 19:28: 19:31
|
||||
//~^ ERROR 17:5: 17:21
|
||||
|
||||
fn main() {}
|
||||
|
@ -13,19 +13,19 @@
|
||||
mod a {
|
||||
extern crate alloc;
|
||||
use alloc::HashMap;
|
||||
//~^ ERROR unresolved import `alloc::HashMap` [E0432]
|
||||
//~^ ERROR unresolved import `alloc` [E0432]
|
||||
//~| Did you mean `self::alloc`?
|
||||
mod b {
|
||||
use alloc::HashMap;
|
||||
//~^ ERROR unresolved import `alloc::HashMap` [E0432]
|
||||
//~^ ERROR unresolved import `alloc` [E0432]
|
||||
//~| Did you mean `a::alloc`?
|
||||
mod c {
|
||||
use alloc::HashMap;
|
||||
//~^ ERROR unresolved import `alloc::HashMap` [E0432]
|
||||
//~^ ERROR unresolved import `alloc` [E0432]
|
||||
//~| Did you mean `a::alloc`?
|
||||
mod d {
|
||||
use alloc::HashMap;
|
||||
//~^ ERROR unresolved import `alloc::HashMap` [E0432]
|
||||
//~^ ERROR unresolved import `alloc` [E0432]
|
||||
//~| Did you mean `a::alloc`?
|
||||
}
|
||||
}
|
||||
|
@ -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` [E0432]
|
||||
use super::f; //~ ERROR unresolved import `super` [E0432]
|
||||
//~^ There are too many initial `super`s.
|
||||
|
||||
fn main() {
|
||||
|
@ -10,7 +10,7 @@
|
||||
|
||||
// ignore-tidy-linelength
|
||||
|
||||
use foo::bar; //~ ERROR unresolved import `foo::bar` [E0432]
|
||||
use foo::bar; //~ ERROR unresolved import `foo` [E0432]
|
||||
//~^ Maybe a missing `extern crate foo;`?
|
||||
|
||||
use bar::Baz as x; //~ ERROR unresolved import `bar::Baz` [E0432]
|
||||
@ -41,7 +41,7 @@ mod m {
|
||||
MyVariant
|
||||
}
|
||||
|
||||
use MyEnum::*; //~ ERROR unresolved import `MyEnum::*` [E0432]
|
||||
use MyEnum::*; //~ ERROR unresolved import `MyEnum` [E0432]
|
||||
//~^ Did you mean `self::MyEnum`?
|
||||
}
|
||||
|
||||
@ -50,7 +50,7 @@ mod items {
|
||||
Variant
|
||||
}
|
||||
|
||||
use Enum::*; //~ ERROR unresolved import `Enum::*` [E0432]
|
||||
use Enum::*; //~ ERROR unresolved import `Enum` [E0432]
|
||||
//~^ Did you mean `self::Enum`?
|
||||
|
||||
fn item() {}
|
||||
|
@ -22,13 +22,13 @@ use use_from_trait_xc::Trait::CONST;
|
||||
//~^ ERROR `CONST` is not directly importable
|
||||
|
||||
use use_from_trait_xc::Foo::new; //~ ERROR struct `Foo` is private
|
||||
//~^ ERROR unresolved import `use_from_trait_xc::Foo::new`
|
||||
//~^ ERROR unresolved import `use_from_trait_xc::Foo`
|
||||
|
||||
use use_from_trait_xc::Foo::C; //~ ERROR struct `Foo` is private
|
||||
//~^ ERROR unresolved import `use_from_trait_xc::Foo::C`
|
||||
//~^ ERROR unresolved import `use_from_trait_xc::Foo`
|
||||
|
||||
use use_from_trait_xc::Bar::new as bnew;
|
||||
//~^ ERROR unresolved import `use_from_trait_xc::Bar::new`
|
||||
//~^ ERROR unresolved import `use_from_trait_xc::Bar`
|
||||
|
||||
use use_from_trait_xc::Baz::new as baznew;
|
||||
//~^ ERROR unresolved import `use_from_trait_xc::Baz::new`
|
||||
|
@ -17,11 +17,11 @@ use Trait::C;
|
||||
//~^ ERROR `C` is not directly importable
|
||||
|
||||
use Foo::new;
|
||||
//~^ ERROR unresolved import `Foo::new` [E0432]
|
||||
//~^ ERROR unresolved import `Foo` [E0432]
|
||||
//~| Not a module `Foo`
|
||||
|
||||
use Foo::C2;
|
||||
//~^ ERROR unresolved import `Foo::C2` [E0432]
|
||||
//~^ ERROR unresolved import `Foo` [E0432]
|
||||
//~| Not a module `Foo`
|
||||
|
||||
pub trait Trait {
|
||||
|
@ -8,7 +8,7 @@
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
use foo::self; //~ ERROR unresolved import `foo::self`
|
||||
use foo::self; //~ ERROR unresolved import `foo`
|
||||
//~^ ERROR `self` imports are only allowed within a { } list
|
||||
|
||||
use std::mem::self;
|
||||
|
@ -2,7 +2,7 @@ error[E0433]: failed to resolve. Use of undeclared type or module `m`
|
||||
--> $DIR/macro_path_as_generic_bound.rs:17:6
|
||||
|
|
||||
17 | foo!(m::m2::A);
|
||||
| ^^^^^^^^ Use of undeclared type or module `m`
|
||||
| ^ Use of undeclared type or module `m`
|
||||
|
||||
error: cannot continue compilation due to previous error
|
||||
|
||||
|
13
src/test/ui/span/non-existing-module-import.rs
Normal file
13
src/test/ui/span/non-existing-module-import.rs
Normal file
@ -0,0 +1,13 @@
|
||||
// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
use std::bar::{foo1, foo2};
|
||||
|
||||
fn main() {}
|
8
src/test/ui/span/non-existing-module-import.stderr
Normal file
8
src/test/ui/span/non-existing-module-import.stderr
Normal file
@ -0,0 +1,8 @@
|
||||
error[E0432]: unresolved import `std::bar`
|
||||
--> $DIR/non-existing-module-import.rs:11:10
|
||||
|
|
||||
11 | use std::bar::{foo1, foo2};
|
||||
| ^^^ Could not find `bar` in `std`
|
||||
|
||||
error: aborting due to previous error
|
||||
|
Loading…
Reference in New Issue
Block a user