Skip to content

Lint for unnecessary impl in return value #10849

@mqudsi

Description

@mqudsi

What it does

Given an opaque (return? other?) type in a function signature by means of multiple impl ... [ + ..] declarations, a lint to catch that one trait automatically implies the other would go a long way to a) reduce verbosity and complexity of the return type definition, b) simplify the type hints for the returned value, c) simplify and make it easier to read the generated rustdoc.

To give a concrete example, clippy should complain on the following code:

fn foo<T>() -> impl Deref<Target = T> + DerefMut<Target = T> { 
    todo!();
}

complaining that DerefMut<Target = T> automatically implies Deref<Target = T>, and with --fix rewrite it to the following code:

fn foo<T>() -> impl DerefMut<Target = T> { 
    todo!();
}

I am humbled to be asked to provide a lint name and category for this and am filling out the form with just a suggestion as I am sure someone on the clippy team can come up with a better and more idiomatic name!

Lint Name

Superflous Impl

Category

complexity

Advantage

  • reduce verbosity and complexity of the return type definition,
  • simplify the type hints for the returned value,
  • simplify and make it easier to read the generated rustdoc.

Drawbacks

In the extremely unlikely case that a trait Foo currently requires implementing types to also implement Bar but a future version of Foo removes that requirement and the particular code returning the impl Foo + Bar in question explicitly wants to document/uphold that both Foo and Bar are implemented by the return type (rather than just Foo and incidentally Bar), when upstream is upgraded to Foo v2 the return type will no longer provide Bar. Without this change/lint, a compiler error would have been emitted that would have allowed catching that Bar is no longer implemented by the return type.

Example

fn foo<T>() -> impl Deref<Target = T> + DerefMut<Target = T> { 
    todo!();
}

complaining that DerefMut<Target = T> automatically implies Deref<Target = T>, and with --fix rewrite it to the following code:

fn foo<T>() -> impl DerefMut<Target = T> { 
    todo!();
}

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