Skip to content

Impls for GAT-parameterized objects with bounds on specific instantation of GAT type result in incorrect mismatched type errors #106832

Description

@inanna-malick

Let me first say thank you for implementing GATs, and also apologize for the heinous haskell-brained madness you see before you. With that out of the way:

I tried to compile this code (https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=674f6412128946f9ef6abf6ddd15dcf7):

pub trait Functor {
    type Layer<X>;
}

pub trait FunctorExt: Functor {
    fn expand_and_collapse<In, Out>(
        seed: In,
        expand: impl Fn(In) -> <Self as Functor>::Layer<In>,
        collapse: impl Fn(<Self as Functor>::Layer<Out>) -> Out,
    ) -> Out;
}

impl<X> FunctorExt for X
where
    X: Functor,
{
    fn expand_and_collapse<In, Out>(
        seed: In,
        expand: impl Fn(In) -> <X as Functor>::Layer<In>,
        collapse: impl Fn(<X as Functor>::Layer<Out>) -> Out,
    ) -> Out {
        todo!()
    }
}

struct Repro<F>(std::marker::PhantomData<F>);

impl<F: Functor> Repro<F>
where
    // The following 'u8' ties the use of F::Layer in the repro fn to 'u8'
    // if this line is commented out, it compiles successfully
    F::Layer<u8>: Clone,
{
    fn repro(x: ()) {
        // there is no reason to expect 'F::Layer<u8>' here
        <F as FunctorExt>::expand_and_collapse(x, |x| todo!(), |_x| ());
    }

    // it works if you provide type annotation, although I do have a much more complex case
    // that I wasn't able to minimize where even type annotations don't fix the problem
    fn works(x: ()) {
        <F as FunctorExt>::expand_and_collapse(
            x,
            |x: ()| -> F::Layer<()> { todo!() },
            |_x: F::Layer<()>| -> () { () },
        );
    }
}

I expected it to compile.

Instead, it failed with

error[[E0308]](https://doc.rust-lang.org/stable/error-index.html#E0308): mismatched types
  --> src/lib.rs:37:69
   |
37 |         <F as FunctorExt>::expand_and_collapse(x, |x| todo!(), |_x| ());
   |                                                                     ^^ expected `u8`, found `()`

For more information about this error, try `rustc --explain E0308`.
error: could not compile `playground` due to previous error

Note: the F::Layer<u8>: Clone bound is not used anywhere in this code, and if that line is commented out, this code compiles.

Meta

The bug occurs in stable and nightly on play.rust-lang.org:
1.66.1
1.68.0-nightly

https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=674f6412128946f9ef6abf6ddd15dcf7

Metadata

Metadata

Assignees

Labels

A-GATsArea: Generic associated types (GATs)C-bugCategory: This is a bug.E-needs-testCall for participation: An issue has been fixed and does not reproduce, but no test has been added.T-typesRelevant to the types team, which will review and decide on the PR/issue.

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions