Skip to content

Commit 88ed621

Browse files
committed
properly elaborate effects implied bounds for super traits
1 parent 4074d49 commit 88ed621

File tree

9 files changed

+98
-79
lines changed

9 files changed

+98
-79
lines changed

compiler/rustc_hir_analysis/src/bounds.rs

+37-5
Original file line numberDiff line numberDiff line change
@@ -85,12 +85,44 @@ impl<'tcx> Bounds<'tcx> {
8585
}
8686
tcx.consts.true_
8787
}
88+
(DefKind::Trait, ty::BoundConstness::ConstIfConst) => {
89+
// we are in a trait, where `bound_trait_ref` is a super trait `trait Foo: ~const Bar` or
90+
// a where clause `where for<..> Something: ~const Bar`. In these cases, we generate
91+
// `<Self as Foo>::Effects: TyCompat<<Self as Bar>::Effects>` and
92+
// `for<..> <Self as Foo>::Effects: TyCompat<<Something as Bar>::Effects>`
93+
let Some(own_fx) = tcx.associated_type_for_effects(defining_def_id) else {
94+
tcx.dcx().span_delayed_bug(span, "should not have allowed `~const` on a trait that doesn't have `#[const_trait]`");
95+
return;
96+
};
97+
let own_fx_ty = Ty::new_projection(
98+
tcx,
99+
own_fx,
100+
ty::GenericArgs::identity_for_item(tcx, own_fx),
101+
);
102+
let Some(their_fx) = tcx.associated_type_for_effects(bound_trait_ref.def_id())
103+
else {
104+
tcx.dcx().span_delayed_bug(span, "`~const` on trait without Effects assoc");
105+
return;
106+
};
107+
let their_fx_ty =
108+
Ty::new_projection(tcx, their_fx, bound_trait_ref.skip_binder().args);
109+
let compat = tcx.require_lang_item(LangItem::EffectsTyCompat, Some(span));
110+
let clause = bound_trait_ref
111+
.map_bound(|_| {
112+
let trait_ref = ty::TraitRef::new(tcx, compat, [own_fx_ty, their_fx_ty]);
113+
ty::ClauseKind::Trait(ty::TraitPredicate {
114+
trait_ref,
115+
polarity: ty::PredicatePolarity::Positive,
116+
})
117+
})
118+
.upcast(tcx);
119+
120+
self.clauses.push((clause, span));
121+
return;
122+
}
88123

89-
(
90-
DefKind::Trait | DefKind::Impl { of_trait: true },
91-
ty::BoundConstness::ConstIfConst,
92-
) => {
93-
// this is either a where clause on an impl/trait header or on a trait.
124+
(DefKind::Impl { of_trait: true }, ty::BoundConstness::ConstIfConst) => {
125+
// this is a where clause on an impl header.
94126
// push `<T as Tr>::Effects` into the set for the `Min` bound.
95127
let Some(assoc) = tcx.associated_type_for_effects(bound_trait_ref.def_id()) else {
96128
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
@@ -127,33 +127,10 @@ pub(super) fn explicit_item_bounds_with_filter(
127127
None => {}
128128
}
129129

130-
if tcx.is_effects_desugared_assoc_ty(def_id.to_def_id()) {
131-
let mut predicates = Vec::new();
132-
133-
let parent = tcx.local_parent(def_id);
134-
135-
let preds = tcx.explicit_predicates_of(parent);
136-
137-
if let ty::AssocItemContainer::TraitContainer = tcx.associated_item(def_id).container {
138-
// for traits, emit `type Effects: TyCompat<<(T1::Effects, ..) as Min>::Output>`
139-
let tup = Ty::new(tcx, ty::Tuple(preds.effects_min_tys));
140-
// FIXME(effects) span
141-
let span = tcx.def_span(def_id);
142-
let assoc = tcx.require_lang_item(hir::LangItem::EffectsIntersectionOutput, Some(span));
143-
let proj = Ty::new_projection(tcx, assoc, [tup]);
144-
let self_proj = Ty::new_projection(
145-
tcx,
146-
def_id.to_def_id(),
147-
ty::GenericArgs::identity_for_item(tcx, def_id),
148-
);
149-
let trait_ = tcx.require_lang_item(hir::LangItem::EffectsTyCompat, Some(span));
150-
let trait_ref = ty::TraitRef::new(tcx, trait_, [self_proj, proj]);
151-
predicates.push((ty::Binder::dummy(trait_ref).upcast(tcx), span));
152-
}
153-
return ty::EarlyBinder::bind(tcx.arena.alloc_from_iter(predicates));
154-
}
155-
156130
let bounds = match tcx.hir_node_by_def_id(def_id) {
131+
_ if tcx.is_effects_desugared_assoc_ty(def_id.to_def_id()) => {
132+
associated_type_bounds(tcx, def_id, &[], tcx.def_span(def_id), filter)
133+
}
157134
hir::Node::TraitItem(hir::TraitItem {
158135
kind: hir::TraitItemKind::Type(bounds, _),
159136
span,

compiler/rustc_middle/src/ty/context.rs

+2
Original file line numberDiff line numberDiff line change
@@ -620,11 +620,13 @@ bidirectional_lang_item_map! {
620620
Destruct,
621621
DiscriminantKind,
622622
DynMetadata,
623+
EffectsCompat,
623624
EffectsIntersection,
624625
EffectsIntersectionOutput,
625626
EffectsMaybe,
626627
EffectsNoRuntime,
627628
EffectsRuntime,
629+
EffectsTyCompat,
628630
Fn,
629631
FnMut,
630632
FnOnce,

compiler/rustc_type_ir/src/elaborate.rs

+52-1
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
11
use std::marker::PhantomData;
22

33
use smallvec::smallvec;
4+
use tracing::trace;
45

56
use crate::data_structures::HashSet;
67
use crate::inherent::*;
8+
use crate::lang_items::TraitSolverLangItem;
79
use crate::outlives::{push_outlives_components, Component};
8-
use crate::{self as ty, Interner, Upcast as _};
10+
use crate::{self as ty, AliasTy, Interner, Upcast as _};
911

1012
/// "Elaboration" is the process of identifying all the predicates that
1113
/// are implied by a source predicate. Currently, this basically means
@@ -89,6 +91,55 @@ impl<I: Interner, O: Elaboratable<I>> Elaborator<I, O> {
8991
return;
9092
}
9193

94+
// N.B. this is a bit of a hack to get implied bounds for effects working..
95+
if cx.is_lang_item(data.def_id(), TraitSolverLangItem::EffectsCompat)
96+
&& matches!(self.mode, Filter::All)
97+
{
98+
// first, ensure that the predicate we've got looks like a `<T as Tr>::Fx: EffectsCompat<somebool>`.
99+
// our plan is to gather information such that we elaborate into `<T as SuperTr>::Fx: EffectsCompat<somebool>`
100+
// when we know that `trait Tr: ~const SuperTr`.
101+
if let ty::Alias(ty::AliasTyKind::Projection, alias_ty) = data.self_ty().kind()
102+
{
103+
// look for effects-level bounds that look like `<Self as Tr>::Fx: TyCompat<<Self as SuperTr>::Fx>`,
104+
// which is proof to us that `Tr: ~const SuperTr`.
105+
let bounds = cx.explicit_implied_predicates_of(cx.parent(alias_ty.def_id));
106+
let expected_args_with_self =
107+
I::GenericArgs::identity_for_item(cx, alias_ty.def_id);
108+
let elaborated = bounds.iter_identity().filter_map(|(clause, _)| {
109+
let ty::ClauseKind::Trait(data2) = clause.kind().skip_binder() else {
110+
return None;
111+
};
112+
if !cx
113+
.is_lang_item(data2.def_id(), TraitSolverLangItem::EffectsTyCompat)
114+
{
115+
return None;
116+
};
117+
let ty2 = data2.trait_ref.args.type_at(1);
118+
let ty::Alias(ty::AliasTyKind::Projection, alias_ty2) = ty2.kind()
119+
else {
120+
return None;
121+
};
122+
if alias_ty2.args != expected_args_with_self {
123+
return None;
124+
};
125+
126+
// important: create `<T as SuperTr>::Fx`, this will need to use the original `alias_ty`'s args
127+
// for the `T` as Self type.
128+
let alias_new =
129+
AliasTy::new_from_args(cx, alias_ty2.def_id, alias_ty.args);
130+
let alias =
131+
I::Ty::new_alias(cx, ty::AliasTyKind::Projection, alias_new);
132+
let mut data = data;
133+
let mut new_args = data.trait_ref.args.to_vec();
134+
new_args[0] = alias.into();
135+
data.trait_ref.args = cx.mk_args(&new_args);
136+
137+
Some(elaboratable.child(bound_clause.rebind(data).upcast(cx)))
138+
});
139+
self.extend_deduped(elaborated);
140+
}
141+
}
142+
92143
let map_to_child_clause =
93144
|(index, (clause, span)): (usize, (I::Clause, I::Span))| {
94145
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.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)