rust-lang / rust-lang/rust

Refining generic bounds in trait method

Open
#129,251 4 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

A-trait-system C-discussion T-lang T-types
Dominant language
Rust
Stars
119k
Forks
16.1k
PR merge metrics
PR metrics pending

Description

This issue documents an aspect of #100706 (refined trait implementations) that to my knowledge has not been previously discussed or documented: refining generic bounds on trait methods.

It also documents the current rustc behavior, which seems to be quite surprising based on conversations I've had with a half dozen very experienced Rustaceans.

Code example

Consider the following setup in a fictional upstream crate:

pub trait Super {}

mod private {
    pub trait Marker: super::Super {}
}

pub trait Subject {
    fn method<IM: private::Marker>(&self);
}

In this case, rustc allows both of the following generic type refinements with no errors or warnings:

struct First;
impl upstream::Subject for First {
    fn method<IM: upstream::Super>(&self) {}
}

struct Second;
impl upstream::Subject for Second {
    fn method<IM>(&self) {}
}

playground

Surprising current behavior

In the above code, First refines the generic bound from IM: upstream::private::Marker to IM: upstream::Super, a supertype of Marker. Second refines the bound away completely, allowing any type.

It's quite surprising that a bare <IM> generic is accepted! It's completely unused and trivially satisfied, and unbounded generics are usually not accepted elsewhere in Rust. Consider for example that PhantomData marker fields must be added if a type declares, but does not use, a generic type.

Relying on the refinement fails at point of use, not declaration

Attempting to rely on either refinement when calling the refined function fail with the trait bound '<type>: Marker' is not satisfied errors:

fn use_first() {
    <First as upstream::Subject>::method::<()>(&First);
}

impl upstream::Super for () {}
fn use_second() {
    <Second as upstream::Subject>::method::<()>(&Second);
}

playground

A warning similar to the one for refined return types (impl trait in impl method signature does not match trait method signature) would be good. An example of that warning can be seen in this playground link.

Related to #121718, #100706

@rustbot label +F-refine +T-lang

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

Reproduce the two generic-bound refinement examples using the linked Rust Playground cases and compare their behavior with the refined return-type warning example. Read related issues #121718 and #100706 to understand the intended refinement rules. Done means reaching agreement on whether these refinements should produce a diagnostic and documenting or testing that behavior.

Written by the indexing model from the issue text.

Assessment

Tech stack
rust
Domain
compilers
Issue type
Feature
Difficulty
5/5
Estimated time
Over a week
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.