From 8bafa8ed88da0d522425c120daf7e0a4e09f88d9 Mon Sep 17 00:00:00 2001 From: Lukas Rytz Date: Tue, 30 Jun 2015 14:12:43 +0200 Subject: [backport] Java parser: default methods in interfaces are not `DEFERRED` The Java parser should not set the `DEFERRED` flag for default methods or static methods in interfaces. Their bytecode doesn't have it either. Also tightens parsing of Java abstract methods to disallow a method body. Here's the log of how Lukas diagnosed this: ``` quick.bin: ... BUILD FAILED /Users/luc/scala/scala/build.xml:69: The following error occurred while executing this line: ... /Users/luc/scala/scala/build-ant-macros.xml:350: Could not create type mk-bin due to java.lang.BootstrapMethodError: call site initialization exception at java.lang.invoke.CallSite.makeSite(CallSite.java:341) at java.lang.invoke.MethodHandleNatives.linkCallSiteImpl(MethodHandleNatives.java:307) at java.lang.invoke.MethodHandleNatives.linkCallSite(MethodHandleNatives.java:297) at scala.sys.BooleanProp$.keyExists(BooleanProp.scala:72) at scala.sys.SystemProperties$.bool(SystemProperties.scala:78) at scala.sys.SystemProperties$.noTraceSupression$lzycompute(SystemProperties.scala:89) at scala.sys.SystemProperties$.noTraceSupression(SystemProperties.scala:89) at scala.util.control.NoStackTrace$.(NoStackTrace.scala:31) at scala.util.control.NoStackTrace$.(NoStackTrace.scala) at scala.util.control.NoStackTrace$class.fillInStackTrace(NoStackTrace.scala:22) at scala.util.control.BreakControl.fillInStackTrace(Breaks.scala:94) at java.lang.Throwable.(Throwable.java:250) at scala.util.control.BreakControl.(Breaks.scala:94) at scala.util.control.Breaks.(Breaks.scala:29) at scala.collection.Traversable$.(Traversable.scala:95) at scala.collection.Traversable$.(Traversable.scala) at scala.package$.(package.scala:40) at scala.package$.(package.scala) at scala.Predef$.(Predef.scala:89) at scala.Predef$.(Predef.scala) at scala.tools.ant.ScalaTool.(ScalaTool.scala:58) [...] Caused by: java.lang.invoke.LambdaConversionException: Incorrect number of parameters for static method invokeStatic scala.sys.BooleanProp$.scala$sys$BooleanProp$$$anonfun$2$adapted:(String)Object; 0 captured parameters, 0 functional interface method parameters, 1 implementation parameters at java.lang.invoke.AbstractValidatingLambdaMetafactory.validateMetafactoryArgs(AbstractValidatingLambdaMetafactory.java:193) at java.lang.invoke.LambdaMetafactory.altMetafactory(LambdaMetafactory.java:473) at java.lang.invoke.CallSite.makeSite(CallSite.java:325) ``` [source code](https://github.com/scala/scala/blob/2.11.x/src/library/scala/sys/BooleanProp.scala#L72): ``` s => s == "" || s.equalsIgnoreCase("true") ``` bytecode: ``` INVOKEDYNAMIC $init$()Lscala/compat/java8/JFunction1; [ // handle kind 0x6 : INVOKESTATIC java/lang/invoke/LambdaMetafactory.altMetafactory(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;[Ljava/lang/Object;)Ljava/lang/invoke/CallSite; // arguments: ()V, // handle kind 0x6 : INVOKESTATIC scala/sys/BooleanProp$.scala$sys$BooleanProp$$$anonfun$2$adapted(Ljava/lang/String;)Ljava/lang/Object;, (Ljava/lang/String;)Ljava/lang/Object;, 3, 1, Lscala/Serializable;.class, 0 ] CHECKCAST scala/Function1 ``` The mistake seems to be that the Scala compiler incorrectly selects `$init$` ([which is a default method](https://github.com/scala/scala/blob/640ffe7fceb5d573b2c12a7c7da09bfd751036a0/src/library/scala/compat/java8/JFunction1.java#L10)) as the abstract method of `JFunction1`, whereas it should be `apply` (inherited from `Function1`). Since we're doing mixed compilation, this is almost certainly a problem of the Java parser. --- src/compiler/scala/tools/nsc/javac/JavaParsers.scala | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) (limited to 'src/compiler') diff --git a/src/compiler/scala/tools/nsc/javac/JavaParsers.scala b/src/compiler/scala/tools/nsc/javac/JavaParsers.scala index 9708cba281..03f0236734 100644 --- a/src/compiler/scala/tools/nsc/javac/JavaParsers.scala +++ b/src/compiler/scala/tools/nsc/javac/JavaParsers.scala @@ -489,8 +489,8 @@ trait JavaParsers extends ast.parser.ParsersCommon with JavaScanners { val vparams = formalParams() if (!isVoid) rtpt = optArrayBrackets(rtpt) optThrows() - val isStatic = mods hasFlag Flags.STATIC - val bodyOk = !inInterface || ((mods hasFlag Flags.DEFAULTMETHOD) || isStatic) + val isConcreteInterfaceMethod = !inInterface || (mods hasFlag Flags.DEFAULTMETHOD) || (mods hasFlag Flags.STATIC) + val bodyOk = !(mods1 hasFlag Flags.DEFERRED) && isConcreteInterfaceMethod val body = if (bodyOk && in.token == LBRACE) { methodBody() @@ -509,7 +509,9 @@ trait JavaParsers extends ast.parser.ParsersCommon with JavaScanners { EmptyTree } } - if (inInterface && !isStatic) mods1 |= Flags.DEFERRED + // for abstract methods (of classes), the `DEFERRED` flag is alredy set. + // here we also set it for interface methods that are not static and not default. + if (!isConcreteInterfaceMethod) mods1 |= Flags.DEFERRED List { atPos(pos) { DefDef(mods1, name.toTermName, tparams, List(vparams), rtpt, body) -- cgit v1.2.3