Skip to content

Commit

Permalink
Auto merge of #15211 - lowr:patch/gats-in-bounds-for-assoc, r=flodiebold
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
bors committed Jul 4, 2023
2 parents 45d4ebc + 9fd5f8c commit e219999
Show file tree
Hide file tree
Showing 2 changed files with 40 additions and 10 deletions.
26 changes: 16 additions & 10 deletions crates/hir-ty/src/chalk_db.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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,
Expand Down
24 changes: 24 additions & 0 deletions crates/hir-ty/src/tests/traits.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4148,6 +4148,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.
Expand Down

0 comments on commit e219999

Please sign in to comment.