Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

SuspendInterop: framework named shared conflicts with object shared #131

Open
boringcactus opened this issue Jan 3, 2025 · 3 comments
Open

Comments

@boringcactus
Copy link

Questions:

What is the problem?

The default Kotlin Multiplatform settings for a new project created in Android Studio name the shared library shared and the iOS framework shared.framework. However, the shared instance of a Kotlin object Foo is named Foo.shared in Swift, and SKIE's generated coroutine wrapper code does not handle this correctly. (Or perhaps its generated code used to work in Xcode 15 but does not work in Xcode 16.)

The Kotlin code

object Foo {
    suspend fun bar() {}
}

will have the Shared.Foo.swift

// Generated by Touchlab SKIE 0.10.0

import Foundation

extension shared.Foo {

    @available(iOS 13, macOS 10.15, watchOS 6, tvOS 13, *)
    public func bar() async throws -> Swift.Void {
        return try await SwiftCoroutineDispatcher.dispatch {
            shared.__SkieSuspendWrappersKt.Skie_Suspend__3__bar(dispatchReceiver: self, suspendHandler: $0)
        }
    }

}

which will cause the build errors

error: Compilation failed: The /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/swiftc command returned non-zero exit code: 1.
output:
generated/Shared/Shared.Foo.swift:10:13: error: static member 'shared' cannot be used on instance of type 'Foo'
 8 |     public func bar() async throws -> Swift.Void {
 9 |         return try await SwiftCoroutineDispatcher.dispatch {
10 |             shared.__SkieSuspendWrappersKt.Skie_Suspend__3__bar(dispatchReceiver: self, suspendHandler: $0)
             `- error: static member 'shared' cannot be used on instance of type 'Foo'
11 |         }
12 |     }

generated/Shared/Shared.Foo.swift:10:20: error: value of type 'Foo' has no member '__SkieSuspendWrappersKt'
 8 |     public func bar() async throws -> Swift.Void {
 9 |         return try await SwiftCoroutineDispatcher.dispatch {
10 |             shared.__SkieSuspendWrappersKt.Skie_Suspend__3__bar(dispatchReceiver: self, suspendHandler: $0)
                    `- error: value of type 'Foo' has no member '__SkieSuspendWrappersKt'
11 |         }
12 |     }

Fixes I can imagine with my limited knowledge of Swift or how SKIE works internally:

  1. By some mechanism disambiguate the reference to be shared-the-module as opposed to shared-the-static-member. It's not clear to me that this is actually possible in Swift, though.
  2. Remove the ambiguous module qualifier and just refer to __SkieSuspendWrappersKt instead of naming it via shared. Presumably the module is specified explicitly for good reasons, though, so this may not be possible in the general case.
  3. Only drop those module qualifiers if the module is named shared. This is worse, and it may still not work depending on the nature of the problems that the module qualifiers are there to fix.
  4. Emit a Gradle error from SKIE directly if the framework is named shared and SuspendInterop is enabled by default. If this error cannot be fixed except by renaming the framework, I'd rather rename the framework early and then never run into this error.
  5. Emit a Gradle error from SKIE directly if the framework is named shared and an object has a suspend fun with SuspendInterop enabled. At the very least, this error message could be more informative than it currently is.

When does the problem occur?

During Swift compilation (when trying to use the generated Kotlin Framework)

How do we reproduce the issue?

build.gradle.kts:

kotlin {
    listOf(
        iosX64(),
        iosArm64(),
        iosSimulatorArm64()
    ).forEach {
        it.binaries.framework {
            baseName = "shared"
        }
    }
}

src/commonMain/kotlin/Foo.kt:

object Foo {
    suspend fun bar() {}
}

What has changed since the last time SKIE worked in your project?

I added a suspend fun to a companion object in a Kotlin Multiplatform project that uses the default structure.

What versions of SKIE, Kotlin, and Gradle do you use?

SKIE 0.10.0, Kotlin 2.1.0, Gradle 8.9.

I'm also using Xcode 16.2, which might be interpreting Swift code that used to work correctly in a different way now, although my environment variables for the Gradle build step include SWIFT_VERSION=5.0 and I'd expect that to be a Swift 6 thing if it was really what was happening.

What is your SKIE Gradle configuration?

(This issue can be reproduced with the default SKIE settings.)

@TadeasKriz
Copy link
Collaborator

Hi @boringcactus, thanks for the report. This is probably a bug in SKIE, because it should already rename the object reference shared to shared_ if the module name is shared and print a warning to the build output about it. I'll try to reproduce it to see why it's not working in this case.

@TadeasKriz
Copy link
Collaborator

I've been informed by a colleague that we didn't implement the shared renaming yet, because we decided to have SKIE error out by default when the framework is called shared along with configuration to instead try and rename the object references shared to shared_.

@kdarrimajoupro
Copy link

kdarrimajoupro commented Jan 7, 2025

Hello !

I have the same issue in my project when I try to build XCFramework with assembleSharedReleaseXCFramework. If I rename the object references shared to shared_, I have this error :

w: Name of XCFramework 'shared' differs from inner frameworks name 'shared_'! Framework renaming is not supported yet

error: the path does not point to a valid framework: ../shared/build/sharedXCFrameworkTemp/fatframework/release/iosSimulator/shared.framework

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants