Here is how method calls work in swift:
-
We find all applicable overloads at compile time and pick the most specific one, using static type information.
-
If the chosen overload is a protocol requirement, we generate code to look up and call the witness.
-
Otherwise we generate a direct call to the implementation of the chosen overload.
-
When checking a conformance of a type to a protocol we find the best witness for each protocol requirement, once again using static type information, as in (1). This is what gets called in 2.
I think some people imagine it as being more like:
-
For every method call, the compiler generates code to collect the dynamic types of all arguments, and does a lookup in some table.
-
All method declarations are added to this table at runtime.
That’s not how it works though, so if you start with that mental model it won’t match reality.