Indeed, it seems like we have the opposite problem. In general, the problematic operation here is
func append<T..., U...>(front: (T...), back: (U...)) -> (T..., U...) { return (...front, ...back) }
Applying append
recursively involves a tree of tuple-to-pack expansions that will inevitably just copy their data into a larger tuple and be immediately destroyed. The explicit append
primitive here is a distillation of a pattern that has been seen as part of the strongly-typed regular expression captures effort which seeks to build precisely these kinds of trees via the function builder transform.
This isn't the end of the world by any means. The flat representation implies we'll have to invest in optimizations that can efficiently perform this kind of recursive compound initialization. For example, it's clear that only the outermost allocation in our hypothetical pack tree is the one that requires meaningful initialization. The inliner is our friend in that case, since it can chop the tree structure apart and a cleanup pass can subsequently forward the sub-expansions from the leaves towards their final destination.
Another more radical approach would be to add an instruction that borrows a fixed non-overlapping region of a pack or tuple to construct an uninitialized sub-structure. Effectively, we'd be implementing the "emit-into" peephole but for tuple structure. That all reads so cleanly in my head but it has wild implications for SIL and its ownership model so I'm definitely open to other ideas.