Skip to content

Failed to unify types when using GATs and HRTBs #93341

Closed
@reinerp

Description

@reinerp

I believe the following code should typecheck under nightly (https://play.rust-lang.org/?version=nightly&mode=debug&edition=2021&gist=f3d45f199cadea62341a727f66c52d86):

#![feature(generic_associated_types)]
use std::marker::PhantomData;

struct Id<'id>(PhantomData<fn(&'id ()) -> &'id ()>);

fn new_id() -> Id<'static> {
    Id(PhantomData)
}

pub trait HasLifetime where {
    type AtLifetime<'a>;
}

pub struct ExistentialLifetime<S: HasLifetime>(S::AtLifetime<'static>);

impl<S: HasLifetime> ExistentialLifetime<S> {
    pub fn new<F>(f: F) -> ExistentialLifetime<S>
        where for<'id> F: FnOnce(Id<'id>) -> S::AtLifetime<'id> {
        ExistentialLifetime(f(new_id()))
    }
}


struct ExampleS<'id>(Id<'id>);

struct ExampleMarker;

impl HasLifetime for ExampleMarker {
    type AtLifetime<'id> = ExampleS<'id>;
}


fn broken0() -> ExistentialLifetime<ExampleMarker> {
    fn new_helper<'id>(id: Id<'id>) -> ExampleS<'id> {
        ExampleS(id)
    }

    ExistentialLifetime::<ExampleMarker>::new(new_helper)
}

fn broken1() -> ExistentialLifetime<ExampleMarker> {
    fn new_helper<'id>(id: Id<'id>) -> <ExampleMarker as HasLifetime>::AtLifetime<'id> {
        ExampleS(id)
    }

    ExistentialLifetime::<ExampleMarker>::new(new_helper)
}

fn broken2() -> ExistentialLifetime<ExampleMarker> {
    ExistentialLifetime::<ExampleMarker>::new(|id| ExampleS(id))
}

Note that this uses generic associated types (AtLifetime<'a>) and it also uses a higher-rank trait bound in fn new.

However, rustc nightly rejects this program with the following error:

 Compiling playground v0.0.1 (/playground)
error[E0271]: type mismatch resolving `for<'id> <for<'id> fn(Id<'id>) -> ExampleS<'id> {broken0::new_helper} as FnOnce<(Id<'id>,)>>::Output == <ExampleMarker as HasLifetime>::AtLifetime<'id>`
  --> src/lib.rs:38:5
   |
38 |     ExistentialLifetime::<ExampleMarker>::new(new_helper)
   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected associated type, found struct `ExampleS`
   |
   = note: expected associated type `<ExampleMarker as HasLifetime>::AtLifetime<'_>`
                       found struct `ExampleS<'_>`
   = help: consider constraining the associated type `<ExampleMarker as HasLifetime>::AtLifetime<'_>` to `ExampleS<'_>` or calling a method that returns `<ExampleMarker as HasLifetime>::AtLifetime<'_>`
   = note: for more information, visit https://doc.rust-lang.org/book/ch19-03-advanced-traits.html
note: required by a bound in `ExistentialLifetime::<S>::new`
  --> src/lib.rs:18:46
   |
17 |     pub fn new<F>(f: F) -> ExistentialLifetime<S>
   |            --- required by a bound in this
18 |         where for<'id> F: FnOnce(Id<'id>) -> S::AtLifetime<'id> {
   |                                              ^^^^^^^^^^^^^^^^^^ required by this bound in `ExistentialLifetime::<S>::new`

error[E0271]: type mismatch resolving `for<'id> <for<'id> fn(Id<'id>) -> <ExampleMarker as HasLifetime>::AtLifetime<'id> {broken1::new_helper} as FnOnce<(Id<'id>,)>>::Output == <ExampleMarker as HasLifetime>::AtLifetime<'id>`
  --> src/lib.rs:46:5
   |
46 |     ExistentialLifetime::<ExampleMarker>::new(new_helper)
   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected associated type, found struct `ExampleS`
   |
   = note: expected associated type `<ExampleMarker as HasLifetime>::AtLifetime<'_>`
                       found struct `ExampleS<'_>`
   = help: consider constraining the associated type `<ExampleMarker as HasLifetime>::AtLifetime<'_>` to `ExampleS<'_>` or calling a method that returns `<ExampleMarker as HasLifetime>::AtLifetime<'_>`
   = note: for more information, visit https://doc.rust-lang.org/book/ch19-03-advanced-traits.html
note: required by a bound in `ExistentialLifetime::<S>::new`
  --> src/lib.rs:18:46
   |
17 |     pub fn new<F>(f: F) -> ExistentialLifetime<S>
   |            --- required by a bound in this
18 |         where for<'id> F: FnOnce(Id<'id>) -> S::AtLifetime<'id> {
   |                                              ^^^^^^^^^^^^^^^^^^ required by this bound in `ExistentialLifetime::<S>::new`

error[E0271]: type mismatch resolving `for<'id> <[closure@src/lib.rs:50:47: 50:64] as FnOnce<(Id<'id>,)>>::Output == <ExampleMarker as HasLifetime>::AtLifetime<'id>`
  --> src/lib.rs:50:5
   |
50 |     ExistentialLifetime::<ExampleMarker>::new(|id| ExampleS(id))
   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected associated type, found struct `ExampleS`
   |
   = note: expected associated type `<ExampleMarker as HasLifetime>::AtLifetime<'_>`
                       found struct `ExampleS<'_>`
   = help: consider constraining the associated type `<ExampleMarker as HasLifetime>::AtLifetime<'_>` to `ExampleS<'_>` or calling a method that returns `<ExampleMarker as HasLifetime>::AtLifetime<'_>`
   = note: for more information, visit https://doc.rust-lang.org/book/ch19-03-advanced-traits.html
note: required by a bound in `ExistentialLifetime::<S>::new`
  --> src/lib.rs:18:46
   |
17 |     pub fn new<F>(f: F) -> ExistentialLifetime<S>
   |            --- required by a bound in this
18 |         where for<'id> F: FnOnce(Id<'id>) -> S::AtLifetime<'id> {
   |                                              ^^^^^^^^^^^^^^^^^^ required by this bound in `ExistentialLifetime::<S>::new`

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

I think rustc is wrong to reject this code. As you can see, it fails to unify type <ExampleMarker as HasLifetime>::AtLifetime<'_> with type ExampleS<'_>. But these types should unify!

Version of rustc: 1.60.0-nightly 2022-01-25 8cdb3cd94efece1e17cb.

Metadata

Metadata

Labels

A-GATsArea: Generic associated types (GATs)C-bugCategory: This is a bug.F-generic_associated_types`#![feature(generic_associated_types)]` a.k.a. GATs

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions