Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

GAT with HRTB yields weird inference errors. #96750

Open
aliemjay opened this issue May 6, 2022 · 5 comments
Open

GAT with HRTB yields weird inference errors. #96750

aliemjay opened this issue May 6, 2022 · 5 comments
Labels
A-GATs Area: Generic associated types (GATs) A-higher-ranked Area: Higher-ranked things (e.g., lifetimes, types, trait bounds aka HRTBs) A-inference Area: Type inference A-lifetimes Area: Lifetimes / regions A-trait-system Area: Trait system fixed-by-next-solver Fixed by the next-generation trait solver, `-Znext-solver`. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.

Comments

@aliemjay
Copy link
Member

aliemjay commented May 6, 2022

I tried this code: (playground)

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

trait AsyncFn<Arg> { type Output; }
trait RequestFamily { type Type<'a>; }
trait Service {}

struct MyFn;
impl AsyncFn<String> for MyFn { type Output = (); }

impl RequestFamily for String { type Type<'a> = String; }

struct ServiceFromAsyncFn<F, Req>(F, PhantomData<Req>);

impl<F, Req, O> Service for ServiceFromAsyncFn<F, Req>
where
    Req: RequestFamily,
    F: AsyncFn<Req>,
    F: for<'a> AsyncFn<Req::Type<'a>, Output = O>,
{
}

fn assert_service() -> impl Service {
    ServiceFromAsyncFn(MyFn, PhantomData)
}

It fails type inference with the following error:

error[E0282]: type annotations needed
  --> src/lib.rs:23:24
   |
23 | fn assert_service() -> impl Service {
   |                        ^^^^^^^^^^^^ cannot infer type for type parameter `O`

This is super weird because type paramters that don't appear in Self type of the impl are not expected to fail inference.
Surprisingly, removing O makes it pass:

-impl<F, Req, O> Service for ServiceFromAsyncFn<F, Req>
+impl<F, Req> Service for ServiceFromAsyncFn<F, Req>
 where
     Req: RequestFamily,
     F: AsyncFn<Req>,
-    F: for<'a> AsyncFn<Req::Type<'a>, Output = O>,
+    F: for<'a> AsyncFn<Req::Type<'a>>,

Meta

Nightly version: 1.62.0-nightly

(2022-05-03 e1b71fe)

@rustbot label F-generic_associated_types T-compiler A-traits A-inference A-lifetimes

@aliemjay aliemjay added the C-bug Category: This is a bug. label May 6, 2022
@rustbot rustbot added A-inference Area: Type inference A-lifetimes Area: Lifetimes / regions A-trait-system Area: Trait system F-generic_associated_types `#![feature(generic_associated_types)]` a.k.a. GATs T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. labels May 6, 2022
@compiler-errors
Copy link
Member

compiler-errors commented May 6, 2022

It also compiles if we do:

fn assert_service() -> impl Service {
-   ServiceFromAsyncFn(MyFn, PhantomData)
+   ServiceFromAsyncFn(MyFn, PhantomData::<String>)
}

edit: specifying the generic in the ServiceFromAsyncFn also does the same thing

@compiler-errors
Copy link
Member

Also like most GAT issues, this seems to be an general underlying higher-kinded + associated types issue:

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

trait AsyncFn<Arg> { type Output; }
trait RequestFamily<'a> { type Type; }
trait Service {}

struct MyFn;
impl AsyncFn<String> for MyFn { type Output = (); }

impl RequestFamily<'_> for String { type Type = String; }

struct ServiceFromAsyncFn<F, Req>(F, PhantomData<Req>);

impl<F, Req, O> Service for ServiceFromAsyncFn<F, Req>
where
    Req: for<'a> RequestFamily<'a>,
    F: AsyncFn<Req>,
    F: for<'a> AsyncFn<<Req as RequestFamily<'a>>::Type, Output = O>,
{
}

fn assert_service() -> impl Service {
    ServiceFromAsyncFn(MyFn, PhantomData)
}

Also fails 😅

@aliemjay
Copy link
Member Author

aliemjay commented May 6, 2022

Prior to #90887, this code is rejected as some form of HRTB projections bugs.

At present it is accepted with the following limitations:

It's not even obvious if the PR #90887 was intended to fix this use case!

@compiler-errors
Copy link
Member

I'm actually surprised that this continues to be ambiguous even after #90887. I have been somewhat out of commission this past week, but I may find some time soon to investigate why this inference issue still persists.

@aliemjay
Copy link
Member Author

aliemjay commented May 6, 2022

FWIW using Fn instead of AsyncFn works unconditionally even when swapping the order of the last two bounds:

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

trait RequestFamily { type Type<'a>; }
trait Service {}

impl RequestFamily for String { type Type<'a> = String; }

struct ServiceFromAsyncFn<F, Req>(F, PhantomData<Req>);

impl<F, Req, O, O2> Service for ServiceFromAsyncFn<F, Req>
where
    Req: RequestFamily,
    F: Fn(Req) -> O2,
    F: for<'a> Fn(Req::Type<'a>) -> O,
{
}

fn assert_service() -> impl Service {
    fn my_fn(_: String) {}
    ServiceFromAsyncFn(my_fn, PhantomData)
}

@compiler-errors compiler-errors added the fixed-by-next-solver Fixed by the next-generation trait solver, `-Znext-solver`. label Mar 13, 2023
@fmease fmease added A-GATs Area: Generic associated types (GATs) A-higher-ranked Area: Higher-ranked things (e.g., lifetimes, types, trait bounds aka HRTBs) and removed C-bug Category: This is a bug. F-generic_associated_types `#![feature(generic_associated_types)]` a.k.a. GATs labels Sep 24, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-GATs Area: Generic associated types (GATs) A-higher-ranked Area: Higher-ranked things (e.g., lifetimes, types, trait bounds aka HRTBs) A-inference Area: Type inference A-lifetimes Area: Lifetimes / regions A-trait-system Area: Trait system fixed-by-next-solver Fixed by the next-generation trait solver, `-Znext-solver`. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.
Projects
None yet
Development

No branches or pull requests

4 participants