I agree that this is an important use case, and I certainly agree that we don’t handle it all that well, and it’s certainly that we had hoped to avoid “splitting” traits into “specialization predicates” and “normal traits”. But at this point I don’t think it’s possible to avoid that split.
The fact is that impls can (and frequently do!) include tests that we just can’t test after erasure. Previously we had hoped to find some solution that basically let the choices made pre- and post-erasure diverge: I suspect this is fundamentally unsound, and that is roughly the point of my post.
In any case, even if it can be made sound, it’s always made me pretty nervous. It seems like it implies that figuring out which code will run is pretty non-trivial for users. I am nervous about this, particularly since I think people will use specialization for more than just optimization, but also for semantic choices.
That seems to leave three options:
- Stop erasing.
- Somehow make all choices at typeck time.
- Restrict the set of specialization impls to those that can be decided equally well at typeck time and at codegen time.
We’ve been discussing the first one (“stop erasing”) on this thread. I believe it is quite infeasible. It would also mean that further improvements like NLL are not possible, or at least much more fraught, since they would change runtime semantics. I expect us to make more such improvements. =)
Making all choices at typeck time is, in a sense a variant on the first option. It would mean that generic functions – which often lack the context for such a choice – must push the choice up to their caller. I’m not even sure this can be done, since often the choices will involve compound types that feature regions from within the function. But even assuming it can be made to work, it’s clear that it has the same downsides in terms of the borrowck and regionck suddenly being in charge of making choices about what code executes (it probably avoids some of the monomorphization explosion, since I imagine we would basically be compiling down to a dictionary passing style, and in practice the dictionaries we resolve would wind up being the same).
So that leaves us with the third option, which is basically what I described. (Were there any other specific proposals for how to implement such a test? It’d be interesting to compare, but I don’t recall anyone giving a detailed proposal.)
Am I missing some alternative?