Did anyone see `Unresolved reference: kotlinx` rec...
# intellij
o
Did anyone see
Unresolved reference: kotlinx
recently on imports like
import kotlinx.coroutines.channels.Channel
? Details in 🧵.
youtrack 1
IntelliJ IDEA 2023.1.3 (Ultimate Edition) with Kotlin Plugin 231-1.9.0-RC-release-336-IJ8770.65 So in a perfectly compiling Kotlin 1.9.0-RC Multiplatform project, the IDE complained
Copy code
Unresolved reference: kotlinx
on import statements like this:
Copy code
import kotlinx.coroutines.channels.Channel
This is what I tried: 1. Gradle clean 2. Restart IDE 3. Re-sync Gradle projects 4. Use IDEA 2023.2 EAP 5. Use IDEA 2023.1.3 with Kotlin Plugin 231-1.8.21-IJ9161.38 This is what helped in the end: • Add a redundant dependency in
commonMain
Copy code
val commonMain by getting {
    dependencies {
        // ...
        implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.2") // <- added redundantly
        implementation(KotlinX.coroutines.core) // <- existed before, using refreshVersions with version.kotlinx.coroutines=1.7.2
        // ...
    }
}
Adding the redundant dependency made the above error disappear. Removing the redundant dependency afterwards was OK. The error did not reappear. Any idea which kind of (supposedly caching) problem is causing this?
a
you’re certain that
KotlinX.coroutines.core
has a GAV of
org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.2
and not a variant, e.g.
org.jetbrains.kotlinx:kotlinx-coroutines-core-jvm:1.7.2
? Can you add a
println()
to try and get the actual GAV of
KotlinX.coroutines.core
?
Are you using composite builds? If so you can try adding
kotlin.mpp.import.enableKgpDependencyResolution=true
to gradle.properties https://kotlinlang.org/docs/whatsnew1820.html#preview-of-gradle-composite-builds-support-in-kotlin-multiplatform
o
_println_(KotlinX.coroutines.core)
yields
org.jetbrains.kotlinx:kotlinx-coroutines-core:_
(the underscore is dealt with by
refreshVersions
). I'm not using composite builds in this case. However, trying
enableKgpDependencyResolution
might be a good idea anyway as it includes:
major bug fixes and improvements to make the import more stable
The strange thing is that this was only an intermittent problem which I can't reproduce any longer once it was resolved. Might even be a collateral of Kotlin IDE plugin crashes which I had seen a lot. In any case it would be useful to know where the plugin stores things and how to reset that.
Just tried:
kotlin.mpp.import.enableKgpDependencyResolution=true
made the error reappear (the redundant dependency trick did not work then). Removing
enableKgpDependencyResolution
solved the issue.
a
hmmm, odd! What Kotlin targets do you have enabled? I’ve experienced some issues with JS caching errors, and I need to clean everything before it will ‘forget’ an error. Perhaps it’s a similar problem
o
In this particular project: Three JVM targets (backend, Compose Desktop frontend, integration test), one Js target (Compose Web/Canvas frontend).
a
can you narrow down the problem to a specific target? Or does it happen for multiple targets?
o
I've tried to create a simple reproducer with two JVM targets and one Js target. No luck there. Seems like it would be a larger task to narrow it down, unfortunately.
a
yeah, that’s most likely true. Hopefully it’ll be coincidentally fixed 🤞
🤞 1
o
Here's a reproducer: KTIJ-26134 MPP: enableKgpDependencyResolution=true produces "Unresolved reference: kotlinx" in IDE @Sebastian Sellmair [JB] Something for you to look at?
s
Hmm, this is sharing code across two jvm platforms, right? This is technically, officially not supported, but I will ensure that the new dependency resolution works like before here. Investigating it right now!
I checked out the project and I think the project configuration is not legit, the dependsOn edges are put onto a the leaf souce sets. Let me try to understand what you want to do here, so I can suggest how to set this up. This configuration will likely not be OK for stable kpm
o
Yes, I know that multiple Jvm targets are not "officially" supported. It worked like a charm with the old resolution in spite of the disclaimer. There is even a workaround now: If I create intermediate source sets right above the Jvm target source sets and declare the diamond dependency on the intermediate source set level, everything works again with
enableKgpDependencyResolution=true
. And since I wanted to check the new source set hierarchy, too, I've come up with another one: https://youtrack.jetbrains.com/issue/KT-60173/KotlinTargetHierarchy-Support-multiple-Jvm-targets Summing it up, it seems there is not that much that is missing, so I wanted to give as much feedback as early as possible.
s
No, the problem is not the code shared across two jvms, its the way that those dependsOn edges are setup!
Btw, 1.9.20 will ship diagnostics that will help you figure out that there are some inverted dependsOn edges. Let me try to re-setup the project, even with targetHierarchy =
Can you maybe describe how you would like to ideally share the code?
o
OK, let's try a graph. Wait...
s
build.gradle.kts.kt
I think something like this would be sufficient to share code across those targets in a diamond. Works like charm!
o
I'll try. In the mean time, my actual graph looks like this (if I did not screw it up):
Copy code
common
    frontendCommon
        frontendUi
            frontendJvm (Compose Desktop target)
            frontendJsUi (Compose Web target)
        frontendJs
            frontendJsUi (*)
    commonJvm
        frontendJvm (*)
            integrationJvm (Backend + Compose Desktop target)
        backendJvm (Ktor server target)
            integrationJvm (*)

(*) additional dependency
s
backendJvm is a leaf source set, so integrationJvm cannot dependOn it. What code are you putting into integartionJvm?
o
Well, it can. It is an executable leaf, but also works as an importable module. integrationJvm uses a special headless Compose Jvm frontend setup with most parts stemming from the real Jvm frontend. And it uses backend (Ktor) server parts in conjunction with a Ktor test server. So it tests an almost complete frontend/backend combination, just without the network communications and without a "physical" UI.
s
Oliver, please do not get me wrong: Yes you can make this work and seemingly 1.8.20 worked for you here, but we are going to stable multiplatform and this configuration will not be supported. You will need to re-structure the code sharing. There will be a way to make this work, but you will not be able to add dependsOn edges to leaf source sets. Ok, I get it: This integration target is a test that is using both backend and frontend to run special tests. In this case ‘dependsOn’ is really not the API you would like to use as you do not intend to create actuals, right?
I think your integration tests should either use a regular ‘implementation’ dependeny, or should move to a separate Gradle project alltogether?
This use case is very interesting, but absolutely out of scope for ‘stable Multiplatform’. I am not saying this to discourage you. Again: This is a really cool idea on testing frontend and backend. Just the approach you have chosen is not what we actively want to support for now
o
Yes, sure that's what I could do. I'd never insist on stabilizing this configuration if it creates too much complexity in MPP. It just happened to work so I'd just wanted to let you know the complete picture.
s
You have been a very active member and created multiple high quality tickets, so how about the following: Let’s schedule a call together in the upcoming two weeks and think of ideas how to model your tests in APIs that will be stable?
Do you have a more complex project that is accessible to tinker around with?
o
Unfortunately, nothing published and everything very much a WIP. But yes. let's schedule a call, just suggest a date&time that works for you. And I know I might be doing exotic stuff here, so I'll adapt to more common ground where necessary. No problem with that!
s
Yes, its certainly the first time I have seen this idea, but I really think its creative and cool so its also just fun to think about this and set this up! Also, I am really happy for all the contributions (being active here, creating tickets, …) so I really want to help!
o
Glad to hear that, but really, don't worry: I'm also just trying to help and get the upcoming versions to fly. Currently, I'm most happy when you guys make progress. I'm eagerly waiting for Compose Multiplatform to compile with 1.9.20 and K2, and I've even contributed fixes to the kotlinx-serialization compiler plugin for 1.9.0. I'll be happy to show you what I did and why but righ now I'm not expecting any real difficulties in splitting my project up differently.
@Sebastian Sellmair [JB] just a short feedback: I have successfully restructured my project and now everything is working without issues so far. 🎉 What has been one Gradle MPP project with an interesting source set graph (1) became a graph of Gradle subprojects (2), each having just a default source set graph (common -> jvm[, js]). Downside: More build script boilerplate (using the same plugins in multiple build scripts while avoiding convenience plugins). Upside: Compiler plugins (Compose, kotlinx-serialization) can target a narrower set of sources instead of everything.
868 Views