Open audunhalland opened 2 years ago
@rustbot label: +F-generic_associated_types
This is not really a GATs issue. It's an issue with associated types that have higher-ranked lifetimes in general [playground].
use std::fmt::Debug;
trait Trait<'a> {
type Assoc;
}
impl<'a> Trait<'a> for () {
type Assoc = ();
}
fn bad<T>(_: T)
where
for<'a> T: Trait<'a>,
for<'a> <T as Trait<'a>>::Assoc: Debug,
{
}
fn main() {
bad(());
}
Technical description of the issue follows:
So we typecheck that function call in two steps:
FnCtxt::instantiate_value_path
. This registers the where-clause bounds of the function.FnCtxt::check_call
. This infers the type _
based on the type signature and the arguments.Importantly, we actually register the where-clause bounds on the function during (1.) instead of (2.)
Since we haven't inferred the generic type T
at step (1.), and still have a type variable in the generics of the call, we end up registering something like for<'a> <_ as Trait<'a>>::Assoc: Debug
. The fact that's a higher-ranked predicate is important as well, since we don't end up replacing that projection type it with a fresh type variable like we would with a projection that does not have escaping bound vars.
The issue happens when we call FnCtxt::structurally_resolved_type
inside FnCtxt::check_call
, which calls select_where_possible
downstream. We then try to select for<'a> <_ as Trait<'a>>::Assoc: Debug
. Since Debug
has no impls which match the self type <_ as Trait<'a>>::Assoc
, it fails to satisfy the obligation, leading to the issue.
I can't think of any good solutions off the top of my head. This ties back down to the problems we have with higher-ranked lifetimes in projection types. I guess we could solve this by doing something like treating an obligation with higher-ranked lifetimes in projections (and infer variables) as ambiguous... but that seems hacky.
I guess we could solve this by doing something like treating an obligation with higher-ranked lifetimes in projections (and infer variables) as ambiguous... but that seems hacky.
This hack does fix the issue. See https://github.com/compiler-errors/rust/commit/5d785d5e3deb25b1d6d81a30035bd0ddd15fd130 -- but I won't actually put it up as a PR and refining it unless someone like @jackh726 thinks it's worthwhile, lol. Anywho, I don't think should be GATs blocking.
This is #89196. I haven't thought about how to fix this, really.
Even though not directly GAT-related, I think this bug will influence how API design is done around GAT traits, as library developers often put in some effort to avoid a required turbofish.
I tried this code:
I expected to see this happen: It compiles
Instead, this happened: It fails type checking, with:
Meta
playground