rust-lang / rust-lang/rust-clippy

New lint: types implementing `Deref` should impl `AsRef<Self::Target>` and `Borrow<Self::Target>` (same with mut versions)

Open
#9,346 1 comment 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

A-lint
Dominant language
Rust
Stars
13.5k
Forks
2.2k
Avg merge
2d 10h
Merged PRs (30d)
32

Description

What it does

If a type implements Deref but does not implement AsRef<<Self as Deref>::Target> and Borrow<<Self as Deref>::Target> or the type implements DerefMut and is missing AsMut or BorrowMut for Target the lint warns about the missing implementations.

The lint suggestion should be machine-applicable.

Lint Name

deref_missing_as_ref_borrow

Category

style

Advantage
  • Smart pointers in Rust usually have those traits implemented and implementing them is keeping things consistent.
  • In generic code it is often better to use AsRef/Borrow bounds (or their mut versions) rather than Deref. Some types implement AsRef for multiple return types - e.g. &str can be treated as bytes. Borrow bound allows treating T and &T the same. Without these traits implemented the smart pointer can not be used in such generic code.
Drawbacks

T: Borrow<U> has an additional restriction that, if implemented, {Partial}Eq, {Partial}Ord, and Hash of U are homomorphic with their implementations on T. It could be the case that the trait is deliberately not implemented because this restriction cannot be satifsfied. The lint could somehow try to take it into account (e.g. try to figure out if the impl just delegates to U) or an argument could be made that a such type should not impl Deref because of potential confusion - functions like sort_by_key could behave differently just because of (de)reference operators. Maybe a different lint should warn about that.

Example
pub struct MySmartPtr<T> {
    ptr: *const T,
}

impl<T> Deref for MySmartPtr<T> {
    type Target = T;

    fn deref(&self) -> &Self::Target {
         unsafe { &*self.ptr }
    }
}

// AsRef<T>, Borrow<T> missing

Could be written as:

```rust
pub struct MySmartPtr<T> {
    ptr: *const T,
}

impl<T> Deref for MySmartPtr<T> {
    type Target = T;

    fn deref(&self) -> &Self::Target {
         unsafe { &*self.ptr }
    }
}

impl<T> AsRef<T> for MySmartPtr<T> {
    fn as_ref(&self) -> &T {
        &*self
    }
}

impl<T> Borrow<T> for MySmartPtr<T> {
    fn borrow(&self) -> &T {
        &*self
    }
}

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

The issue names the proposed deref_missing_as_ref_borrow lint but does not identify implementation files or tests. Start by locating existing Clippy lint implementations and their registration and UI-test patterns, then assess how the stated Deref and DerefMut cases and machine-applicable suggestions fit those patterns; done means the lint behavior and diagnostic suggestions are covered by tests.

Written by the indexing model from the issue text.

Assessment

Tech stack
rust
Domain
tooling
Issue type
Feature
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.