Unnamed repository; edit this file 'description' to name the repository.
Auto merge of #15211 - lowr:patch/gats-in-bounds-for-assoc, r=flodiebold
Support GATs in bounds for associated types Chalk has a dedicated IR for bounds on trait associated type: `rust_ir::InlineBound`. We have been failing to convert GATs inside those bounds from our IR to chalk IR. This PR provides an easy fix for it: properly take GATs into account during the conversion.
bors 2023-07-04
parent 45d4ebc · parent 9fd5f8c · commit e219999
-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 ff80d4cf9d..0038b0d183 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 97ae732a90..5f5cd79451 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(