Skip to content

const_trait_impl: investigate how to put Self: ~const Trait bounds in traits #92158

@fee1-dead

Description

@fee1-dead
Member

The predicates_of query currently inserts Self: Trait as a generic predicate for traits. This could become Self: ~const Trait and probably resolves some of the hackery around default_method_body_is_const. For example, we have explicitly allowed calling other methods inside the same trait for default_method_body_is_const bodies during const checking. If we had Self: ~const Trait as a caller bound then we don't need to explicitly allow this.

There is also another issue that would be resolved by this:

#![feature(const_trait_impl)]
#![feature(const_fn_trait_bound)]

pub trait Foo {
    #[default_method_body_is_const]
    fn do_stuff(self) where Self: Sized {
        do_stuff_as_foo(self);
    }
}

const fn do_stuff_as_foo<T: ~const Foo>(foo: T) {
    std::mem::forget(foo);
}

The snippet above currently fails to compile. If we had Self: ~const Foo then it would work.

The problem is that I tried doing this and there was a lot of mysterious errors. So I limited Self: ~const Trait to default_method_body_is_const methods. It compiled but some ui tests related to object safety fails after the change. Below is the diff of my current progress:

diff --git a/compiler/rustc_typeck/src/collect.rs b/compiler/rustc_typeck/src/collect.rs
index e7b728d491b..74ca462c470 100644
--- a/compiler/rustc_typeck/src/collect.rs
+++ b/compiler/rustc_typeck/src/collect.rs
@@ -1986,6 +1986,14 @@ fn predicates_defined_on(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericPredicate
 fn predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericPredicates<'_> {
     let mut result = tcx.predicates_defined_on(def_id);
 
+    if tcx.has_attr(def_id, sym::default_method_body_is_const) {
+        let span = rustc_span::DUMMY_SP;
+        result.predicates =
+            tcx.arena.alloc_from_iter(result.predicates.iter().copied().chain(std::iter::once((
+                ty::TraitRef::identity(tcx, tcx.parent(def_id).unwrap()).with_constness(ty::BoundConstness::ConstIfConst).to_predicate(tcx),
+                span,
+            ))));
+    }
     if tcx.is_trait(def_id) {
         // For traits, add `Self: Trait` predicate. This is
         // not part of the predicates that a user writes, but it
diff --git a/library/core/src/cmp.rs b/library/core/src/cmp.rs
index deed9901cc9..61d5352be2c 100644
--- a/library/core/src/cmp.rs
+++ b/library/core/src/cmp.rs
@@ -1243,7 +1243,8 @@ mod impls {
     macro_rules! partial_eq_impl {
         ($($t:ty)*) => ($(
             #[stable(feature = "rust1", since = "1.0.0")]
-            impl PartialEq for $t {
+            #[rustc_const_unstable(feature = "const_cmp", issue = "none")]
+            impl const PartialEq for $t {
                 #[inline]
                 fn eq(&self, other: &$t) -> bool { (*self) == (*other) }
                 #[inline]
@@ -1280,10 +1281,11 @@ impl Eq for $t {}
     macro_rules! partial_ord_impl {
         ($($t:ty)*) => ($(
             #[stable(feature = "rust1", since = "1.0.0")]
-            impl PartialOrd for $t {
+            #[rustc_const_unstable(feature = "const_cmp", issue = "none")]
+            impl const PartialOrd for $t {
                 #[inline]
                 fn partial_cmp(&self, other: &$t) -> Option<Ordering> {
-                    match (self <= other, self >= other) {
+                    match (*self <= *other, *self >= *other) {
                         (false, false) => None,
                         (false, true) => Some(Greater),
                         (true, false) => Some(Less),
@@ -1323,10 +1325,13 @@ fn partial_cmp(&self, other: &bool) -> Option<Ordering> {
     macro_rules! ord_impl {
         ($($t:ty)*) => ($(
             #[stable(feature = "rust1", since = "1.0.0")]
-            impl PartialOrd for $t {
+            #[rustc_const_unstable(feature = "const_cmp", issue = "none")]
+            impl const PartialOrd for $t {
                 #[inline]
                 fn partial_cmp(&self, other: &$t) -> Option<Ordering> {
-                    Some(self.cmp(other))
+                    Some(if *self < *other { Less }
+                        else if *self == *other { Equal }
+                        else { Greater })
                 }
                 #[inline]
                 fn lt(&self, other: &$t) -> bool { (*self) < (*other) }

Activity

fee1-dead

fee1-dead commented on Dec 21, 2021

@fee1-dead
MemberAuthor
self-assigned this
on Dec 23, 2021
oli-obk

oli-obk commented on Dec 23, 2021

@oli-obk
Contributor

Do you have the object safety failures handy? I'm guessing than non-const uses of the default method are now getting confused by the Self: ~const Trait bound's constness

fee1-dead

fee1-dead commented on Dec 23, 2021

@fee1-dead
MemberAuthor

I fixed this by changing the object safety checking code to use predicates_defined_on instead of predicates_of, I will make a PR in a moment.

added a commit that references this issue on May 30, 2022
added
A-const-evalArea: Constant evaluation, covers all const contexts (static, const fn, ...)
on Dec 1, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

A-const-evalArea: Constant evaluation, covers all const contexts (static, const fn, ...)F-const_trait_impl`#![feature(const_trait_impl)]`

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

    Participants

    @RalfJung@oli-obk@fee1-dead

    Issue actions

      `const_trait_impl`: investigate how to put `Self: ~const Trait` bounds in traits · Issue #92158 · rust-lang/rust