about summary refs log tree commit diff
diff options
context:
space:
mode:
authorDeadbeef <ent3rm4n@gmail.com>2024-08-24 14:01:00 +0800
committerDeadbeef <ent3rm4n@gmail.com>2024-09-27 22:36:46 +0800
commit7c2a24b50c48c9716a88e3053064a7d4470b011f (patch)
tree6ba80688c80f0e3b2c159de316b71aea5097afad
parent4428a051679ec6194a118424f4616d922249a1e6 (diff)
downloadrust-7c2a24b50c48c9716a88e3053064a7d4470b011f.tar.gz
rust-7c2a24b50c48c9716a88e3053064a7d4470b011f.zip
properly elaborate effects implied bounds for super traits
-rw-r--r--compiler/rustc_hir_analysis/src/bounds.rs44
-rw-r--r--compiler/rustc_hir_analysis/src/collect/item_bounds.rs29
-rw-r--r--compiler/rustc_middle/src/ty/context.rs2
-rw-r--r--compiler/rustc_type_ir/src/elaborate.rs65
-rw-r--r--compiler/rustc_type_ir/src/lang_items.rs2
-rw-r--r--tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-3.rs2
-rw-r--r--tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-3.yy.stderr22
-rw-r--r--tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail.rs2
-rw-r--r--tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail.stderr23
-rw-r--r--tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits.rs3
-rw-r--r--tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits.stderr22
11 files changed, 132 insertions, 84 deletions
diff --git a/compiler/rustc_hir_analysis/src/bounds.rs b/compiler/rustc_hir_analysis/src/bounds.rs
index caf9960741d..8947e7a2216 100644
--- a/compiler/rustc_hir_analysis/src/bounds.rs
+++ b/compiler/rustc_hir_analysis/src/bounds.rs
@@ -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");
diff --git a/compiler/rustc_hir_analysis/src/collect/item_bounds.rs b/compiler/rustc_hir_analysis/src/collect/item_bounds.rs
index 7557219aaa6..f44b4728ad5 100644
--- a/compiler/rustc_hir_analysis/src/collect/item_bounds.rs
+++ b/compiler/rustc_hir_analysis/src/collect/item_bounds.rs
@@ -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,
diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs
index f017216489d..f1732e4859d 100644
--- a/compiler/rustc_middle/src/ty/context.rs
+++ b/compiler/rustc_middle/src/ty/context.rs
@@ -622,11 +622,13 @@ bidirectional_lang_item_map! {
     Destruct,
     DiscriminantKind,
     DynMetadata,
+    EffectsCompat,
     EffectsIntersection,
     EffectsIntersectionOutput,
     EffectsMaybe,
     EffectsNoRuntime,
     EffectsRuntime,
+    EffectsTyCompat,
     Fn,
     FnMut,
     FnOnce,
diff --git a/compiler/rustc_type_ir/src/elaborate.rs b/compiler/rustc_type_ir/src/elaborate.rs
index 3db9b8b0661..61736633cfa 100644
--- a/compiler/rustc_type_ir/src/elaborate.rs
+++ b/compiler/rustc_type_ir/src/elaborate.rs
@@ -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 _};
 
@@ -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(
diff --git a/compiler/rustc_type_ir/src/lang_items.rs b/compiler/rustc_type_ir/src/lang_items.rs
index 265a4118827..c680c844746 100644
--- a/compiler/rustc_type_ir/src/lang_items.rs
+++ b/compiler/rustc_type_ir/src/lang_items.rs
@@ -20,11 +20,13 @@ pub enum TraitSolverLangItem {
     Destruct,
     DiscriminantKind,
     DynMetadata,
+    EffectsCompat,
     EffectsIntersection,
     EffectsIntersectionOutput,
     EffectsMaybe,
     EffectsNoRuntime,
     EffectsRuntime,
+    EffectsTyCompat,
     Fn,
     FnMut,
     FnOnce,
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-3.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-3.rs
index 66943512650..c7e224dcce0 100644
--- a/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-3.rs
+++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-3.rs
@@ -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 {
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-3.yy.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-3.yy.stderr
deleted file mode 100644
index ea0e6c690b7..00000000000
--- a/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail-3.yy.stderr
+++ /dev/null
@@ -1,22 +0,0 @@
-error[E0277]: the trait bound `Foo::{synthetic#0}: ~const Compat` is not satisfied
-  --> $DIR/super-traits-fail-3.rs:22:7
-   |
-LL |     x.a();
-   |       ^ the trait `~const Compat` is not implemented for `Foo::{synthetic#0}`
-   |
-note: required by a bound in `Foo::a`
-  --> $DIR/super-traits-fail-3.rs:8:25
-   |
-LL | #[cfg_attr(any(yy, yn), const_trait)]
-   |                         ^^^^^^^^^^^ required by this bound in `Foo::a`
-LL | trait Foo {
-LL |     fn a(&self);
-   |        - required by a bound in this associated function
-help: consider further restricting the associated type
-   |
-LL | const fn foo<T: ~const Bar>(x: &T) where Foo::{synthetic#0}: ~const Compat {
-   |                                    +++++++++++++++++++++++++++++++++++++++
-
-error: aborting due to 1 previous error
-
-For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail.rs
index 6c320c0462e..da41d7fcc72 100644
--- a/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail.rs
+++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail.rs
@@ -17,6 +17,6 @@ impl Foo for S {
 }
 
 impl const Bar for S {}
-// FIXME(effects) bad span
+//~^ ERROR the trait bound
 
 fn main() {}
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail.stderr
index 9a907bbee0a..3870f0f722f 100644
--- a/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail.stderr
+++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits-fail.stderr
@@ -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`.
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits.rs
index fbe89b00b97..ff7349bba3c 100644
--- a/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits.rs
+++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits.rs
@@ -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)]
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits.stderr
deleted file mode 100644
index 5b6b39ee05e..00000000000
--- a/tests/ui/rfcs/rfc-2632-const-trait-impl/super-traits.stderr
+++ /dev/null
@@ -1,22 +0,0 @@
-error[E0277]: the trait bound `Foo::{synthetic#0}: ~const Compat` is not satisfied
-  --> $DIR/super-traits.rs:23:7
-   |
-LL |     t.a();
-   |       ^ the trait `~const Compat` is not implemented for `Foo::{synthetic#0}`
-   |
-note: required by a bound in `Foo::a`
-  --> $DIR/super-traits.rs:7:1
-   |
-LL | #[const_trait]
-   | ^^^^^^^^^^^^^^ required by this bound in `Foo::a`
-LL | trait Foo {
-LL |     fn a(&self);
-   |        - required by a bound in this associated function
-help: consider further restricting the associated type
-   |
-LL | const fn foo<T: ~const Bar>(t: &T) where Foo::{synthetic#0}: ~const Compat {
-   |                                    +++++++++++++++++++++++++++++++++++++++
-
-error: aborting due to 1 previous error
-
-For more information about this error, try `rustc --explain E0277`.