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

java.lang.ClassCastException: to CoroutineStackFrame at kotlinx.coroutines.internal.ScopeCoroutine.getCallerFrame(Scopes.kt:19) #2386

Closed
willbuck opened this issue Nov 13, 2020 · 4 comments
Assignees
Labels

Comments

@willbuck
Copy link
Contributor

For library authors wishing to implement a custom kotlin.coroutines.Continuation class, casting to an internal class like CoroutineStackFrame is problematic.

See, for example, this issue filed against micronaut:

micronaut-projects/micronaut-core#4438

The error comes on this line, where micronaut has implemented Continuation with the CompletableFutureContinuation class

https://github.com/micronaut-projects/micronaut-core/blob/0afdef29d0a6b38b55dc39e3ef2a72bea85be45f/aop/src/main/java/io/micronaut/aop/internal/intercepted/KotlinInterceptedMethod.java#L123

I think the solve is to have ScopeCoroutine optionally cast uCont to CoroutineStackFrame, as callerFrame is nullable anyway (and it also seems like what other implementations of CoroutineStackFrame, like SelectBuilderImpl and StackFrameContinuation are doing).

I can work on adding a test to reproduce this issue and create a PR since I'm already in the weeds on it, will update once I do!

willbuck added a commit to willbuck/kotlinx.coroutines that referenced this issue Nov 14, 2020
@elizarov elizarov added the bug label Nov 14, 2020
@qwwdfsad
Copy link
Member

qwwdfsad commented Nov 16, 2020

Thanks for the report! Filed https://youtrack.jetbrains.com/issue/KT-43395

This is indeed bug on our side worth fixing, but while we are here, I would strongly suggest implementing CoroutineStackFrame in CompletableFutureContinuation in the following way:

class CompletableFutureContinuation(private val continuation: Continuation<Any>) : Continuation<Any>, CoroutineStackFrame {

    override val callerFrame: CoroutineStackFrame?
            get() = continuation as? CoroutineStackFrame

    override fun getStackTraceElement(): StackTraceElement? = null
}

This change will improve debugging experience of Micronaut+coroutines usage, including IDE debugging and runtime exceptions recovery machinery

@willbuck
Copy link
Contributor Author

willbuck commented Nov 17, 2020

@qwwdfsad thanks for the feedback! As far as we could tell, CoroutineStackFrame is an internal class, and thus would not be accessible outside of the kotlinx.coroutines module for Micronaut to extend it. Is that mistaken?

@qwwdfsad
Copy link
Member

qwwdfsad commented Nov 17, 2020

CoroutineStackFrame is actually a public interface from kotlin stdlib, in the package kotlin.coroutines.jvm.internal.

While it may seem dangerous to implement it because it is internal, we are not going to change it because a lot of binary code already depend on it. The worst thing we can do is to "deprecate it" with a replacement to the same very interface but in another package

@willbuck
Copy link
Contributor Author

@qwwdfsad alright then, sounds like something to PR against micronaut :) thanks for the clarification!

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

3 participants