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

KotlinReflectionInternalError when a kotlin.time.Duration parameter has a default value #237

Closed
OliverO2 opened this issue Nov 16, 2021 · 11 comments
Labels

Comments

@OliverO2
Copy link

OliverO2 commented Nov 16, 2021

Cause: Duration is an inline class (a value class annotated with @JvmInline). There is a known bug KT-27598, causing the error when a constructor with inline class parameters is called via reflection.

Versions used:

version.com.sksamuel.hoplite..hoplite-hocon=1.4.14
version.kotlin=1.5.31 and 1.6.0
version.kotlinx.datetime=0.3.1

Source:

import com.sksamuel.hoplite.ConfigLoader
import com.sksamuel.hoplite.PropertySource
import kotlin.time.Duration
import kotlin.time.ExperimentalTime

@OptIn(ExperimentalTime::class)
data class Config constructor(
    val medium: Duration = Duration.days(1),
    val high: Duration = Duration.days(10)
)

fun main() {
    val config = ConfigLoader.Builder()
        .addPropertySource(
            PropertySource.string(
                """
                    medium = 4 hours
                """.trimIndent(), "props"
            )
        )
        .build()
        .loadConfigOrThrow<Config>()

    println("$config")
}

Build script modifications:

tasks.withType<KotlinCompile>() {
    kotlinOptions {
        jvmTarget = "11"
        freeCompilerArgs = listOf("-Xopt-in=kotlin.RequiresOptIn")
    }
}

Exception produced:

Exception in thread "main" kotlin.reflect.jvm.internal.KotlinReflectionInternalError: This callable does not support a default call: public constructor Config(medium: kotlin.time.Duration = ..., high: kotlin.time.Duration = ...) defined in Config[DeserializedClassConstructorDescriptor@22bac7bc]
	at kotlin.reflect.jvm.internal.KCallableImpl.callDefaultMethod$kotlin_reflection(KCallableImpl.kt:164)
	at kotlin.reflect.jvm.internal.KCallableImpl.callBy(KCallableImpl.kt:112)
	at com.sksamuel.hoplite.decoder.DataClassDecoder.construct(DataClassDecoder.kt:128)
	at com.sksamuel.hoplite.decoder.DataClassDecoder.safeDecode(DataClassDecoder.kt:116)
	at com.sksamuel.hoplite.decoder.NullHandlingDecoder$DefaultImpls.decode(Decoder.kt:85)
	at com.sksamuel.hoplite.decoder.DataClassDecoder.decode(DataClassDecoder.kt:28)
	at com.sksamuel.hoplite.ConfigLoader.decode(ConfigLoader.kt:400)
	at com.sksamuel.hoplite.ConfigLoader.loadConfig(ConfigLoader.kt:386)
	at MainKt.main(Main.kt:26)
	at MainKt.main(Main.kt)
@sksamuel
Copy link
Owner

I'm not sure what we can do if the bug is in the compiler.

@OliverO2
Copy link
Author

For now, at least this issue documents the case, so that people catching the error can find out what's going on without incurring extra research effort.

I'm not sure about a solution either. Maybe we can just live with it for now. Or someone comes up with a bright idea. Maybe something like a wrapper or a delegate would do?

@sksamuel
Copy link
Owner

sksamuel commented Nov 16, 2021 via email

@OliverO2
Copy link
Author

Good to know! With an extra level of indirection in Kotlin code, configurations can benefit from Duration default values.

This change...

data class DurationValue(val value: Duration)

data class Config constructor(
    val medium: DurationValue = DurationValue(Duration.days(1)),
    val high: DurationValue = DurationValue(Duration.days(10))
)

...makes the above example print:

Config(medium=DurationValue(value=4h), high=DurationValue(value=10d))

@stale
Copy link

stale bot commented Jan 17, 2022

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.

@stale stale bot added the wontfix This will not be worked on label Jan 17, 2022
@stale stale bot closed this as completed Jan 24, 2022
@vlushn
Copy link

vlushn commented Feb 3, 2022

While this issue has a workaround, it's still very much current and will be until the compiler bug is fixed.

@OliverO2
Copy link
Author

OliverO2 commented Apr 14, 2022

The required compiler fix is included in Kotlin builds build-1.7.0-Beta-3 and above, so can be expected to land in Kotlin 1.7.

@sksamuel
Copy link
Owner

sksamuel commented Apr 14, 2022 via email

@OliverO2
Copy link
Author

...as well as letting me know ;-). Ideally, such stuff could be automated, so that we could get a reminder once the Kotlin fix is released. But I am not aware of such an option.

@sksamuel sksamuel reopened this Apr 14, 2022
@stale stale bot removed the wontfix This will not be worked on label Apr 14, 2022
@Virtlink
Copy link
Contributor

The fix has been released in Kotlin 1.7.0. Changing the kotlin-reflect dependency to the latest 1.7.10 fixed it for me.

@sksamuel
Copy link
Owner

Closing as confirmed fixed in 1.7.x

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

No branches or pull requests

4 participants