You can have a same-shape constraint between packs at different lexical depths in the generic signature. The restriction in the proposal is using the term "depth" differently, to describe nested pack expansions.
For example, I can write this:
struct Outer<each T> {
struct Inner<each U> where repeat each T == each U {}
}
The requirement repeat each T == each U
states that each T
and each U
are exactly the same pack; T
and U
have the same shape, and each element of T
is equivalent to each element of U
at the same position.
You can also state that two packs have unified elements using an intermediate scalar type parameter:
struct Outer<each T> {
struct Inner<each U, Element> where repeat each T == Element, repeat each U == Element {}
}
The requirements repeat each T == Element, repeat each U == Element
state that the elements of T
and U
are all equivalent, but T
and U
are not required to have the same shape. There's no way to write a requirement that unifies all elements of T
and U
without an intermediate type parameter, e.g. Element
in the above example, but such a requirement is possible theoretically through requirement inference involving nested requirement expansions:
struct Unify<Element, each T> where repeat each T == Element {}
func unifyAllElements<each U, each V>(_: repeat Unify<each U, repeat each V>))
The application of Unify
inside of a pack expansion would infer the requirement repeat each T == Element
where Element := each U
and each T := Pack{repeat each V}
for each element of U
. This effectively says that all elements of each U
and each V
are the same type, but without requiring them to have the same shape. Concretely, given each U := Pack{X, Y, Z}, each V := Pack{A, B}
, we end up with 6 expanded requirements:
repeat Unify<each U, repeat each V>, each U := Pack{X, Y, Z}, each V := Pack{A, B}
-> Unify<X, A, B>, Unify<Y, A, B>, Unify<Z, A, B>
-> A == X, B == X, A == Y, B == Y, A == Z, B == Z
This isn't a requirement that's supported in our generics system - each mention of each U
or each V
is effectively reduced to a scalar type parameter, but we have no such type parameter in the signature of unifyAllElements
to reduce these types down to.
So, repeat Unify<each U, repeat each V>
has a nested pack expansion, and the proposal is using "depth" to refer to the nesting level of these expansions. The outer expansion that iterates over each U
has an expansion depth 0, and the inner expansion that iterates over each V
has an expansion depth 1. The inferred requirement ends up capturing each U
at expansion depth 0, and each V
at expansion depth 1, and equating pack elements at different expansion depths is when we can end up with this funky pack element unification with no type parameter to describe the reduced type.