Skip to content

Commit

Permalink
properly elaborate effects implied bounds for super traits
Browse files Browse the repository at this point in the history
  • Loading branch information
fee1-dead committed Aug 24, 2024
1 parent 4074d49 commit 88ed621
Show file tree
Hide file tree
Showing 9 changed files with 98 additions and 79 deletions.
42 changes: 37 additions & 5 deletions compiler/rustc_hir_analysis/src/bounds.rs
Original file line number Diff line number Diff line change
Expand Up @@ -85,12 +85,44 @@ impl<'tcx> Bounds<'tcx> {
}
tcx.consts.true_
}
(DefKind::Trait, ty::BoundConstness::ConstIfConst) => {
// we are in a trait, where `bound_trait_ref` is a super trait `trait Foo: ~const Bar` or
// a where clause `where for<..> Something: ~const Bar`. In these cases, we generate
// `<Self as Foo>::Effects: TyCompat<<Self as Bar>::Effects>` and
// `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 @@ -127,33 +127,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 @@ -620,11 +620,13 @@ bidirectional_lang_item_map! {
Destruct,
DiscriminantKind,
DynMetadata,
EffectsCompat,
EffectsIntersection,
EffectsIntersectionOutput,
EffectsMaybe,
EffectsNoRuntime,
EffectsRuntime,
EffectsTyCompat,
Fn,
FnMut,
FnOnce,
Expand Down
53 changes: 52 additions & 1 deletion compiler/rustc_type_ir/src/elaborate.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
use std::marker::PhantomData;

use smallvec::smallvec;
use tracing::trace;

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

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

// N.B. this is a bit of a hack to get implied bounds for effects working..
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>`.
// our plan is to gather information such that we elaborate into `<T as SuperTr>::Fx: EffectsCompat<somebool>`
// when we know that `trait Tr: ~const SuperTr`.
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>`,
// which is proof to us that `Tr: ~const SuperTr`.
let bounds = cx.explicit_implied_predicates_of(cx.parent(alias_ty.def_id));
let expected_args_with_self =
I::GenericArgs::identity_for_item(cx, alias_ty.def_id);
let elaborated = bounds.iter_identity().filter_map(|(clause, _)| {
let ty::ClauseKind::Trait(data2) = clause.kind().skip_binder() else {
return None;
};
if !cx
.is_lang_item(data2.def_id(), TraitSolverLangItem::EffectsTyCompat)
{
return None;
};
let ty2 = data2.trait_ref.args.type_at(1);
let ty::Alias(ty::AliasTyKind::Projection, alias_ty2) = ty2.kind()
else {
return None;
};
if alias_ty2.args != expected_args_with_self {
return None;
};

// important: create `<T as SuperTr>::Fx`, this will need to use the original `alias_ty`'s args
// for the `T` as Self type.
let alias_new =
AliasTy::new_from_args(cx, alias_ty2.def_id, alias_ty.args);
let alias =
I::Ty::new_alias(cx, ty::AliasTyKind::Projection, alias_new);
let mut data = data;
let mut new_args = data.trait_ref.args.to_vec();
new_args[0] = alias.into();
data.trait_ref.args = cx.mk_args(&new_args);

Some(elaboratable.child(bound_clause.rebind(data).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.

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.

0 comments on commit 88ed621

Please sign in to comment.