Skip to content

Surprising diagnostics about using const value in match pattern #92454

Closed
@djc

Description

@djc
Contributor

Given the following code (playground:

use std::borrow::Cow;

fn main() {
    let foo = Foo { inner: "foo".into() };
    println!("{}", match foo {
        FOO => "match",
        _ => "no"
    });
}

#[derive(PartialEq, Eq)]
struct Foo {
    inner: Cow<'static, str>,
}

const FOO: Foo = Foo { inner: Cow::Borrowed("foo") };

The current output is:

error: to use a constant of type `Cow` in a pattern, `Cow` must be annotated with `#[derive(PartialEq, Eq)]`
 --> src/main.rs:6:9
  |
6 |         FOO => "match",
  |         ^^^

Surprisingly to me at least, using a custom PartialEq implementation still results in the same issue (playground):

struct Foo {
    inner: Cow<'static, str>,
}

impl PartialEq for Foo {
    fn eq(&self, other: &Self) -> bool {
        self.inner.as_ref() == other.inner.as_ref()
    }
}

impl Eq for Foo {}

This seems pretty unclear:

  • Why is the compiler telling me I should derive PartialEq for Cow when I'm comparing matching against Foo?
  • Why is the compiler telling me to derive PartialEq instead of having a custom impl?

I don't know exactly what kind of contract match depends on, but I would have thought any kind of PartialEq impl (that is, even non-const) would be enough here.

Original issue here: open-telemetry/opentelemetry-rust#685. This also links to a potential fix in sfackler/rust-postgres@05a0643 (involving adding another layer of indirection), but I'd really like to understand why that is even necessary.

(To be clear: the diagnostic is unclear here, but maybe there's an actual compiler problem here, too?)

cc @estebank

Activity

added
A-diagnosticsArea: Messages for errors, warnings, and lints
T-compilerRelevant to the compiler team, which will review and decide on the PR/issue.
on Dec 31, 2021
fee1-dead

fee1-dead commented on Dec 31, 2021

@fee1-dead
Member

This is because Cow is not "StructualEq" (because it compares the borrowed version only and it is possible for Cow::Owned to be equal to a Cow::Borrowed) so constants of that type cannot be used in matches. I do believe the diagnostic should be improved.

cc @rust-lang/wg-const-eval

djc

djc commented on Dec 31, 2021

@djc
ContributorAuthor

@fee1-dead that's helpful, my intuition was that it had something to do with const stuff.

Still, it seems this story is still really hard to explain:

  • So the type actually has to be StructuralEq?
  • And you can only be StructuralEq if you derive Eq?
  • But if I derive Eq and keep my custom PartialEq, that's not sufficient either

This all seems really weird because apparently StructuralEq is not just a trait implemented by a type but also something that must be present for all of its inner types... or something?

RalfJung

RalfJung commented on Jan 1, 2022

@RalfJung
Member

StructuralEq is kind of a mess currently and something we want to clean up. Also see #74446.

djc

djc commented on Jan 1, 2022

@djc
ContributorAuthor

Okay, but then we should definitely improve diagnostics such that the messiness from an unstable filter leak out into stable Rust via crappy errors (especially as there seems to be no clear/fast path towards stabilization).

raphaelcohn

raphaelcohn commented on Apr 20, 2022

@raphaelcohn

Just took an hour googling to end up here with the same error message. Anything that at least adds a bit more information (eg 'can not be structurally equal' or includes a compiler error number) would be much appreciated.

RalfJung

RalfJung commented on Nov 15, 2023

@RalfJung
Member

I don't know exactly what kind of contract match depends on, but I would have thought any kind of PartialEq impl (that is, even non-const) would be enough here.

The error explicitly says #[derive(PartialEq, Eq)]. So it doesn't explain why, but it does explain that your assumption here is wrong.

See rust-lang/lang-team#220 for some recent discussion of the subject. The current plan is to keep this a hard error.

estebank

estebank commented on Jan 11, 2025

@estebank
Contributor

Current output:

error: constant of non-structural type `Cow<'_, str>` in a pattern
   --> src/main.rs:6:9
    |
6   |         FOO => "match",
    |         ^^^ constant of non-structural type
...
16  | const FOO: Foo = Foo { inner: Cow::Borrowed("foo") };
    | -------------- constant defined here
    |
   ::: /playground/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/alloc/src/borrow.rs:179:1
    |
179 | pub enum Cow<'a, B: ?Sized + 'a>
    | -------------------------------- `Cow<'_, str>` must be annotated with `#[derive(PartialEq)]` to be usable in patterns
    |
    = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralPartialEq.html for details
error: constant of non-structural type `Foo` in a pattern
  --> src/main.rs:6:9
   |
6  |         FOO => "match",
   |         ^^^ constant of non-structural type
...
11 | struct Foo {
   | ---------- `Foo` must be annotated with `#[derive(PartialEq)]` to be usable in patterns
...
21 | const FOO: Foo = Foo { inner: Cow::Borrowed("foo") };
   | -------------- constant defined here
   |
note: the `PartialEq` trait must be derived, manual `impl`s are not sufficient; see https://doc.rust-lang.org/stable/std/marker/trait.StructuralPartialEq.html for details
  --> src/main.rs:15:1
   |
15 | impl PartialEq for Foo {
   | ^^^^^^^^^^^^^^^^^^^^^^
added a commit that references this issue on Jan 11, 2025

Auto merge of rust-lang#135360 - RalfJung:structural-partial-eq, r=co…

added a commit that references this issue on Mar 11, 2025

Auto merge of rust-lang#135360 - RalfJung:structural-partial-eq, r=co…

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    A-diagnosticsArea: Messages for errors, warnings, and lintsT-compilerRelevant to the compiler team, which will review and decide on the PR/issue.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

      Development

      Participants

      @djc@RalfJung@raphaelcohn@estebank@fee1-dead

      Issue actions

        Surprising diagnostics about using const value in match pattern · Issue #92454 · rust-lang/rust