about summary refs log tree commit diff
diff options
context:
space:
mode:
authorDavid Barsky <me@davidbarsky.com>2025-03-28 02:53:14 +0000
committerGitHub <noreply@github.com>2025-03-28 02:53:14 +0000
commitc2ce9a9d7d693f322299c6775d5eecfb87d7bae0 (patch)
tree142958b9a56151a72a5d8843102cca9d082fc0dc
parent5aeb82f6677dca53318d9a633cecb590c024aa4a (diff)
parent14410b6369e7fbe221f37421b1840c51c663c6ca (diff)
downloadrust-c2ce9a9d7d693f322299c6775d5eecfb87d7bae0.tar.gz
rust-c2ce9a9d7d693f322299c6775d5eecfb87d7bae0.zip
Merge pull request #19466 from ChayimFriedman2/bug-coherence
fix: Fix a bug in orphan rules calculation
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/method_resolution.rs29
-rw-r--r--src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/trait_impl_orphan.rs13
2 files changed, 30 insertions, 12 deletions
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/method_resolution.rs b/src/tools/rust-analyzer/crates/hir-ty/src/method_resolution.rs
index d887013b6ff..10b8dd2a3a6 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/method_resolution.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/method_resolution.rs
@@ -874,21 +874,26 @@ pub fn check_orphan_rules(db: &dyn HirDatabase, impl_: ImplId) -> bool {
         return true;
     }
 
-    let unwrap_fundamental = |ty: Ty| match ty.kind(Interner) {
-        TyKind::Ref(_, _, referenced) => referenced.clone(),
-        &TyKind::Adt(AdtId(hir_def::AdtId::StructId(s)), ref subs) => {
-            let struct_data = db.struct_data(s);
-            if struct_data.flags.contains(StructFlags::IS_FUNDAMENTAL) {
-                let next = subs.type_parameters(Interner).next();
-                match next {
-                    Some(ty) => ty,
-                    None => ty,
+    let unwrap_fundamental = |mut ty: Ty| {
+        // Unwrap all layers of fundamental types with a loop.
+        loop {
+            match ty.kind(Interner) {
+                TyKind::Ref(_, _, referenced) => ty = referenced.clone(),
+                &TyKind::Adt(AdtId(hir_def::AdtId::StructId(s)), ref subs) => {
+                    let struct_data = db.struct_data(s);
+                    if struct_data.flags.contains(StructFlags::IS_FUNDAMENTAL) {
+                        let next = subs.type_parameters(Interner).next();
+                        match next {
+                            Some(it) => ty = it,
+                            None => break ty,
+                        }
+                    } else {
+                        break ty;
+                    }
                 }
-            } else {
-                ty
+                _ => break ty,
             }
         }
-        _ => ty,
     };
     //   - At least one of the types `T0..=Tn`` must be a local type. Let `Ti`` be the first such type.
     let is_not_orphan = trait_ref.substitution.type_parameters(Interner).any(|ty| {
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/trait_impl_orphan.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/trait_impl_orphan.rs
index 78a04e15424..35dc9b0fac8 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/trait_impl_orphan.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/trait_impl_orphan.rs
@@ -104,4 +104,17 @@ impl<T> foo::Foo<dyn LocalTrait> for Bar {}
 "#,
         );
     }
+
+    #[test]
+    fn twice_fundamental() {
+        check_diagnostics(
+            r#"
+//- /foo.rs crate:foo
+pub trait Trait {}
+//- /bar.rs crate:bar deps:foo
+struct Foo;
+impl foo::Trait for &&Foo {}
+        "#,
+        );
+    }
 }