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

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

Closed
fee1-dead opened this issue Dec 21, 2021 · 3 comments
Closed
Assignees
Labels
A-const-fn Area: const fn foo(..) {..}. Pure functions which can be applied at compile time. F-const_trait_impl `#![feature(const_trait_impl)]`

Comments

@fee1-dead
Copy link
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) }
@fee1-dead fee1-dead added A-const-fn Area: const fn foo(..) {..}. Pure functions which can be applied at compile time. F-const_trait_impl `#![feature(const_trait_impl)]` labels Dec 21, 2021
@fee1-dead
Copy link
Member Author

cc @oli-obk

@fee1-dead fee1-dead self-assigned this Dec 23, 2021
@oli-obk
Copy link
Contributor

oli-obk commented Dec 23, 2021

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
Copy link
Member Author

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.

bors added a commit to rust-lang-ci/rust that referenced this issue May 30, 2022
…rrors

Replace `#[default_method_body_is_const]` with `#[const_trait]`

pulled out of rust-lang#96077

related issues:  rust-lang#67792 and rust-lang#92158

cc `@fee1-dead`

This is groundwork to only allowing `impl const Trait` for traits that are marked with `#[const_trait]`. This is necessary to prevent adding a new default method from becoming a breaking change (as it could be a non-const fn).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-const-fn Area: const fn foo(..) {..}. Pure functions which can be applied at compile time. F-const_trait_impl `#![feature(const_trait_impl)]`
Projects
None yet
2 participants