Hey folks. I need some help in diagnosing a test f...
# getting-started
k
Hey folks. I need some help in diagnosing a test failure possibly related to design. Suppose I have this:
Copy code
interface MyType

value class Wrapper(value: Int) : MyType, WrapperAddOp

interface WrapperAddOp : MyType {
  operator fun plus(rhs: Wrapper): Wrapper = // default implementation
}
When I try to run a test (JVM), I get a
NoSuchMethodError
when I try to invoke the
plus
method on
Wrapper
, saying that a mangled name starting with
plus
on
Wrapper
doesn't exist. Anyone with any insights on this?
n
Do you get the same error when trying to run the application normally, or does it only occur in tests on JVM?
k
My only tests are on JVM, so I can't really tell.
n
Does the issue persist if you move the
plus
operator function inside the
Wrapper
value class, or does it only happen when the operator is declared in an interface separate from the value class?
k
Looking into the error further, the
NoSuchMethodError
is being flagged on a mangled
plus
with
Int
args, even though my code only defines
plus
on
Wrapper
.
Copy code
java.lang.NoSuchMethodError 'int Wrapper.plus-<mangled>(int, int)'
n
Well, yes, and that makes sense in that
Wrapper
is basically an opaque type for
value: Int
, but at runtime it is technically just a normal
Int
for optimization reasons.
k
That's kind of what I figured - if
Wrapper
wasn't a value class, this would work fine, but the fact that it is creates a design problem for me.
n
My guess is that there might be a bug in the compiler with value classes and operators inherited from implemented interfaces. I'll play around with some of my own code to see if I can verify in just moment. I have a few value classes with example the plus operator, but they live inside the value class.
k
Possible. It wouldn't make any real sense to say "no operator overloads of primitive type wrappers".
n
Can you provide a complete example? Mine isn't really fit to be modified to quite a similar example as to what you have provided. But extracting the operator to a different interface and implementing it inside the
Wrapper
works. Are you reusing the default implementation of
WrapperAddOp
in
Wrapper
or did you override it with a different implementation?
k
I'm reusing the default implementation of
WrapperAddOp
in
Wrapper
, no overrides
n
Can you try overriding it with just the same implementation or whatever and check if the issue persists?
k
Explicit override in the value class passes the test - so the issue is only when
Wrapper
inherits the body of
WrapperAddOp.plus
Even a simple implementation like
Copy code
value class Wrapper(value: Int) : MyType, WrapperAddOp {
  override fun plus(rhs: Wrapper): Wrapper = super.plus(rhs)
}
Seems to do the trick
So there is probably something with 1) value types wrapped on primitive types and 2) inheriting a default implementation of an operator overload from an interface
n
Yeah, that was my best guess as well. I'm pretty sure this is a compiler, it might be a regression in K2, but I have no idea to be honest. Can you confirm if this is an issue for all default functions, or if it only happens for operator functions, and if so both for unary and binary?
k
For sure unary operators, binary operators, and infix binary functions. I don't have an example of a regular non-infix binary function to work with in my code.
n
I'd assume it's an issue for all not explicitly declared/inherited default functions then blob shrug
k
Is there a bug that can be filed somewhere for it?
n
k
Interesting. If I set my JVM compiler options to
Copy code
kotlin {
  jvm {
    compilerOptions {
      jvmDefault.set(JvmDefaultMode.NO_COMPATIBILITY)
    }
  }
}
The issues seem to disappear entirely, so it must be a Kotlin 2.2.0 thing. To what extent this can be considered a regression is probably beyond my understanding.
n
IIRC Kotlin 2.0.0 signifies the complete move to the new K2 compiler, so it very well could be an overlooked regression, because it seems like it is something else should just work.