From bbd3b2f2539e60c8938d4574a69b7b0a125636d3 Mon Sep 17 00:00:00 2001 From: jvican Date: Thu, 14 Sep 2017 12:59:12 +0200 Subject: [PATCH] Fix #389: Ignore null in generic lambdas parameters Because of the way lambdas are synthesized by the JVM, at the call-site, it is not possible to know which generic types do lambdas have via the current reflection API. Related but not strictly reasons why this happens can be found in JDK's issue tracker: https://bugs.openjdk.java.net/browse/JDK-8178523?jql=text%20%7E%20%22lambda%20generic%20type%22 As a result, we ignore nulls that are returned by `getGenericParameterTypes`. --- .../scala/sbt/internal/inc/ClassToAPI.scala | 10 +++++-- project/Dependencies.scala | 1 + .../java-typeparameters/Example.java | 26 +++++++++++++++++++ .../java-typeparameters/test | 1 + 4 files changed, 36 insertions(+), 2 deletions(-) create mode 100644 zinc/src/sbt-test/source-dependencies/java-typeparameters/Example.java create mode 100644 zinc/src/sbt-test/source-dependencies/java-typeparameters/test diff --git a/internal/zinc-apiinfo/src/main/scala/sbt/internal/inc/ClassToAPI.scala b/internal/zinc-apiinfo/src/main/scala/sbt/internal/inc/ClassToAPI.scala index f4a08e3085..98c184e892 100644 --- a/internal/zinc-apiinfo/src/main/scala/sbt/internal/inc/ClassToAPI.scala +++ b/internal/zinc-apiinfo/src/main/scala/sbt/internal/inc/ClassToAPI.scala @@ -548,13 +548,19 @@ object ClassToAPI { }.toMap def primitive(name: String): api.Type = PrimitiveRefs(name) + // sbt/zinc#389: Ignore nulls coming from generic parameter types of lambdas + private[this] def ignoreNulls(genericTypes: Array[Type]): Array[Type] = + genericTypes.filterNot(_ == null) + private[this] def returnType(f: Field): Type = f.getGenericType private[this] def returnType(m: Method): Type = m.getGenericReturnType private[this] def exceptionTypes(c: Constructor[_]): Array[Type] = c.getGenericExceptionTypes private[this] def exceptionTypes(m: Method): Array[Type] = m.getGenericExceptionTypes - private[this] def parameterTypes(m: Method): Array[Type] = m.getGenericParameterTypes - private[this] def parameterTypes(c: Constructor[_]): Array[Type] = c.getGenericParameterTypes + private[this] def parameterTypes(m: Method): Array[Type] = + ignoreNulls(m.getGenericParameterTypes) + private[this] def parameterTypes(c: Constructor[_]): Array[Type] = + ignoreNulls(c.getGenericParameterTypes) private[this] def typeParameterTypes[T](m: Constructor[T]): Array[TypeVariable[Constructor[T]]] = m.getTypeParameters diff --git a/project/Dependencies.scala b/project/Dependencies.scala index 729bca6115..d8b3fbc866 100644 --- a/project/Dependencies.scala +++ b/project/Dependencies.scala @@ -79,6 +79,7 @@ object Dependencies { val scalaCheck = "org.scalacheck" %% "scalacheck" % "1.13.4" val scalatest = "org.scalatest" %% "scalatest" % "3.0.1" val junit = "junit" % "junit" % "4.11" + val typetools = "net.jodah" % "typetools" % "0.5.0" val sjsonnew = Def.setting { "com.eed3si9n" %% "sjson-new-core" % contrabandSjsonNewVersion.value } diff --git a/zinc/src/sbt-test/source-dependencies/java-typeparameters/Example.java b/zinc/src/sbt-test/source-dependencies/java-typeparameters/Example.java new file mode 100644 index 0000000000..413bb68d59 --- /dev/null +++ b/zinc/src/sbt-test/source-dependencies/java-typeparameters/Example.java @@ -0,0 +1,26 @@ +package typeparameters; + +import java.util.function.Supplier; + +public class Example { + + static void call() { + Supplier> blah = () -> + new BaseBlah() { + @Override + protected O getResponseInternal(I i) { + return null; + } + }; + } + + public static void main(String[] args) { + Example.call(); + } +} + +abstract class BaseBlah { + protected O getResponseInternal(I i) { + return null; + } +} \ No newline at end of file diff --git a/zinc/src/sbt-test/source-dependencies/java-typeparameters/test b/zinc/src/sbt-test/source-dependencies/java-typeparameters/test new file mode 100644 index 0000000000..73a68203f3 --- /dev/null +++ b/zinc/src/sbt-test/source-dependencies/java-typeparameters/test @@ -0,0 +1 @@ +> compile \ No newline at end of file