Chalkify TraitRef

This commit is contained in:
Florian Diebold 2021-03-18 21:53:19 +01:00
parent b70bea0d79
commit 7a7e47eab7
15 changed files with 99 additions and 73 deletions

View file

@ -1462,7 +1462,7 @@ impl TypeParam {
.into_iter()
.filter_map(|pred| match &pred.value {
hir_ty::GenericPredicate::Implemented(trait_ref) => {
Some(Trait::from(trait_ref.trait_))
Some(Trait::from(trait_ref.hir_trait_id()))
}
_ => None,
})
@ -1757,8 +1757,8 @@ impl Type {
pub fn impls_trait(&self, db: &dyn HirDatabase, trait_: Trait, args: &[Type]) -> bool {
let trait_ref = hir_ty::TraitRef {
trait_: trait_.id,
substs: Substitution::build_for_def(db, trait_.id)
trait_id: hir_ty::to_chalk_trait_id(trait_.id),
substitution: Substitution::build_for_def(db, trait_.id)
.push(self.ty.value.clone())
.fill(args.iter().map(|t| t.ty.value.clone()))
.build(),
@ -2023,7 +2023,7 @@ impl Type {
it.into_iter()
.filter_map(|pred| match pred {
hir_ty::GenericPredicate::Implemented(trait_ref) => {
Some(Trait::from(trait_ref.trait_))
Some(Trait::from(trait_ref.hir_trait_id()))
}
_ => None,
})
@ -2067,7 +2067,7 @@ impl Type {
match pred {
GenericPredicate::Implemented(trait_ref) => {
cb(type_.clone());
walk_substs(db, type_, &trait_ref.substs, cb);
walk_substs(db, type_, &trait_ref.substitution, cb);
}
_ => (),
}

View file

@ -12,7 +12,7 @@ use log::{info, warn};
use crate::{
db::HirDatabase,
to_assoc_type_id,
to_assoc_type_id, to_chalk_trait_id,
traits::{InEnvironment, Solution},
utils::generics,
BoundVar, Canonical, DebruijnIndex, Interner, Obligation, Substitution, TraitRef, Ty, TyKind,
@ -68,7 +68,8 @@ fn deref_by_trait(
Substitution::build_for_generics(&generic_params).push(ty.value.value.clone()).build();
// Check that the type implements Deref at all
let trait_ref = TraitRef { trait_: deref_trait, substs: parameters.clone() };
let trait_ref =
TraitRef { trait_id: to_chalk_trait_id(deref_trait), substitution: parameters.clone() };
let implements_goal = Canonical {
kinds: ty.value.kinds.clone(),
value: InEnvironment {

View file

@ -344,7 +344,7 @@ impl HirDisplay for Ty {
};
if let [GenericPredicate::Implemented(trait_ref), _] = predicates.as_ref() {
let trait_ = trait_ref.trait_;
let trait_ = trait_ref.hir_trait_id();
if fn_traits(f.db.upcast(), trait_).any(|it| it == trait_) {
return write!(f, "{}", ty_display);
}
@ -670,7 +670,7 @@ fn write_bounds_like_dyn_trait(
for p in predicates.iter() {
match p {
GenericPredicate::Implemented(trait_ref) => {
let trait_ = trait_ref.trait_;
let trait_ = trait_ref.hir_trait_id();
if !is_fn_trait {
is_fn_trait = fn_traits(f.db.upcast(), trait_).any(|it| it == trait_);
}
@ -685,7 +685,7 @@ fn write_bounds_like_dyn_trait(
// existential) here, which is the only thing that's
// possible in actual Rust, and hence don't print it
write!(f, "{}", f.db.trait_data(trait_).name)?;
if let [_, params @ ..] = &*trait_ref.substs.0 {
if let [_, params @ ..] = &*trait_ref.substitution.0 {
if is_fn_trait {
if let Some(args) = params.first().and_then(|it| it.as_tuple()) {
write!(f, "(")?;
@ -745,16 +745,16 @@ impl TraitRef {
return write!(f, "{}", TYPE_HINT_TRUNCATION);
}
self.substs[0].hir_fmt(f)?;
self.substitution[0].hir_fmt(f)?;
if use_as {
write!(f, " as ")?;
} else {
write!(f, ": ")?;
}
write!(f, "{}", f.db.trait_data(self.trait_).name)?;
if self.substs.len() > 1 {
write!(f, "{}", f.db.trait_data(self.hir_trait_id()).name)?;
if self.substitution.len() > 1 {
write!(f, "<")?;
f.write_joined(&self.substs[1..], ", ")?;
f.write_joined(&self.substitution[1..], ", ")?;
write!(f, ">")?;
}
Ok(())

View file

@ -42,7 +42,7 @@ use super::{
};
use crate::{
db::HirDatabase, infer::diagnostics::InferenceDiagnostic, lower::ImplTraitLoweringMode,
to_assoc_type_id, AliasTy, Interner, TyKind,
to_assoc_type_id, to_chalk_trait_id, AliasTy, Interner, TyKind,
};
pub(crate) use unify::unify;
@ -394,7 +394,8 @@ impl<'a> InferenceContext<'a> {
.push(inner_ty)
.fill(params.iter().cloned())
.build();
let trait_ref = TraitRef { trait_, substs: substs.clone() };
let trait_ref =
TraitRef { trait_id: to_chalk_trait_id(trait_), substitution: substs.clone() };
let projection = ProjectionPredicate {
ty: ty.clone(),
projection_ty: ProjectionTy {

View file

@ -8,7 +8,8 @@ use chalk_ir::{Mutability, TyVariableKind};
use hir_def::lang_item::LangItemTarget;
use crate::{
autoderef, traits::Solution, Interner, Obligation, Substitution, TraitRef, Ty, TyKind,
autoderef, to_chalk_trait_id, traits::Solution, Interner, Obligation, Substitution, TraitRef,
Ty, TyKind,
};
use super::{InEnvironment, InferenceContext};
@ -140,7 +141,8 @@ impl<'a> InferenceContext<'a> {
.push(from_ty.clone())
.push(to_ty.clone())
.build();
let trait_ref = TraitRef { trait_: coerce_unsized_trait, substs };
let trait_ref =
TraitRef { trait_id: to_chalk_trait_id(coerce_unsized_trait), substitution: substs };
let goal = InEnvironment::new(self.trait_env.clone(), Obligation::Trait(trait_ref));
let canonicalizer = self.canonicalizer();

View file

@ -18,7 +18,7 @@ use crate::{
lower::lower_to_chalk_mutability,
method_resolution, op,
primitive::{self, UintTy},
to_assoc_type_id,
to_assoc_type_id, to_chalk_trait_id,
traits::{chalk::from_chalk, FnTrait, InEnvironment},
utils::{generics, variant_data, Generics},
AdtId, Binders, CallableDefId, FnPointer, FnSig, Interner, Obligation, Rawness, Scalar,
@ -90,8 +90,10 @@ impl<'a> InferenceContext<'a> {
Substitution::build_for_generics(&generic_params).push(ty.clone()).push(arg_ty).build();
let trait_env = Arc::clone(&self.trait_env);
let implements_fn_trait =
Obligation::Trait(TraitRef { trait_: fn_once_trait, substs: substs.clone() });
let implements_fn_trait = Obligation::Trait(TraitRef {
trait_id: to_chalk_trait_id(fn_once_trait),
substitution: substs.clone(),
});
let goal = self.canonicalizer().canonicalize_obligation(InEnvironment {
value: implements_fn_trait.clone(),
environment: trait_env,
@ -948,7 +950,10 @@ impl<'a> InferenceContext<'a> {
// construct a TraitDef
let substs =
parameters.prefix(generics(self.db.upcast(), trait_.into()).len());
self.obligations.push(Obligation::Trait(TraitRef { trait_, substs }));
self.obligations.push(Obligation::Trait(TraitRef {
trait_id: to_chalk_trait_id(trait_),
substitution: substs,
}));
}
}
CallableDefId::StructId(_) | CallableDefId::EnumVariantId(_) => {}

View file

@ -9,7 +9,9 @@ use hir_def::{
};
use hir_expand::name::Name;
use crate::{method_resolution, Interner, Substitution, Ty, TyKind, ValueTyDefId};
use crate::{
method_resolution, to_chalk_trait_id, Interner, Substitution, Ty, TyKind, ValueTyDefId,
};
use super::{ExprOrPatId, InferenceContext, TraitRef};
@ -165,7 +167,7 @@ impl<'a> InferenceContext<'a> {
segment: PathSegment<'_>,
id: ExprOrPatId,
) -> Option<(ValueNs, Option<Substitution>)> {
let trait_ = trait_ref.trait_;
let trait_ = trait_ref.hir_trait_id();
let item =
self.db.trait_data(trait_).items.iter().map(|(_name, id)| (*id)).find_map(|item| {
match item {
@ -200,7 +202,7 @@ impl<'a> InferenceContext<'a> {
};
self.write_assoc_resolution(id, item);
Some((def, Some(trait_ref.substs)))
Some((def, Some(trait_ref.substitution)))
}
fn resolve_ty_assoc_item(
@ -255,8 +257,8 @@ impl<'a> InferenceContext<'a> {
.fill(std::iter::repeat_with(|| self.table.new_type_var()))
.build();
self.obligations.push(super::Obligation::Trait(TraitRef {
trait_,
substs: trait_substs.clone(),
trait_id: to_chalk_trait_id(trait_),
substitution: trait_substs.clone(),
}));
Some(trait_substs)
}

View file

@ -390,9 +390,9 @@ impl InferenceTable {
) -> bool {
match (pred1, pred2) {
(GenericPredicate::Implemented(tr1), GenericPredicate::Implemented(tr2))
if tr1.trait_ == tr2.trait_ =>
if tr1.trait_id == tr2.trait_id =>
{
self.unify_substs(&tr1.substs, &tr2.substs, depth + 1)
self.unify_substs(&tr1.substitution, &tr2.substitution, depth + 1)
}
(GenericPredicate::Projection(proj1), GenericPredicate::Projection(proj2))
if proj1.projection_ty.associated_ty_id == proj2.projection_ty.associated_ty_id =>

View file

@ -58,6 +58,8 @@ pub type ClosureId = chalk_ir::ClosureId<Interner>;
pub type OpaqueTyId = chalk_ir::OpaqueTyId<Interner>;
pub type PlaceholderIndex = chalk_ir::PlaceholderIndex;
pub type ChalkTraitId = chalk_ir::TraitId<Interner>;
#[derive(Clone, PartialEq, Eq, Debug, Hash)]
pub enum Lifetime {
Parameter(LifetimeParamId),
@ -81,7 +83,10 @@ pub struct ProjectionTy {
impl ProjectionTy {
pub fn trait_ref(&self, db: &dyn HirDatabase) -> TraitRef {
TraitRef { trait_: self.trait_(db), substs: self.substitution.clone() }
TraitRef {
trait_id: to_chalk_trait_id(self.trait_(db)),
substitution: self.substitution.clone(),
}
}
fn trait_(&self, db: &dyn HirDatabase) -> TraitId {
@ -493,23 +498,25 @@ impl<T: TypeWalk> TypeWalk for Binders<T> {
}
/// A trait with type parameters. This includes the `Self`, so this represents a concrete type implementing the trait.
/// Name to be bikeshedded: TraitBound? TraitImplements?
#[derive(Clone, PartialEq, Eq, Debug, Hash)]
pub struct TraitRef {
/// FIXME name?
pub trait_: TraitId,
pub substs: Substitution,
pub trait_id: ChalkTraitId,
pub substitution: Substitution,
}
impl TraitRef {
pub fn self_ty(&self) -> &Ty {
&self.substs[0]
pub fn self_type_parameter(&self) -> &Ty {
&self.substitution[0]
}
pub fn hir_trait_id(&self) -> TraitId {
from_chalk_trait_id(self.trait_id)
}
}
impl TypeWalk for TraitRef {
fn walk(&self, f: &mut impl FnMut(&Ty)) {
self.substs.walk(f);
self.substitution.walk(f);
}
fn walk_mut_binders(
@ -517,7 +524,7 @@ impl TypeWalk for TraitRef {
f: &mut impl FnMut(&mut Ty, DebruijnIndex),
binders: DebruijnIndex,
) {
self.substs.walk_mut_binders(f, binders);
self.substitution.walk_mut_binders(f, binders);
}
}
@ -784,7 +791,7 @@ impl Ty {
/// If this is a `dyn Trait`, returns that trait.
pub fn dyn_trait(&self) -> Option<TraitId> {
self.dyn_trait_ref().map(|it| it.trait_)
self.dyn_trait_ref().map(|it| it.trait_id).map(from_chalk_trait_id)
}
fn builtin_deref(&self) -> Option<Ty> {
@ -868,8 +875,8 @@ impl Ty {
// Parameters will be walked outside, and projection predicate is not used.
// So just provide the Future trait.
let impl_bound = GenericPredicate::Implemented(TraitRef {
trait_: future_trait,
substs: Substitution::empty(),
trait_id: to_chalk_trait_id(future_trait),
substitution: Substitution::empty(),
});
Some(vec![impl_bound])
} else {
@ -1158,3 +1165,11 @@ pub fn to_placeholder_idx(db: &dyn HirDatabase, id: TypeParamId) -> PlaceholderI
idx: salsa::InternKey::as_intern_id(&interned_id).as_usize(),
}
}
pub fn to_chalk_trait_id(id: TraitId) -> ChalkTraitId {
chalk_ir::TraitId(salsa::InternKey::as_intern_id(&id))
}
pub fn from_chalk_trait_id(id: ChalkTraitId) -> TraitId {
salsa::InternKey::from_intern_id(id.0)
}

View file

@ -27,7 +27,7 @@ use stdx::impl_from;
use crate::{
db::HirDatabase,
to_assoc_type_id, to_placeholder_idx,
to_assoc_type_id, to_chalk_trait_id, to_placeholder_idx,
traits::chalk::{Interner, ToChalk},
utils::{
all_super_trait_refs, associated_type_by_name_including_super_traits, generics,
@ -360,7 +360,7 @@ impl<'a> TyLoweringContext<'a> {
// FIXME handle type parameters on the segment
TyKind::Alias(AliasTy::Projection(ProjectionTy {
associated_ty_id: to_assoc_type_id(associated_ty),
substitution: super_trait_ref.substs,
substitution: super_trait_ref.substitution,
}))
.intern(&Interner)
}
@ -470,9 +470,9 @@ impl<'a> TyLoweringContext<'a> {
"there should be generics if there's a generic param",
),
);
t.substs.clone().subst_bound_vars(&s)
t.substitution.clone().subst_bound_vars(&s)
}
TypeParamLoweringMode::Variable => t.substs.clone(),
TypeParamLoweringMode::Variable => t.substitution.clone(),
};
// We need to shift in the bound vars, since
// associated_type_shorthand_candidates does not do that
@ -641,7 +641,7 @@ impl<'a> TyLoweringContext<'a> {
if let Some(self_ty) = explicit_self_ty {
substs.0[0] = self_ty;
}
TraitRef { trait_: resolved, substs }
TraitRef { trait_id: to_chalk_trait_id(resolved), substitution: substs }
}
fn lower_trait_ref(
@ -743,7 +743,7 @@ impl<'a> TyLoweringContext<'a> {
};
let projection_ty = ProjectionTy {
associated_ty_id: to_assoc_type_id(associated_ty),
substitution: super_trait_ref.substs,
substitution: super_trait_ref.substitution,
};
let mut preds = SmallVec::with_capacity(
binding.type_ref.as_ref().map_or(0, |_| 1) + binding.bounds.len(),
@ -820,8 +820,8 @@ pub fn associated_type_shorthand_candidates<R>(
== TypeParamProvenance::TraitSelf
{
let trait_ref = TraitRef {
trait_: trait_id,
substs: Substitution::bound_vars(&generics, DebruijnIndex::INNERMOST),
trait_id: to_chalk_trait_id(trait_id),
substitution: Substitution::bound_vars(&generics, DebruijnIndex::INNERMOST),
};
traits_.push(trait_ref);
}
@ -832,7 +832,7 @@ pub fn associated_type_shorthand_candidates<R>(
};
for t in traits_from_env.into_iter().flat_map(move |t| all_super_trait_refs(db, t)) {
let data = db.trait_data(t.trait_);
let data = db.trait_data(t.hir_trait_id());
for (name, assoc_id) in &data.items {
match assoc_id {
@ -926,7 +926,7 @@ pub(crate) fn trait_environment_query(
continue;
}
if let GenericPredicate::Implemented(tr) = &pred {
traits_in_scope.push((tr.self_ty().clone(), tr.trait_));
traits_in_scope.push((tr.self_type_parameter().clone(), tr.hir_trait_id()));
}
let program_clause: chalk_ir::ProgramClause<Interner> =
pred.clone().to_chalk(db).cast(&Interner);
@ -950,7 +950,7 @@ pub(crate) fn trait_environment_query(
// inside consts or type aliases)
cov_mark::hit!(trait_self_implements_self);
let substs = Substitution::type_params(db, trait_id);
let trait_ref = TraitRef { trait_: trait_id, substs };
let trait_ref = TraitRef { trait_id: to_chalk_trait_id(trait_id), substitution: substs };
let pred = GenericPredicate::Implemented(trait_ref);
let program_clause: chalk_ir::ProgramClause<Interner> =
pred.clone().to_chalk(db).cast(&Interner);

View file

@ -19,6 +19,7 @@ use crate::{
db::HirDatabase,
from_foreign_def_id,
primitive::{self, FloatTy, IntTy, UintTy},
to_chalk_trait_id,
utils::all_super_traits,
AdtId, Canonical, DebruijnIndex, FnPointer, FnSig, ForeignDefId, InEnvironment, Interner,
Scalar, Substitution, TraitEnvironment, TraitRef, Ty, TyKind, TypeWalk,
@ -101,7 +102,7 @@ impl TraitImpls {
for (_module_id, module_data) in crate_def_map.modules() {
for impl_id in module_data.scope.impls() {
let target_trait = match db.impl_trait(impl_id) {
Some(tr) => tr.value.trait_,
Some(tr) => tr.value.hir_trait_id(),
None => continue,
};
let self_ty = db.impl_self_ty(impl_id);
@ -773,7 +774,7 @@ fn generic_implements_goal(
.fill_with_bound_vars(DebruijnIndex::INNERMOST, kinds.len())
.build();
kinds.extend(iter::repeat(chalk_ir::TyVariableKind::General).take(substs.len() - 1));
let trait_ref = TraitRef { trait_, substs };
let trait_ref = TraitRef { trait_id: to_chalk_trait_id(trait_), substitution: substs };
let obligation = super::Obligation::Trait(trait_ref);
Canonical { kinds: kinds.into(), value: InEnvironment::new(env, obligation) }
}

View file

@ -137,7 +137,7 @@ pub(crate) fn trait_solve_query(
goal: Canonical<InEnvironment<Obligation>>,
) -> Option<Solution> {
let _p = profile::span("trait_solve_query").detail(|| match &goal.value.value {
Obligation::Trait(it) => db.trait_data(it.trait_).name.to_string(),
Obligation::Trait(it) => db.trait_data(it.hir_trait_id()).name.to_string(),
Obligation::Projection(_) => "projection".to_string(),
});
log::info!("trait_solve_query({})", goal.value.value.display(db));

View file

@ -19,7 +19,7 @@ use crate::{
display::HirDisplay,
from_assoc_type_id,
method_resolution::{TyFingerprint, ALL_FLOAT_FPS, ALL_INT_FPS},
to_assoc_type_id,
to_assoc_type_id, to_chalk_trait_id,
utils::generics,
BoundVar, CallableDefId, CallableSig, DebruijnIndex, FnDefId, GenericPredicate,
ProjectionPredicate, ProjectionTy, Substitution, TraitRef, Ty, TyKind,
@ -219,9 +219,9 @@ impl<'a> chalk_solve::RustIrDatabase<Interner> for ChalkContext<'a> {
// for<T> <Self> [Future<Self>, Future::Output<Self> = T]
// ^1 ^0 ^0 ^0 ^1
let impl_bound = GenericPredicate::Implemented(TraitRef {
trait_: future_trait,
trait_id: to_chalk_trait_id(future_trait),
// Self type as the first parameter.
substs: Substitution::single(
substitution: Substitution::single(
TyKind::BoundVar(BoundVar {
debruijn: DebruijnIndex::INNERMOST,
index: 0,
@ -546,7 +546,7 @@ fn impl_def_datum(
let generic_params = generics(db.upcast(), impl_id.into());
let bound_vars = Substitution::bound_vars(&generic_params, DebruijnIndex::INNERMOST);
let trait_ = trait_ref.trait_;
let trait_ = trait_ref.hir_trait_id();
let impl_type = if impl_id.lookup(db.upcast()).container.krate() == krate {
rust_ir::ImplType::Local
} else {
@ -614,7 +614,7 @@ fn type_alias_associated_ty_value(
let trait_ref = db.impl_trait(impl_id).expect("assoc ty value should not exist").value; // we don't return any assoc ty values if the impl'd trait can't be resolved
let assoc_ty = db
.trait_data(trait_ref.trait_)
.trait_data(trait_ref.hir_trait_id())
.associated_type_by_name(&type_alias_data.name)
.expect("assoc ty value should not exist"); // validated when building the impl data as well
let ty = db.ty(type_alias.into());

View file

@ -239,15 +239,15 @@ impl ToChalk for TraitRef {
type Chalk = chalk_ir::TraitRef<Interner>;
fn to_chalk(self: TraitRef, db: &dyn HirDatabase) -> chalk_ir::TraitRef<Interner> {
let trait_id = self.trait_.to_chalk(db);
let substitution = self.substs.to_chalk(db);
let trait_id = self.trait_id;
let substitution = self.substitution.to_chalk(db);
chalk_ir::TraitRef { trait_id, substitution }
}
fn from_chalk(db: &dyn HirDatabase, trait_ref: chalk_ir::TraitRef<Interner>) -> Self {
let trait_ = from_chalk(db, trait_ref.trait_id);
let trait_id = trait_ref.trait_id;
let substs = from_chalk(db, trait_ref.substitution);
TraitRef { trait_, substs }
TraitRef { trait_id, substitution: substs }
}
}
@ -515,17 +515,16 @@ pub(super) fn generic_predicate_to_inline_bound(
// We don't have a special type for this, but Chalk does.
match pred {
GenericPredicate::Implemented(trait_ref) => {
if &trait_ref.substs[0] != self_ty {
if &trait_ref.substitution[0] != self_ty {
// we can only convert predicates back to type bounds if they
// have the expected self type
return None;
}
let args_no_self = trait_ref.substs[1..]
let args_no_self = trait_ref.substitution[1..]
.iter()
.map(|ty| ty.clone().to_chalk(db).cast(&Interner))
.collect();
let trait_bound =
rust_ir::TraitBound { trait_id: trait_ref.trait_.to_chalk(db), args_no_self };
let trait_bound = rust_ir::TraitBound { trait_id: trait_ref.trait_id, args_no_self };
Some(rust_ir::InlineBound::TraitBound(trait_bound))
}
GenericPredicate::Projection(proj) => {

View file

@ -55,9 +55,9 @@ fn direct_super_trait_refs(db: &dyn HirDatabase, trait_ref: &TraitRef) -> Vec<Tr
// lifetime problems, but since there usually shouldn't be more than a
// few direct traits this should be fine (we could even use some kind of
// SmallVec if performance is a concern)
let generic_params = db.generic_params(trait_ref.trait_.into());
let generic_params = db.generic_params(trait_ref.hir_trait_id().into());
let trait_self = match generic_params.find_trait_self_param() {
Some(p) => TypeParamId { parent: trait_ref.trait_.into(), local_id: p },
Some(p) => TypeParamId { parent: trait_ref.hir_trait_id().into(), local_id: p },
None => return Vec::new(),
};
db.generic_predicates_for_param(trait_self)
@ -68,7 +68,7 @@ fn direct_super_trait_refs(db: &dyn HirDatabase, trait_ref: &TraitRef) -> Vec<Tr
_ => None,
})
})
.map(|pred| pred.subst(&trait_ref.substs))
.map(|pred| pred.subst(&trait_ref.substitution))
.collect()
}
@ -108,7 +108,7 @@ pub(super) fn all_super_trait_refs(db: &dyn HirDatabase, trait_ref: TraitRef) ->
// yeah this is quadratic, but trait hierarchies should be flat
// enough that this doesn't matter
for tt in direct_super_trait_refs(db, t) {
if !result.iter().any(|tr| tr.trait_ == tt.trait_) {
if !result.iter().any(|tr| tr.trait_id == tt.trait_id) {
result.push(tt);
}
}
@ -123,7 +123,7 @@ pub(super) fn associated_type_by_name_including_super_traits(
name: &Name,
) -> Option<(TraitRef, TypeAliasId)> {
all_super_trait_refs(db, trait_ref).into_iter().find_map(|t| {
let assoc_type = db.trait_data(t.trait_).associated_type_by_name(name)?;
let assoc_type = db.trait_data(t.hir_trait_id()).associated_type_by_name(name)?;
Some((t, assoc_type))
})
}