about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--crates/hir-ty/src/chalk_db.rs26
-rw-r--r--crates/hir-ty/src/tests/traits.rs24
2 files changed, 40 insertions, 10 deletions
diff --git a/crates/hir-ty/src/chalk_db.rs b/crates/hir-ty/src/chalk_db.rs
index ff80d4cf9d5..0038b0d1836 100644
--- a/crates/hir-ty/src/chalk_db.rs
+++ b/crates/hir-ty/src/chalk_db.rs
@@ -5,7 +5,7 @@ use std::{iter, sync::Arc};
 
 use tracing::debug;
 
-use chalk_ir::{cast::Cast, fold::shift::Shift, CanonicalVarKinds};
+use chalk_ir::{cast::Caster, fold::shift::Shift, CanonicalVarKinds};
 use chalk_solve::rust_ir::{self, OpaqueTyDatumBound, WellKnownTrait};
 
 use base_db::CrateId;
@@ -846,28 +846,34 @@ pub(super) fn generic_predicate_to_inline_bound(
             }
             let args_no_self = trait_ref.substitution.as_slice(Interner)[1..]
                 .iter()
-                .map(|ty| ty.clone().cast(Interner))
+                .cloned()
+                .casted(Interner)
                 .collect();
             let trait_bound = rust_ir::TraitBound { trait_id: trait_ref.trait_id, args_no_self };
             Some(chalk_ir::Binders::new(binders, rust_ir::InlineBound::TraitBound(trait_bound)))
         }
         WhereClause::AliasEq(AliasEq { alias: AliasTy::Projection(projection_ty), ty }) => {
-            let trait_ = projection_ty.trait_(db);
-            if projection_ty.self_type_parameter(db) != self_ty_shifted_in {
+            let generics =
+                generics(db.upcast(), from_assoc_type_id(projection_ty.associated_ty_id).into());
+            let (assoc_args, trait_args) =
+                projection_ty.substitution.as_slice(Interner).split_at(generics.len_self());
+            let (self_ty, args_no_self) =
+                trait_args.split_first().expect("projection without trait self type");
+            if self_ty.assert_ty_ref(Interner) != &self_ty_shifted_in {
                 return None;
             }
-            let args_no_self = projection_ty.substitution.as_slice(Interner)[1..]
-                .iter()
-                .map(|ty| ty.clone().cast(Interner))
-                .collect();
+
+            let args_no_self = args_no_self.iter().cloned().casted(Interner).collect();
+            let parameters = assoc_args.to_vec();
+
             let alias_eq_bound = rust_ir::AliasEqBound {
                 value: ty.clone(),
                 trait_bound: rust_ir::TraitBound {
-                    trait_id: to_chalk_trait_id(trait_),
+                    trait_id: to_chalk_trait_id(projection_ty.trait_(db)),
                     args_no_self,
                 },
                 associated_ty_id: projection_ty.associated_ty_id,
-                parameters: Vec::new(), // FIXME we don't support generic associated types yet
+                parameters,
             };
             Some(chalk_ir::Binders::new(
                 binders,
diff --git a/crates/hir-ty/src/tests/traits.rs b/crates/hir-ty/src/tests/traits.rs
index 97ae732a904..5f5cd794512 100644
--- a/crates/hir-ty/src/tests/traits.rs
+++ b/crates/hir-ty/src/tests/traits.rs
@@ -4149,6 +4149,30 @@ where
 }
 
 #[test]
+fn gats_in_bounds_for_assoc() {
+    check_types(
+        r#"
+trait Trait {
+    type Assoc: Another<Gat<i32> = usize>;
+    type Assoc2<T>: Another<Gat<T> = T>;
+}
+trait Another {
+    type Gat<T>;
+    fn foo(&self) -> Self::Gat<i32>;
+    fn bar<T>(&self) -> Self::Gat<T>;
+}
+
+fn test<T: Trait>(a: T::Assoc, b: T::Assoc2<isize>) {
+    let v = a.foo();
+      //^ usize
+    let v = b.bar::<isize>();
+      //^ isize
+}
+"#,
+    );
+}
+
+#[test]
 fn bin_op_with_scalar_fallback() {
     // Extra impls are significant so that chalk doesn't give us definite guidances.
     check_types(