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

Derive PartialOrd via Ord when deriving both on a concrete type #137459

Open
scottmcm opened this issue Feb 23, 2025 · 1 comment
Open

Derive PartialOrd via Ord when deriving both on a concrete type #137459

scottmcm opened this issue Feb 23, 2025 · 1 comment
Labels
C-optimization Category: An issue highlighting optimization opportunities or PRs implementing such I-heavy Issue: Problems and improvements with respect to binary size of generated code. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.

Comments

@scottmcm
Copy link
Member

scottmcm commented Feb 23, 2025

Today, if you do https://play.rust-lang.org/?version=nightly&mode=debug&edition=2024&gist=1ba35655ac2a5a415dc94df6a2b04988

#[derive(Copy, Clone)]
struct Foo(i32, u32);

it expands to

#[automatically_derived]
impl ::core::marker::Copy for Foo { }
#[automatically_derived]
impl ::core::clone::Clone for Foo {
    #[inline]
    fn clone(&self) -> Foo {
        let _: ::core::clone::AssertParamIsClone<i32>;
        let _: ::core::clone::AssertParamIsClone<u32>;
        *self
    }
}

That's wonderful -- it's simpler than a bunch of clone calls, and likely codegens better too.

However, if you try

#[derive(Ord, PartialOrd)]
struct Foo(i32, u32);

you just get

#[automatically_derived]
impl ::core::cmp::Ord for Foo {
    #[inline]
    fn cmp(&self, other: &Foo) -> ::core::cmp::Ordering {
        match ::core::cmp::Ord::cmp(&self.0, &other.0) {
            ::core::cmp::Ordering::Equal =>
                ::core::cmp::Ord::cmp(&self.1, &other.1),
            cmp => cmp,
        }
    }
}
#[automatically_derived]
impl ::core::cmp::PartialOrd for Foo {
    #[inline]
    fn partial_cmp(&self, other: &Foo)
        -> ::core::option::Option<::core::cmp::Ordering> {
        match ::core::cmp::PartialOrd::partial_cmp(&self.0, &other.0) {
            ::core::option::Option::Some(::core::cmp::Ordering::Equal) =>
                ::core::cmp::PartialOrd::partial_cmp(&self.1, &other.1),
            cmp => cmp,
        }
    }
}

which is unfortunate, because all those options take more time to compile and are harder for backends to optimize away.

It would be nice if, instead, it expanded to something like

#[automatically_derived]
impl ::core::cmp::Ord for Foo {
    #[inline]
    fn cmp(&self, other: &Foo) -> ::core::cmp::Ordering {
        match ::core::cmp::Ord::cmp(&self.0, &other.0) {
            ::core::cmp::Ordering::Equal =>
                ::core::cmp::Ord::cmp(&self.1, &other.1),
            cmp => cmp,
        }
    }
}
#[automatically_derived]
impl ::core::cmp::PartialOrd for Foo {
    #[inline]
    fn partial_cmp(&self, other: &Foo)
        -> ::core::option::Option<::core::cmp::Ordering> {
        let _: ::core::cmp::AssertParamIsPartialOrd<i32>;
        let _: ::core::cmp::AssertParamIsPartialOrd<u32>;
        Some(::core::cmp::Ord::cmp(self, other))
    }
}

Re-using the logic from Ord and making it easier for the optimizer to know that Foo::partial_cmp never actually returns None.

Like with Clone, this must only be done for fully concrete (non-generic) types, where the fact that Ord is also derived is enough to guarantee that we can call Ord from PartialOrd (as there will be a compiler error in the derived Ord if not).

@rustbot rustbot added the needs-triage This issue may need triage. Remove it if it has been sufficiently triaged. label Feb 23, 2025
@lolbinarycat lolbinarycat added T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. I-heavy Issue: Problems and improvements with respect to binary size of generated code. C-optimization Category: An issue highlighting optimization opportunities or PRs implementing such labels Feb 24, 2025
@jieyouxu jieyouxu removed the needs-triage This issue may need triage. Remove it if it has been sufficiently triaged. label Feb 26, 2025
@scottmcm
Copy link
Member Author

Thinking further, I don't know if the AssertParamIsPartialOrd is needed -- the Ord derive will use Ord on all the fields, which will make sure they're PartialOrd, and that might be sufficient.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
C-optimization Category: An issue highlighting optimization opportunities or PRs implementing such I-heavy Issue: Problems and improvements with respect to binary size of generated code. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.
Projects
None yet
Development

No branches or pull requests

4 participants