If a type parameter has a protocol conformance and a concrete type,
we want to map associated types of the conformance to their concrete
type witnesses.
This is implemented as a post-processing pass in the completion
procedure that runs after the equivalence class map has been built.
If we have an equivalence class T => { conforms_to: [ P ], concrete: Foo },
then for each associated type A of P, we generate a new rule:
T.[P:A].[concrete: Foo.A] => T.[P:A] (if Foo.A is concrete)
T.[P:A] => T.(Foo.A) (if Foo.A is abstract)
If this process introduced any new rules, we check for any new
overlaps by re-running Knuth-Bendix completion; this may in turn
introduce new concrete associated type overlaps, and so on.
The overall completion procedure now alternates between Knuth-Bendix
and rebuilding the equivalence class map; the rewrite system is
complete when neither step is able to introduce any new rules.
We used to assert that the merged protocol set was larger than or
equal to in size to both the left hand side and the right hand
side.
However, there is a counter-example:
protocol P {}
protocol Q {}
protocol R : P, Q {}
LHS = [P&Q:T], RHS = [R:T]
The merged atom is `[R:T]` which has fewer protocols than the
left hand side.
The `if (other.size() > size())` check was bogus; we can still have an
overlap of the second kind if the other term is longer than this term.
Remove this check, and rewrite the algorithm to be clearer in general.
Also move a all headers other than RequirementMachine.h there, since
I don't expect they will be used outside of the rewrite system
implementation itself.