Auto merge of #129499 - fee1-dead-contrib:supereffects, r=compiler-errors

properly elaborate effects implied bounds for super traits

Summary: This PR makes it so that we elaborate `<T as Tr>::Fx: EffectsCompat<somebool>` into `<T as SuperTr>::Fx: EffectsCompat<somebool>` when we know that `trait Tr: ~const SuperTr`.

Some discussion at https://github.com/rust-lang/project-const-traits/issues/2.

r? project-const-traits
`@rust-lang/project-const-traits:` how do we feel about this approach?
This commit is contained in:
bors 2024-09-30 00:30:09 +00:00
commit 4e91cedaed
11 changed files with 132 additions and 84 deletions

View file

@ -91,12 +91,46 @@ impl<'tcx> Bounds<'tcx> {
}
tcx.consts.true_
}
(DefKind::Trait, ty::BoundConstness::ConstIfConst) => {
// we are in a trait, where `bound_trait_ref` could be:
// (1) a super trait `trait Foo: ~const Bar`.
// - This generates `<Self as Foo>::Effects: TyCompat<<Self as Bar>::Effects>`
//
// (2) a where clause `where for<..> Something: ~const Bar`.
// - This generates `for<..> <Self as Foo>::Effects: TyCompat<<Something as Bar>::Effects>`
let Some(own_fx) = tcx.associated_type_for_effects(defining_def_id) else {
tcx.dcx().span_delayed_bug(span, "should not have allowed `~const` on a trait that doesn't have `#[const_trait]`");
return;
};
let own_fx_ty = Ty::new_projection(
tcx,
own_fx,
ty::GenericArgs::identity_for_item(tcx, own_fx),
);
let Some(their_fx) = tcx.associated_type_for_effects(bound_trait_ref.def_id())
else {
tcx.dcx().span_delayed_bug(span, "`~const` on trait without Effects assoc");
return;
};
let their_fx_ty =
Ty::new_projection(tcx, their_fx, bound_trait_ref.skip_binder().args);
let compat = tcx.require_lang_item(LangItem::EffectsTyCompat, Some(span));
let clause = bound_trait_ref
.map_bound(|_| {
let trait_ref = ty::TraitRef::new(tcx, compat, [own_fx_ty, their_fx_ty]);
ty::ClauseKind::Trait(ty::TraitPredicate {
trait_ref,
polarity: ty::PredicatePolarity::Positive,
})
})
.upcast(tcx);
(
DefKind::Trait | DefKind::Impl { of_trait: true },
ty::BoundConstness::ConstIfConst,
) => {
// this is either a where clause on an impl/trait header or on a trait.
self.clauses.push((clause, span));
return;
}
(DefKind::Impl { of_trait: true }, ty::BoundConstness::ConstIfConst) => {
// this is a where clause on an impl header.
// push `<T as Tr>::Effects` into the set for the `Min` bound.
let Some(assoc) = tcx.associated_type_for_effects(bound_trait_ref.def_id()) else {
tcx.dcx().span_delayed_bug(span, "`~const` on trait without Effects assoc");

View file

@ -360,33 +360,10 @@ pub(super) fn explicit_item_bounds_with_filter(
None => {}
}
if tcx.is_effects_desugared_assoc_ty(def_id.to_def_id()) {
let mut predicates = Vec::new();
let parent = tcx.local_parent(def_id);
let preds = tcx.explicit_predicates_of(parent);
if let ty::AssocItemContainer::TraitContainer = tcx.associated_item(def_id).container {
// for traits, emit `type Effects: TyCompat<<(T1::Effects, ..) as Min>::Output>`
let tup = Ty::new(tcx, ty::Tuple(preds.effects_min_tys));
// FIXME(effects) span
let span = tcx.def_span(def_id);
let assoc = tcx.require_lang_item(hir::LangItem::EffectsIntersectionOutput, Some(span));
let proj = Ty::new_projection(tcx, assoc, [tup]);
let self_proj = Ty::new_projection(
tcx,
def_id.to_def_id(),
ty::GenericArgs::identity_for_item(tcx, def_id),
);
let trait_ = tcx.require_lang_item(hir::LangItem::EffectsTyCompat, Some(span));
let trait_ref = ty::TraitRef::new(tcx, trait_, [self_proj, proj]);
predicates.push((ty::Binder::dummy(trait_ref).upcast(tcx), span));
}
return ty::EarlyBinder::bind(tcx.arena.alloc_from_iter(predicates));
}
let bounds = match tcx.hir_node_by_def_id(def_id) {
_ if tcx.is_effects_desugared_assoc_ty(def_id.to_def_id()) => {
associated_type_bounds(tcx, def_id, &[], tcx.def_span(def_id), filter)
}
hir::Node::TraitItem(hir::TraitItem {
kind: hir::TraitItemKind::Type(bounds, _),
span,