Skip to content

Commit b6780b3

Browse files
authored
Rollup merge of #83669 - kwj2104:issue-81508-fix, r=varkor
Issue 81508 fix Fix #81508 **Problem**: When variable name is used incorrectly as path, error and warning point to undeclared/unused name, when in fact the name is used, just incorrectly (should be used as a variable, not part of a path). **Summary for fix**: When path resolution errs, diagnostics checks for variables in ```ValueNS``` that have the same name (e.g., variable rather than path named Foo), and adds additional suggestion that user may actually intend to use the variable name rather than a path. The fix does not suppress or otherwise change the *warning* that results. I did not find a straightforward way in the code to modify this, but would love to make changes here as well with any guidance.
2 parents a866124 + f51f25a commit b6780b3

File tree

4 files changed

+107
-3
lines changed

4 files changed

+107
-3
lines changed

compiler/rustc_resolve/src/late.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1031,7 +1031,6 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
10311031
}
10321032

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

compiler/rustc_resolve/src/lib.rs

+63-2
Original file line numberDiff line numberDiff line change
@@ -891,6 +891,10 @@ pub struct Resolver<'a> {
891891
/// "self-confirming" import resolutions during import validation.
892892
unusable_binding: Option<&'a NameBinding<'a>>,
893893

894+
// Spans for local variables found during pattern resolution.
895+
// Used for suggestions during error reporting.
896+
pat_span_map: NodeMap<Span>,
897+
894898
/// Resolutions for nodes that have a single resolution.
895899
partial_res_map: NodeMap<PartialRes>,
896900
/// Resolutions for import nodes, which have multiple resolutions in different namespaces.
@@ -1270,6 +1274,7 @@ impl<'a> Resolver<'a> {
12701274
last_import_segment: false,
12711275
unusable_binding: None,
12721276

1277+
pat_span_map: Default::default(),
12731278
partial_res_map: Default::default(),
12741279
import_res_map: Default::default(),
12751280
label_res_map: Default::default(),
@@ -1917,7 +1922,6 @@ impl<'a> Resolver<'a> {
19171922
return Some(LexicalScopeBinding::Item(binding));
19181923
}
19191924
}
1920-
19211925
self.early_resolve_ident_in_lexical_scope(
19221926
orig_ident,
19231927
ScopeSet::Late(ns, module, record_used_id),
@@ -2394,7 +2398,59 @@ impl<'a> Resolver<'a> {
23942398
.next()
23952399
.map_or(false, |c| c.is_ascii_uppercase())
23962400
{
2397-
(format!("use of undeclared type `{}`", ident), None)
2401+
// Check whether the name refers to an item in the value namespace.
2402+
let suggestion = if ribs.is_some() {
2403+
let match_span = match self.resolve_ident_in_lexical_scope(
2404+
ident,
2405+
ValueNS,
2406+
parent_scope,
2407+
None,
2408+
path_span,
2409+
&ribs.unwrap()[ValueNS],
2410+
) {
2411+
// Name matches a local variable. For example:
2412+
// ```
2413+
// fn f() {
2414+
// let Foo: &str = "";
2415+
// println!("{}", Foo::Bar); // Name refers to local
2416+
// // variable `Foo`.
2417+
// }
2418+
// ```
2419+
Some(LexicalScopeBinding::Res(Res::Local(id))) => {
2420+
Some(*self.pat_span_map.get(&id).unwrap())
2421+
}
2422+
2423+
// Name matches item from a local name binding
2424+
// created by `use` declaration. For example:
2425+
// ```
2426+
// pub Foo: &str = "";
2427+
//
2428+
// mod submod {
2429+
// use super::Foo;
2430+
// println!("{}", Foo::Bar); // Name refers to local
2431+
// // binding `Foo`.
2432+
// }
2433+
// ```
2434+
Some(LexicalScopeBinding::Item(name_binding)) => {
2435+
Some(name_binding.span)
2436+
}
2437+
_ => None,
2438+
};
2439+
2440+
if let Some(span) = match_span {
2441+
Some((
2442+
vec![(span, String::from(""))],
2443+
format!("`{}` is defined here, but is not a type", ident),
2444+
Applicability::MaybeIncorrect,
2445+
))
2446+
} else {
2447+
None
2448+
}
2449+
} else {
2450+
None
2451+
};
2452+
2453+
(format!("use of undeclared type `{}`", ident), suggestion)
23982454
} else {
23992455
(format!("use of undeclared crate or module `{}`", ident), None)
24002456
}
@@ -2805,6 +2861,11 @@ impl<'a> Resolver<'a> {
28052861
}
28062862
}
28072863

2864+
fn record_pat_span(&mut self, node: NodeId, span: Span) {
2865+
debug!("(recording pat) recording {:?} for {:?}", node, span);
2866+
self.pat_span_map.insert(node, span);
2867+
}
2868+
28082869
fn is_accessible_from(&self, vis: ty::Visibility, module: Module<'a>) -> bool {
28092870
vis.is_accessible_from(module.nearest_parent_mod, self)
28102871
}

src/test/ui/resolve/issue-81508.rs

+22
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
// Confusing diagnostic when using variable as a type:
2+
//
3+
// Previous warnings indicate Foo is not used, when in fact it is
4+
// used improperly as a variable or constant. New warning points
5+
// out user may be trying to use variable as a type. Test demonstrates
6+
// cases for both local variable and const.
7+
8+
fn main() {
9+
let Baz: &str = "";
10+
11+
println!("{}", Baz::Bar); //~ ERROR: failed to resolve: use of undeclared type `Baz`
12+
}
13+
14+
#[allow(non_upper_case_globals)]
15+
pub const Foo: &str = "";
16+
17+
mod submod {
18+
use super::Foo;
19+
fn function() {
20+
println!("{}", Foo::Bar); //~ ERROR: failed to resolve: use of undeclared type `Foo`
21+
}
22+
}
+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
error[E0433]: failed to resolve: use of undeclared type `Baz`
2+
--> $DIR/issue-81508.rs:11:20
3+
|
4+
LL | let Baz: &str = "";
5+
| --- help: `Baz` is defined here, but is not a type
6+
LL |
7+
LL | println!("{}", Baz::Bar);
8+
| ^^^ use of undeclared type `Baz`
9+
10+
error[E0433]: failed to resolve: use of undeclared type `Foo`
11+
--> $DIR/issue-81508.rs:20:24
12+
|
13+
LL | use super::Foo;
14+
| ---------- help: `Foo` is defined here, but is not a type
15+
LL | fn function() {
16+
LL | println!("{}", Foo::Bar);
17+
| ^^^ use of undeclared type `Foo`
18+
19+
error: aborting due to 2 previous errors
20+
21+
For more information about this error, try `rustc --explain E0433`.

0 commit comments

Comments
 (0)