about summary refs log tree commit diff
path: root/compiler
diff options
context:
space:
mode:
Diffstat (limited to 'compiler')
-rw-r--r--compiler/rustc_resolve/src/late.rs46
1 files changed, 24 insertions, 22 deletions
diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs
index 2f4da29133f..87aa3bed2ca 100644
--- a/compiler/rustc_resolve/src/late.rs
+++ b/compiler/rustc_resolve/src/late.rs
@@ -4150,34 +4150,36 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
             PathResult::Indeterminate => bug!("indeterminate path result in resolve_qpath"),
         };
 
-        if path.len() > 1
-            && let Some(res) = result.full_res()
-            && let Some((&last_segment, prev_segs)) = path.split_last()
-            && prev_segs.iter().all(|seg| !seg.has_generic_args)
-            && res != Res::Err
-            && path[0].ident.name != kw::PathRoot
-            && path[0].ident.name != kw::DollarCrate
-        {
-            let unqualified_result = {
-                match self.resolve_path(&[last_segment], Some(ns), None) {
-                    PathResult::NonModule(path_res) => path_res.expect_full_res(),
-                    PathResult::Module(ModuleOrUniformRoot::Module(module)) => {
-                        module.res().unwrap()
-                    }
-                    _ => return Ok(Some(result)),
-                }
-            };
-            if res == unqualified_result {
-                let lint = lint::builtin::UNUSED_QUALIFICATIONS;
+        if path.iter().all(|seg| !seg.ident.span.from_expansion()) {
+            let end_pos =
+                path.iter().position(|seg| seg.has_generic_args).map_or(path.len(), |pos| pos + 1);
+            let unqualified =
+                path[..end_pos].iter().enumerate().skip(1).rev().find_map(|(i, seg)| {
+                    // Preserve the current namespace for the final path segment, but use the type
+                    // namespace for all preceding segments
+                    //
+                    // e.g. for `std::env::args` check the `ValueNS` for `args` but the `TypeNS` for
+                    // `std` and `env`
+                    //
+                    // If the final path segment is beyond `end_pos` all the segments to check will
+                    // use the type namespace
+                    let ns = if i + 1 == path.len() { ns } else { TypeNS };
+                    let res = self.r.partial_res_map.get(&seg.id?)?.full_res()?;
+                    let binding = self.resolve_ident_in_lexical_scope(seg.ident, ns, None, None)?;
+
+                    (res == binding.res()).then_some(seg)
+                });
+
+            if let Some(unqualified) = unqualified {
                 self.r.lint_buffer.buffer_lint_with_diagnostic(
-                    lint,
+                    lint::builtin::UNUSED_QUALIFICATIONS,
                     finalize.node_id,
                     finalize.path_span,
                     "unnecessary qualification",
                     lint::BuiltinLintDiagnostics::UnusedQualifications {
-                        removal_span: finalize.path_span.until(last_segment.ident.span),
+                        removal_span: finalize.path_span.until(unqualified.ident.span),
                     },
-                )
+                );
             }
         }