Skip to content

refining_impl_trait only fires on public traits #119535

Open
@tmandry

Description

@tmandry
Member

The refining_impl_trait lint only fires for public traits. It does not fire without the pub keyword in the code sample below:

pub trait Foo {
//^ Required for lint to fire
    fn foo(self) -> impl Debug;
}

impl Foo for u32 {
    fn foo(self) -> String {
//                  ^^^^^^
//  warning: impl trait in impl method signature does not match trait method signature
        self.to_string()
    }
}

Difference from async_fn_in_trait lint

Apparently I was part of the discussion of this at one point (see also the zulip topic on this). I think it got lumped together with the discussion about the lint for async fn in traits, though, when there are some important distinctions:

  • The async fn lint is only temporary to help avoid footguns created by missing language features, and we want to make non-footgunny uses more convenient.
  • Refinement is a mechanism that will always exist and is fundamental to trait implementations.
  • Refinement's ability to "punch through" abstraction boundaries can happen accidentally, even within a crate.

The second point is important, because as a user I would expect such a fundamental mechanism to behave independently of whether the trait happens to be crate-public or not. This can lead to false expectations being created about the behavior in the other case.

Violating abstraction boundaries within a crate

As an example of the last point, let's say I as a user want to define a trait that my type implements ahead of actually generalizing my code:

trait Application {
    fn windows(&self) -> Vec<impl Window>;
}
trait Window {
    fn title(&self) -> Option<String>;
}

struct App;
struct Win;

impl Application for App {
    fn windows(&self) -> Vec<Win> { todo!() }
}
impl Window for Win {
    fn title(&self) -> Option<String> { todo!() }
}

fn all_windows(apps: &[App]) -> Vec<Win> {
    apps.iter().map(|a| a.windows()).flatten().collect()
}

Later on, I want to write a test for all_windows. But in order to do that, I have to change it to accept impl Application, which requires changing the output type to impl Window + '_, and possibly changing all the users of all_windows as well. This can get unwieldy quick.

We can say that the user should have used impl Trait from the beginning, but that might be inconvenient when prototyping. If they are leaning on traits to provide the outlines of an abstraction boundary, we should let them opt in before punching through said boundary, IMO.

cc @compiler-errors

Activity

added
needs-triageThis issue may need triage. Remove it if it has been sufficiently triaged.
on Jan 3, 2024
added
A-lintsArea: Lints (warnings about flaws in source code) such as unused_mut.
T-langRelevant to the language team
I-lang-nominatedNominated for discussion during a lang team meeting.
F-refine`#![feature(refine)]`; RFC #3245
and removed
needs-triageThis issue may need triage. Remove it if it has been sufficiently triaged.
on Jan 3, 2024
traviscross

traviscross commented on Jan 25, 2024

@traviscross
Contributor

@rustbot labels -I-lang-nominated

We discussed this today in triage and developed a consensus to:

  • Add a separate lint against impls that refine a return type defined with RPITIT even when the trait is not crate public.
  • Place that in a lint group along with the analogous crate public lint.
  • Create an issue to solicit feedback on these lints (or perhaps two separate ones).
  • Have the warnings displayed with each lint reference this issue in a similar manner to how we do that today with the required Self: '0' bound on GATs.
  • Make a note to review this feedback on 2-3 release cycles.
removed
I-lang-nominatedNominated for discussion during a lang team meeting.
on Jan 25, 2024
added a commit that references this issue on Mar 16, 2024

Rollup merge of rust-lang#121720 - tmandry:split-refining, r=compiler…

0995508
added a commit that references this issue on Mar 17, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    A-lintsArea: Lints (warnings about flaws in source code) such as unused_mut.A-trait-systemArea: Trait systemF-refine`#![feature(refine)]`; RFC #3245F-return_position_impl_trait_in_trait`#![feature(return_position_impl_trait_in_trait)]`T-langRelevant to the language team

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

      Development

      No branches or pull requests

        Participants

        @traviscross@tmandry@rustbot

        Issue actions

          `refining_impl_trait` only fires on public traits · Issue #119535 · rust-lang/rust