swiftswiftpm

Referring to a type in another module with the same name as a type in the current module when the other module has a type with its own name in Swift


I am using the swift package manager. I have a module ModuleA which exports two types: ModuleA and Test. I have a module ModuleB which defines a single type: Test. In ModuleB, how can I refer to the type Test from ModuleA? Ideally, I would like syntax such as #module(ModuleA) to refer directly to the module ModuleA.

Reproducible example:

Package.swift:

// swift-tools-version:5.3

import PackageDescription

let package = Package(
    name: "ShadowingTest",
    products: [
        .library(
            name: "ModuleA",
            targets: ["ModuleA"]),
        .library(
            name: "ModuleB",
            targets: ["ModuleB"]),
    ],
    dependencies: [
    ],
    targets: [
        .target(
            name: "ModuleA",
            dependencies: []),
        .target(
            name: "ModuleB",
            dependencies: ["ModuleA"]),
    ]
)

Sources/ModuleA/ModuleA.swift:

public enum ModuleA {}
public struct Test {
    public static let module: String = "ModuleA"
}

Sources/ModuleB/ModuleB.swift:

import ModuleA

struct Test {
    static let module: String = "ModuleB"
}

func test() {
    print(ModuleA.Test.module)
}

Running swift build errors with

Sources/ModuleB/ModuleB.swift:8:19: error: type 'ModuleA' has no member 'Test'

but succeeds when public is removed from the ModuleA enum in ModuleA.


Solution

  • the issue is ModuleA enum in ModuleA module does not have Test.

    When you remove public in ModuleA enum then ModuleB cannot recognize there is a ModuleA enum because its access modifier is internal by default so ModuleB recognizes Test struct in ModuleA instead of trying to find Test in ModuleA enum


    Bonus: There is a answer in SO about access modifiers I think you'll find useful.


    EDIT:

    If you need to use ModuleA.Test even there is an enum named ModuleA then you can use import (class|struct|func|protocol|enum) <needed_component> so in your case you should import like this:

    import struct ModuleA.Test
    

    If you want to use the struct with another name to avoid naming conflicts then you can set a typealias ->

    import struct ModuleA.Test
    
    typealias TestA = ModuleA.Test