Yeah. I apologize for the confusion. I think intuitively we all understand the expected behavior of same-element requirements as specified in SE-0393. This will give us the ability to unify the elements, as you're calling it, with the help of an intermediate non-pack type parameter. I think for the user-visible part, this suffices. To realize this, there are three primary missing pieces:
- we need to define the rewrite rule for a same-element requirement which gives us the expected behavior with derived requirements/minimization.
- we need a generic signature query which given a generic signature and type parameter pack, returns the pack's "unified" element type, if there is one.
- when building the element environment for a pack expansion, if some type parameter pack has an element type, instead of instantiating the element archetype we map its element type into context.
I would say the first one is a "design" question, even though it's not user-visible. The second two are straightforward (I hope) matter of "implementation" ;-)
What I was getting at with the discussion of derived requirements was that internally we might need to model the "weird" kinds of same-element requirements and this might inform the rewrite system changes, but I'm not sure yet. It would be certainly nice if we could avoid it, just from a simplicity standpoint.
EDIT: if there was some way to write the moral equivalent of (each S).Element .== (each T).Element
(collapsing the element types of two packs into a single scalar, without an intermediate parameter), then what is the element type of (each S).Element
(or (each T).Element
)?
Can we avoid this entirely? With requirement inference, you can do some odd things:
typealias G<each T: Sequence, E: Sequence> = E
where (each T).Element == E.Element
func foo<each U, each V>(_: each U,
_: repeat G<repeat each U, each V>)
Note that the second parameter's type desugars to repeat each V
because the type alias is trivial, but it introduces an inferred requirement! Requirement inference is defined by applying a substitution map to the requirements of G
. The substitution map replaces the non-pack type E
with the pack reference each V
because G
appears inside of another pack expansion. It's not even completely clear to me what this means in the general case.
It seems the generic signature of foo
would have this weird requirement:
<each U, each V where each U: Sequence, each V: Sequence, (each U).Element .== (each V).Element>
But we could also just ban this. This interaction between requirement inference and nested pack expansions seems very magical, and difficult to "prove" correctness of.