lightbend-labs / mima

A tool for catching binary incompatibility in Scala
Apache License 2.0
459 stars 71 forks source link

False positive InheritedNewAbstractMethodProblem with lazy val (in Scala 2.12)? #187

Closed dwijnand closed 5 years ago

dwijnand commented 7 years ago

I'm setting up MiMa in sbt/util, and I'm seeing it complain about the change in https://github.com/sbt/util/pull/105

The relevant bits is it defines a SuccessEventFormats trait, which contains a SuccessEventFormat lazy val, and then mixes in that SuccessEventFormats trait into a JsonProtocol trait.

When I run mimaReportBinaryIssues I'm getting:

[error]  * abstract method SuccessEventFormat()sjsonnew.JsonFormat in trait sbt.internal.util.codec.SuccessEventFormats is inherited by class JsonProtocol in current version.

Here's my (attempt) to try and reproduce the situation and see if I can trigger a linking error of any shape:

Before

A.scala

package p

trait Show[-A] {
  def show(x: A): String
}

trait BooleanShows {
  implicit lazy val ShowBoolean: Show[Boolean] =
    new Show[Boolean] { def show(x: Boolean) = x.toString }
}

trait IntShows {
  implicit lazy val ShowInt: Show[Int] =
    new Show[Int] { def show(x: Int) = x.toString }
}

trait BasicShows extends AnyRef
  with BooleanShows
  with IntShows

object BasicShows extends BasicShows

B.scala

package p

final class Foo(val x: Int)

object MyShows extends AnyRef
  with BasicShows
{
  implicit lazy val ShowFoo: Show[Foo] =
    new Show[Foo] { def show(x: Foo) = s"Foo(${x.x})" }
}

object Main {
  import MyShows._

  def main(args: Array[String]): Unit = {
    println(implicitly[Show[Int]] show 1)
    println(implicitly[Show[Foo]] show new Foo(1))
  }
}

test: compile everything and run it

$ scalac *.scala
$ scala p.Main
1
Foo(1)

After

Define StringShows and add it to BasicShows in A.scala:

diff --git a/A.scala b/A.scala
index 68bba1d..efffd0a 100644
--- a/A.scala
+++ b/A.scala
@@ -14,8 +14,14 @@ trait IntShows {
     new Show[Int] { def show(x: Int) = x.toString }
 }

+trait StringShows {
+  implicit lazy val ShowString: Show[String] =
+    new Show[String] { def show(x: String) = x }
+}
+
 trait BasicShows extends AnyRef
   with BooleanShows
   with IntShows
+  with StringShows

 object BasicShows extends BasicShows

test: recompile just A.scala and run it

$ scalac A.scala
$ scala p.Main
1
Foo(1)

I've also been looking at diffs of javap output (via libscala's textconv-javap) and I see some things change, but I'm not sure what to make of them as, again, I can't find a way to trigger a failure.

dwijnand commented 5 years ago

Who knows. Don't care enough any more.