ikvmnet / ikvm

A Java Virtual Machine and Bytecode-to-IL Converter for .NET
Other
1.15k stars 110 forks source link

AbstractMethodError for default method on base class interface #461

Open zznty opened 6 months ago

zznty commented 6 months ago

Repro project: IkvmIssueRepro.zip

Basically SlashCommandInteractionEvent internally holds instance of SlashCommandInteractionImpl which is subclass of CommandInteractionImpl that implements interface CommandInteractionPayloadMixin with default method body for getName()

But when i try to call getName() it throws java.lang.AbstractMethodError as ikvm has generated for it (see screenshot) image

wasabii commented 6 months ago

Having had a chance to look at this. Here's what I've found so far. It is probably a bug.

IKVM implements default interface methods as Miranda methods. That is, methods which are implicitely created on sub-types based on the declaration on the extended super type. We do this because historically .NET has not supported any notion of default interface methods. Core does now, but Framework still does not.

In this case, CommandInteractionPayload exposes the method getName() as an abstract. Because it is an interface with no default implementation. CommandInteractionPayloadMixin implements CommandInteractionPayload, and redeclares the method as an override with a default. Thus, anybody extending CommandInteractionPayloadMixin, should derive a miranda implementation from CommandInteractionPayloadMixin.

However, the interface SlashCommandInteraction implements CommandInteraction which implements CommandInteractionPayload. But does NOT implement CommandInteracationPayloadMixin.

So there are two paths to getName(). One through an interface tree, and the other through the implementation tree, where the implementation tree contains the default implementation, but the interface tree does not. I guess this is what they mean by a mixin: a set of default implementations for interfaces which can optionally be declared.

I'm going to have to sit down with the JVM spec for awhile and figure out what we're supposed to be doing here, and whether we're doing what we're supposed to be doing.

But what I think is happening is that when discovering the implemented methods, we go in order of implementation expressed by the class file metadata, which expresses the hierarchy. And since the Mixin appears later, at that time, we've already traversed an interface hierarchy where no default implementation existed. Essentially we're seeing getName on CommandInteractionPayload with no body before we encounter CommandInteractionPayloadMixin with a body.