In Swift, a generic type conforms to a protocol in exactly one way. The way that it conforms is determined statically at compile-time, where the conformance is declared.
A “conformance” to a protocol means, essentially, a lookup table to identify the implementation satisfying each of the protocol’s requirements.
So at the point where Foo is declared as conforming to P, the compiler constructs a table to specify, for each requirement of P, which member of Foo satisfies that requirement.
This is a single table for Foo, which does not depend on the generic parameter Bar. Every instance of Foo conforms to P in the same way, using the same table.
At the point where Foo conforms to P, there is only one available implementation for the bar requirement, namely the stored property in Foo.
There is only one available implementation for the printTypeOfBar requirement, namely the function in the unconstrained extension P.
And there is also only one available implementation for the typeOfBar requirement, namely the computed property in the unconstrained extension P.
The constrained extension is not available for all possible instances of Foo, so the version of typeOfBar found there cannot be the implementation that goes in the conformance table. The conformance table must work for every instance of Foo.
That means Foo conforms to P by using the version of typeOfBar from the unconstrained extension.
When you write foo.typeOfBar, the compiler performs static dispatch on the instance foo. It sees two possible implementations for typeOfBar: one from the unconstrained extension on P, and one from the constrained extension.
The compiler chooses the version from the constrained extension, since it is a closer match to the type of foo. That is why you see “Int” as the first output.
When you write foo.printTypeOfBar(), the compiler still performs static dispatch on the instance foo. It sees only one possible implementation, from the unconstrained extension on P.
Inside the body of printTypeOfBar, however, the call to typeOfBar uses dynamic dispatch through the protocol requirement. This is because the implementation is located in an extension of P, where the only thing known about Self is that it conforms to P.
So printTypeOfBar calls the version of typeOfBar found in the conformance table for Foo, which as we saw earlier is the one from the unconstrained extension on P.
That is why you see “Not Int” as the second output.