Skip to content

Commit d1c1bbe

Browse files
committed
Move path resolution error to rustc_resolve::diagnostics.
1 parent 886613c commit d1c1bbe

File tree

2 files changed

+207
-164
lines changed

2 files changed

+207
-164
lines changed

compiler/rustc_resolve/src/diagnostics.rs

+195-3
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,13 @@ use rustc_errors::{
88
};
99
use rustc_feature::BUILTIN_ATTRIBUTES;
1010
use rustc_hir::def::Namespace::{self, *};
11-
use rustc_hir::def::{self, CtorKind, CtorOf, DefKind, NonMacroAttrKind};
11+
use rustc_hir::def::{self, CtorKind, CtorOf, DefKind, NonMacroAttrKind, PerNS};
1212
use rustc_hir::def_id::{DefId, CRATE_DEF_INDEX, LOCAL_CRATE};
1313
use rustc_hir::PrimTy;
1414
use rustc_middle::bug;
1515
use rustc_middle::ty::DefIdTree;
1616
use rustc_session::Session;
17+
use rustc_span::edition::Edition;
1718
use rustc_span::hygiene::MacroKind;
1819
use rustc_span::lev_distance::find_best_match_for_name;
1920
use rustc_span::source_map::SourceMap;
@@ -22,10 +23,11 @@ use rustc_span::{BytePos, Span};
2223
use tracing::debug;
2324

2425
use crate::imports::{Import, ImportKind, ImportResolver};
26+
use crate::late::Rib;
2527
use crate::path_names_to_string;
26-
use crate::{AmbiguityError, AmbiguityErrorMisc, AmbiguityKind};
28+
use crate::{AmbiguityError, AmbiguityErrorMisc, AmbiguityKind, Finalize};
2729
use crate::{BindingError, HasGenericParams, MacroRulesScope, Module, ModuleOrUniformRoot};
28-
use crate::{NameBinding, NameBindingKind, PrivacyError, VisResolutionError};
30+
use crate::{LexicalScopeBinding, NameBinding, NameBindingKind, PrivacyError, VisResolutionError};
2931
use crate::{ParentScope, PathResult, ResolutionError, Resolver, Scope, ScopeSet, Segment};
3032

3133
type Res = def::Res<ast::NodeId>;
@@ -1377,6 +1379,196 @@ impl<'a> Resolver<'a> {
13771379
sugg => sugg,
13781380
}
13791381
}
1382+
1383+
crate fn report_path_resolution_error(
1384+
&mut self,
1385+
path: &[Segment],
1386+
opt_ns: Option<Namespace>, // `None` indicates a module path in import
1387+
parent_scope: &ParentScope<'a>,
1388+
finalize_full: Finalize,
1389+
ribs: Option<&PerNS<Vec<Rib<'a>>>>,
1390+
unusable_binding: Option<&'a NameBinding<'a>>,
1391+
module: Option<ModuleOrUniformRoot<'a>>,
1392+
i: usize,
1393+
ident: Ident,
1394+
) -> (String, Option<Suggestion>) {
1395+
let finalize = finalize_full.path_span();
1396+
let is_last = i == path.len() - 1;
1397+
let ns = if is_last { opt_ns.unwrap_or(TypeNS) } else { TypeNS };
1398+
let module_res = match module {
1399+
Some(ModuleOrUniformRoot::Module(module)) => module.res(),
1400+
_ => None,
1401+
};
1402+
if module_res == self.graph_root.res() {
1403+
let is_mod = |res| matches!(res, Res::Def(DefKind::Mod, _));
1404+
let mut candidates = self.lookup_import_candidates(ident, TypeNS, parent_scope, is_mod);
1405+
candidates
1406+
.sort_by_cached_key(|c| (c.path.segments.len(), pprust::path_to_string(&c.path)));
1407+
if let Some(candidate) = candidates.get(0) {
1408+
(
1409+
String::from("unresolved import"),
1410+
Some((
1411+
vec![(ident.span, pprust::path_to_string(&candidate.path))],
1412+
String::from("a similar path exists"),
1413+
Applicability::MaybeIncorrect,
1414+
)),
1415+
)
1416+
} else if self.session.edition() == Edition::Edition2015 {
1417+
(format!("maybe a missing crate `{}`?", ident), None)
1418+
} else {
1419+
(format!("could not find `{}` in the crate root", ident), None)
1420+
}
1421+
} else if i == 0 {
1422+
if ident.name.as_str().chars().next().map_or(false, |c| c.is_ascii_uppercase()) {
1423+
// Check whether the name refers to an item in the value namespace.
1424+
let suggestion = if ribs.is_some() {
1425+
let match_span = match self.resolve_ident_in_lexical_scope(
1426+
ident,
1427+
ValueNS,
1428+
parent_scope,
1429+
Finalize::No,
1430+
&ribs.unwrap()[ValueNS],
1431+
unusable_binding,
1432+
) {
1433+
// Name matches a local variable. For example:
1434+
// ```
1435+
// fn f() {
1436+
// let Foo: &str = "";
1437+
// println!("{}", Foo::Bar); // Name refers to local
1438+
// // variable `Foo`.
1439+
// }
1440+
// ```
1441+
Some(LexicalScopeBinding::Res(Res::Local(id))) => {
1442+
Some(*self.pat_span_map.get(&id).unwrap())
1443+
}
1444+
1445+
// Name matches item from a local name binding
1446+
// created by `use` declaration. For example:
1447+
// ```
1448+
// pub Foo: &str = "";
1449+
//
1450+
// mod submod {
1451+
// use super::Foo;
1452+
// println!("{}", Foo::Bar); // Name refers to local
1453+
// // binding `Foo`.
1454+
// }
1455+
// ```
1456+
Some(LexicalScopeBinding::Item(name_binding)) => Some(name_binding.span),
1457+
_ => None,
1458+
};
1459+
1460+
if let Some(span) = match_span {
1461+
Some((
1462+
vec![(span, String::from(""))],
1463+
format!("`{}` is defined here, but is not a type", ident),
1464+
Applicability::MaybeIncorrect,
1465+
))
1466+
} else {
1467+
None
1468+
}
1469+
} else {
1470+
None
1471+
};
1472+
1473+
(format!("use of undeclared type `{}`", ident), suggestion)
1474+
} else {
1475+
(
1476+
format!("use of undeclared crate or module `{}`", ident),
1477+
if ident.name == sym::alloc {
1478+
Some((
1479+
vec![],
1480+
String::from("add `extern crate alloc` to use the `alloc` crate"),
1481+
Applicability::MaybeIncorrect,
1482+
))
1483+
} else {
1484+
self.find_similarly_named_module_or_crate(ident.name, &parent_scope.module)
1485+
.map(|sugg| {
1486+
(
1487+
vec![(ident.span, sugg.to_string())],
1488+
String::from("there is a crate or module with a similar name"),
1489+
Applicability::MaybeIncorrect,
1490+
)
1491+
})
1492+
},
1493+
)
1494+
}
1495+
} else {
1496+
let parent = path[i - 1].ident.name;
1497+
let parent = match parent {
1498+
// ::foo is mounted at the crate root for 2015, and is the extern
1499+
// prelude for 2018+
1500+
kw::PathRoot if self.session.edition() > Edition::Edition2015 => {
1501+
"the list of imported crates".to_owned()
1502+
}
1503+
kw::PathRoot | kw::Crate => "the crate root".to_owned(),
1504+
_ => {
1505+
format!("`{}`", parent)
1506+
}
1507+
};
1508+
1509+
let mut msg = format!("could not find `{}` in {}", ident, parent);
1510+
if ns == TypeNS || ns == ValueNS {
1511+
let ns_to_try = if ns == TypeNS { ValueNS } else { TypeNS };
1512+
let binding = if let Some(module) = module {
1513+
self.resolve_ident_in_module(
1514+
module,
1515+
ident,
1516+
ns_to_try,
1517+
parent_scope,
1518+
finalize,
1519+
false,
1520+
unusable_binding,
1521+
).ok()
1522+
} else if let Some(ribs) = ribs
1523+
&& let Some(TypeNS | ValueNS) = opt_ns
1524+
{
1525+
match self.resolve_ident_in_lexical_scope(
1526+
ident,
1527+
ns_to_try,
1528+
parent_scope,
1529+
finalize_full,
1530+
&ribs[ns_to_try],
1531+
unusable_binding,
1532+
) {
1533+
// we found a locally-imported or available item/module
1534+
Some(LexicalScopeBinding::Item(binding)) => Some(binding),
1535+
_ => None,
1536+
}
1537+
} else {
1538+
let scopes = ScopeSet::All(ns_to_try, opt_ns.is_none());
1539+
self.early_resolve_ident_in_lexical_scope(
1540+
ident,
1541+
scopes,
1542+
parent_scope,
1543+
finalize,
1544+
finalize.is_some(),
1545+
false,
1546+
unusable_binding,
1547+
).ok()
1548+
};
1549+
if let Some(binding) = binding {
1550+
let mut found = |what| {
1551+
msg = format!(
1552+
"expected {}, found {} `{}` in {}",
1553+
ns.descr(),
1554+
what,
1555+
ident,
1556+
parent
1557+
)
1558+
};
1559+
if binding.module().is_some() {
1560+
found("module")
1561+
} else {
1562+
match binding.res() {
1563+
Res::Def(kind, id) => found(kind.descr(id)),
1564+
_ => found(ns_to_try.descr()),
1565+
}
1566+
}
1567+
};
1568+
}
1569+
(msg, None)
1570+
}
1571+
}
13801572
}
13811573

13821574
impl<'a, 'b> ImportResolver<'a, 'b> {

0 commit comments

Comments
 (0)