Description
What is this
This is a design document for const generics. Any discussions about its content should be on zulip. The conclusions of these discussions should then be edited back into this issue. Please do not post any comments directly in this issue.
Content
If we start supporting unbraced const path arguments, e.g. Foo<T::ASSOC>
this could pose issues with associated const equality where we cannot tell from context if the T::ASSOC
argument is for a const or type associated item. For example something like this:
#![feature(associated_const_equality, min_generic_const_args)]
trait Trait {
type ASSOC;
#[mgca_const]
const ASSOC: usize;
}
trait HasConst {
#[mgca_const]
const ASSOC: usize;
}
trait HasType {
type ASSOC;
}
fn foo<T: Trait<ASSOC = U::ASSOC>, U: HasConst + HasType>() {}
In the T: Trait<ASSOC
binding it's not clear whether ASSOC
refers to the assoc const or the assoc type. This means that we cannot use the position of the argument U::ASSOC
to disambiguate whether it is a type or a const argument.
There is already some ambiguity when resolving associated type bindings as supertraits can introduce same-named associated types, currently we just prefer to resolve to associated items in the subtrait (though this does nothing to help with trait objects which wind up requiring unwriteable associated type bounds).
In order for ambig gen args + assoc const equality to not make matters worse when it comes to the lack of expressiveness when resolving assoc bindings, I think we should forbid having a mgca_const
on a trait that also defines a same-named associated type. This would be fully backwards compatible as no mgca_const
assoc items exist today. There is no need to introduce any restrictions for non-mgca_const
associated consts as I do not expect us to want to support T: Trait<ASSOC
for arbitrary non-type-system associated constants.
When resolving assoc item bindings we should also attempt to find either a type or a const so that we do not arbitrarily prefer a supertraits associated type over a subtraits associated const when either would have been valid:
#![feature(associated_const_equality, min_generic_const_args)]
trait SuperTrait {
type ASSOC;
}
trait Trait: SuperTrait {
#[mgca_const]
const ASSOC: usize;
}
trait HasConst {
#[mgca_const]
const ASSOC: usize;
}
trait HasType {
type ASSOC;
}
fn foo<T: Trait<ASSOC = U::ASSOC>, U: HasConst + HasType>() {}
T: Trait<ASSOC
here should resolve to the associated constant on Trait
not the associated type on SuperTrait
as we already prefer subtrait assoc items over super trait assoc items see this example.
It is also worth noting that most of this is likely to not matter whatsoever in practice as the naming scheme for associated types and consts are different. Typically we would write type Assoc
and const ASSOC: usize
which does not result in equally named associated items. This is likely to only ever crop up in the case of single-letter associated items where type N
and const N: usize
are both written according to the expected naming guidelines