Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Crash on null from Method.getGenericParameterTypes #389

Closed
stuhood opened this issue Aug 10, 2017 · 14 comments
Closed

Crash on null from Method.getGenericParameterTypes #389

stuhood opened this issue Aug 10, 2017 · 14 comments

Comments

@stuhood
Copy link

stuhood commented Aug 10, 2017

In some cases (seemingly related to lambdas), Method.getGenericParameterTypes will return an array containing null Types, which are then passed into def defLike to cause crashes.

This commit has a self-contained repro: twitter/pants@aaa07c3 ... that crashes when compiled with zinc 1.0.0-rc3:

[error] ## Exception when compiling 1 sources to current/classes
[error] null
[error] sbt.internal.inc.ClassToAPI$.reference(ClassToAPI.scala:506)
[error] sbt.internal.inc.ClassToAPI$.parameter(ClassToAPI.scala:375)
[error] sbt.internal.inc.ClassToAPI$$anonfun$16.apply(ClassToAPI.scala:351)
[error] sbt.internal.inc.ClassToAPI$$anonfun$16.apply(ClassToAPI.scala:350)
[error] scala.runtime.Tuple3Zipped$$anonfun$map$extension$1.apply(Tuple3Zipped.scala:44)
[error] scala.runtime.Tuple3Zipped$$anonfun$map$extension$1.apply(Tuple3Zipped.scala:42)
[error] scala.collection.IndexedSeqOptimized$class.foreach(IndexedSeqOptimized.scala:33)
[error] scala.collection.mutable.ArrayOps$ofRef.foreach(ArrayOps.scala:186)
[error] scala.runtime.Tuple3Zipped$.map$extension(Tuple3Zipped.scala:42)
[error] sbt.internal.inc.ClassToAPI$.defLike(ClassToAPI.scala:350)
[error] sbt.internal.inc.ClassToAPI$.methodToDef(ClassToAPI.scala:308)
[error] sbt.internal.inc.ClassToAPI$$anonfun$4.apply(ClassToAPI.scala:182)
[error] sbt.internal.inc.ClassToAPI$$anonfun$4.apply(ClassToAPI.scala:182)
[error] sbt.internal.inc.ClassToAPI$$anonfun$mergeMap$1.apply(ClassToAPI.scala:398)
[error] sbt.internal.inc.ClassToAPI$$anonfun$mergeMap$1.apply(ClassToAPI.scala:398)
[error] scala.collection.TraversableLike$$anonfun$flatMap$1.apply(TraversableLike.scala:241)
[error] scala.collection.TraversableLike$$anonfun$flatMap$1.apply(TraversableLike.scala:241)
[error] scala.collection.IndexedSeqOptimized$class.foreach(IndexedSeqOptimized.scala:33)
[error] scala.collection.mutable.WrappedArray.foreach(WrappedArray.scala:35)
[error] scala.collection.TraversableLike$class.flatMap(TraversableLike.scala:241)
[error] scala.collection.AbstractTraversable.flatMap(Traversable.scala:104)
[error] sbt.internal.inc.ClassToAPI$.merge(ClassToAPI.scala:408)
[error] sbt.internal.inc.ClassToAPI$.mergeMap(ClassToAPI.scala:398)
[error] sbt.internal.inc.ClassToAPI$.structure(ClassToAPI.scala:182)
[error] sbt.internal.inc.ClassToAPI$.x$2$lzycompute$1(ClassToAPI.scala:133)
[error] sbt.internal.inc.ClassToAPI$.x$2$1(ClassToAPI.scala:133)
[error] sbt.internal.inc.ClassToAPI$.instance$lzycompute$1(ClassToAPI.scala:133)
[error] sbt.internal.inc.ClassToAPI$.sbt$internal$inc$ClassToAPI$$instance$1(ClassToAPI.scala:133)
[error] sbt.internal.inc.ClassToAPI$$anonfun$2.apply(ClassToAPI.scala:140)
[error] sbt.internal.inc.ClassToAPI$$anonfun$2.apply(ClassToAPI.scala:140)
[error] xsbti.api.SafeLazyProxy$$anon$1.get(SafeLazyProxy.scala:26)
[error] xsbti.api.SafeLazy$Impl.get(SafeLazy.java:58)
[error] sbt.internal.inc.ClassToAPI$$anonfun$process$2.apply(ClassToAPI.scala:29)
[error] sbt.internal.inc.ClassToAPI$$anonfun$process$2.apply(ClassToAPI.scala:29)
[error] scala.collection.immutable.List.foreach(List.scala:392)
[error] scala.collection.generic.TraversableForwarder$class.foreach(TraversableForwarder.scala:35)
[error] scala.collection.mutable.ListBuffer.foreach(ListBuffer.scala:45)
[error] sbt.internal.inc.ClassToAPI$.process(ClassToAPI.scala:29)
[error] sbt.internal.inc.javac.AnalyzingJavaCompiler.sbt$internal$inc$javac$AnalyzingJavaCompiler$$readAPI$1(AnalyzingJavaCompiler.scala:143)
[error] sbt.internal.inc.javac.AnalyzingJavaCompiler$$anonfun$compile$2$$anonfun$apply$mcV$sp$2$$anonfun$apply$4.apply(AnalyzingJavaCompiler.scala:161)
[error] sbt.internal.inc.javac.AnalyzingJavaCompiler$$anonfun$compile$2$$anonfun$apply$mcV$sp$2$$anonfun$apply$4.apply(AnalyzingJavaCompiler.scala:161)
[error] sbt.internal.inc.classfile.Analyze$$anonfun$apply$12.readInheritanceDependencies$1(Analyze.scala:134)
[error] sbt.internal.inc.classfile.Analyze$$anonfun$apply$12.apply(Analyze.scala:150)
[error] sbt.internal.inc.classfile.Analyze$$anonfun$apply$12.apply(Analyze.scala:67)
[error] scala.collection.TraversableLike$WithFilter$$anonfun$foreach$1.apply(TraversableLike.scala:733)
[error] scala.collection.mutable.HashMap$$anonfun$foreach$1.apply(HashMap.scala:130)
[error] scala.collection.mutable.HashMap$$anonfun$foreach$1.apply(HashMap.scala:130)
[error] scala.collection.mutable.HashTable$class.foreachEntry(HashTable.scala:236)
[error] scala.collection.mutable.HashMap.foreachEntry(HashMap.scala:40)
[error] scala.collection.mutable.HashMap.foreach(HashMap.scala:130)
[error] scala.collection.TraversableLike$WithFilter.foreach(TraversableLike.scala:732)
[error] sbt.internal.inc.classfile.Analyze$.apply(Analyze.scala:67)
[error] sbt.internal.inc.javac.AnalyzingJavaCompiler$$anonfun$compile$2$$anonfun$apply$mcV$sp$2.apply(AnalyzingJavaCompiler.scala:161)
[error] sbt.internal.inc.javac.AnalyzingJavaCompiler$$anonfun$compile$2$$anonfun$apply$mcV$sp$2.apply(AnalyzingJavaCompiler.scala:159)
[error] scala.collection.TraversableLike$WithFilter$$anonfun$foreach$1.apply(TraversableLike.scala:733)
[error] scala.collection.immutable.List.foreach(List.scala:392)
[error] scala.collection.TraversableLike$WithFilter.foreach(TraversableLike.scala:732)
[error] sbt.internal.inc.javac.AnalyzingJavaCompiler$$anonfun$compile$2.apply$mcV$sp(AnalyzingJavaCompiler.scala:159)
[error] sbt.internal.inc.javac.AnalyzingJavaCompiler$$anonfun$compile$2.apply(AnalyzingJavaCompiler.scala:159)
[error] sbt.internal.inc.javac.AnalyzingJavaCompiler$$anonfun$compile$2.apply(AnalyzingJavaCompiler.scala:159)
[error] sbt.internal.inc.javac.AnalyzingJavaCompiler.timed(AnalyzingJavaCompiler.scala:196)
[error] sbt.internal.inc.javac.AnalyzingJavaCompiler.compile(AnalyzingJavaCompiler.scala:158)
[error] sbt.internal.inc.MixedAnalyzingCompiler$$anonfun$compileJava$1$1.apply$mcV$sp(MixedAnalyzingCompiler.scala:96)
[error] sbt.internal.inc.MixedAnalyzingCompiler$$anonfun$compileJava$1$1.apply(MixedAnalyzingCompiler.scala:89)
[error] sbt.internal.inc.MixedAnalyzingCompiler$$anonfun$compileJava$1$1.apply(MixedAnalyzingCompiler.scala:89)
[error] sbt.internal.inc.MixedAnalyzingCompiler.timed(MixedAnalyzingCompiler.scala:132)
[error] sbt.internal.inc.MixedAnalyzingCompiler.compileJava$1(MixedAnalyzingCompiler.scala:89)
[error] sbt.internal.inc.MixedAnalyzingCompiler.compile(MixedAnalyzingCompiler.scala:115)
[error] sbt.internal.inc.IncrementalCompilerImpl$$anonfun$4.apply(IncrementalCompilerImpl.scala:305)
[error] sbt.internal.inc.IncrementalCompilerImpl$$anonfun$4.apply(IncrementalCompilerImpl.scala:305)
[error] sbt.internal.inc.Incremental$.doCompile(Incremental.scala:101)
[error] sbt.internal.inc.Incremental$$anonfun$1$$anonfun$apply$1.apply(Incremental.scala:82)
[error] sbt.internal.inc.Incremental$$anonfun$1$$anonfun$apply$1.apply(Incremental.scala:82)
[error] sbt.internal.inc.IncrementalCommon.recompileClasses(IncrementalCommon.scala:118)
[error] sbt.internal.inc.IncrementalCommon.cycle(IncrementalCommon.scala:58)
[error] sbt.internal.inc.Incremental$$anonfun$1.apply(Incremental.scala:76)
[error] sbt.internal.inc.Incremental$$anonfun$1.apply(Incremental.scala:75)
[error] sbt.internal.inc.Incremental$.manageClassfiles(Incremental.scala:129)
[error] sbt.internal.inc.Incremental$.compile(Incremental.scala:75)
[error] sbt.internal.inc.IncrementalCompile$.apply(Compile.scala:70)
[error] sbt.internal.inc.IncrementalCompilerImpl.compileInternal(IncrementalCompilerImpl.scala:302)
[error] sbt.internal.inc.IncrementalCompilerImpl$$anonfun$compileIncrementally$1.apply(IncrementalCompilerImpl.scala:263)
[error] sbt.internal.inc.IncrementalCompilerImpl$$anonfun$compileIncrementally$1.apply(IncrementalCompilerImpl.scala:237)
[error] sbt.internal.inc.IncrementalCompilerImpl.handleCompilationError(IncrementalCompilerImpl.scala:158)
[error] sbt.internal.inc.IncrementalCompilerImpl.compileIncrementally(IncrementalCompilerImpl.scala:237)
[error] sbt.internal.inc.IncrementalCompilerImpl.compile(IncrementalCompilerImpl.scala:68)
@jvican
Copy link
Member

jvican commented Aug 10, 2017

Thanks for reporting @stuhood, I'll be looking into this today.

@jvican
Copy link
Member

jvican commented Aug 11, 2017

I have bad news; this bug is caused by a fundamental deficiency in the reflection API. It's not possible to know what the type parameters of a lambda class are going to be if we're not at the call-site (since lambdas are generated at runtime based on the call-site information).

References:

  1. How to resolve generic type of lambda parameter.
  2. The three first reported bugs here.

So, this means we need to use low-level, internal runtime tricks to get the actual type parameters of lambdas (which could not work in all the VMs).

The only plausible workaround that I can implement in Zinc is to ignore nulls returned by parameter types and parameterized types. This has several inconveniences: it's ugly and error-prone (we don't know to which parts the lambda classes leak with 100% certainty). However, I think it's better than nothing for now. I don't mind doing so, it's up to you to decide @stuhood.

There's a github repo supposed to fix this problem (https://github.com/jhalterman/typetools) but it doesn't solve it in its entirety (it cannot get type parameters that are not used in the implemented functional interfaces; see example in README) and it has certain requirements that I'm not sure we have in Zinc (like access to the class representing the lhs of a local variable).

All in all, I think it may be best to synchronize with the Intellij team and see what they're doing to work around this limitation (their java incremental compiler must have encountered these issues at some point in the past). I think that a deeper investigation of this issue is required before proposing a stable fix -- and FTR it's not even clear to me if this solution exists or not.

@stuhood
Copy link
Author

stuhood commented Aug 11, 2017

@jvican : A filter for the null (or something to widen the type to Object, I suppose) would be good... leaving a nice big comment to explain it would be sufficient. Thanks for investigating!

I'll be out for the next month, so no hurry to land anything.

@jvican
Copy link
Member

jvican commented Aug 14, 2017

Perfect, I'll wait and look into a better fix then -- if there's such a fix. Enjoy the vacation @stuhood.

@jvican
Copy link
Member

jvican commented Aug 31, 2017

@stuhood Let me know when you're back from vacation and we'll sync up on how to move forward on this one.

@stuhood
Copy link
Author

stuhood commented Sep 14, 2017

@jvican : Hey Jorge: I'm back.

So, presumably the risk here is that if we don't detect some type as used, we won't invalidate correctly when that type changes? Are there any sorts of guarantees that types used in lambdas are already in scope elsewhere? In a nearby method signature, for example? Alternatively, if the type is not known at all at compile time, is it by-definition safe not to have the type trigger invalidation?

Given that this is one of the last issues blocking upgrading pants to this version of zinc, I think I'd be willing to live with hackier solutions that might cause overcompilation, or undercompilation even (as long as we continued to track it as a bug?).

@ktoso
Copy link
Member

ktoso commented Sep 28, 2017

We can confirm this is happening in Akka as well;
We only noticed it when building under JDK9 (and Scala 2.12.3, sbt 1.0.2), though perhaps those are not the root of the issue but rather changed some timing or something that made this happen more often?

Example Akka build where it happened: https://jenkins.akka.io:8498/job/akka-nightly-jdk9/13/consoleFull

We planned to release a JDK9 compatible and build today, hope we can work around this issue.

@retronym
Copy link
Member

Am I correct in assuming that a lambda implementation method is being looked at when the null's arise? These methods are private. Is there a reason that Zinc actually needs to reflect over private methods in Java compiled classes?

@retronym
Copy link
Member

retronym commented Sep 28, 2017

To answer my own question: No.

In @stuhood's test:

import java.util.function.Supplier;

public class Example {

  static <I, O> void call() {
    Supplier<BaseBlah<I, O>> blah = () ->
      new BaseBlah<I, O>() {
        @Override
        protected O getResponseInternal(I i) {
          return null;
        }
      };
  }

  public static void main(String[] args) {
    Example.<String, String>call();
  }
}

abstract class BaseBlah<I, O> {
  protected O getResponseInternal(I i) {
    return null;
  }
}

The context for the crash is:

protected java.lang.Object Example$1.getResponseInternal(java.lang.Object)

Is the one that (sometimes?) gives:

m.getGenericParameterTypes = {null}
m.toGenericString = "<java.lang.NullPointerException>"
m.getDeclaringClass = class Example$1
m.getDeclaringClass.getEnclosingMethod
m.signature = "(TI;)TO;"

If we can assume that these null-s are only going to show up in place of references to generic type parameters, it would probably be safe to ignore the reference, as it is intra-compilation unit and should not be material to Zinc.

This method has a generic signature of "(TI;)TO;", but Java reflection is unable to find the declarations of these generics as the lambda implementation method is taken as the enclosing method, rather than the original source method Example.call.

Is there a JDK bug that specifically covers this problem? JDK-8178523 appears to be similar but not the same.

@retronym
Copy link
Member

retronym commented Sep 28, 2017

Here's a standalone reproduction of the JDK bug.

import java.util.function.Supplier;

public class Example {

  static <I, O> void call() {
    Supplier<BaseBlah<I, O>> blah = () ->
      new BaseBlah<I, O>() {
        @Override
        protected O getResponseInternal(I i) {
          return null;
        }
      };
  }

  public static void main(String[] args) {
    Example.<String, String>call();
  }
}

abstract class BaseBlah<I, O> {
  protected O getResponseInternal(I i) {
    return null;
  }
}
⚡ javac -version; javac -d /tmp /tmp/Example.java ; jshell --class-path /tmp
javac 9
|  Welcome to JShell -- Version 9
|  For an introduction type: /help intro

jshell> java.lang.reflect.Method m = Class.forName("Example$1").getDeclaredMethods()[0]
m ==> protected java.lang.Object Example$1.getResponseInternal(java.lang.Object)

jshell> m.getGenericParameterTypes()
$2 ==> Type[1] { null }

jshell> m.getDeclaringClass()
$3 ==> class Example$1

jshell> m.getDeclaringClass().getEnclosingMethod()
$4 ==> private static BaseBlah Example.lambda$call$0()

@jvican
Copy link
Member

jvican commented Sep 28, 2017

Today I'm sending a PR to fix this.

@dwijnand dwijnand added this to the 1.0.2 milestone Sep 28, 2017
jvican added a commit to scalacenter/zinc that referenced this issue Sep 28, 2017
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`.
jvican added a commit to scalacenter/zinc that referenced this issue Sep 28, 2017
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`.
jvican added a commit to scalacenter/zinc that referenced this issue Sep 28, 2017
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`.
jvican added a commit to scalacenter/zinc that referenced this issue Sep 28, 2017
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`.
jvican added a commit to scalacenter/zinc that referenced this issue Sep 28, 2017
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`.

Fixes sbt#389.
jvican added a commit to scalacenter/zinc that referenced this issue Sep 28, 2017
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`.

Fixes sbt#389.
jvican added a commit to scalacenter/zinc that referenced this issue Sep 28, 2017
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`.

Fixes sbt#389.
jvican added a commit to scalacenter/zinc that referenced this issue Sep 28, 2017
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`.

Fixes sbt#389.
jvican added a commit to scalacenter/zinc that referenced this issue Sep 28, 2017
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`.

Fixes sbt#389.
jvican added a commit to scalacenter/zinc that referenced this issue Sep 29, 2017
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`.

Fixes sbt#389.
jvican added a commit to scalacenter/zinc that referenced this issue Sep 29, 2017
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`.

Fixes sbt#389.
@dwijnand dwijnand modified the milestones: 1.0.2, 1.0.3 Oct 2, 2017
@stuhood
Copy link
Author

stuhood commented Oct 5, 2017

Thanks for continuing to investigate gang! Looking forward to consuming 1.0.0.

jvican added a commit to scalacenter/zinc that referenced this issue Oct 26, 2017
`Method.getGenericParameterType` may sometimes return `null` for the
return types when the method's return type is indeed generic. It's not
clear yet where this "sometimes" happens, but it looks like the JDK is
not able to tell the return type of a lambda returning the generic
class.

This can be seen in the `java-lambda-typeparams` scripted test. In this
context, lambda metafactory synthesizes a lambda class that returns a
class that is parameterized in its return type. In that context, when
`ClassToAPI` inspects the synthesized lambda and tries to figure out the
full return type of it, the `null` is returned.

It looks like the Java reflection API sparingly returns `null`s. We can
see that in `ClassToAPI` where we guard against `null`s in lots of other
places. So the guard added by this commit is not a novelty, but rather
the norm.

Fixes sbt#389.
@jvican
Copy link
Member

jvican commented Oct 26, 2017

The bugfix is expected to ship in 1.0.3.

eed3si9n pushed a commit to eed3si9n/zinc that referenced this issue Oct 26, 2017
`Method.getGenericParameterType` may sometimes return `null` for the
return types when the method's return type is indeed generic. It's not
clear yet where this "sometimes" happens, but it looks like the JDK is
not able to tell the return type of a lambda returning the generic
class.

This can be seen in the `java-lambda-typeparams` scripted test. In this
context, lambda metafactory synthesizes a lambda class that returns a
class that is parameterized in its return type. In that context, when
`ClassToAPI` inspects the synthesized lambda and tries to figure out the
full return type of it, the `null` is returned.

It looks like the Java reflection API sparingly returns `null`s. We can
see that in `ClassToAPI` where we guard against `null`s in lots of other
places. So the guard added by this commit is not a novelty, but rather
the norm.

Fixes sbt#389.
@eed3si9n eed3si9n self-assigned this Oct 26, 2017
@jvican jvican closed this as completed Oct 27, 2017
@stuhood
Copy link
Author

stuhood commented Nov 3, 2017

Confirmed fixed in 1.0.3... thanks a bunch!

stuhood pushed a commit to pantsbuild/pants that referenced this issue Nov 3, 2017
### Problem

#4729 is currently blocked on the fix for sbt/zinc#389, which is now released in zinc `1.0.3`.

### Solution

Bump to zinc 1.0.3 to pick up that fix.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

6 participants