Not just that; the stricter these rules are, the more difficult it becomes to evolve protocols in a source-compatible way.
For example, I mentioned in a recent thread that I wanted a function returning a concrete type to be able to witness a requirement returning an existential. The idea was to write something like this:
protocol MyProto {
#if swift(>=5.7)
func doSomething() -> any Collection<UInt8>
#else
func doSomething() -> AnyCollection<UInt8>
#endif
}
I've benchmarked algorithms using language-integrated existentials as being up to 80x faster than the same algorithm using the stdlib's versions, so I would really like to use them, but I still want this API to be available in some form to people building with older compilers.
The idea is that those pre-5.7 users could write conformances like this:
struct MyStruct: MyProto {
func doSomething() -> AnyCollection<UInt8> { ... }
}
And that when they eventually upgrade to 5.7, it would still match as a witness to the same requirement. Yes, the result would be an stdlib "existential" wrapped in a language existential, which is suboptimal for performance, but it would at least be a source-compatible change.
Since witness matching is too strict to allow for this kind of evolution, I'm having to limit this entire API to Swift 5.7+ with no compatibility fallback. It's the only part of the library that is limited in this way.
So yeah - while I understand the desire to make everything very strict, it can be impractical. We should be mindful of the benefits of being more relaxed, as long as everything still obeys some kind of comprehensible principles.