bug
bug copied to clipboard
Subtractable nightmare on array loops in 2.12
I am constantly having things like:
[error] /home/antonkulaga/denigma/processors/main/src/main/scala/org/clulab/swirl2/Reader.scala:173: type arguments [?,Iterable[Any] with Int => Any with scala.collection.generic.Subtractable[_ >: (Int, Int, String) with Int, Iterable[Any] with Int => Any with scala.collection.generic.Subtractable[_ >: (Int, Int, String) with Int, Equals]]{def seq: Iterable[Any] with Int => Any}] do not conform to trait Subtractable's type parameter bounds [A,+Repr <: scala.collection.generic.Subtractable[A,Repr]]
[error] for(modifier <- tokens.indices) {
(note the code is from https://github.com/antonkulaga/processors that I try to port to 2.12.1) with java array loops in Scala 2.12.1 (same code works well on Scala 2.11.8).
Imported From: https://issues.scala-lang.org/browse/SI-10151?orig=1 Reporter: Anton Kulaga (antonkulaga) Affected Versions: 2.12.1
@som-snytt said: Reducedly,
package badindices
import scala.collection.mutable
import scala.collection.mutable.{ArrayBuffer, ListBuffer}
case class DirectedGraph[A](a: A)
class Reader {
class CoNLLToken(
val word:String,
val pos:String,
val lemma:String,
val dep:(Int, String), // head, label
val pred:Int,
val frameBits:Array[String]) {
override def toString:String = word + "/" + pos + "/" + dep._1 + "/" + dep._2 + "/" + pred
}
def toDirectedGraph(tokens:Array[CoNLLToken]):DirectedGraph[String] = {
val edges = new mutable.ListBuffer[(Int, Int, String)] // head, modifier, label
val roots = new mutable.HashSet[Int]()
for(modifier <- tokens.indices) {
val head = tokens(modifier).dep._1
if(head >= 0)
edges += new Tuple3(head, modifier, tokens(modifier).dep._2)
else
roots += modifier
}
DirectedGraph[String]("hi")
}
}
with the challenging inference
scala.Predef.refArrayOps[Reader.this.CoNLLToken](tokens).indices.foreach[scala.collection.mutable.Iterable[_ >: (Int, Int, String) with Int] with scala.collection.AbstractIterable[Any] with scala.collection.mutable.Cloneable[scala.collection.mutable.Iterable[_ >: (Int, Int, String) with Int] with scala.collection.mutable.Cloneable[scala.collection.mutable.Iterable[_ >: (Int, Int, String) with Int] with scala.collection.mutable.Cloneable[Cloneable with Mutable with Equals] with Int => Any{def seq: Cloneable with Mutable with Equals}] with Int => Any] with scala.collection.mutable.Builder[(Int, Int, String) with Int,Iterable[Any] with Int => Any{def seq: Iterable[Any] with Int => Any}] with Int => Any with Serializable with scala.collection.generic.Shrinkable[(Int, Int, String) with Int] with scala.collection.generic.Subtractable[_ >: (Int, Int, String) with Int, Iterable[Any] with Int => Any with scala.collection.generic.Subtractable[_ >: (Int, Int, String) with Int, Iterable[Any] with Int => Any with scala.collection.generic.Subtractable[_ >: (Int, Int, String) with Int, Equals]]{def seq: Iterable[Any] with Int => Any}] with scala.collection.script.Scriptable[_ >: (Int, Int, String) with Int]](((modifier: Int) => {
val head: Int = tokens.apply(modifier).dep._1;
if (head.>=(0))
edges.+=(new (Int, Int, String)(head, modifier, tokens.apply(modifier).dep._2))
else
roots.+=(modifier)
}));
@som-snytt said: The workaround is to add a unit value after the if/else and avoid the inference.
Encountered this one today... pretty awkward.
Here is another example of how to reproduce (note the example is a bit contrived as we reduced to remove unnecessary logic)
case class Country(name: String)
object Countries {
def find(name: String): Option[Country] = None
}
import scala.collection.mutable
object Main extends App {
val data: Seq[(String, String)] = Nil
val invalid = mutable.Set[String]()
val countries = mutable.ListBuffer[Country]()
data.foreach { case (label, code) =>
Countries.find(code) match {
case None => invalid
case Some(c) => countries
}
}
}
sbt compile results in:
[error] /web/foo/Main.scala:16: type arguments [?,Iterable[java.io.Serializable] with String with Int => Any with scala.collection.generic.Subtractable[_ >: String with Country <: java.io.Serializable, Iterable[java.io.Serializable] with String with Int => Any with scala.collection.generic.Subtractable[_ >: String with Country <: java.io.Serializable, Equals]]{def seq: Iterable[java.io.Serializable] with String with Int => Any}] do not conform to trait Subtractable's type parameter bounds [A,+Repr <: scala.collection.generic.Subtractable[A,Repr]]
[error] data.foreach { case (label, code) =>
[error] ^
[error] one error found
[error] (compile:compileIncremental) Compilation failed
[error] Total time: 5 s, completed Jul 27, 2017 4:06:22 PM
https://github.com/scala/bug/issues/10359 has a nice short reproduction (of what at least seems to be the same issue, investigation would be needed to confirm)
I'm putting this on the 2.13.0-M4 milestone because I think we should at least check whether any of these reproducers still fail after new collections land. (If they stop failing, it won't mean the real inference issue is fixed, but it will lower the significance of the bug.)
There are other type inference issues related to F-bounded types (I assume this is the case here) like #3528. The problem is in glb/lub of such types.
I’ve tried compiling the code of https://github.com/scala/bug/issues/10151#issuecomment-318390443 in 2.13.x branch and there is no error anymore (note that we have removed Subtractable in the new collections)
Can someone suggest a more informative title for this ticket?
I've created a gist displaying what I believe is the same bug but with a workaround that is slightly different than the samples shown above: https://gist.github.com/nivekastoreth/5c0e005c986a3827aa29a17a9274fb40
Because these are specs2 tests and not some unit loop, the workaround mentioned previously in this ticket wasn't applicable.