Skip to content

Commit 9be9b5e

Browse files
committed
Auto merge of #107614 - compiler-errors:allow-elaborator-to-filter-only-super-traits, r=oli-obk
Split implied and super predicate queries, then allow elaborator to filter only supertraits Split the `super_predicates_of` query into a new `implied_predicates_of` query. The former now only returns the *real* supertraits of a trait alias, and the latter now returns the implied predicates (which include all of the `where` clauses of the trait alias). The behavior of these queries is identical for regular traits. Now that the two queries are split, we can add a new filter method to the elaborator, `filter_only_self()`, which can be used in instances that we need only the *supertrait* predicates, such as during the elaboration used in closure signature deduction. This toggles the usage of `super_predicates_of` instead of `implied_predicates_of` during elaboration of a trait predicate. This supersedes #104745, and fixes the four independent bugs identified in that PR. Fixes #104719 Fixes #106238 Fixes #110023 Fixes #109514 r? types
2 parents 0d7ed3b + 7ec72ef commit 9be9b5e

File tree

28 files changed

+308
-150
lines changed

28 files changed

+308
-150
lines changed

compiler/rustc_hir_analysis/src/astconv/mod.rs

+37-31
Original file line numberDiff line numberDiff line change
@@ -1663,39 +1663,45 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
16631663
})
16641664
});
16651665

1666-
let existential_projections = projection_bounds.iter().map(|(bound, _)| {
1667-
bound.map_bound(|mut b| {
1668-
assert_eq!(b.projection_ty.self_ty(), dummy_self);
1669-
1670-
// Like for trait refs, verify that `dummy_self` did not leak inside default type
1671-
// parameters.
1672-
let references_self = b.projection_ty.substs.iter().skip(1).any(|arg| {
1673-
if arg.walk().any(|arg| arg == dummy_self.into()) {
1674-
return true;
1666+
let existential_projections = projection_bounds
1667+
.iter()
1668+
// We filter out traits that don't have `Self` as their self type above,
1669+
// we need to do the same for projections.
1670+
.filter(|(bound, _)| bound.skip_binder().self_ty() == dummy_self)
1671+
.map(|(bound, _)| {
1672+
bound.map_bound(|mut b| {
1673+
assert_eq!(b.projection_ty.self_ty(), dummy_self);
1674+
1675+
// Like for trait refs, verify that `dummy_self` did not leak inside default type
1676+
// parameters.
1677+
let references_self = b.projection_ty.substs.iter().skip(1).any(|arg| {
1678+
if arg.walk().any(|arg| arg == dummy_self.into()) {
1679+
return true;
1680+
}
1681+
false
1682+
});
1683+
if references_self {
1684+
let guar = tcx.sess.delay_span_bug(
1685+
span,
1686+
"trait object projection bounds reference `Self`",
1687+
);
1688+
let substs: Vec<_> = b
1689+
.projection_ty
1690+
.substs
1691+
.iter()
1692+
.map(|arg| {
1693+
if arg.walk().any(|arg| arg == dummy_self.into()) {
1694+
return tcx.ty_error(guar).into();
1695+
}
1696+
arg
1697+
})
1698+
.collect();
1699+
b.projection_ty.substs = tcx.mk_substs(&substs);
16751700
}
1676-
false
1677-
});
1678-
if references_self {
1679-
let guar = tcx
1680-
.sess
1681-
.delay_span_bug(span, "trait object projection bounds reference `Self`");
1682-
let substs: Vec<_> = b
1683-
.projection_ty
1684-
.substs
1685-
.iter()
1686-
.map(|arg| {
1687-
if arg.walk().any(|arg| arg == dummy_self.into()) {
1688-
return tcx.ty_error(guar).into();
1689-
}
1690-
arg
1691-
})
1692-
.collect();
1693-
b.projection_ty.substs = tcx.mk_substs(&substs);
1694-
}
16951701

1696-
ty::ExistentialProjection::erase_self_ty(tcx, b)
1697-
})
1698-
});
1702+
ty::ExistentialProjection::erase_self_ty(tcx, b)
1703+
})
1704+
});
16991705

17001706
let regular_trait_predicates = existential_trait_refs
17011707
.map(|trait_ref| trait_ref.map_bound(ty::ExistentialPredicate::Trait));

compiler/rustc_hir_analysis/src/collect.rs

+2
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@ pub fn provide(providers: &mut Providers) {
6464
predicates_defined_on,
6565
explicit_predicates_of: predicates_of::explicit_predicates_of,
6666
super_predicates_of: predicates_of::super_predicates_of,
67+
implied_predicates_of: predicates_of::implied_predicates_of,
6768
super_predicates_that_define_assoc_type:
6869
predicates_of::super_predicates_that_define_assoc_type,
6970
trait_explicit_predicates_and_bounds: predicates_of::trait_explicit_predicates_and_bounds,
@@ -596,6 +597,7 @@ fn convert_item(tcx: TyCtxt<'_>, item_id: hir::ItemId) {
596597
}
597598
hir::ItemKind::TraitAlias(..) => {
598599
tcx.ensure().generics_of(def_id);
600+
tcx.at(it.span).implied_predicates_of(def_id);
599601
tcx.at(it.span).super_predicates_of(def_id);
600602
tcx.ensure().predicates_of(def_id);
601603
}

compiler/rustc_hir_analysis/src/collect/predicates_of.rs

+81-32
Original file line numberDiff line numberDiff line change
@@ -125,7 +125,7 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen
125125
// on a trait we need to add in the supertrait bounds and bounds found on
126126
// associated types.
127127
if let Some(_trait_ref) = is_trait {
128-
predicates.extend(tcx.super_predicates_of(def_id).predicates.iter().cloned());
128+
predicates.extend(tcx.implied_predicates_of(def_id).predicates.iter().cloned());
129129
}
130130

131131
// In default impls, we can assume that the self type implements
@@ -534,31 +534,62 @@ pub(super) fn explicit_predicates_of<'tcx>(
534534
}
535535
}
536536

537+
#[derive(Copy, Clone, Debug)]
538+
pub enum PredicateFilter {
539+
/// All predicates may be implied by the trait
540+
All,
541+
542+
/// Only traits that reference `Self: ..` are implied by the trait
543+
SelfOnly,
544+
545+
/// Only traits that reference `Self: ..` and define an associated type
546+
/// with the given ident are implied by the trait
547+
SelfThatDefines(Ident),
548+
}
549+
537550
/// Ensures that the super-predicates of the trait with a `DefId`
538551
/// of `trait_def_id` are converted and stored. This also ensures that
539552
/// the transitive super-predicates are converted.
540553
pub(super) fn super_predicates_of(
541554
tcx: TyCtxt<'_>,
542555
trait_def_id: LocalDefId,
543556
) -> ty::GenericPredicates<'_> {
544-
tcx.super_predicates_that_define_assoc_type((trait_def_id.to_def_id(), None))
557+
implied_predicates_with_filter(tcx, trait_def_id.to_def_id(), PredicateFilter::SelfOnly)
558+
}
559+
560+
pub(super) fn super_predicates_that_define_assoc_type(
561+
tcx: TyCtxt<'_>,
562+
(trait_def_id, assoc_name): (DefId, Ident),
563+
) -> ty::GenericPredicates<'_> {
564+
implied_predicates_with_filter(tcx, trait_def_id, PredicateFilter::SelfThatDefines(assoc_name))
565+
}
566+
567+
pub(super) fn implied_predicates_of(
568+
tcx: TyCtxt<'_>,
569+
trait_def_id: LocalDefId,
570+
) -> ty::GenericPredicates<'_> {
571+
if tcx.is_trait_alias(trait_def_id.to_def_id()) {
572+
implied_predicates_with_filter(tcx, trait_def_id.to_def_id(), PredicateFilter::All)
573+
} else {
574+
tcx.super_predicates_of(trait_def_id)
575+
}
545576
}
546577

547578
/// Ensures that the super-predicates of the trait with a `DefId`
548579
/// of `trait_def_id` are converted and stored. This also ensures that
549580
/// the transitive super-predicates are converted.
550-
pub(super) fn super_predicates_that_define_assoc_type(
581+
pub(super) fn implied_predicates_with_filter(
551582
tcx: TyCtxt<'_>,
552-
(trait_def_id, assoc_name): (DefId, Option<Ident>),
583+
trait_def_id: DefId,
584+
filter: PredicateFilter,
553585
) -> ty::GenericPredicates<'_> {
554586
let Some(trait_def_id) = trait_def_id.as_local() else {
555587
// if `assoc_name` is None, then the query should've been redirected to an
556588
// external provider
557-
assert!(assoc_name.is_some());
589+
assert!(matches!(filter, PredicateFilter::SelfThatDefines(_)));
558590
return tcx.super_predicates_of(trait_def_id);
559591
};
560592

561-
debug!("local trait");
562593
let trait_hir_id = tcx.hir().local_def_id_to_hir_id(trait_def_id);
563594

564595
let Node::Item(item) = tcx.hir().get(trait_hir_id) else {
@@ -573,48 +604,66 @@ pub(super) fn super_predicates_that_define_assoc_type(
573604

574605
let icx = ItemCtxt::new(tcx, trait_def_id);
575606

576-
// Convert the bounds that follow the colon, e.g., `Bar + Zed` in `trait Foo: Bar + Zed`.
577607
let self_param_ty = tcx.types.self_param;
578-
let superbounds1 = if let Some(assoc_name) = assoc_name {
579-
icx.astconv().compute_bounds_that_match_assoc_type(self_param_ty, bounds, assoc_name)
580-
} else {
581-
icx.astconv().compute_bounds(self_param_ty, bounds)
608+
let (superbounds, where_bounds_that_match) = match filter {
609+
PredicateFilter::All => (
610+
// Convert the bounds that follow the colon (or equal in trait aliases)
611+
icx.astconv().compute_bounds(self_param_ty, bounds),
612+
// Also include all where clause bounds
613+
icx.type_parameter_bounds_in_generics(
614+
generics,
615+
item.owner_id.def_id,
616+
self_param_ty,
617+
OnlySelfBounds(false),
618+
None,
619+
),
620+
),
621+
PredicateFilter::SelfOnly => (
622+
// Convert the bounds that follow the colon (or equal in trait aliases)
623+
icx.astconv().compute_bounds(self_param_ty, bounds),
624+
// Include where clause bounds for `Self`
625+
icx.type_parameter_bounds_in_generics(
626+
generics,
627+
item.owner_id.def_id,
628+
self_param_ty,
629+
OnlySelfBounds(true),
630+
None,
631+
),
632+
),
633+
PredicateFilter::SelfThatDefines(assoc_name) => (
634+
// Convert the bounds that follow the colon (or equal) that reference the associated name
635+
icx.astconv().compute_bounds_that_match_assoc_type(self_param_ty, bounds, assoc_name),
636+
// Include where clause bounds for `Self` that reference the associated name
637+
icx.type_parameter_bounds_in_generics(
638+
generics,
639+
item.owner_id.def_id,
640+
self_param_ty,
641+
OnlySelfBounds(true),
642+
Some(assoc_name),
643+
),
644+
),
582645
};
583646

584-
let superbounds1 = superbounds1.predicates();
585-
586-
// Convert any explicit superbounds in the where-clause,
587-
// e.g., `trait Foo where Self: Bar`.
588-
// In the case of trait aliases, however, we include all bounds in the where-clause,
589-
// so e.g., `trait Foo = where u32: PartialEq<Self>` would include `u32: PartialEq<Self>`
590-
// as one of its "superpredicates".
591-
let is_trait_alias = tcx.is_trait_alias(trait_def_id.to_def_id());
592-
let superbounds2 = icx.type_parameter_bounds_in_generics(
593-
generics,
594-
item.owner_id.def_id,
595-
self_param_ty,
596-
OnlySelfBounds(!is_trait_alias),
597-
assoc_name,
598-
);
599-
600647
// Combine the two lists to form the complete set of superbounds:
601-
let superbounds = &*tcx.arena.alloc_from_iter(superbounds1.into_iter().chain(superbounds2));
602-
debug!(?superbounds);
648+
let implied_bounds = &*tcx
649+
.arena
650+
.alloc_from_iter(superbounds.predicates().into_iter().chain(where_bounds_that_match));
651+
debug!(?implied_bounds);
603652

604653
// Now require that immediate supertraits are converted,
605654
// which will, in turn, reach indirect supertraits.
606-
if assoc_name.is_none() {
655+
if matches!(filter, PredicateFilter::SelfOnly) {
607656
// Now require that immediate supertraits are converted,
608657
// which will, in turn, reach indirect supertraits.
609-
for &(pred, span) in superbounds {
658+
for &(pred, span) in implied_bounds {
610659
debug!("superbound: {:?}", pred);
611660
if let ty::PredicateKind::Clause(ty::Clause::Trait(bound)) = pred.kind().skip_binder() {
612661
tcx.at(span).super_predicates_of(bound.def_id());
613662
}
614663
}
615664
}
616665

617-
ty::GenericPredicates { parent: None, predicates: superbounds }
666+
ty::GenericPredicates { parent: None, predicates: implied_bounds }
618667
}
619668

620669
/// Returns the predicates defined on `item_def_id` of the form

compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs

+1-2
Original file line numberDiff line numberDiff line change
@@ -1749,8 +1749,7 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
17491749
if trait_defines_associated_type_named(def_id) {
17501750
break Some(bound_vars.into_iter().collect());
17511751
}
1752-
let predicates =
1753-
tcx.super_predicates_that_define_assoc_type((def_id, Some(assoc_name)));
1752+
let predicates = tcx.super_predicates_that_define_assoc_type((def_id, assoc_name));
17541753
let obligations = predicates.predicates.iter().filter_map(|&(pred, _)| {
17551754
let bound_predicate = pred.kind();
17561755
match bound_predicate.skip_binder() {

compiler/rustc_hir_typeck/src/closure.rs

+4-1
Original file line numberDiff line numberDiff line change
@@ -210,7 +210,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
210210
// and we want to keep inference generally in the same order of
211211
// the registered obligations.
212212
predicates.rev(),
213-
) {
213+
)
214+
// We only care about self bounds
215+
.filter_only_self()
216+
{
214217
debug!(?pred);
215218
let bound_predicate = pred.kind();
216219

compiler/rustc_infer/src/traits/util.rs

+28-19
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@ impl<'tcx> Extend<ty::Predicate<'tcx>> for PredicateSet<'tcx> {
6969
pub struct Elaborator<'tcx, O> {
7070
stack: Vec<O>,
7171
visited: PredicateSet<'tcx>,
72+
only_self: bool,
7273
}
7374

7475
/// Describes how to elaborate an obligation into a sub-obligation.
@@ -170,7 +171,8 @@ pub fn elaborate<'tcx, O: Elaboratable<'tcx>>(
170171
tcx: TyCtxt<'tcx>,
171172
obligations: impl IntoIterator<Item = O>,
172173
) -> Elaborator<'tcx, O> {
173-
let mut elaborator = Elaborator { stack: Vec::new(), visited: PredicateSet::new(tcx) };
174+
let mut elaborator =
175+
Elaborator { stack: Vec::new(), visited: PredicateSet::new(tcx), only_self: false };
174176
elaborator.extend_deduped(obligations);
175177
elaborator
176178
}
@@ -185,14 +187,25 @@ impl<'tcx, O: Elaboratable<'tcx>> Elaborator<'tcx, O> {
185187
self.stack.extend(obligations.into_iter().filter(|o| self.visited.insert(o.predicate())));
186188
}
187189

190+
/// Filter to only the supertraits of trait predicates, i.e. only the predicates
191+
/// that have `Self` as their self type, instead of all implied predicates.
192+
pub fn filter_only_self(mut self) -> Self {
193+
self.only_self = true;
194+
self
195+
}
196+
188197
fn elaborate(&mut self, elaboratable: &O) {
189198
let tcx = self.visited.tcx;
190199

191200
let bound_predicate = elaboratable.predicate().kind();
192201
match bound_predicate.skip_binder() {
193202
ty::PredicateKind::Clause(ty::Clause::Trait(data)) => {
194-
// Get predicates declared on the trait.
195-
let predicates = tcx.super_predicates_of(data.def_id());
203+
// Get predicates implied by the trait, or only super predicates if we only care about self predicates.
204+
let predicates = if self.only_self {
205+
tcx.super_predicates_of(data.def_id())
206+
} else {
207+
tcx.implied_predicates_of(data.def_id())
208+
};
196209

197210
let obligations =
198211
predicates.predicates.iter().enumerate().map(|(index, &(mut pred, span))| {
@@ -350,18 +363,16 @@ pub fn supertraits<'tcx>(
350363
tcx: TyCtxt<'tcx>,
351364
trait_ref: ty::PolyTraitRef<'tcx>,
352365
) -> impl Iterator<Item = ty::PolyTraitRef<'tcx>> {
353-
let pred: ty::Predicate<'tcx> = trait_ref.to_predicate(tcx);
354-
FilterToTraits::new(elaborate(tcx, [pred]))
366+
elaborate(tcx, [trait_ref.to_predicate(tcx)]).filter_only_self().filter_to_traits()
355367
}
356368

357369
pub fn transitive_bounds<'tcx>(
358370
tcx: TyCtxt<'tcx>,
359371
trait_refs: impl Iterator<Item = ty::PolyTraitRef<'tcx>>,
360372
) -> impl Iterator<Item = ty::PolyTraitRef<'tcx>> {
361-
FilterToTraits::new(elaborate(
362-
tcx,
363-
trait_refs.map(|trait_ref| -> ty::Predicate<'tcx> { trait_ref.to_predicate(tcx) }),
364-
))
373+
elaborate(tcx, trait_refs.map(|trait_ref| trait_ref.to_predicate(tcx)))
374+
.filter_only_self()
375+
.filter_to_traits()
365376
}
366377

367378
/// A specialized variant of `elaborate` that only elaborates trait references that may
@@ -381,10 +392,8 @@ pub fn transitive_bounds_that_define_assoc_type<'tcx>(
381392
while let Some(trait_ref) = stack.pop() {
382393
let anon_trait_ref = tcx.anonymize_bound_vars(trait_ref);
383394
if visited.insert(anon_trait_ref) {
384-
let super_predicates = tcx.super_predicates_that_define_assoc_type((
385-
trait_ref.def_id(),
386-
Some(assoc_name),
387-
));
395+
let super_predicates =
396+
tcx.super_predicates_that_define_assoc_type((trait_ref.def_id(), assoc_name));
388397
for (super_predicate, _) in super_predicates.predicates {
389398
let subst_predicate = super_predicate.subst_supertrait(tcx, &trait_ref);
390399
if let Some(binder) = subst_predicate.to_opt_poly_trait_pred() {
@@ -404,18 +413,18 @@ pub fn transitive_bounds_that_define_assoc_type<'tcx>(
404413
// Other
405414
///////////////////////////////////////////////////////////////////////////
406415

416+
impl<'tcx> Elaborator<'tcx, ty::Predicate<'tcx>> {
417+
fn filter_to_traits(self) -> FilterToTraits<Self> {
418+
FilterToTraits { base_iterator: self }
419+
}
420+
}
421+
407422
/// A filter around an iterator of predicates that makes it yield up
408423
/// just trait references.
409424
pub struct FilterToTraits<I> {
410425
base_iterator: I,
411426
}
412427

413-
impl<I> FilterToTraits<I> {
414-
fn new(base: I) -> FilterToTraits<I> {
415-
FilterToTraits { base_iterator: base }
416-
}
417-
}
418-
419428
impl<'tcx, I: Iterator<Item = ty::Predicate<'tcx>>> Iterator for FilterToTraits<I> {
420429
type Item = ty::PolyTraitRef<'tcx>;
421430

0 commit comments

Comments
 (0)