Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

properly elaborate effects implied bounds for super traits #129499

Merged
merged 1 commit into from
Sep 30, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 39 additions & 5 deletions compiler/rustc_hir_analysis/src/bounds.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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);

self.clauses.push((clause, span));
return;
}

(
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.
(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");
Expand Down
29 changes: 3 additions & 26 deletions compiler/rustc_hir_analysis/src/collect/item_bounds.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
2 changes: 2 additions & 0 deletions compiler/rustc_middle/src/ty/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -622,11 +622,13 @@ bidirectional_lang_item_map! {
Destruct,
DiscriminantKind,
DynMetadata,
EffectsCompat,
EffectsIntersection,
EffectsIntersectionOutput,
EffectsMaybe,
EffectsNoRuntime,
EffectsRuntime,
EffectsTyCompat,
Fn,
FnMut,
FnOnce,
Expand Down
65 changes: 65 additions & 0 deletions compiler/rustc_type_ir/src/elaborate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ use smallvec::smallvec;

use crate::data_structures::HashSet;
use crate::inherent::*;
use crate::lang_items::TraitSolverLangItem;
use crate::outlives::{Component, push_outlives_components};
use crate::{self as ty, Interner, Upcast as _};

Expand Down Expand Up @@ -89,6 +90,70 @@ impl<I: Interner, O: Elaboratable<I>> Elaborator<I, O> {
return;
}

// HACK(effects): The following code is required to get implied bounds for effects associated
// types to work with super traits.
//
// Suppose `data` is a trait predicate with the form `<T as Tr>::Fx: EffectsCompat<somebool>`
// and we know that `trait Tr: ~const SuperTr`, we need to elaborate this predicate into
// `<T as SuperTr>::Fx: EffectsCompat<somebool>`.
//
// Since the semantics for elaborating bounds about effects is equivalent to elaborating
// bounds about super traits (elaborate `T: Tr` into `T: SuperTr`), we place effects elaboration
// next to super trait elaboration.
if cx.is_lang_item(data.def_id(), TraitSolverLangItem::EffectsCompat)
&& matches!(self.mode, Filter::All)
{
// first, ensure that the predicate we've got looks like a `<T as Tr>::Fx: EffectsCompat<somebool>`.
if let ty::Alias(ty::AliasTyKind::Projection, alias_ty) = data.self_ty().kind()
{
// look for effects-level bounds that look like `<Self as Tr>::Fx: TyCompat<<Self as SuperTr>::Fx>`
// on the trait, which is proof to us that `Tr: ~const SuperTr`. We're looking for bounds on the
// associated trait, so we use `explicit_implied_predicates_of` since it gives us more than just
// `Self: SuperTr` bounds.
let bounds = cx.explicit_implied_predicates_of(cx.parent(alias_ty.def_id));

// instantiate the implied bounds, so we get `<T as Tr>::Fx` and not `<Self as Tr>::Fx`.
let elaborated = bounds.iter_instantiated(cx, alias_ty.args).filter_map(
|(clause, _)| {
let ty::ClauseKind::Trait(tycompat_bound) =
clause.kind().skip_binder()
else {
return None;
};
if !cx.is_lang_item(
tycompat_bound.def_id(),
TraitSolverLangItem::EffectsTyCompat,
) {
return None;
}

// extract `<T as SuperTr>::Fx` from the `TyCompat` bound.
let supertrait_effects_ty =
tycompat_bound.trait_ref.args.type_at(1);
let ty::Alias(ty::AliasTyKind::Projection, supertrait_alias_ty) =
supertrait_effects_ty.kind()
else {
return None;
};

// The self types (`T`) must be equal for `<T as Tr>::Fx` and `<T as SuperTr>::Fx`.
if supertrait_alias_ty.self_ty() != alias_ty.self_ty() {
return None;
};

// replace the self type in the original bound `<T as Tr>::Fx: EffectsCompat<somebool>`
// to the effects type of the super trait. (`<T as SuperTr>::Fx`)
let elaborated_bound = data.with_self_ty(cx, supertrait_effects_ty);
Some(
elaboratable
.child(bound_clause.rebind(elaborated_bound).upcast(cx)),
)
},
);
self.extend_deduped(elaborated);
}
}

let map_to_child_clause =
|(index, (clause, span)): (usize, (I::Clause, I::Span))| {
elaboratable.child_with_derived_cause(
Expand Down
2 changes: 2 additions & 0 deletions compiler/rustc_type_ir/src/lang_items.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,13 @@ pub enum TraitSolverLangItem {
Destruct,
DiscriminantKind,
DynMetadata,
EffectsCompat,
EffectsIntersection,
EffectsIntersectionOutput,
EffectsMaybe,
EffectsNoRuntime,
EffectsRuntime,
EffectsTyCompat,
Fn,
FnMut,
FnOnce,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
#![feature(const_trait_impl, effects)]

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

#[cfg_attr(any(yy, yn), const_trait)]
trait Foo {
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,6 @@ impl Foo for S {
}

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

fn main() {}
23 changes: 18 additions & 5 deletions tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail.stderr
Original file line number Diff line number Diff line change
@@ -1,11 +1,24 @@
error[E0277]: the trait bound `Maybe: TyCompat<<(Foo::{synthetic#0},) as std::marker::effects::Intersection>::Output>` is not satisfied
error[E0277]: the trait bound `Bar::{synthetic#0}: TyCompat<Foo::{synthetic#0}>` is not satisfied
--> $DIR/super-traits-fail.rs:19:12
|
LL | impl const Bar for S {}
| ^^^ the trait `TyCompat<Foo::{synthetic#0}>` is not implemented for `Bar::{synthetic#0}`, which is required by `S: Bar`
|
= help: the trait `Bar` is implemented for `S`
note: required for `S` to implement `Bar`
--> $DIR/super-traits-fail.rs:12:7
|
LL | trait Bar: ~const Foo {}
| ^^^

error[E0277]: the trait bound `Maybe: TyCompat<Foo::{synthetic#0}>` is not satisfied
|
note: required by a bound in `Bar::{synthetic#0}`
--> $DIR/super-traits-fail.rs:11:1
--> $DIR/super-traits-fail.rs:12:12
|
LL | #[const_trait]
| ^^^^^^^^^^^^^^ required by this bound in `Bar::{synthetic#0}`
LL | trait Bar: ~const Foo {}
| ^^^^^^^^^^ required by this bound in `Bar::{synthetic#0}`

error: aborting due to 1 previous error
error: aborting due to 2 previous errors

For more information about this error, try `rustc --explain E0277`.
3 changes: 1 addition & 2 deletions tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
// FIXME(effects) check-pass
//@ known-bug: #110395
//@ check-pass
//@ compile-flags: -Znext-solver
#![allow(incomplete_features)]
#![feature(const_trait_impl, effects)]
Expand Down
22 changes: 0 additions & 22 deletions tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits.stderr

This file was deleted.

Loading