Skip to content

Lint for unintentionally using default trait implementations #14728

Open
@GnomedDev

Description

@GnomedDev

What it does

This lint would trigger when a trait such as std::hash::Hasher was implemented but relying on the slow delgated method (write) without implementing the performance improving specialised methods (write_u8).

I have thought of three ways for this lint to trigger:

  1. A restriction lint that the user has to enable for the specific impl block, called something like missing_overrides
  2. A pedantic lint which triggers when a trait implementation is delegating all the methods it has implemented, but some default methods are being provided.
  3. A pedantic lint which triggers when a trait impl block is relying on default implemented methods. This would be noisy and expect to be expected in quite a lot of places.

Advantage

  • Newtypes which are implementing traits via delegation do not miss out on the fast path implementations (ie: std::hash::Hasher)
  • Traits which default implementations just return errors don't accidentally turn a compile time issue to a runtime issue (ie: serde::de::Visitor)

Drawbacks

Method 1 would require knowledge of the lint to know to enable it, which probably means the user is going to implement all the default provided methods correctly anyway. Method 2 and 3 could be too noisy, even for pedantic.

Example

#![warn(clippy::pedantic)]

use std::hash::Hasher;

struct NewType(std::hash::DefaultHasher);

impl Hasher for NewType {
    fn write(&mut self, bytes: &[u8]) {
        self.0.write(bytes)
    }

    fn finish(&self) -> u64 {
        self.0.finish()
    }
}

Could be written as:

use std::hash::Hasher;

struct NewType(std::hash::DefaultHasher);

impl Hasher for NewType {
    fn write(&mut self, bytes: &[u8]) {
        self.0.write(bytes)
    }

    fn write_u8(&mut self, val: u8) {
        self.0.write_u8(val);
    }

    fn write_u16(&mut self, val: u16) {
        self.0.write_u16(val);
    }

    fn write_u32(&mut self, val: u32) {
        self.0.write_u32(val);
    }

    // etc, etc, etc

    fn finish(&self) -> u64 {
        self.0.finish()
    }
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    A-lintArea: New lints

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions