scala3 icon indicating copy to clipboard operation
scala3 copied to clipboard

Java Generic Lambda conversion causes runtime crash

Open lenguyenthanh opened this issue 1 year ago • 3 comments

Compiler version

3.3.1

Minimized code

Full context here in lila-ws repository: https://github.com/lichess-org/lila-ws/pull/525/commits/7f47bc39a8b36a0f076b24dd75da17150502040e

This code below crash the runtime:

  private def shutdown(channel: Channel, code: Int, reason: String): Unit =
    channel.writeAndFlush(CloseWebSocketFrame(code, reason)).addListener(_ => channel.close())

The fix is annotating the lambda with type:

  private def shutdown(channel: Channel, code: Int, reason: String): Unit =
    val close: GenericFutureListener[ChannelFuture] = _ => channel.close()
    channel.writeAndFlush(CloseWebSocketFrame(code, reason)).addListener(close)

Stacktrace:

WARN i.n.c.DefaultChannelPipeline [KQueueEventLoopGroup-6-3] An exceptionCaught() event was fired, and it reached at the tail of the pipeline. It usually means the last handler in the pipeline did not handle the exc eption. java.lang.BootstrapMethodError: bootstrap method initialization exception at java.base/java.lang.invoke.BootstrapMethodInvoker.invoke(BootstrapMethodInvoker.java:188) at java.base/java.lang.invoke.CallSite.makeSite(CallSite.java:316) at java.base/java.lang.invoke.MethodHandleNatives.linkCallSiteImpl(MethodHandleNatives.java:274) at java.base/java.lang.invoke.MethodHandleNatives.linkCallSite(MethodHandleNatives.java:264) at lila.ws.netty.FrameHandler.shutdown(FrameHandler.scala:62) at lila.ws.netty.FrameHandler.channelRead0(FrameHandler.scala:27) at lila.ws.netty.FrameHandler.channelRead0(FrameHandler.scala:17) at io.netty.channel.SimpleChannelInboundHandler.channelRead(SimpleChannelInboundHandler.java:99) at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:444) at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:420) at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:412) at io.netty.handler.codec.MessageToMessageDecoder.channelRead(MessageToMessageDecoder.java:103) at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:444) at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:420) at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:412) at io.netty.channel.ChannelInboundHandlerAdapter.channelRead(ChannelInboundHandlerAdapter.java:93) at io.netty.handler.codec.http.websocketx.Utf8FrameValidator.channelRead(Utf8FrameValidator.java:89) at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:444) at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:420) at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:412) at io.netty.channel.SimpleChannelInboundHandler.channelRead(SimpleChannelInboundHandler.java:102) at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:444) at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:420) at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:412) at io.netty.handler.codec.ByteToMessageDecoder.fireChannelRead(ByteToMessageDecoder.java:346) at io.netty.handler.codec.ByteToMessageDecoder.channelRead(ByteToMessageDecoder.java:318) at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:444) at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:420) at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:412) at io.netty.channel.DefaultChannelPipeline$HeadContext.channelRead(DefaultChannelPipeline.java:1410) at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:440) at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:420) at io.netty.channel.DefaultChannelPipeline.fireChannelRead(DefaultChannelPipeline.java:919) at io.netty.channel.kqueue.AbstractKQueueStreamChannel$KQueueStreamUnsafe.readReady(AbstractKQueueStreamChannel.java:544) at io.netty.channel.kqueue.AbstractKQueueChannel$AbstractKQueueUnsafe.readReady(AbstractKQueueChannel.java:387) at io.netty.channel.kqueue.KQueueEventLoop.processReady(KQueueEventLoop.java:218) at io.netty.channel.kqueue.KQueueEventLoop.run(KQueueEventLoop.java:296) at io.netty.util.concurrent.SingleThreadEventExecutor$4.run(SingleThreadEventExecutor.java:997) at io.netty.util.internal.ThreadExecutorMap$2.run(ThreadExecutorMap.java:74) at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30) at java.base/java.lang.Thread.run(Thread.java:1583) Caused by: java.lang.invoke.LambdaConversionException: Type mismatch for dynamic parameter 0: class scala.runtime.Nothing$ is not a subtype of interface io.netty.util.concurrent.Future at java.base/java.lang.invoke.AbstractValidatingLambdaMetafactory.checkDescriptor(AbstractValidatingLambdaMetafactory.java:327) at java.base/java.lang.invoke.AbstractValidatingLambdaMetafactory.validateMetafactoryArgs(AbstractValidatingLambdaMetafactory.java:313) at java.base/java.lang.invoke.LambdaMetafactory.altMetafactory(LambdaMetafactory.java:535) at java.base/java.lang.invoke.BootstrapMethodInvoker.invoke(BootstrapMethodInvoker.java:147) ... 40 common frames omitted

Expectation

Either compile error or We shouldn't need to annotate the type.

lenguyenthanh avatar Feb 19 '24 03:02 lenguyenthanh

This issue was picked for the Scala Issue Spree of tomorrow, April 9th. @hamzaremmal, @Sporarum, @jan-pieter will be working on it. If you have any insight into the issue or guidance on how to fix it, please leave it here.

mbovel avatar Apr 08 '24 08:04 mbovel

It looks very similar to #20114

hamzaremmal avatar Apr 09 '24 14:04 hamzaremmal

java.lang.BootstrapMethodError: bootstrap method initialization exception at java.base/java.lang.invoke.BootstrapMethodInvoker.invoke(BootstrapMethodInvoker.java:188) at

Seems like the compiler insert a Nothing type, because Nothing is a sub type of Future, the listener needs a ? extends Future<?> as input, so scala compiler inser a Nothing?

For the lambda we need insert a Future<?> instead.

I still remember when using scala 2.12.x with completionStage, I have to use stage.[Unit]handle(...) for the compiler to work properly.

He-Pin avatar Apr 09 '24 18:04 He-Pin