Unnamed repository; edit this file 'description' to name the repository.
Fix a cycle in bounds lowering
Those will never cease to surprise me. Basically, an associated type bound can be either `Trait<Assoc: Trait>` or `Self::Assoc: Trait`. The former is included in `explicit_implied_predicates_of()` and therefore in elaboration, but the later is not. We included both, so fix that. This does not fix the fundamental issue that cycles in elaboration can cause hangs/stack overflows, just this incorrect case. rustc deals with cycles by detecting them ahead of time (before any elaboration) and aborting with an error, I'm not sure yet how to handle them for r-a. Also refactor the code a bit (the hundredth time) in an attempt to make it clearer, and return iterators instead of slices from the functions to be more flexible.
Chayim Refael Friedman 8 weeks ago
parent f1297b2 · commit 7c4af83
-rw-r--r--crates/hir-ty/src/builtin_derive.rs15
-rw-r--r--crates/hir-ty/src/display.rs4
-rw-r--r--crates/hir-ty/src/dyn_compatibility.rs10
-rw-r--r--crates/hir-ty/src/infer/expr.rs2
-rw-r--r--crates/hir-ty/src/infer/path.rs2
-rw-r--r--crates/hir-ty/src/lower.rs103
-rw-r--r--crates/hir-ty/src/method_resolution.rs2
-rw-r--r--crates/hir-ty/src/method_resolution/confirm.rs4
-rw-r--r--crates/hir-ty/src/method_resolution/probe.rs2
-rw-r--r--crates/hir-ty/src/next_solver/interner.rs92
-rw-r--r--crates/hir-ty/src/next_solver/ty.rs2
-rw-r--r--crates/hir-ty/src/specialization.rs2
-rw-r--r--crates/hir-ty/src/tests/regression.rs15
-rw-r--r--crates/hir/src/display.rs4
-rw-r--r--crates/hir/src/lib.rs2
15 files changed, 134 insertions, 127 deletions
diff --git a/crates/hir-ty/src/builtin_derive.rs b/crates/hir-ty/src/builtin_derive.rs
index 92629b7a05..eb3922f4b6 100644
--- a/crates/hir-ty/src/builtin_derive.rs
+++ b/crates/hir-ty/src/builtin_derive.rs
@@ -174,8 +174,11 @@ pub fn predicates<'db>(db: &'db dyn HirDatabase, impl_: BuiltinDeriveImplId) ->
if matches!(loc.adt, AdtId::EnumId(_)) {
// Enums don't have extra bounds.
GenericPredicates::from_explicit_own_predicates(StoredEarlyBinder::bind(
- Clauses::new_from_slice(adt_predicates.explicit_predicates().skip_binder())
- .store(),
+ Clauses::new_from_iter(
+ interner,
+ adt_predicates.own_explicit_predicates().skip_binder(),
+ )
+ .store(),
))
} else {
simple_trait_predicates(interner, loc, generic_params, adt_predicates, trait_id)
@@ -191,7 +194,7 @@ pub fn predicates<'db>(db: &'db dyn HirDatabase, impl_: BuiltinDeriveImplId) ->
));
};
let duplicated_bounds =
- adt_predicates.explicit_predicates().iter_identity_copied().filter_map(|pred| {
+ adt_predicates.explicit_predicates().iter_identity().filter_map(|pred| {
let mentions_pointee =
pred.visit_with(&mut MentionsPointee { pointee_param_idx }).is_break();
if !mentions_pointee {
@@ -212,7 +215,7 @@ pub fn predicates<'db>(db: &'db dyn HirDatabase, impl_: BuiltinDeriveImplId) ->
interner,
adt_predicates
.explicit_predicates()
- .iter_identity_copied()
+ .iter_identity()
.chain(duplicated_bounds)
.chain(unsize_bound),
)
@@ -313,7 +316,7 @@ fn simple_trait_predicates<'db>(
interner,
adt_predicates
.explicit_predicates()
- .iter_identity_copied()
+ .iter_identity()
.chain(extra_predicates)
.chain(assoc_type_bounds),
)
@@ -440,7 +443,7 @@ mod tests {
format_to!(
predicates,
"{}\n\n",
- preds.iter().format_with("\n", |pred, formatter| formatter(&format_args!(
+ preds.format_with("\n", |pred, formatter| formatter(&format_args!(
"{pred:?}"
))),
);
diff --git a/crates/hir-ty/src/display.rs b/crates/hir-ty/src/display.rs
index d680588645..0c4e34db7d 100644
--- a/crates/hir-ty/src/display.rs
+++ b/crates/hir-ty/src/display.rs
@@ -640,7 +640,7 @@ fn write_projection<'db>(
// FIXME: We shouldn't use `param.id`, it should be removed. We should know the
// `GenericDefId` from the formatted type (store it inside the `HirFormatter`).
let bounds = GenericPredicates::query_all(f.db, param.id.parent())
- .iter_identity_copied()
+ .iter_identity()
.filter(|wc| {
let ty = match wc.kind().skip_binder() {
ClauseKind::Trait(tr) => tr.self_ty(),
@@ -1466,7 +1466,7 @@ impl<'db> HirDisplay<'db> for Ty<'db> {
}
TypeParamProvenance::ArgumentImplTrait => {
let bounds = GenericPredicates::query_all(f.db, param.id.parent())
- .iter_identity_copied()
+ .iter_identity()
.filter(|wc| match wc.kind().skip_binder() {
ClauseKind::Trait(tr) => tr.self_ty() == *self,
ClauseKind::Projection(proj) => proj.self_ty() == *self,
diff --git a/crates/hir-ty/src/dyn_compatibility.rs b/crates/hir-ty/src/dyn_compatibility.rs
index 4c300affd8..e70918f8e1 100644
--- a/crates/hir-ty/src/dyn_compatibility.rs
+++ b/crates/hir-ty/src/dyn_compatibility.rs
@@ -141,7 +141,7 @@ pub fn generics_require_sized_self(db: &dyn HirDatabase, def: GenericDefId) -> b
// FIXME: We should use `explicit_predicates_of` here, which hasn't been implemented to
// rust-analyzer yet
// https://github.com/rust-lang/rust/blob/ddaf12390d3ffb7d5ba74491a48f3cd528e5d777/compiler/rustc_hir_analysis/src/collect/predicates_of.rs#L490
- elaborate::elaborate(interner, predicates.iter_identity_copied()).any(|pred| {
+ elaborate::elaborate(interner, predicates.iter_identity()).any(|pred| {
match pred.kind().skip_binder() {
ClauseKind::Trait(trait_pred) => {
if sized == trait_pred.def_id().0
@@ -164,7 +164,7 @@ pub fn generics_require_sized_self(db: &dyn HirDatabase, def: GenericDefId) -> b
// So, just return single boolean value for existence of such `Self` reference
fn predicates_reference_self(db: &dyn HirDatabase, trait_: TraitId) -> bool {
GenericPredicates::query_explicit(db, trait_.into())
- .iter_identity_copied()
+ .iter_identity()
.any(|pred| predicate_references_self(db, trait_, pred, AllowSelfProjection::No))
}
@@ -360,8 +360,8 @@ where
cb(MethodViolationCode::UndispatchableReceiver)?;
}
- let predicates = GenericPredicates::query_own(db, func.into());
- for pred in predicates.iter_identity_copied() {
+ let predicates = GenericPredicates::query_own_explicit(db, func.into());
+ for pred in predicates.iter_identity() {
let pred = pred.kind().skip_binder();
if matches!(pred, ClauseKind::TypeOutlives(_)) {
@@ -459,7 +459,7 @@ fn receiver_is_dispatchable<'db>(
clauses: Clauses::new_from_iter(
interner,
generic_predicates
- .iter_identity_copied()
+ .iter_identity()
.chain([unsize_predicate.upcast(interner), trait_predicate.upcast(interner)])
.chain(meta_sized_predicate),
),
diff --git a/crates/hir-ty/src/infer/expr.rs b/crates/hir-ty/src/infer/expr.rs
index dc57b1d1c2..ee34a30eba 100644
--- a/crates/hir-ty/src/infer/expr.rs
+++ b/crates/hir-ty/src/infer/expr.rs
@@ -2158,7 +2158,7 @@ impl<'db> InferenceContext<'_, 'db> {
);
let param_env = self.table.param_env;
self.table.register_predicates(clauses_as_obligations(
- generic_predicates.iter_instantiated_copied(self.interner(), parameters.as_slice()),
+ generic_predicates.iter_instantiated(self.interner(), parameters.as_slice()),
ObligationCause::new(),
param_env,
));
diff --git a/crates/hir-ty/src/infer/path.rs b/crates/hir-ty/src/infer/path.rs
index 71d68ccd47..3cadc8e933 100644
--- a/crates/hir-ty/src/infer/path.rs
+++ b/crates/hir-ty/src/infer/path.rs
@@ -228,7 +228,7 @@ impl<'db> InferenceContext<'_, 'db> {
let predicates = GenericPredicates::query_all(self.db, def);
let param_env = self.table.param_env;
self.table.register_predicates(clauses_as_obligations(
- predicates.iter_instantiated_copied(interner, subst.as_slice()),
+ predicates.iter_instantiated(interner, subst.as_slice()),
ObligationCause::new(),
param_env,
));
diff --git a/crates/hir-ty/src/lower.rs b/crates/hir-ty/src/lower.rs
index 7259099107..71a7db6559 100644
--- a/crates/hir-ty/src/lower.rs
+++ b/crates/hir-ty/src/lower.rs
@@ -2016,17 +2016,21 @@ 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 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`.
+ // The order is the following:
+ //
+ // 1. If `has_trait_implied_predicate == true`, the implicit trait predicate.
+ // 2. The bounds of the associated types of the parents, coming from `Trait<Assoc: Trait>`.
+ // Note: associated type bounds from `Self::Assoc: Trait` on traits *won't* be included
+ // here, they are in 3.
+ // 3. The explicit, self-only predicates for the parent.
+ // 4. The explicit, self-only trait predicate for the child,
+ // 5. The bounds of the associated types of the child.
predicates: StoredEarlyBinder<StoredClauses>,
+ // Keep this ordered according to the above.
+ has_trait_implied_predicate: bool,
parent_explicit_self_predicates_start: u32,
own_predicates_start: u32,
own_assoc_ty_bounds_start: u32,
- is_trait: bool,
- parent_is_trait: bool,
}
#[salsa::tracked]
@@ -2065,11 +2069,10 @@ impl GenericPredicates {
let len = predicates.get().skip_binder().len() as u32;
Self {
predicates,
+ has_trait_implied_predicate: false,
parent_explicit_self_predicates_start: 0,
own_predicates_start: 0,
own_assoc_ty_bounds_start: len,
- is_trait: false,
- parent_is_trait: false,
}
}
@@ -2082,58 +2085,68 @@ impl GenericPredicates {
pub fn query_all<'db>(
db: &'db dyn HirDatabase,
def: GenericDefId,
- ) -> EarlyBinder<'db, &'db [Clause<'db>]> {
+ ) -> EarlyBinder<'db, impl Iterator<Item = Clause<'db>>> {
Self::query(db, def).all_predicates()
}
#[inline]
- pub fn query_own<'db>(
+ pub fn query_own_explicit<'db>(
db: &'db dyn HirDatabase,
def: GenericDefId,
- ) -> EarlyBinder<'db, &'db [Clause<'db>]> {
- Self::query(db, def).own_predicates()
+ ) -> EarlyBinder<'db, impl Iterator<Item = Clause<'db>>> {
+ Self::query(db, def).own_explicit_predicates()
}
#[inline]
pub fn query_explicit<'db>(
db: &'db dyn HirDatabase,
def: GenericDefId,
- ) -> EarlyBinder<'db, &'db [Clause<'db>]> {
+ ) -> EarlyBinder<'db, impl Iterator<Item = Clause<'db>>> {
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()
+ pub fn all_predicates(&self) -> EarlyBinder<'_, impl Iterator<Item = Clause<'_>>> {
+ self.predicates.get().map_bound(|it| it.as_slice().iter().copied())
}
#[inline]
- pub fn all_predicates(&self) -> EarlyBinder<'_, &[Clause<'_>]> {
- self.predicates.get().map_bound(|it| it.as_slice())
+ pub fn own_explicit_predicates(&self) -> EarlyBinder<'_, impl Iterator<Item = Clause<'_>>> {
+ self.predicates
+ .get()
+ .map_bound(|it| it.as_slice()[self.own_predicates_start as usize..].iter().copied())
}
#[inline]
- pub fn own_predicates(&self) -> EarlyBinder<'_, &[Clause<'_>]> {
- self.predicates.get().map_bound(|it| &it.as_slice()[self.own_predicates_start as usize..])
+ pub fn explicit_predicates(&self) -> EarlyBinder<'_, impl Iterator<Item = Clause<'_>>> {
+ self.predicates.get().map_bound(|it| {
+ it.as_slice()[usize::from(self.has_trait_implied_predicate)..].iter().copied()
+ })
}
- /// 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<'_>]> {
+ pub fn explicit_non_assoc_types_predicates(
+ &self,
+ ) -> EarlyBinder<'_, impl Iterator<Item = Clause<'_>>> {
self.predicates.get().map_bound(|it| {
- &it.as_slice()[self.parent_explicit_self_predicates_start as usize
+ it.as_slice()[self.parent_explicit_self_predicates_start as usize
..self.own_assoc_ty_bounds_start as usize]
+ .iter()
+ .copied()
})
}
#[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)]
+ pub fn explicit_assoc_types_predicates(
+ &self,
+ ) -> EarlyBinder<'_, impl Iterator<Item = Clause<'_>>> {
+ self.predicates.get().map_bound(|predicates| {
+ let predicates = predicates.as_slice();
+ predicates[usize::from(self.has_trait_implied_predicate)
+ ..self.parent_explicit_self_predicates_start as usize]
+ .iter()
+ .copied()
+ .chain(predicates[self.own_assoc_ty_bounds_start as usize..].iter().copied())
})
}
}
@@ -2142,10 +2155,8 @@ pub(crate) fn param_env_from_predicates<'db>(
interner: DbInterner<'db>,
predicates: &'db GenericPredicates,
) -> ParamEnv<'db> {
- let clauses = rustc_type_ir::elaborate::elaborate(
- interner,
- predicates.all_predicates().iter_identity_copied(),
- );
+ let clauses =
+ rustc_type_ir::elaborate::elaborate(interner, predicates.all_predicates().iter_identity());
let clauses = Clauses::new_from_iter(interner, clauses);
// FIXME: We should normalize projections here, like rustc does.
@@ -2290,42 +2301,28 @@ fn generic_predicates(db: &dyn HirDatabase, def: GenericDefId) -> (GenericPredic
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(own_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 has_trait_implied_predicate =
+ parent_implicit_trait_predicate.is_some() || own_implicit_trait_predicate.is_some();
let parent_explicit_self_predicates_start =
- parent_is_trait as u32 + parent_assoc_ty_bounds.len() as u32;
+ has_trait_implied_predicate 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 {
+ has_trait_implied_predicate,
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);
diff --git a/crates/hir-ty/src/method_resolution.rs b/crates/hir-ty/src/method_resolution.rs
index 05b9ea5d74..b18e48c1fe 100644
--- a/crates/hir-ty/src/method_resolution.rs
+++ b/crates/hir-ty/src/method_resolution.rs
@@ -324,7 +324,7 @@ impl<'db> InferenceTable<'db> {
// any late-bound regions appearing in its bounds.
let bounds = GenericPredicates::query_all(self.db, method_item.into());
let bounds = clauses_as_obligations(
- bounds.iter_instantiated_copied(interner, args.as_slice()),
+ bounds.iter_instantiated(interner, args.as_slice()),
ObligationCause::new(),
self.param_env,
);
diff --git a/crates/hir-ty/src/method_resolution/confirm.rs b/crates/hir-ty/src/method_resolution/confirm.rs
index ec589085a8..94c70c29f7 100644
--- a/crates/hir-ty/src/method_resolution/confirm.rs
+++ b/crates/hir-ty/src/method_resolution/confirm.rs
@@ -136,7 +136,7 @@ impl<'a, 'b, 'db> ConfirmContext<'a, 'b, 'db> {
);
let illegal_sized_bound = self.predicates_require_illegal_sized_bound(
GenericPredicates::query_all(self.db(), self.candidate.into())
- .iter_instantiated_copied(self.interner(), filler_args.as_slice()),
+ .iter_instantiated(self.interner(), filler_args.as_slice()),
);
// Unify the (adjusted) self type with what the method expects.
@@ -509,7 +509,7 @@ impl<'a, 'b, 'db> ConfirmContext<'a, 'b, 'db> {
let def_id = self.candidate;
let method_predicates = clauses_as_obligations(
GenericPredicates::query_all(self.db(), def_id.into())
- .iter_instantiated_copied(self.interner(), all_args),
+ .iter_instantiated(self.interner(), all_args),
ObligationCause::new(),
self.ctx.table.param_env,
);
diff --git a/crates/hir-ty/src/method_resolution/probe.rs b/crates/hir-ty/src/method_resolution/probe.rs
index 8c76bfbc07..3604076ccd 100644
--- a/crates/hir-ty/src/method_resolution/probe.rs
+++ b/crates/hir-ty/src/method_resolution/probe.rs
@@ -1595,7 +1595,7 @@ impl<'a, 'db, Choice: ProbeChoice<'db>> ProbeContext<'a, 'db, Choice> {
// Check whether the impl imposes obligations we have to worry about.
let impl_bounds = GenericPredicates::query_all(self.db(), impl_def_id.into());
let impl_bounds = clauses_as_obligations(
- impl_bounds.iter_instantiated_copied(self.interner(), impl_args.as_slice()),
+ impl_bounds.iter_instantiated(self.interner(), impl_args.as_slice()),
ObligationCause::new(),
self.param_env(),
);
diff --git a/crates/hir-ty/src/next_solver/interner.rs b/crates/hir-ty/src/next_solver/interner.rs
index 5b81c7675d..622648bc8d 100644
--- a/crates/hir-ty/src/next_solver/interner.rs
+++ b/crates/hir-ty/src/next_solver/interner.rs
@@ -1439,81 +1439,55 @@ impl<'db> Interner for DbInterner<'db> {
}
}
- #[tracing::instrument(level = "debug", skip(self), ret)]
fn predicates_of(
self,
def_id: Self::DefId,
) -> EarlyBinder<Self, impl IntoIterator<Item = Self::Clause>> {
- predicates_of(self.db, def_id).all_predicates().map_bound(|it| it.iter().copied())
+ predicates_of(self.db, def_id).all_predicates()
}
- #[tracing::instrument(level = "debug", skip(self), ret)]
fn own_predicates_of(
self,
def_id: Self::DefId,
) -> EarlyBinder<Self, impl IntoIterator<Item = Self::Clause>> {
- predicates_of(self.db, def_id).own_predicates().map_bound(|it| it.iter().copied())
+ predicates_of(self.db, def_id).own_explicit_predicates()
}
- #[tracing::instrument(skip(self), ret)]
fn explicit_super_predicates_of(
self,
def_id: Self::TraitId,
) -> EarlyBinder<Self, impl IntoIterator<Item = (Self::Clause, Self::Span)>> {
- let is_self = |ty: Ty<'db>| match ty.kind() {
- rustc_type_ir::TyKind::Param(param) => param.index == 0,
- _ => false,
- };
-
- GenericPredicates::query_explicit(self.db, def_id.0.into()).map_bound(move |predicates| {
- predicates
- .iter()
- .copied()
- .filter(move |p| match p.kind().skip_binder() {
- // rustc has the following assertion:
- // https://github.com/rust-lang/rust/blob/52618eb338609df44978b0ca4451ab7941fd1c7a/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs#L525-L608
- ClauseKind::Trait(it) => is_self(it.self_ty()),
- ClauseKind::TypeOutlives(it) => is_self(it.0),
- ClauseKind::Projection(it) => is_self(it.self_ty()),
- ClauseKind::HostEffect(it) => is_self(it.self_ty()),
- _ => false,
- })
- .map(|p| (p, Span::dummy()))
- })
+ GenericPredicates::query(self.db, def_id.0.into())
+ .explicit_non_assoc_types_predicates()
+ .map_bound(move |predicates| {
+ predicates.filter(|p| is_clause_at_ty(p, is_ty_self)).map(|p| (p, Span::dummy()))
+ })
}
- #[tracing::instrument(skip(self), ret)]
fn explicit_implied_predicates_of(
self,
def_id: Self::DefId,
) -> EarlyBinder<Self, impl IntoIterator<Item = (Self::Clause, Self::Span)>> {
- fn is_self_or_assoc(ty: Ty<'_>) -> bool {
- match ty.kind() {
- rustc_type_ir::TyKind::Param(param) => param.index == 0,
- rustc_type_ir::TyKind::Alias(rustc_type_ir::AliasTyKind::Projection, alias) => {
- is_self_or_assoc(alias.self_ty())
- }
- _ => false,
+ fn is_ty_assoc_of_self(ty: Ty<'_>) -> bool {
+ // FIXME: Is this correct wrt. combined kind of assoc type bounds, i.e. `where Self::Assoc: Trait<Assoc2: Trait>`
+ // wrt. `Assoc2`, which we should exclude?
+ if let TyKind::Alias(AliasTyKind::Projection, alias) = ty.kind() {
+ is_ty_assoc_of_self(alias.self_ty())
+ } else {
+ is_ty_self(ty)
}
}
- predicates_of(self.db, def_id).explicit_implied_predicates().map_bound(|predicates| {
- predicates
- .iter()
- .copied()
- .filter(|p| match p.kind().skip_binder() {
- ClauseKind::Trait(it) => is_self_or_assoc(it.self_ty()),
- ClauseKind::TypeOutlives(it) => is_self_or_assoc(it.0),
- ClauseKind::Projection(it) => is_self_or_assoc(it.self_ty()),
- ClauseKind::HostEffect(it) => is_self_or_assoc(it.self_ty()),
- // FIXME: Not sure is this correct to allow other clauses but we might replace
- // `generic_predicates_ns` query here with something closer to rustc's
- // `implied_bounds_with_filter`, which is more granular lowering than this
- // "lower at once and then filter" implementation.
- _ => true,
- })
- .map(|p| (p, Span::dummy()))
- })
+ let predicates = predicates_of(self.db, def_id);
+ let non_assoc_types = predicates
+ .explicit_non_assoc_types_predicates()
+ .skip_binder()
+ .filter(|p| is_clause_at_ty(p, is_ty_self));
+ let assoc_types = predicates
+ .explicit_assoc_types_predicates()
+ .skip_binder()
+ .filter(|p| is_clause_at_ty(p, is_ty_assoc_of_self));
+ EarlyBinder::bind(non_assoc_types.chain(assoc_types).map(|it| (it, Span::dummy())))
}
fn impl_super_outlives(
@@ -2294,6 +2268,24 @@ impl<'db> Interner for DbInterner<'db> {
}
}
+fn is_ty_self(ty: Ty<'_>) -> bool {
+ match ty.kind() {
+ TyKind::Param(param) => param.index == 0,
+ _ => false,
+ }
+}
+fn is_clause_at_ty(p: &Clause<'_>, filter: impl FnOnce(Ty<'_>) -> bool) -> bool {
+ match p.kind().skip_binder() {
+ // rustc has the following assertion:
+ // https://github.com/rust-lang/rust/blob/52618eb338609df44978b0ca4451ab7941fd1c7a/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs#L525-L608
+ ClauseKind::Trait(it) => filter(it.self_ty()),
+ ClauseKind::TypeOutlives(it) => filter(it.0),
+ ClauseKind::Projection(it) => filter(it.self_ty()),
+ ClauseKind::HostEffect(it) => filter(it.self_ty()),
+ _ => false,
+ }
+}
+
impl<'db> DbInterner<'db> {
pub fn shift_bound_var_indices<T>(self, bound_vars: usize, value: T) -> T
where
diff --git a/crates/hir-ty/src/next_solver/ty.rs b/crates/hir-ty/src/next_solver/ty.rs
index 192cdb70ae..8e892b65ea 100644
--- a/crates/hir-ty/src/next_solver/ty.rs
+++ b/crates/hir-ty/src/next_solver/ty.rs
@@ -696,7 +696,7 @@ impl<'db> Ty<'db> {
TypeOrConstParamData::TypeParamData(p) => match p.provenance {
TypeParamProvenance::ArgumentImplTrait => {
let predicates = GenericPredicates::query_all(db, param.id.parent())
- .iter_identity_copied()
+ .iter_identity()
.filter(|wc| match wc.kind().skip_binder() {
ClauseKind::Trait(tr) => tr.self_ty() == self,
ClauseKind::Projection(pred) => pred.self_ty() == self,
diff --git a/crates/hir-ty/src/specialization.rs b/crates/hir-ty/src/specialization.rs
index 90cbcfea6a..8bc6c51fae 100644
--- a/crates/hir-ty/src/specialization.rs
+++ b/crates/hir-ty/src/specialization.rs
@@ -109,7 +109,7 @@ fn specializes_query(
// only be referenced via projection predicates.
ocx.register_obligations(clauses_as_obligations(
GenericPredicates::query_all(db, parent_impl_def_id.into())
- .iter_instantiated_copied(interner, parent_args.as_slice()),
+ .iter_instantiated(interner, parent_args.as_slice()),
cause.clone(),
param_env,
));
diff --git a/crates/hir-ty/src/tests/regression.rs b/crates/hir-ty/src/tests/regression.rs
index e4fc7e56c6..d3dfc44c22 100644
--- a/crates/hir-ty/src/tests/regression.rs
+++ b/crates/hir-ty/src/tests/regression.rs
@@ -2841,3 +2841,18 @@ fn wrapped_abs<T: SelfAbs<Output = T>>(v: T) -> T {
"#,
);
}
+
+#[test]
+fn regression_21899() {
+ check_no_mismatches(
+ r#"
+trait B where
+ Self::T: B,
+{
+ type T;
+}
+
+fn foo<T: B>(v: T::T) {}
+ "#,
+ );
+}
diff --git a/crates/hir/src/display.rs b/crates/hir/src/display.rs
index 4bfdd239f9..53f24713cd 100644
--- a/crates/hir/src/display.rs
+++ b/crates/hir/src/display.rs
@@ -76,7 +76,7 @@ fn write_builtin_derive_impl_method<'db>(
let predicates =
hir_ty::builtin_derive::predicates(db, impl_).explicit_predicates().skip_binder();
- write_params_bounds(f, predicates)?;
+ write_params_bounds(f, &Vec::from_iter(predicates))?;
}
Ok(())
@@ -578,7 +578,7 @@ impl<'db> HirDisplay<'db> for TypeParam {
let ty = self.ty(f.db).ty;
let predicates = GenericPredicates::query_all(f.db, self.id.parent());
let predicates = predicates
- .iter_identity_copied()
+ .iter_identity()
.filter(|wc| match wc.kind().skip_binder() {
ClauseKind::Trait(tr) => tr.self_ty() == ty,
ClauseKind::Projection(proj) => proj.self_ty() == ty,
diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs
index bc5e164830..eb5b3b37a6 100644
--- a/crates/hir/src/lib.rs
+++ b/crates/hir/src/lib.rs
@@ -4680,7 +4680,7 @@ impl TypeParam {
pub fn trait_bounds(self, db: &dyn HirDatabase) -> Vec<Trait> {
let self_ty = self.ty(db).ty;
GenericPredicates::query_explicit(db, self.id.parent())
- .iter_identity_copied()
+ .iter_identity()
.filter_map(|pred| match &pred.kind().skip_binder() {
ClauseKind::Trait(trait_ref) if trait_ref.self_ty() == self_ty => {
Some(Trait::from(trait_ref.def_id().0))