ZenCodeLang / ZenCode

The ZenCode project.
MIT License
12 stars 8 forks source link

Unable to call a method with an array of functions #11

Closed TheSilkMiner closed 3 years ago

TheSilkMiner commented 3 years ago

It is currently impossible to call a method that accepts as a parameter an array of functional interfaces.

The following tests have been performed not on the latest commit of ZenCode/development, rather on b22610c4357b4137aff716cdd0c11141425d8042 due to the major refactors caused by the addition of native types. Nevertheless, the code path that throws the exception seems to be mostly unaffected by the changes.

Consider the following example method:

@ZenCodeType.Method public void register(final String name, final ILootCondition[] conditions, final ILootModifier modifier) {}

In this case, ILootCondition corresponds to a functional interface that corresponds to a (MCLootContext) => bool function in ZenCode, whereas ILootModifier is another functional interface that wraps the function (List<IItemStack>, MCLootContext) => List<IItemStack>.

Consider now the following script:

loot.modifiers.register("yeet_lights", [(context) => context.blockState.lightLevel > 10], (loot, context) => { return new List<IItemStack>(); });
loot.modifiers.register("no_op_but_two_conditions", [(context) => true, (context) => true] as ILootCondition[], (loot, context) => loot);

Attempting to run this script causes a compilation error on the second line with the following message:

[14:14:39.875][DONE][CLIENT][ERROR] loot_modifier_test.zs:19:0 No matching method found for register:
Parameter 1: cannot cast ILootCondition[] to function(arg0 as MCLootContext) as bool[]

Note that the same error doesn't appear for the first script line because of the lack of the explicit ILootCondition[] cast. Adding the explicit cast onto the first line causes the same issue.

If the cast from the second line is removed, an UnsupportedOperationException is instead thrown on compilation stage, of which the stacktrace will be provided at the end of this issue. The fact that commenting out the last line of the script does not prevent the exception from being thrown makes me assume that the lack of a cast is confusing the compiler and it cannot determine the result of the expression.

Stacktrace ``` [14:13:32.802][DONE][CLIENT][ERROR] Error running scripts java.lang.UnsupportedOperationException: Invalid type: Could not infer return type at org.openzen.zenscript.codemodel.type.TypeVisitor.visitInvalid(TypeVisitor.java:34) at org.openzen.zenscript.codemodel.type.InvalidTypeID.accept(InvalidTypeID.java:63) at org.openzen.zenscript.javashared.JavaTypeGenericVisitor.getGenericSignature(JavaTypeGenericVisitor.java:25) at org.openzen.zenscript.javashared.JavaTypeGenericVisitor.getGenericMethodSignature(JavaTypeGenericVisitor.java:88) at org.openzen.zenscript.javashared.JavaContext.getMethodSignature(JavaContext.java:243) at org.openzen.zenscript.javabytecode.compiler.JavaExpressionVisitor.visitFunction(JavaExpressionVisitor.java:2038) at org.openzen.zenscript.javabytecode.compiler.JavaExpressionVisitor.visitFunction(JavaExpressionVisitor.java:30) at org.openzen.zenscript.codemodel.expression.FunctionExpression.accept(FunctionExpression.java:46) at org.openzen.zenscript.javabytecode.compiler.JavaExpressionVisitor.visitCall(JavaExpressionVisitor.java:445) at org.openzen.zenscript.javabytecode.compiler.JavaExpressionVisitor.visitCall(JavaExpressionVisitor.java:30) at org.openzen.zenscript.codemodel.expression.CallExpression.accept(CallExpression.java:38) at org.openzen.zenscript.javabytecode.compiler.JavaStatementVisitor.visitVar(JavaStatementVisitor.java:336) at org.openzen.zenscript.javabytecode.compiler.JavaStatementVisitor.visitVar(JavaStatementVisitor.java:16) at org.openzen.zenscript.codemodel.statement.VarStatement.accept(VarStatement.java:39) at org.openzen.zenscript.javabytecode.JavaCompiler.compile(JavaCompiler.java:109) at org.openzen.zencode.java.ScriptingEngine.createRunUnit(ScriptingEngine.java:139) at org.openzen.zencode.java.ScriptingEngine.run(ScriptingEngine.java:147) at com.blamejared.crafttweaker.api.zencode.impl.loaders.ScriptRun.readAndExecuteScripts(ScriptRun.java:107) at com.blamejared.crafttweaker.api.zencode.impl.loaders.ScriptRun.run(ScriptRun.java:76) at com.blamejared.crafttweaker.api.CraftTweakerAPI.loadScripts(CraftTweakerAPI.java:124) at com.blamejared.crafttweaker.api.CraftTweakerAPI.loadScriptsFromRecipeManager(CraftTweakerAPI.java:155) at com.blamejared.crafttweaker.CraftTweaker.getRecipes(CraftTweaker.java:177) at net.minecraftforge.eventbus.ASMEventHandler_18_CraftTweaker_getRecipes_RecipesUpdatedEvent.invoke(.dynamic) at net.minecraftforge.eventbus.ASMEventHandler.invoke(ASMEventHandler.java:85) at net.minecraftforge.eventbus.EventBus.post(EventBus.java:297) at net.minecraftforge.client.ForgeHooksClient.onRecipesUpdated(ForgeHooksClient.java:692) at net.minecraft.client.network.play.ClientPlayNetHandler.handleUpdateRecipes(ClientPlayNetHandler.java:1455) at net.minecraft.network.play.server.SUpdateRecipesPacket.processPacket(SUpdateRecipesPacket.java:30) at net.minecraft.network.play.server.SUpdateRecipesPacket.processPacket(SUpdateRecipesPacket.java:16) at net.minecraft.network.PacketThreadUtil.lambda$checkThreadAndEnqueue$0(PacketThreadUtil.java:19) at net.minecraft.util.concurrent.ThreadTaskExecutor.run(ThreadTaskExecutor.java:139) at net.minecraft.util.concurrent.RecursiveEventLoop.run(RecursiveEventLoop.java:22) at net.minecraft.util.concurrent.ThreadTaskExecutor.driveOne(ThreadTaskExecutor.java:109) at net.minecraft.util.concurrent.ThreadTaskExecutor.drainTasks(ThreadTaskExecutor.java:97) at net.minecraft.client.Minecraft.runGameLoop(Minecraft.java:973) at net.minecraft.client.Minecraft.run(Minecraft.java:612) at net.minecraft.client.main.Main.main(Main.java:184) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:498) at net.minecraftforge.userdev.FMLUserdevClientLaunchProvider.lambda$launchService$0(FMLUserdevClientLaunchProvider.java:52) at cpw.mods.modlauncher.LaunchServiceHandlerDecorator.launch(LaunchServiceHandlerDecorator.java:37) at cpw.mods.modlauncher.LaunchServiceHandler.launch(LaunchServiceHandler.java:54) at cpw.mods.modlauncher.LaunchServiceHandler.launch(LaunchServiceHandler.java:72) at cpw.mods.modlauncher.Launcher.run(Launcher.java:82) at cpw.mods.modlauncher.Launcher.main(Launcher.java:66) at net.minecraftforge.userdev.LaunchTesting.main(LaunchTesting.java:105) ```
stanhebben commented 3 years ago

Annoying and complicated issue. The functional interface is not identical to the function type, and thus the casts act up. I'll have a detailed look at this and see how it can best be fixed.