# Why I cannot compare two \`&'static str\`s in a const context?

**URL:** https://internals.rust-lang.org/t/why-i-cannot-compare-two-static-str-s-in-a-const-context/17726
**Category:** Uncategorized
**Created:** [November 10, 2022, 5:17pm UTC](https://internals.rust-lang.org/t/why-i-cannot-compare-two-static-str-s-in-a-const-context/17726 "2022-11-10T17:17:10Z")
**Posts on this page:** 9
**Page:** 1

<div class="post-metadata">

### Author: ![stackinspector](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/stackinspector/32/9487_2.png) [@stackinspector](https://internals.rust-lang.org/u/stackinspector)
#### Post date: [November 10, 2022, 5:17pm UTC](https://internals.rust-lang.org/t/why-i-cannot-compare-two-static-str-s-in-a-const-context/17726/1 "2022-11-10T17:17:10Z")

</div>

```rust
macro_rules! id_name_conv {
    ($($id:literal -> $name:literal)*) => {
        const fn id2name(id: u32) -> &'static str {
            match id {
                $($id => $name,)*
                _ => unreachable!(),
            }
        }

        const fn name2id(name: &'static str) -> u32 {
            match name {
                $($name => $id,)*
                _ => unreachable!(),
            }
        }
    };
}

id_name_conv!(
    0 -> "a"
    1 -> "b"
);

```

raises:

```rust
error[E0015]: calls in constant functions are limited to constant functions, tuple structs and tuple variants
  --> main.rs:13:23
   |
13 | $($name => $id,)*
   | ^^^^^
...
20 | / id_name_conv!(
21 | | 0 -> "a"
22 | | 1 -> "b"
23 | | );
   | | _____ - in this macro invocation
   |
   = note: this error originates in the macro `id_name_conv` (in Nightly builds, run with -Z macro-backtrace for more info)

error: aborting due to previous error

For more information about this error, try `rustc --explain E0015`.

```

After search I found [an open issue](https://github.com/rust-lang/rust/issues/90237), proves that the error is caused by comparing two `&'static str`s, and also mentions that comparing two `&'static [u8]`s is fine. Without getting into the confusing error reporting, is there any reason why this cannot be implemented?

---

<div class="post-metadata">

### Author: ![CAD97](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/cad97/32/3460_2.png) [@CAD97](https://internals.rust-lang.org/u/CAD97)
#### Post date: [November 10, 2022, 7:42pm UTC](https://internals.rust-lang.org/t/why-i-cannot-compare-two-static-str-s-in-a-const-context/17726/2 "2022-11-10T19:42:06Z")

</div>

> [@stackinspector](#):
>
> comparing two `&'static [u8]`s is fine

This isn't actually quite correct, as this is still a compile error:

```rust
const fn f(lhs: &'static [u8], rhs: &'static [u8]) -> bool { lhs == rhs }

```

```rust
error[E0277]: can't compare `[u8]` with `_` in const contexts
 --> src/lib.rs:1:66
  |
1 | const fn f(lhs: &'static [u8], rhs: &'static [u8]) -> bool { lhs == rhs }
  | ^^ no implementation for `[u8] == _`
  |
  = help: the trait `~const PartialEq<_>` is not implemented for `[u8]`
note: the trait `PartialEq<_>` is implemented for `[u8]`, but that implementation is not `const`
 --> src/lib.rs:1:66
  |
1 | const fn f(lhs: &'static [u8], rhs: &'static [u8]) -> bool { lhs == rhs }
  | ^^
  = note: required for `&[u8]` to implement `~const PartialEq<&_>`

```

(The error is clearer now than it used to be, although it's not ideal that it's referring to unstable `~const` syntax rather than just saying the trait implementation cannot be used in const contexts.)

It is interesting that it works in a `match`, though:

```rust
const X: &[u8] = b"";
const fn f(s: &'static [u8]) -> bool {
    match s {
        X => true,
        _ => false,
    }
}

```

AIUI the reason this occurs is because matching on `&str` goes through the `derive(PartialEq)` implementation, whereas matching on `&[_]` actually becomes a slice pattern instead, and the primitive matching on both slices and `u8` _can_ be used on `const` contexts as they don't go through `PartialEq`/`StructuralEq`.

You can see this in effect [on the playground](https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=f06caaf42620b1cc0a3755c6b67d7d08) by choosing to show MIR:

```rust
pub fn str(s: &'static str) -> bool {
    match s {
        "" => true,
        _ => false,
    }
}

pub fn u8s(s: &'static [u8]) -> bool {
    match s {
        b"" => true,
        _ => false,
    }
}

```

```rust
// WARNING: This output format is intended for human consumers only
// and is subject to change without notice. Knock yourself out.
// Editorialized by @CAD97
fn str(_s: &str) -> bool {
    let _return: bool;
    let _eq: bool; // tmp

    bb0: {
        _eq = <str as PartialEq>::eq(_s, const "") -> bb1;
    }

    bb1: {
        switchInt(move _eq) -> [false: bb2, otherwise: bb3];
    }

    bb2: {
        _return = const false;
        goto -> bb4;
    }

    bb3: {
        _return = const true;
        goto -> bb4;
    }

    bb4: {
        return;
    }
}

fn u8s(_s: &[u8]) -> bool {
    let _return: bool;
    let _len_s: usize;
    let _len_pat: usize;
    let _4: bool;

    bb0: {
        _len_s = Len((*_s));
        _len_pat = const 0_usize;
        _eq = Eq(move _len_s, move _len_pat);
        switchInt(move _4) -> [false: bb1, otherwise: bb2];
    }

    bb1: {
        _return = const false;
        goto -> bb3;
    }

    bb2: {
        _return = const true;
        goto -> bb3;
    }

    bb3: {
        return;
    }
}

```

---

<div class="post-metadata">

### Author: ![jhpratt](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/jhpratt/32/11640_2.png) [@jhpratt](https://internals.rust-lang.org/u/jhpratt)
#### Post date: [November 11, 2022, 2:50am UTC](https://internals.rust-lang.org/t/why-i-cannot-compare-two-static-str-s-in-a-const-context/17726/3 "2022-11-11T02:50:14Z")

</div>

> [@CAD97](#):
>
> The error is clearer now than it used to be, although it's not ideal that it's referring to unstable `~const` syntax rather than just saying the trait implementation cannot be used in const contexts.

To prevent duplication, I have already filed an issue about this.

> <https://github.com/rust-lang/rust/issues/103040>
>
> (\[playground\](https://play.rust-lang.org/?version=nightly&mode=debug&edition=202…1&gist=a3365f81cce126a3852fa1b9ee193a45))
> 
> \`\`\`rust
> \#!\[feature(const\_trait\_impl, const\_cmp)\]
> 
> pub struct MyInstant(pub std::time::Instant);
> 
> impl const PartialEq\<MyInstant\> for std::time::Instant {
> fn eq(&self, rhs: &MyInstant) -\> bool {
> self.eq(&rhs.0)
> }
> }
> \`\`\`
> 
> \`\`\`text
> error\[E0308\]: mismatched types
> --\> src/lib.rs:7:17
> |
> 7 | self.eq(&rhs.0)
> | -- ^^^^^^ expected struct \`MyInstant\`, found struct \`Instant\`
> | |
> | arguments to this function are incorrect
> |
> = note: expected reference \`&MyInstant\`
> found reference \`&Instant\`
> note: associated function defined here
> \`\`\`
> 
> This error is \_technically\_ correct, as the only const \`eq\` method on \`std::time::Instant\` is the one being written. However, it is quite misleading. \`&Instant\` \_is\_ the type that we want to accept as a parameter, with one caveat. \`Instant\` has to implement \`const PartialEq\`. It doesn't so the code shouldn't compile, but with a significantly different error message — ideally one pointing to that fact.
> 
> I have deliberately chosen \`Instant\` for this example because it is unlikely to ever implement \`const PartialEq\`. As such it can be used in tests without much concern.
> 
> For reference, the diagnostic is pretty much as expected (although still a bit suboptimal in my opinion) when not writing a trait method with the same name. (\[playground\](https://play.rust-lang.org/?version=nightly&mode=debug&edition=2021&gist=f574a4519434f0a5ebc7dc95ac96a393))
> 
> \`\`\`rust
> \#!\[feature(const\_trait\_impl, const\_cmp)\]
> 
> pub struct MyInstant(pub std::time::Instant);
> 
> pub const fn check\_equality(mine: MyInstant, theirs: std::time::Instant) -\> bool {
> theirs.eq(&mine.0)
> }
> \`\`\`
> 
> \`\`\`
> error\[E0277\]: can't compare \`Instant\` with \`\_\` in const contexts
> --\> src/lib.rs:6:15
> |
> 6 | theirs.eq(&mine.0)
> | -- ^^^^^^^ no implementation for \`Instant == \_\`
> | |
> | required by a bound introduced by this call
> |
> = help: the trait \`~const PartialEq\<\_\>\` is not implemented for \`Instant\`
> note: the trait \`PartialEq\<\_\>\` is implemented for \`Instant\`, but that implementation is not \`const\`
> --\> src/lib.rs:6:15
> |
> 6 | theirs.eq(&mine.0)
> | ^^^^^^^
> \`\`\`
> 
> @rustbot label +A-const-fn +A-diagnostics +D-confusing +F-const-trait-impl +T-compiler +requires-nightly

---

<div class="post-metadata">

### Author: ![Nugine](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/nugine/32/6957_2.png) [@Nugine](https://internals.rust-lang.org/u/Nugine)
#### Post date: [November 11, 2022, 12:55pm UTC](https://internals.rust-lang.org/t/why-i-cannot-compare-two-static-str-s-in-a-const-context/17726/4 "2022-11-11T12:55:01Z")

</div>

In fact, you can compare &str in a const context now. Const evaluation supports while-loop, comparing bytes and slice indexing.

[https://docs.rs/const-str/latest/const\_str/macro.equal.html](https://docs.rs/const-str/latest/const_str/macro.equal.html)

---

<div class="post-metadata">

### Author: ![stackinspector](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/stackinspector/32/9487_2.png) [@stackinspector](https://internals.rust-lang.org/u/stackinspector)
#### Post date: [November 11, 2022, 1:38pm UTC](https://internals.rust-lang.org/t/why-i-cannot-compare-two-static-str-s-in-a-const-context/17726/5 "2022-11-11T13:38:55Z")

</div>

Good job! But how to use it in `match`? We cannot impl PartialEq for primitive types.

---

<div class="post-metadata">

### Author: ![stackinspector](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/stackinspector/32/9487_2.png) [@stackinspector](https://internals.rust-lang.org/u/stackinspector)
#### Post date: [November 11, 2022, 1:40pm UTC](https://internals.rust-lang.org/t/why-i-cannot-compare-two-static-str-s-in-a-const-context/17726/6 "2022-11-11T13:40:43Z")

</div>

Seems that I have to generate `if`s. What the progress of impl it in std?

---

<div class="post-metadata">

### Author: ![Nugine](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/nugine/32/6957_2.png) [@Nugine](https://internals.rust-lang.org/u/Nugine)
#### Post date: [November 11, 2022, 1:58pm UTC](https://internals.rust-lang.org/t/why-i-cannot-compare-two-static-str-s-in-a-const-context/17726/7 "2022-11-11T13:58:41Z")

</div>

Maybe this: [https://github.com/rust-lang/rust/issues/67792](https://github.com/rust-lang/rust/issues/67792)

---

<div class="post-metadata">

### Author: ![stackinspector](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/stackinspector/32/9487_2.png) [@stackinspector](https://internals.rust-lang.org/u/stackinspector)
#### Post date: [November 11, 2022, 2:07pm UTC](https://internals.rust-lang.org/t/why-i-cannot-compare-two-static-str-s-in-a-const-context/17726/8 "2022-11-11T14:07:01Z")

</div>

My final code is like:

```rust
    const fn const_bytes_equal(lhs: &[u8], rhs: &[u8]) -> bool {
        if lhs.len() != rhs.len() {
            return false;
        }
        let mut i = 0;
        while i < lhs.len() {
            if lhs[i] != rhs[i] {
                return false;
            }
            i += 1;
        }
        true
    }
    
    const fn const_str_equal(lhs: &str, rhs: &str) -> bool {
        const_bytes_equal(lhs.as_bytes(), rhs.as_bytes())
    }

    macro_rules! id_name_conv {
        ($($id:literal -> $name:literal)*) => {
            const fn id2name(id: u32) -> &'static str {
                match id {
                    $($id => $name,)*
                    _ => unreachable!(),
                }
            }
    
            const fn name2id(name: &'static str) -> u32 {
                $(if const_str_equal(name, $name) {
                    return $id
                })*
                unreachable!();
            }
        };
    }
    
    id_name_conv!(
        0 -> "a"
        1 -> "b"
    );
    
    assert_eq!(id2name(0), "a");
    assert_eq!(name2id("b"), 1);

```

---

<div class="post-metadata">

### Author: ![system](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/system/32/14092_2.png) [@system](https://internals.rust-lang.org/u/system)
#### Post date: [February 9, 2023, 2:07pm UTC](https://internals.rust-lang.org/t/why-i-cannot-compare-two-static-str-s-in-a-const-context/17726/9 "2023-02-09T14:07:49Z")

</div>

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.
