about summary refs log tree commit diff
diff options
context:
space:
mode:
authorLukas Wirth <lukastw97@gmail.com>2025-02-17 11:23:18 +0000
committerGitHub <noreply@github.com>2025-02-17 11:23:18 +0000
commit2a0d16f3c481cdf28366f88d3824f4a30ff806c9 (patch)
tree586d7021a1765ff0d6efeb038c876b772b9e9f01
parentc7a2986c201af4dd7c26aa8e3b1833b9122e14d5 (diff)
parentb7a9a321265c0e9a597762c7c8107d4b7eba378b (diff)
downloadrust-2a0d16f3c481cdf28366f88d3824f4a30ff806c9.tar.gz
rust-2a0d16f3c481cdf28366f88d3824f4a30ff806c9.zip
Merge pull request #19167 from ChayimFriedman2/fix-ref-pat
fix: Fix detection of ref patterns for path patterns
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/infer/diagnostics.rs21
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/infer/pat.rs13
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/infer/path.rs26
-rw-r--r--src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/type_mismatch.rs21
4 files changed, 64 insertions, 17 deletions
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer/diagnostics.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer/diagnostics.rs
index 8c0446953a6..e4f5b5ed378 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/infer/diagnostics.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer/diagnostics.rs
@@ -7,6 +7,7 @@ use std::ops::{Deref, DerefMut};
 
 use either::Either;
 use hir_def::{hir::ExprOrPatId, path::Path, resolver::Resolver, type_ref::TypesMap, TypeOwnerId};
+use la_arena::{Idx, RawIdx};
 
 use crate::{
     db::HirDatabase,
@@ -81,6 +82,26 @@ impl<'a> InferenceTyLoweringContext<'a> {
         };
         PathLoweringContext::new(&mut self.ctx, on_diagnostic, path)
     }
+
+    #[inline]
+    pub(super) fn at_path_forget_diagnostics<'b>(
+        &'b mut self,
+        path: &'b Path,
+    ) -> PathLoweringContext<'b, 'a> {
+        let on_diagnostic = PathDiagnosticCallback {
+            data: Either::Right(PathDiagnosticCallbackData {
+                diagnostics: self.diagnostics,
+                node: ExprOrPatId::ExprId(Idx::from_raw(RawIdx::from_u32(0))),
+            }),
+            callback: |_data, _, _diag| {},
+        };
+        PathLoweringContext::new(&mut self.ctx, on_diagnostic, path)
+    }
+
+    #[inline]
+    pub(super) fn forget_diagnostics(&mut self) {
+        self.ctx.diagnostics.clear();
+    }
 }
 
 impl<'a> Deref for InferenceTyLoweringContext<'a> {
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer/pat.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer/pat.rs
index d0fe00ecebd..db93116f107 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/infer/pat.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer/pat.rs
@@ -565,16 +565,9 @@ impl InferenceContext<'_> {
             | Pat::Slice { .. } => true,
             Pat::Or(pats) => pats.iter().all(|p| self.is_non_ref_pat(body, *p)),
             Pat::Path(path) => {
-                // A const is a reference pattern, but other value ns things aren't (see #16131). We don't need more than
-                // the hir-def resolver for this, because if there are segments left, this can only be an (associated) const.
-                //
-                // Do not use `TyLoweringContext`'s resolution, we want to ignore errors here (they'll be reported elsewhere).
-                let resolution = self.resolver.resolve_path_in_value_ns_fully(
-                    self.db.upcast(),
-                    path,
-                    body.pat_path_hygiene(pat),
-                );
-                resolution.is_some_and(|it| !matches!(it, hir_def::resolver::ValueNs::ConstId(_)))
+                // A const is a reference pattern, but other value ns things aren't (see #16131).
+                let resolved = self.resolve_value_path_inner(path, pat.into(), true);
+                resolved.is_some_and(|it| !matches!(it.0, hir_def::resolver::ValueNs::ConstId(_)))
             }
             Pat::ConstBlock(..) => false,
             Pat::Lit(expr) => !matches!(
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer/path.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer/path.rs
index 3794912ee98..6254bc12392 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/infer/path.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer/path.rs
@@ -40,7 +40,7 @@ impl InferenceContext<'_> {
     }
 
     fn resolve_value_path(&mut self, path: &Path, id: ExprOrPatId) -> Option<ValuePathResolution> {
-        let (value, self_subst) = self.resolve_value_path_inner(path, id)?;
+        let (value, self_subst) = self.resolve_value_path_inner(path, id, false)?;
 
         let value_def: ValueTyDefId = match value {
             ValueNs::FunctionId(it) => it.into(),
@@ -152,6 +152,7 @@ impl InferenceContext<'_> {
         &mut self,
         path: &Path,
         id: ExprOrPatId,
+        no_diagnostics: bool,
     ) -> Option<(ValueNs, Option<chalk_ir::Substitution<Interner>>)> {
         // Don't use `self.make_ty()` here as we need `orig_ns`.
         let mut ctx = TyLoweringContext::new(
@@ -162,7 +163,11 @@ impl InferenceContext<'_> {
             &self.diagnostics,
             InferenceTyDiagnosticSource::Body,
         );
-        let mut path_ctx = ctx.at_path(path, id);
+        let mut path_ctx = if no_diagnostics {
+            ctx.at_path_forget_diagnostics(path)
+        } else {
+            ctx.at_path(path, id)
+        };
         let (value, self_subst) = if let Some(type_ref) = path.type_anchor() {
             let last = path.segments().last()?;
 
@@ -172,7 +177,7 @@ impl InferenceContext<'_> {
 
             path_ctx.ignore_last_segment();
             let (ty, _) = path_ctx.lower_ty_relative_path(ty, orig_ns);
-            drop(ctx);
+            drop_ctx(ctx, no_diagnostics);
             let ty = self.table.insert_type_vars(ty);
             let ty = self.table.normalize_associated_types_in(ty);
             self.resolve_ty_assoc_item(ty, last.name, id).map(|(it, substs)| (it, Some(substs)))?
@@ -183,7 +188,7 @@ impl InferenceContext<'_> {
 
             match value_or_partial {
                 ResolveValueResult::ValueNs(it, _) => {
-                    drop(ctx);
+                    drop_ctx(ctx, no_diagnostics);
                     (it, None)
                 }
                 ResolveValueResult::Partial(def, remaining_index, _) => {
@@ -202,7 +207,7 @@ impl InferenceContext<'_> {
                             let self_ty = self.table.new_type_var();
                             let trait_ref =
                                 path_ctx.lower_trait_ref_from_resolved_path(trait_, self_ty);
-                            drop(ctx);
+                            drop_ctx(ctx, no_diagnostics);
                             self.resolve_trait_assoc_item(trait_ref, last_segment, id)
                         }
                         (def, _) => {
@@ -212,7 +217,7 @@ impl InferenceContext<'_> {
                             // as Iterator>::Item::default`)
                             path_ctx.ignore_last_segment();
                             let (ty, _) = path_ctx.lower_partly_resolved_path(def, true);
-                            drop(ctx);
+                            drop_ctx(ctx, no_diagnostics);
                             if ty.is_unknown() {
                                 return None;
                             }
@@ -227,7 +232,14 @@ impl InferenceContext<'_> {
                 }
             }
         };
-        Some((value, self_subst))
+        return Some((value, self_subst));
+
+        #[inline]
+        fn drop_ctx(mut ctx: TyLoweringContext<'_>, no_diagnostics: bool) {
+            if no_diagnostics {
+                ctx.forget_diagnostics();
+            }
+        }
     }
 
     fn add_required_obligations_for_value_path(&mut self, def: GenericDefId, subst: &Substitution) {
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/type_mismatch.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/type_mismatch.rs
index 73dcbc13b79..7cf8282d052 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/type_mismatch.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/type_mismatch.rs
@@ -1235,4 +1235,25 @@ fn f() {
 "#,
         );
     }
+
+    #[test]
+    fn complex_enum_variant_non_ref_pat() {
+        check_diagnostics(
+            r#"
+enum Enum { Variant }
+
+trait Trait {
+    type Assoc;
+}
+impl Trait for () {
+    type Assoc = Enum;
+}
+
+fn foo(v: &Enum) {
+    let <Enum>::Variant = v;
+    let <() as Trait>::Assoc::Variant = v;
+}
+    "#,
+        );
+    }
 }