fix: Properly lower SelfOnly predicates

This commit is contained in:
Shoyu Vanilla 2026-01-04 19:10:10 +09:00
parent 978d75e373
commit dc64aef1ed
5 changed files with 373 additions and 112 deletions

View file

@ -77,6 +77,7 @@ pub struct ImplTraits {
#[derive(PartialEq, Eq, Debug, Hash)]
pub struct ImplTrait {
pub(crate) predicates: StoredClauses,
pub(crate) assoc_ty_bounds_start: u32,
}
pub type ImplTraitIdx = Idx<ImplTrait>;
@ -166,6 +167,12 @@ impl<'db> LifetimeElisionKind<'db> {
}
}
#[derive(Clone, Copy, PartialEq, Debug)]
pub(crate) enum GenericPredicateSource {
SelfOnly,
AssocTyBound,
}
#[derive(Debug)]
pub struct TyLoweringContext<'db, 'a> {
pub db: &'db dyn HirDatabase,
@ -465,10 +472,10 @@ impl<'db, 'a> TyLoweringContext<'db, 'a> {
// this dance is to make sure the data is in the right
// place even if we encounter more opaque types while
// lowering the bounds
let idx = self
.impl_trait_mode
.opaque_type_data
.alloc(ImplTrait { predicates: Clauses::empty(interner).store() });
let idx = self.impl_trait_mode.opaque_type_data.alloc(ImplTrait {
predicates: Clauses::empty(interner).store(),
assoc_ty_bounds_start: 0,
});
let impl_trait_id = origin.either(
|f| ImplTraitId::ReturnTypeImplTrait(f, idx),
@ -608,7 +615,7 @@ impl<'db, 'a> TyLoweringContext<'db, 'a> {
ignore_bindings: bool,
generics: &Generics,
predicate_filter: PredicateFilter,
) -> impl Iterator<Item = Clause<'db>> + use<'a, 'b, 'db> {
) -> impl Iterator<Item = (Clause<'db>, GenericPredicateSource)> + use<'a, 'b, 'db> {
match where_predicate {
WherePredicate::ForLifetime { target, bound, .. }
| WherePredicate::TypeBound { target, bound } => {
@ -634,8 +641,8 @@ impl<'db, 'a> TyLoweringContext<'db, 'a> {
let self_ty = self.lower_ty(*target);
Either::Left(Either::Right(self.lower_type_bound(bound, self_ty, ignore_bindings)))
}
&WherePredicate::Lifetime { bound, target } => {
Either::Right(iter::once(Clause(Predicate::new(
&WherePredicate::Lifetime { bound, target } => Either::Right(iter::once((
Clause(Predicate::new(
self.interner,
Binder::dummy(rustc_type_ir::PredicateKind::Clause(
rustc_type_ir::ClauseKind::RegionOutlives(OutlivesPredicate(
@ -643,8 +650,9 @@ impl<'db, 'a> TyLoweringContext<'db, 'a> {
self.lower_lifetime(target),
)),
)),
))))
}
)),
GenericPredicateSource::SelfOnly,
))),
}
.into_iter()
}
@ -654,7 +662,7 @@ impl<'db, 'a> TyLoweringContext<'db, 'a> {
bound: &'b TypeBound,
self_ty: Ty<'db>,
ignore_bindings: bool,
) -> impl Iterator<Item = Clause<'db>> + use<'b, 'a, 'db> {
) -> impl Iterator<Item = (Clause<'db>, GenericPredicateSource)> + use<'b, 'a, 'db> {
let interner = self.interner;
let meta_sized = self.lang_items.MetaSized;
let pointee_sized = self.lang_items.PointeeSized;
@ -712,7 +720,10 @@ impl<'db, 'a> TyLoweringContext<'db, 'a> {
}
TypeBound::Use(_) | TypeBound::Error => {}
}
clause.into_iter().chain(assoc_bounds.into_iter().flatten())
clause
.into_iter()
.map(|pred| (pred, GenericPredicateSource::SelfOnly))
.chain(assoc_bounds.into_iter().flatten())
}
fn lower_dyn_trait(&mut self, bounds: &[TypeBound]) -> Ty<'db> {
@ -732,7 +743,7 @@ impl<'db, 'a> TyLoweringContext<'db, 'a> {
for b in bounds {
let db = ctx.db;
ctx.lower_type_bound(b, dummy_self_ty, false).for_each(|b| {
ctx.lower_type_bound(b, dummy_self_ty, false).for_each(|(b, _)| {
match b.kind().skip_binder() {
rustc_type_ir::ClauseKind::Trait(t) => {
let id = t.def_id();
@ -990,35 +1001,49 @@ impl<'db, 'a> TyLoweringContext<'db, 'a> {
rustc_type_ir::AliasTyKind::Opaque,
AliasTy::new_from_args(interner, def_id, args),
);
let predicates = self.with_shifted_in(DebruijnIndex::from_u32(1), |ctx| {
let mut predicates = Vec::new();
for b in bounds {
predicates.extend(ctx.lower_type_bound(b, self_ty, false));
}
let (predicates, assoc_ty_bounds_start) =
self.with_shifted_in(DebruijnIndex::from_u32(1), |ctx| {
let mut predicates = Vec::new();
let mut assoc_ty_bounds = Vec::new();
for b in bounds {
for (pred, source) in ctx.lower_type_bound(b, self_ty, false) {
match source {
GenericPredicateSource::SelfOnly => predicates.push(pred),
GenericPredicateSource::AssocTyBound => assoc_ty_bounds.push(pred),
}
}
}
if !ctx.unsized_types.contains(&self_ty) {
let sized_trait = self.lang_items.Sized;
let sized_clause = sized_trait.map(|trait_id| {
let trait_ref = TraitRef::new_from_args(
interner,
trait_id.into(),
GenericArgs::new_from_slice(&[self_ty.into()]),
);
Clause(Predicate::new(
interner,
Binder::dummy(rustc_type_ir::PredicateKind::Clause(
rustc_type_ir::ClauseKind::Trait(TraitPredicate {
trait_ref,
polarity: rustc_type_ir::PredicatePolarity::Positive,
}),
)),
))
});
predicates.extend(sized_clause);
}
predicates
});
ImplTrait { predicates: Clauses::new_from_slice(&predicates).store() }
if !ctx.unsized_types.contains(&self_ty) {
let sized_trait = self.lang_items.Sized;
let sized_clause = sized_trait.map(|trait_id| {
let trait_ref = TraitRef::new_from_args(
interner,
trait_id.into(),
GenericArgs::new_from_slice(&[self_ty.into()]),
);
Clause(Predicate::new(
interner,
Binder::dummy(rustc_type_ir::PredicateKind::Clause(
rustc_type_ir::ClauseKind::Trait(TraitPredicate {
trait_ref,
polarity: rustc_type_ir::PredicatePolarity::Positive,
}),
)),
))
});
predicates.extend(sized_clause);
}
let assoc_ty_bounds_start = predicates.len() as u32;
predicates.extend(assoc_ty_bounds);
(predicates, assoc_ty_bounds_start)
});
ImplTrait {
predicates: Clauses::new_from_slice(&predicates).store(),
assoc_ty_bounds_start,
}
}
pub(crate) fn lower_lifetime(&mut self, lifetime: LifetimeRefId) -> Region<'db> {
@ -1139,6 +1164,31 @@ impl ImplTraitId {
.expect("owner should have opaque type")
.get_with(|it| it.impl_traits[idx].predicates.as_ref().as_slice())
}
#[inline]
pub fn self_predicates<'db>(
self,
db: &'db dyn HirDatabase,
) -> EarlyBinder<'db, &'db [Clause<'db>]> {
let (impl_traits, idx) = match self {
ImplTraitId::ReturnTypeImplTrait(owner, idx) => {
(ImplTraits::return_type_impl_traits(db, owner), idx)
}
ImplTraitId::TypeAliasImplTrait(owner, idx) => {
(ImplTraits::type_alias_impl_traits(db, owner), idx)
}
};
let predicates =
impl_traits.as_deref().expect("owner should have opaque type").get_with(|it| {
let impl_trait = &it.impl_traits[idx];
(
impl_trait.predicates.as_ref().as_slice(),
impl_trait.assoc_ty_bounds_start as usize,
)
});
predicates.map_bound(|(preds, len)| &preds[..len])
}
}
impl InternedOpaqueTyId {
@ -1146,6 +1196,14 @@ impl InternedOpaqueTyId {
pub fn predicates<'db>(self, db: &'db dyn HirDatabase) -> EarlyBinder<'db, &'db [Clause<'db>]> {
self.loc(db).predicates(db)
}
#[inline]
pub fn self_predicates<'db>(
self,
db: &'db dyn HirDatabase,
) -> EarlyBinder<'db, &'db [Clause<'db>]> {
self.loc(db).self_predicates(db)
}
}
#[salsa::tracked]
@ -1655,12 +1713,15 @@ pub(crate) fn generic_predicates_for_param<'db>(
ctx.store = maybe_parent_generics.store();
for pred in maybe_parent_generics.where_predicates() {
if predicate(pred, &mut ctx) {
predicates.extend(ctx.lower_where_predicate(
pred,
true,
maybe_parent_generics,
PredicateFilter::All,
));
predicates.extend(
ctx.lower_where_predicate(
pred,
true,
maybe_parent_generics,
PredicateFilter::All,
)
.map(|(pred, _)| pred),
);
}
}
}
@ -1696,21 +1757,44 @@ pub(crate) fn type_alias_bounds<'db>(
db: &'db dyn HirDatabase,
type_alias: TypeAliasId,
) -> EarlyBinder<'db, &'db [Clause<'db>]> {
type_alias_bounds_with_diagnostics(db, type_alias).0.map_bound(|it| it.as_slice())
type_alias_bounds_with_diagnostics(db, type_alias).0.predicates.map_bound(|it| it.as_slice())
}
pub(crate) fn type_alias_bounds_with_diagnostics<'db>(
#[inline]
pub(crate) fn type_alias_self_bounds<'db>(
db: &'db dyn HirDatabase,
type_alias: TypeAliasId,
) -> (EarlyBinder<'db, Clauses<'db>>, Diagnostics) {
let (bounds, diags) = type_alias_bounds_with_diagnostics_query(db, type_alias);
return (bounds.get(), diags.clone());
) -> EarlyBinder<'db, &'db [Clause<'db>]> {
let (TypeAliasBounds { predicates, assoc_ty_bounds_start }, _) =
type_alias_bounds_with_diagnostics(db, type_alias);
predicates.map_bound(|it| &it.as_slice()[..assoc_ty_bounds_start as usize])
}
#[derive(PartialEq, Eq, Debug, Hash)]
struct TypeAliasBounds<T> {
predicates: T,
assoc_ty_bounds_start: u32,
}
fn type_alias_bounds_with_diagnostics<'db>(
db: &'db dyn HirDatabase,
type_alias: TypeAliasId,
) -> (TypeAliasBounds<EarlyBinder<'db, Clauses<'db>>>, Diagnostics) {
let (TypeAliasBounds { predicates, assoc_ty_bounds_start }, diags) =
type_alias_bounds_with_diagnostics_query(db, type_alias);
return (
TypeAliasBounds {
predicates: predicates.get(),
assoc_ty_bounds_start: *assoc_ty_bounds_start,
},
diags.clone(),
);
#[salsa::tracked(returns(ref))]
pub fn type_alias_bounds_with_diagnostics_query<'db>(
db: &'db dyn HirDatabase,
type_alias: TypeAliasId,
) -> (StoredEarlyBinder<StoredClauses>, Diagnostics) {
) -> (TypeAliasBounds<StoredEarlyBinder<StoredClauses>>, Diagnostics) {
let type_alias_data = db.type_alias_signature(type_alias);
let resolver = hir_def::resolver::HasResolver::resolver(type_alias, db);
let mut ctx = TyLoweringContext::new(
@ -1727,10 +1811,18 @@ pub(crate) fn type_alias_bounds_with_diagnostics<'db>(
let interner_ty = Ty::new_projection_from_args(interner, def_id, item_args);
let mut bounds = Vec::new();
let mut assoc_ty_bounds = Vec::new();
for bound in &type_alias_data.bounds {
ctx.lower_type_bound(bound, interner_ty, false).for_each(|pred| {
bounds.push(pred);
});
ctx.lower_type_bound(bound, interner_ty, false).for_each(
|(pred, source)| match source {
GenericPredicateSource::SelfOnly => {
bounds.push(pred);
}
GenericPredicateSource::AssocTyBound => {
assoc_ty_bounds.push(pred);
}
},
);
}
if !ctx.unsized_types.contains(&interner_ty) {
@ -1745,8 +1837,14 @@ pub(crate) fn type_alias_bounds_with_diagnostics<'db>(
};
}
let assoc_ty_bounds_start = bounds.len() as u32;
bounds.extend(assoc_ty_bounds);
(
StoredEarlyBinder::bind(Clauses::new_from_slice(&bounds).store()),
TypeAliasBounds {
predicates: StoredEarlyBinder::bind(Clauses::new_from_slice(&bounds).store()),
assoc_ty_bounds_start,
},
create_diagnostics(ctx.diagnostics),
)
}
@ -1754,11 +1852,15 @@ pub(crate) fn type_alias_bounds_with_diagnostics<'db>(
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct GenericPredicates {
// The order is the following: first, if `parent_is_trait == true`, comes the implicit trait predicate for the
// parent. Then come the explicit predicates for the parent, then the explicit trait predicate for the child,
// The order is the following: first, if `parent_is_trait == true`, comes the implicit trait
// predicate for the parent. Then come the bounds of the associated types of the parents,
// then the explicit, self-only predicates for the parent, then the explicit, self-only trait
// predicate for the child, then the bounds of the associated types of the child,
// then the implicit trait predicate for the child, if `is_trait` is `true`.
predicates: StoredEarlyBinder<StoredClauses>,
parent_explicit_self_predicates_start: u32,
own_predicates_start: u32,
own_assoc_ty_bounds_start: u32,
is_trait: bool,
parent_is_trait: bool,
}
@ -1782,7 +1884,15 @@ impl GenericPredicates {
pub(crate) fn from_explicit_own_predicates(
predicates: StoredEarlyBinder<StoredClauses>,
) -> Self {
Self { predicates, own_predicates_start: 0, is_trait: false, parent_is_trait: false }
let len = predicates.get().skip_binder().len() as u32;
Self {
predicates,
parent_explicit_self_predicates_start: 0,
own_predicates_start: 0,
own_assoc_ty_bounds_start: len,
is_trait: false,
parent_is_trait: false,
}
}
#[inline]
@ -1814,6 +1924,14 @@ impl GenericPredicates {
Self::query(db, def).explicit_predicates()
}
#[inline]
pub fn query_explicit_implied<'db>(
db: &'db dyn HirDatabase,
def: GenericDefId,
) -> EarlyBinder<'db, &'db [Clause<'db>]> {
Self::query(db, def).explicit_implied_predicates()
}
#[inline]
pub fn all_predicates(&self) -> EarlyBinder<'_, &[Clause<'_>]> {
self.predicates.get().map_bound(|it| it.as_slice())
@ -1824,9 +1942,18 @@ impl GenericPredicates {
self.predicates.get().map_bound(|it| &it.as_slice()[self.own_predicates_start as usize..])
}
/// Returns the predicates, minus the implicit `Self: Trait` predicate for a trait.
/// Returns the predicates, minus the implicit `Self: Trait` predicate and bounds of the
/// associated types for a trait.
#[inline]
pub fn explicit_predicates(&self) -> EarlyBinder<'_, &[Clause<'_>]> {
self.predicates.get().map_bound(|it| {
&it.as_slice()[self.parent_explicit_self_predicates_start as usize
..self.own_assoc_ty_bounds_start as usize]
})
}
#[inline]
pub fn explicit_implied_predicates(&self) -> EarlyBinder<'_, &[Clause<'_>]> {
self.predicates.get().map_bound(|it| {
&it.as_slice()[usize::from(self.parent_is_trait)..it.len() - usize::from(self.is_trait)]
})
@ -1902,26 +2029,22 @@ where
);
let sized_trait = ctx.lang_items.Sized;
let mut predicates = Vec::new();
// We need to lower parents and self separately - see the comment below lowering of implicit
// `Sized` predicates for why.
let mut own_predicates = Vec::new();
let mut parent_predicates = Vec::new();
let mut own_assoc_ty_bounds = Vec::new();
let mut parent_assoc_ty_bounds = Vec::new();
let all_generics =
std::iter::successors(Some(&generics), |generics| generics.parent_generics())
.collect::<ArrayVec<_, 2>>();
let mut is_trait = false;
let mut parent_is_trait = false;
if all_generics.len() > 1 {
add_implicit_trait_predicate(
interner,
all_generics.last().unwrap().def(),
predicate_filter,
&mut predicates,
&mut parent_is_trait,
);
}
// We need to lower parent predicates first - see the comment below lowering of implicit `Sized` predicates
// for why.
let mut own_predicates_start = 0;
let own_implicit_trait_predicate = implicit_trait_predicate(interner, def, predicate_filter);
let parent_implicit_trait_predicate = if all_generics.len() > 1 {
implicit_trait_predicate(interner, all_generics.last().unwrap().def(), predicate_filter)
} else {
None
};
for &maybe_parent_generics in all_generics.iter().rev() {
let current_def_predicates_start = predicates.len();
// Collect only diagnostics from the child, not including parents.
ctx.diagnostics.clear();
@ -1929,15 +2052,37 @@ where
ctx.store = maybe_parent_generics.store();
for pred in maybe_parent_generics.where_predicates() {
tracing::debug!(?pred);
predicates.extend(ctx.lower_where_predicate(
pred,
false,
maybe_parent_generics,
predicate_filter,
));
for (pred, source) in
ctx.lower_where_predicate(pred, false, maybe_parent_generics, predicate_filter)
{
match source {
GenericPredicateSource::SelfOnly => {
if maybe_parent_generics.def() == def {
own_predicates.push(pred);
} else {
parent_predicates.push(pred);
}
}
GenericPredicateSource::AssocTyBound => {
if maybe_parent_generics.def() == def {
own_assoc_ty_bounds.push(pred);
} else {
parent_assoc_ty_bounds.push(pred);
}
}
}
}
}
push_const_arg_has_type_predicates(db, &mut predicates, maybe_parent_generics);
if maybe_parent_generics.def() == def {
push_const_arg_has_type_predicates(db, &mut own_predicates, maybe_parent_generics);
} else {
push_const_arg_has_type_predicates(
db,
&mut parent_predicates,
maybe_parent_generics,
);
}
if let Some(sized_trait) = sized_trait {
let mut add_sized_clause = |param_idx, param_id, param_data| {
@ -1971,7 +2116,11 @@ where
}),
)),
));
predicates.push(clause);
if maybe_parent_generics.def() == def {
own_predicates.push(clause);
} else {
parent_predicates.push(clause);
}
};
let parent_params_len = maybe_parent_generics.len_parent();
maybe_parent_generics.iter_self().enumerate().for_each(
@ -1990,30 +2139,55 @@ where
// predicates before lowering the child, as a child cannot define a `?Sized` predicate for its parent.
// But we do have to lower the parent first.
}
if maybe_parent_generics.def() == def {
own_predicates_start = current_def_predicates_start as u32;
}
}
add_implicit_trait_predicate(interner, def, predicate_filter, &mut predicates, &mut is_trait);
let diagnostics = create_diagnostics(ctx.diagnostics);
// The order is:
//
// 1. parent implicit trait pred
// 2. parent assoc bounds
// 3. parent self only preds
// 4. own self only preds
// 5. own assoc ty bounds
// 6. own implicit trait pred
//
// The purpose of this is to index the slice of the followings, without making extra `Vec`s or
// iterators:
// - explicit self only predicates, of own or own + self
// - explicit predicates, of own or own + self
let predicates = parent_implicit_trait_predicate
.iter()
.chain(parent_assoc_ty_bounds.iter())
.chain(parent_predicates.iter())
.chain(own_predicates.iter())
.chain(own_assoc_ty_bounds.iter())
.chain(own_implicit_trait_predicate.iter())
.copied()
.collect::<Vec<_>>();
let parent_is_trait = parent_implicit_trait_predicate.is_some();
let is_trait = own_implicit_trait_predicate.is_some();
let parent_explicit_self_predicates_start =
parent_is_trait as u32 + parent_assoc_ty_bounds.len() as u32;
let own_predicates_start =
parent_explicit_self_predicates_start + parent_predicates.len() as u32;
let own_assoc_ty_bounds_start = own_predicates_start + own_predicates.len() as u32;
let predicates = GenericPredicates {
parent_explicit_self_predicates_start,
own_predicates_start,
own_assoc_ty_bounds_start,
is_trait,
parent_is_trait,
predicates: StoredEarlyBinder::bind(Clauses::new_from_slice(&predicates).store()),
};
return (predicates, diagnostics);
fn add_implicit_trait_predicate<'db>(
fn implicit_trait_predicate<'db>(
interner: DbInterner<'db>,
def: GenericDefId,
predicate_filter: PredicateFilter,
predicates: &mut Vec<Clause<'db>>,
set_is_trait: &mut bool,
) {
) -> Option<Clause<'db>> {
// For traits, add `Self: Trait` predicate. This is
// not part of the predicates that a user writes, but it
// is something that one must prove in order to invoke a
@ -2029,8 +2203,9 @@ where
if let GenericDefId::TraitId(def_id) = def
&& predicate_filter == PredicateFilter::All
{
*set_is_trait = true;
predicates.push(TraitRef::identity(interner, def_id.into()).upcast(interner));
Some(TraitRef::identity(interner, def_id.into()).upcast(interner))
} else {
None
}
}
}
@ -2327,7 +2502,7 @@ pub(crate) fn associated_ty_item_bounds<'db>(
let mut bounds = Vec::new();
for bound in &type_alias_data.bounds {
ctx.lower_type_bound(bound, self_ty, false).for_each(|pred| {
ctx.lower_type_bound(bound, self_ty, false).for_each(|(pred, _)| {
if let Some(bound) = pred
.kind()
.map_bound(|c| match c {

View file

@ -32,7 +32,8 @@ use crate::{
db::HirDatabase,
generics::{Generics, generics},
lower::{
LifetimeElisionKind, PathDiagnosticCallbackData, named_associated_type_shorthand_candidates,
GenericPredicateSource, LifetimeElisionKind, PathDiagnosticCallbackData,
named_associated_type_shorthand_candidates,
},
next_solver::{
Binder, Clause, Const, DbInterner, ErrorGuaranteed, GenericArg, GenericArgs, Predicate,
@ -853,7 +854,8 @@ impl<'a, 'b, 'db> PathLoweringContext<'a, 'b, 'db> {
pub(super) fn assoc_type_bindings_from_type_bound<'c>(
mut self,
trait_ref: TraitRef<'db>,
) -> Option<impl Iterator<Item = Clause<'db>> + use<'a, 'b, 'c, 'db>> {
) -> Option<impl Iterator<Item = (Clause<'db>, GenericPredicateSource)> + use<'a, 'b, 'c, 'db>>
{
let interner = self.ctx.interner;
self.current_or_prev_segment.args_and_bindings.map(|args_and_bindings| {
args_and_bindings.bindings.iter().enumerate().flat_map(move |(binding_idx, binding)| {
@ -921,21 +923,29 @@ impl<'a, 'b, 'db> PathLoweringContext<'a, 'b, 'db> {
),
)),
));
predicates.push(pred);
predicates.push((pred, GenericPredicateSource::SelfOnly));
}
}
})
}
for bound in binding.bounds.iter() {
predicates.extend(self.ctx.lower_type_bound(
bound,
Ty::new_alias(
self.ctx.interner,
AliasTyKind::Projection,
AliasTy::new_from_args(self.ctx.interner, associated_ty.into(), args),
),
false,
));
predicates.extend(
self.ctx
.lower_type_bound(
bound,
Ty::new_alias(
self.ctx.interner,
AliasTyKind::Projection,
AliasTy::new_from_args(
self.ctx.interner,
associated_ty.into(),
args,
),
),
false,
)
.map(|(pred, _)| (pred, GenericPredicateSource::AssocTyBound)),
);
}
predicates
})

View file

@ -41,7 +41,8 @@ use crate::{
AdtIdWrapper, AnyImplId, BoundConst, CallableIdWrapper, CanonicalVarKind, ClosureIdWrapper,
CoroutineIdWrapper, Ctor, FnSig, FxIndexMap, GeneralConstIdWrapper, OpaqueTypeKey,
RegionAssumptions, SimplifiedType, SolverContext, SolverDefIds, TraitIdWrapper,
TypeAliasIdWrapper, UnevaluatedConst, util::explicit_item_bounds,
TypeAliasIdWrapper, UnevaluatedConst,
util::{explicit_item_bounds, explicit_item_self_bounds},
},
};
@ -1421,7 +1422,7 @@ impl<'db> Interner for DbInterner<'db> {
self,
def_id: Self::DefId,
) -> EarlyBinder<Self, impl IntoIterator<Item = Self::Clause>> {
explicit_item_bounds(self, def_id)
explicit_item_self_bounds(self, def_id)
.map_bound(|bounds| elaborate(self, bounds).filter_only_self())
}
@ -1500,7 +1501,7 @@ impl<'db> Interner for DbInterner<'db> {
}
}
predicates_of(self.db, def_id).explicit_predicates().map_bound(|predicates| {
predicates_of(self.db, def_id).explicit_implied_predicates().map_bound(|predicates| {
predicates
.iter()
.copied()

View file

@ -455,6 +455,21 @@ pub fn explicit_item_bounds<'db>(
clauses.map_bound(|clauses| clauses.iter().copied())
}
pub fn explicit_item_self_bounds<'db>(
interner: DbInterner<'db>,
def_id: SolverDefId,
) -> EarlyBinder<'db, impl DoubleEndedIterator<Item = Clause<'db>> + ExactSizeIterator> {
let db = interner.db();
let clauses = match def_id {
SolverDefId::TypeAliasId(type_alias) => {
crate::lower::type_alias_self_bounds(db, type_alias)
}
SolverDefId::InternedOpaqueTyId(id) => id.self_predicates(db),
_ => panic!("Unexpected GenericDefId"),
};
clauses.map_bound(|clauses| clauses.iter().copied())
}
pub struct ContainsTypeErrors;
impl<'db> TypeVisitor<DbInterner<'db>> for ContainsTypeErrors {

View file

@ -750,3 +750,63 @@ fn main() {
"#]],
);
}
#[test]
fn regression_19339() {
check_infer(
r#"
trait Bar {
type Baz;
fn baz(&self) -> Self::Baz;
}
trait Foo {
type Bar;
fn bar(&self) -> Self::Bar;
}
trait FooFactory {
type Output: Foo<Bar: Bar<Baz = u8>>;
fn foo(&self) -> Self::Output;
fn foo_rpit(&self) -> impl Foo<Bar: Bar<Baz = u8>>;
}
fn test1(foo: impl Foo<Bar: Bar<Baz = u8>>) {
let baz = foo.bar().baz();
}
fn test2<T: FooFactory>(factory: T) {
let baz = factory.foo().bar().baz();
let baz = factory.foo_rpit().bar().baz();
}
"#,
expect![[r#"
39..43 'self': &'? Self
101..105 'self': &'? Self
198..202 'self': &'? Self
239..243 'self': &'? Self
290..293 'foo': impl Foo + ?Sized
325..359 '{ ...z(); }': ()
335..338 'baz': u8
341..344 'foo': impl Foo + ?Sized
341..350 'foo.bar()': impl Bar
341..356 'foo.bar().baz()': u8
385..392 'factory': T
397..487 '{ ...z(); }': ()
407..410 'baz': u8
413..420 'factory': T
413..426 'factory.foo()': <T as FooFactory>::Output
413..432 'factor....bar()': <<T as FooFactory>::Output as Foo>::Bar
413..438 'factor....baz()': u8
448..451 'baz': u8
454..461 'factory': T
454..472 'factor...rpit()': impl Foo + Bar<Baz = u8> + ?Sized
454..478 'factor....bar()': <impl Foo + Bar<Baz = u8> + ?Sized as Foo>::Bar
454..484 'factor....baz()': u8
"#]],
);
}