Support GATs in bounds for associated types

This commit is contained in:
Ryo Yoshida 2023-07-04 18:58:19 +09:00
parent e175595985
commit 9fd5f8c670
No known key found for this signature in database
GPG Key ID: E25698A930586171
2 changed files with 40 additions and 10 deletions

View File

@ -5,7 +5,7 @@
use tracing::debug; 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 chalk_solve::rust_ir::{self, OpaqueTyDatumBound, WellKnownTrait};
use base_db::CrateId; 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..] let args_no_self = trait_ref.substitution.as_slice(Interner)[1..]
.iter() .iter()
.map(|ty| ty.clone().cast(Interner)) .cloned()
.casted(Interner)
.collect(); .collect();
let trait_bound = rust_ir::TraitBound { trait_id: trait_ref.trait_id, args_no_self }; 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))) Some(chalk_ir::Binders::new(binders, rust_ir::InlineBound::TraitBound(trait_bound)))
} }
WhereClause::AliasEq(AliasEq { alias: AliasTy::Projection(projection_ty), ty }) => { WhereClause::AliasEq(AliasEq { alias: AliasTy::Projection(projection_ty), ty }) => {
let trait_ = projection_ty.trait_(db); let generics =
if projection_ty.self_type_parameter(db) != self_ty_shifted_in { 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; return None;
} }
let args_no_self = projection_ty.substitution.as_slice(Interner)[1..]
.iter() let args_no_self = args_no_self.iter().cloned().casted(Interner).collect();
.map(|ty| ty.clone().cast(Interner)) let parameters = assoc_args.to_vec();
.collect();
let alias_eq_bound = rust_ir::AliasEqBound { let alias_eq_bound = rust_ir::AliasEqBound {
value: ty.clone(), value: ty.clone(),
trait_bound: rust_ir::TraitBound { 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, args_no_self,
}, },
associated_ty_id: projection_ty.associated_ty_id, 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( Some(chalk_ir::Binders::new(
binders, binders,

View File

@ -4148,6 +4148,30 @@ fn f<T>(t: T)
); );
} }
#[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] #[test]
fn bin_op_with_scalar_fallback() { fn bin_op_with_scalar_fallback() {
// Extra impls are significant so that chalk doesn't give us definite guidances. // Extra impls are significant so that chalk doesn't give us definite guidances.