OK... this is difficult to explain (and to come up with a title for) but I'll try my best.
We first discovered this when using Carthage to import stuff but setting up a sample project in Xcode (without using Carthage) it seems to have done the same thing.
First, here's a screenshot of the sample project we set up...
The have a target Test20000 and it has a dependency A.
The A framework then has a dependency on B.
Important
The Test20000 app does NOT add B as a direct dependency.
The frameworks
In B there is a struct like...
import Foundation
public struct BType {
public let value = "Hello, B!"
}
In A there is a file like...
import Foundation
import B
public struct AType {
public let value = "Hello, A!"
public func doAThing() {
print(BType().value)
}
}
The App
Now in the Test20000 app we do something like...
import Foundation
import A
struct TestType {
func doSomething() {
let aType = AType()
print(aType.value)
aType.doAThing()
}
}
This works as expected. It prints...
Hello, A! Hello, B!
If I change the function to something like this...
import Foundation
import A
struct TestType {
func doSomething() {
let bType = BType()
print(bType.value)
}
}
Then this doesn't compile as B is not imported and so BType
can't be accessed.
The catch!
However! If you declare an extension in B something like...
extension String {
func doAThingInB() {
print(self)
}
}
Then now... without any changes to the imports and the dependencies, I can now change my app code to...
import Foundation
import A
struct TestType {
func doSomething() {
"Hello, bug!".doAThingInB()
}
}
And this will print out as though the extension is public to the actual App. It sort of "bunny hops" from B, over A and into the app.
I feel like this shouldn't happen at all.
We can't find a way to turn this off or to stop this happening.
Is this a bug?
Is there something we need to do to stop this?
Thanks