Fixed diagnostic and added test for issue 81508

This commit is contained in:
Kevin Jiang 2021-03-18 00:15:39 -04:00 committed by K
parent 926ec1cb8b
commit e433f55852
4 changed files with 100 additions and 14 deletions

View file

@ -1031,7 +1031,6 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
}
ItemKind::Static(ref ty, _, ref expr) | ItemKind::Const(_, ref ty, ref expr) => {
debug!("resolve_item ItemKind::Const");
self.with_item_rib(HasGenericParams::No, |this| {
this.visit_ty(ty);
if let Some(expr) = expr {
@ -1597,6 +1596,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
.try_resolve_as_non_binding(pat_src, pat, bmode, ident, has_sub)
.unwrap_or_else(|| self.fresh_binding(ident, pat.id, pat_src, bindings));
self.r.record_partial_res(pat.id, PartialRes::new(res));
self.r.record_local_span(pat.id, pat.span);
}
PatKind::TupleStruct(ref path, ref sub_patterns) => {
self.smart_resolve_path(

View file

@ -884,6 +884,10 @@ pub struct Resolver<'a> {
/// "self-confirming" import resolutions during import validation.
unusable_binding: Option<&'a NameBinding<'a>>,
// Spans for local variables found during resolution
// Used for suggestions during error reporting
local_span_map: NodeMap<Span>,
/// Resolutions for nodes that have a single resolution.
partial_res_map: NodeMap<PartialRes>,
/// Resolutions for import nodes, which have multiple resolutions in different namespaces.
@ -1262,6 +1266,7 @@ impl<'a> Resolver<'a> {
last_import_segment: false,
unusable_binding: None,
local_span_map: Default::default(),
partial_res_map: Default::default(),
import_res_map: Default::default(),
label_res_map: Default::default(),
@ -1879,7 +1884,6 @@ impl<'a> Resolver<'a> {
ribs,
)));
}
module = match ribs[i].kind {
ModuleRibKind(module) => module,
MacroDefinition(def) if def == self.macro_def(ident.span.ctxt()) => {
@ -1890,7 +1894,6 @@ impl<'a> Resolver<'a> {
}
_ => continue,
};
match module.kind {
ModuleKind::Block(..) => {} // We can see through blocks
_ => break,
@ -1909,17 +1912,19 @@ impl<'a> Resolver<'a> {
return Some(LexicalScopeBinding::Item(binding));
}
}
let returned_item = self
.early_resolve_ident_in_lexical_scope(
orig_ident,
ScopeSet::Late(ns, module, record_used_id),
parent_scope,
record_used,
record_used,
path_span,
)
.ok()
.map(LexicalScopeBinding::Item);
self.early_resolve_ident_in_lexical_scope(
orig_ident,
ScopeSet::Late(ns, module, record_used_id),
parent_scope,
record_used,
record_used,
path_span,
)
.ok()
.map(LexicalScopeBinding::Item)
returned_item
}
fn hygienic_lexical_parent(
@ -2386,7 +2391,40 @@ impl<'a> Resolver<'a> {
.next()
.map_or(false, |c| c.is_ascii_uppercase())
{
(format!("use of undeclared type `{}`", ident), None)
// Add check case for similarly named item in alternative namespace
let mut suggestion = None;
if ribs.is_some() {
if let Some(res) = self.resolve_ident_in_lexical_scope(
ident,
ValueNS,
parent_scope,
None,
path_span,
&ribs.unwrap()[ValueNS],
) {
let mut match_span: Option<Span> = None;
match res {
LexicalScopeBinding::Res(Res::Local(id)) => {
match_span =
Some(*self.local_span_map.get(&id).unwrap());
}
LexicalScopeBinding::Item(name_binding) => {
match_span = Some(name_binding.span);
}
_ => (),
};
if let Some(span) = match_span {
suggestion = Some((
vec![(span, String::from(""))],
format!("{} is defined here, but is not a type", ident),
Applicability::MaybeIncorrect,
));
}
}
}
(format!("use of undeclared type `{}`", ident), suggestion)
} else {
(format!("use of undeclared crate or module `{}`", ident), None)
}
@ -2797,6 +2835,11 @@ impl<'a> Resolver<'a> {
}
}
fn record_local_span(&mut self, node: NodeId, span: Span) {
debug!("(recording local) recording {:?} for {:?}", node, span);
self.local_span_map.insert(node, span);
}
fn is_accessible_from(&self, vis: ty::Visibility, module: Module<'a>) -> bool {
vis.is_accessible_from(module.nearest_parent_mod, self)
}