Skip to content

Commit 0e67c64

Browse files
committed
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 rust-lang/project-const-traits#2. r? project-const-traits `@rust-lang/project-const-traits:` how do we feel about this approach?
2 parents 42ff2ee + 7c2a24b commit 0e67c64

File tree

11 files changed

+132
-84
lines changed

11 files changed

+132
-84
lines changed

compiler/rustc_hir_analysis/src/bounds.rs

+39-5
Original file line numberDiff line numberDiff line change
@@ -91,12 +91,46 @@ impl<'tcx> Bounds<'tcx> {
9191
}
9292
tcx.consts.true_
9393
}
94+
(DefKind::Trait, ty::BoundConstness::ConstIfConst) => {
95+
// we are in a trait, where `bound_trait_ref` could be:
96+
// (1) a super trait `trait Foo: ~const Bar`.
97+
// - This generates `<Self as Foo>::Effects: TyCompat<<Self as Bar>::Effects>`
98+
//
99+
// (2) a where clause `where for<..> Something: ~const Bar`.
100+
// - This generates `for<..> <Self as Foo>::Effects: TyCompat<<Something as Bar>::Effects>`
101+
let Some(own_fx) = tcx.associated_type_for_effects(defining_def_id) else {
102+
tcx.dcx().span_delayed_bug(span, "should not have allowed `~const` on a trait that doesn't have `#[const_trait]`");
103+
return;
104+
};
105+
let own_fx_ty = Ty::new_projection(
106+
tcx,
107+
own_fx,
108+
ty::GenericArgs::identity_for_item(tcx, own_fx),
109+
);
110+
let Some(their_fx) = tcx.associated_type_for_effects(bound_trait_ref.def_id())
111+
else {
112+
tcx.dcx().span_delayed_bug(span, "`~const` on trait without Effects assoc");
113+
return;
114+
};
115+
let their_fx_ty =
116+
Ty::new_projection(tcx, their_fx, bound_trait_ref.skip_binder().args);
117+
let compat = tcx.require_lang_item(LangItem::EffectsTyCompat, Some(span));
118+
let clause = bound_trait_ref
119+
.map_bound(|_| {
120+
let trait_ref = ty::TraitRef::new(tcx, compat, [own_fx_ty, their_fx_ty]);
121+
ty::ClauseKind::Trait(ty::TraitPredicate {
122+
trait_ref,
123+
polarity: ty::PredicatePolarity::Positive,
124+
})
125+
})
126+
.upcast(tcx);
127+
128+
self.clauses.push((clause, span));
129+
return;
130+
}
94131

95-
(
96-
DefKind::Trait | DefKind::Impl { of_trait: true },
97-
ty::BoundConstness::ConstIfConst,
98-
) => {
99-
// this is either a where clause on an impl/trait header or on a trait.
132+
(DefKind::Impl { of_trait: true }, ty::BoundConstness::ConstIfConst) => {
133+
// this is a where clause on an impl header.
100134
// push `<T as Tr>::Effects` into the set for the `Min` bound.
101135
let Some(assoc) = tcx.associated_type_for_effects(bound_trait_ref.def_id()) else {
102136
tcx.dcx().span_delayed_bug(span, "`~const` on trait without Effects assoc");

compiler/rustc_hir_analysis/src/collect/item_bounds.rs

+3-26
Original file line numberDiff line numberDiff line change
@@ -360,33 +360,10 @@ pub(super) fn explicit_item_bounds_with_filter(
360360
None => {}
361361
}
362362

363-
if tcx.is_effects_desugared_assoc_ty(def_id.to_def_id()) {
364-
let mut predicates = Vec::new();
365-
366-
let parent = tcx.local_parent(def_id);
367-
368-
let preds = tcx.explicit_predicates_of(parent);
369-
370-
if let ty::AssocItemContainer::TraitContainer = tcx.associated_item(def_id).container {
371-
// for traits, emit `type Effects: TyCompat<<(T1::Effects, ..) as Min>::Output>`
372-
let tup = Ty::new(tcx, ty::Tuple(preds.effects_min_tys));
373-
// FIXME(effects) span
374-
let span = tcx.def_span(def_id);
375-
let assoc = tcx.require_lang_item(hir::LangItem::EffectsIntersectionOutput, Some(span));
376-
let proj = Ty::new_projection(tcx, assoc, [tup]);
377-
let self_proj = Ty::new_projection(
378-
tcx,
379-
def_id.to_def_id(),
380-
ty::GenericArgs::identity_for_item(tcx, def_id),
381-
);
382-
let trait_ = tcx.require_lang_item(hir::LangItem::EffectsTyCompat, Some(span));
383-
let trait_ref = ty::TraitRef::new(tcx, trait_, [self_proj, proj]);
384-
predicates.push((ty::Binder::dummy(trait_ref).upcast(tcx), span));
385-
}
386-
return ty::EarlyBinder::bind(tcx.arena.alloc_from_iter(predicates));
387-
}
388-
389363
let bounds = match tcx.hir_node_by_def_id(def_id) {
364+
_ if tcx.is_effects_desugared_assoc_ty(def_id.to_def_id()) => {
365+
associated_type_bounds(tcx, def_id, &[], tcx.def_span(def_id), filter)
366+
}
390367
hir::Node::TraitItem(hir::TraitItem {
391368
kind: hir::TraitItemKind::Type(bounds, _),
392369
span,

compiler/rustc_middle/src/ty/context.rs

+2
Original file line numberDiff line numberDiff line change
@@ -622,11 +622,13 @@ bidirectional_lang_item_map! {
622622
Destruct,
623623
DiscriminantKind,
624624
DynMetadata,
625+
EffectsCompat,
625626
EffectsIntersection,
626627
EffectsIntersectionOutput,
627628
EffectsMaybe,
628629
EffectsNoRuntime,
629630
EffectsRuntime,
631+
EffectsTyCompat,
630632
Fn,
631633
FnMut,
632634
FnOnce,

compiler/rustc_type_ir/src/elaborate.rs

+65
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ use smallvec::smallvec;
44

55
use crate::data_structures::HashSet;
66
use crate::inherent::*;
7+
use crate::lang_items::TraitSolverLangItem;
78
use crate::outlives::{Component, push_outlives_components};
89
use crate::{self as ty, Interner, Upcast as _};
910

@@ -89,6 +90,70 @@ impl<I: Interner, O: Elaboratable<I>> Elaborator<I, O> {
8990
return;
9091
}
9192

93+
// HACK(effects): The following code is required to get implied bounds for effects associated
94+
// types to work with super traits.
95+
//
96+
// Suppose `data` is a trait predicate with the form `<T as Tr>::Fx: EffectsCompat<somebool>`
97+
// and we know that `trait Tr: ~const SuperTr`, we need to elaborate this predicate into
98+
// `<T as SuperTr>::Fx: EffectsCompat<somebool>`.
99+
//
100+
// Since the semantics for elaborating bounds about effects is equivalent to elaborating
101+
// bounds about super traits (elaborate `T: Tr` into `T: SuperTr`), we place effects elaboration
102+
// next to super trait elaboration.
103+
if cx.is_lang_item(data.def_id(), TraitSolverLangItem::EffectsCompat)
104+
&& matches!(self.mode, Filter::All)
105+
{
106+
// first, ensure that the predicate we've got looks like a `<T as Tr>::Fx: EffectsCompat<somebool>`.
107+
if let ty::Alias(ty::AliasTyKind::Projection, alias_ty) = data.self_ty().kind()
108+
{
109+
// look for effects-level bounds that look like `<Self as Tr>::Fx: TyCompat<<Self as SuperTr>::Fx>`
110+
// on the trait, which is proof to us that `Tr: ~const SuperTr`. We're looking for bounds on the
111+
// associated trait, so we use `explicit_implied_predicates_of` since it gives us more than just
112+
// `Self: SuperTr` bounds.
113+
let bounds = cx.explicit_implied_predicates_of(cx.parent(alias_ty.def_id));
114+
115+
// instantiate the implied bounds, so we get `<T as Tr>::Fx` and not `<Self as Tr>::Fx`.
116+
let elaborated = bounds.iter_instantiated(cx, alias_ty.args).filter_map(
117+
|(clause, _)| {
118+
let ty::ClauseKind::Trait(tycompat_bound) =
119+
clause.kind().skip_binder()
120+
else {
121+
return None;
122+
};
123+
if !cx.is_lang_item(
124+
tycompat_bound.def_id(),
125+
TraitSolverLangItem::EffectsTyCompat,
126+
) {
127+
return None;
128+
}
129+
130+
// extract `<T as SuperTr>::Fx` from the `TyCompat` bound.
131+
let supertrait_effects_ty =
132+
tycompat_bound.trait_ref.args.type_at(1);
133+
let ty::Alias(ty::AliasTyKind::Projection, supertrait_alias_ty) =
134+
supertrait_effects_ty.kind()
135+
else {
136+
return None;
137+
};
138+
139+
// The self types (`T`) must be equal for `<T as Tr>::Fx` and `<T as SuperTr>::Fx`.
140+
if supertrait_alias_ty.self_ty() != alias_ty.self_ty() {
141+
return None;
142+
};
143+
144+
// replace the self type in the original bound `<T as Tr>::Fx: EffectsCompat<somebool>`
145+
// to the effects type of the super trait. (`<T as SuperTr>::Fx`)
146+
let elaborated_bound = data.with_self_ty(cx, supertrait_effects_ty);
147+
Some(
148+
elaboratable
149+
.child(bound_clause.rebind(elaborated_bound).upcast(cx)),
150+
)
151+
},
152+
);
153+
self.extend_deduped(elaborated);
154+
}
155+
}
156+
92157
let map_to_child_clause =
93158
|(index, (clause, span)): (usize, (I::Clause, I::Span))| {
94159
elaboratable.child_with_derived_cause(

compiler/rustc_type_ir/src/lang_items.rs

+2
Original file line numberDiff line numberDiff line change
@@ -20,11 +20,13 @@ pub enum TraitSolverLangItem {
2020
Destruct,
2121
DiscriminantKind,
2222
DynMetadata,
23+
EffectsCompat,
2324
EffectsIntersection,
2425
EffectsIntersectionOutput,
2526
EffectsMaybe,
2627
EffectsNoRuntime,
2728
EffectsRuntime,
29+
EffectsTyCompat,
2830
Fn,
2931
FnMut,
3032
FnOnce,

tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-3.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
#![feature(const_trait_impl, effects)]
44

55
//@ revisions: yy yn ny nn
6-
//@[yy] known-bug: #110395
6+
//@[yy] check-pass
77

88
#[cfg_attr(any(yy, yn), const_trait)]
99
trait Foo {

tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-3.yy.stderr

-22
This file was deleted.

tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,6 @@ impl Foo for S {
1717
}
1818

1919
impl const Bar for S {}
20-
// FIXME(effects) bad span
20+
//~^ ERROR the trait bound
2121

2222
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,24 @@
1-
error[E0277]: the trait bound `Maybe: TyCompat<<(Foo::{synthetic#0},) as std::marker::effects::Intersection>::Output>` is not satisfied
1+
error[E0277]: the trait bound `Bar::{synthetic#0}: TyCompat<Foo::{synthetic#0}>` is not satisfied
2+
--> $DIR/super-traits-fail.rs:19:12
3+
|
4+
LL | impl const Bar for S {}
5+
| ^^^ the trait `TyCompat<Foo::{synthetic#0}>` is not implemented for `Bar::{synthetic#0}`, which is required by `S: Bar`
6+
|
7+
= help: the trait `Bar` is implemented for `S`
8+
note: required for `S` to implement `Bar`
9+
--> $DIR/super-traits-fail.rs:12:7
10+
|
11+
LL | trait Bar: ~const Foo {}
12+
| ^^^
13+
14+
error[E0277]: the trait bound `Maybe: TyCompat<Foo::{synthetic#0}>` is not satisfied
215
|
316
note: required by a bound in `Bar::{synthetic#0}`
4-
--> $DIR/super-traits-fail.rs:11:1
17+
--> $DIR/super-traits-fail.rs:12:12
518
|
6-
LL | #[const_trait]
7-
| ^^^^^^^^^^^^^^ required by this bound in `Bar::{synthetic#0}`
19+
LL | trait Bar: ~const Foo {}
20+
| ^^^^^^^^^^ required by this bound in `Bar::{synthetic#0}`
821

9-
error: aborting due to 1 previous error
22+
error: aborting due to 2 previous errors
1023

1124
For more information about this error, try `rustc --explain E0277`.

tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits.rs

+1-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
1-
// FIXME(effects) check-pass
2-
//@ known-bug: #110395
1+
//@ check-pass
32
//@ compile-flags: -Znext-solver
43
#![allow(incomplete_features)]
54
#![feature(const_trait_impl, effects)]

tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits.stderr

-22
This file was deleted.

0 commit comments

Comments
 (0)