Skip to content

Function with impl trait in argument position does not see all impls of trait on value returned from function with impl trait in return position #59365

Closed

Description

@mwchase
struct A {}
struct B {}

trait Marker {}

impl Marker for A {}
impl Marker for B {}

trait Marked<M: Marker> {}

struct Singleton {}

impl<M: Marker> Marked<M> for Singleton {}

fn produce_a() -> impl Marked<A> {
    Singleton{}
}

fn produce_b() -> impl Marked<B> {
    Singleton{}
}

fn combine<M1: Marker, M2: Marker>(_t1: &impl Marked<M1>, _t2: &impl Marked<M2>) -> impl Marked<M1> + Marked<M2> {
    Singleton{}
}

fn consume_a(_: &impl Marked<A>) {}

fn main() {
    let an_a = produce_a();
    consume_a(&an_a);
    consume_a(&an_a);
    let a_b = produce_b();
    //consume_a(&a_b); // Errors, as hoped.
    let combined1 = combine(&a_b, &an_a);
    let combined2 = combine(&an_a, &a_b);
    consume_a(&combined1);
    consume_a(&combined2);
    let combined3 = combine(&combined1, &a_b);
    let combined4 = combine(&combined2, &a_b);
    consume_a(&combined3);
    //consume_a(&combined4); // Errors???
    println!("Hello, world!");
}

(Playground)

Output:

Hello, world!

Errors:

   Compiling playground v0.0.1 (/playground)
warning: unused variable: `combined4`
  --> src/main.rs:40:9
   |
40 |     let combined4 = combine(&combined2, &a_b);
   |         ^^^^^^^^^ help: consider using `_combined4` instead
   |
   = note: #[warn(unused_variables)] on by default

warning: struct is never constructed: `B`
 --> src/main.rs:2:1
  |
2 | struct B {}
  | ^^^^^^^^
  |
  = note: #[warn(dead_code)] on by default

    Finished dev [unoptimized + debuginfo] target(s) in 0.77s
     Running `target/debug/playground`

With the second commented line uncommented:

   Compiling playground v0.0.1 (/playground)
error[E0277]: the trait bound `impl Marked<B>+Marked<B>: Marked<A>` is not satisfied
  --> src/main.rs:42:5
   |
42 |     consume_a(&combined4); // Errors???
   |     ^^^^^^^^^ the trait `Marked<A>` is not implemented for `impl Marked<B>+Marked<B>`
   |
note: required by `consume_a`
  --> src/main.rs:27:1
   |
27 | fn consume_a(_: &impl Marked<A>) {}
   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

error: aborting due to previous error

For more information about this error, try `rustc --explain E0277`.
error: Could not compile `playground`.

To learn more, run the command again with --verbose.

I tested this across Stable, Beta, and Nightly in the playground, same behavior in all of them.

My intent with this code was to have a set of "markers" that could be associated with a type purely at a type-system level, with the actual implementation being a single concrete ZST. As the first commented-out line shows, this works in the simple case, but things get confused if you compose markers together multiple times.

Activity

  1. added
    A-impl-traitArea: `impl Trait`. Universally / existentially quantified anonymous types with static dispatch.
    on Mar 22, 2019
  2. istankovic commented on Oct 20, 2023

    @istankovic
    Contributor

    This seems to have been fixed. Tested with 1.73.

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-impl-traitArea: `impl Trait`. Universally / existentially quantified anonymous types with static dispatch.

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions