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

A lint to detect when a type implements all three of Hash, Borrow<str> and Borrow<[u8]> #11710

Closed
thomcc opened this issue Oct 25, 2023 · 2 comments · Fixed by #11781
Closed
Assignees
Labels
A-lint Area: New lints

Comments

@thomcc
Copy link
Member

thomcc commented Oct 25, 2023

What it does

Detects when a type which implements Hash also implements both Borrow<str> and Borrow<[u8]>.

Advantage

It's impossible to implement both of these correctly, as str and [u8] hash differently in incompatible ways, and implementing Borrow<T> for your type guaratees that you hash equivalent to T.

This is worth adding because this impl is tempting to add, as the distinction between Borrow and AsRef is very subtle, and the AsRef impl for both is correct (as is implementing both for types which do not implement Hash).

See BurntSushi/bstr#168 for some discussion (As this would not quite have caught the problem in that issue, it's possible my formulation of it is too narrow. For the most part, I am chucking this lint proposal over the wall, and am not tied to the specifics here).

Drawbacks

It's rather niche.

Example

impl Hash for MyType {
    // ...
}

impl Borrow<str> for MyType {
    // ...
}

impl Borrow<[u8]> for MyType {
    // ...
}

is wrong, either remove any one of those impls to be correct.

@thomcc thomcc added the A-lint Area: New lints label Oct 25, 2023
@m-rph
Copy link
Contributor

m-rph commented Nov 8, 2023

@rustbot claim

This looks interesting. I will give it a shot.

@m-rph
Copy link
Contributor

m-rph commented Nov 10, 2023

Maybe there should be another pedantic lint warning against implementing Borrow<T: Hash> and Hash unless the Hash impl calls borrow internally. Can this be identified?

Possibly another for implementation of Borrow<T:Hash> for multiple T warning that they should be identical.

This is a can of worms :D. I will do the special case for Borrow<str> and Borrow<[u8]> for now.

bors added a commit that referenced this issue Nov 19, 2023
Verify Borrow<T> semantics for types that implement Hash, Borrow<str> and Borrow<[u8]>.

Fixes #11710

The essence of the issue is that types that implement Borrow<T> provide a facet or a representation of the underlying type. Under these semantics `hash(a) == hash(a.borrow())`.

This is a problem when a type implements `Borrow<str>`, `Borrow<[u8]>` and Hash, it is expected that the hash of all three types is identical. The problem is that the hash of [u8] is not the same as that of a String, even when the byte reference ([u8]) is derived from `.as_bytes()`

- [x] Followed [lint naming conventions][lint_naming]
- [x] Added passing UI tests (including committed `.stderr` file)
- [x] `cargo test` passes locally
- [x] Executed `cargo dev update_lints`
- [x] Added lint documentation
- [x] Run `cargo dev fmt`

---

 - [x] Explanation of the issue in the code
 - [x] Tests reproducing the issue
 - [x] Lint rule and emission
@bors bors closed this as completed in 9c3a365 Nov 19, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-lint Area: New lints
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants