Skip to content

Commit

Permalink
SI-8372: unspliceable type printed in error message
Browse files Browse the repository at this point in the history
The b8a76f6 introduced ArrayOps.{unzip,
unzip3} methods. Both of those methods have ClassTags as context bounds on
their type parameters so they can create (and return) instances of Arrays.
The type inference for those methods is supposed to be guided by
implicit evidence that T <: (T1, T2) (or T <: (T1, T2, T3) in unzip3 case).
However, context bounds are desugared into implicit parameters that
prepended in front of implicit parameters declared in source code. That
means the implicit evidence won't have a chance to guide type inference
because it comes as last implicit parameter.

This commit desugars context bounds and puts them at the end of implicit
parameter list. This way type inference is guided properly and we get
expected compiler errors for missing class tags.

The change to parameters order breaks binary compatibility with respect
to 2.11.0-RC1. I added filters to our binary compatibility configuration
files. We can get rid of them as soon as 2.11.0 is out.
  • Loading branch information
gkossakowski committed Mar 7, 2014
1 parent 9b0d0a8 commit ed74326
Show file tree
Hide file tree
Showing 4 changed files with 218 additions and 5 deletions.
99 changes: 99 additions & 0 deletions bincompat-backward.whitelist.conf
Expand Up @@ -4,4 +4,103 @@ filter {
# "scala.concurrent.impl"
# "scala.reflect.runtime"
]
// see SI-8372
problems=[
{
matchName="scala.collection.mutable.ArrayOps#ofChar.unzip"
problemName=IncompatibleMethTypeProblem
},
{
matchName="scala.collection.mutable.ArrayOps#ofChar.unzip3"
problemName=IncompatibleMethTypeProblem
},
{
matchName="scala.collection.mutable.ArrayOps#ofByte.unzip"
problemName=IncompatibleMethTypeProblem
},
{
matchName="scala.collection.mutable.ArrayOps#ofByte.unzip3"
problemName=IncompatibleMethTypeProblem
},
{
matchName="scala.collection.mutable.ArrayOps#ofShort.unzip"
problemName=IncompatibleMethTypeProblem
},
{
matchName="scala.collection.mutable.ArrayOps#ofShort.unzip3"
problemName=IncompatibleMethTypeProblem
},
{
matchName="scala.collection.mutable.ArrayOps#ofLong.unzip"
problemName=IncompatibleMethTypeProblem
},
{
matchName="scala.collection.mutable.ArrayOps#ofLong.unzip3"
problemName=IncompatibleMethTypeProblem
},
{
matchName="scala.collection.mutable.ArrayOps#ofInt.unzip"
problemName=IncompatibleMethTypeProblem
},
{
matchName="scala.collection.mutable.ArrayOps#ofInt.unzip3"
problemName=IncompatibleMethTypeProblem
},
{
matchName="scala.collection.mutable.ArrayOps.unzip"
problemName=MissingMethodProblem
},
{
matchName="scala.collection.mutable.ArrayOps.unzip3"
problemName=MissingMethodProblem
},
{
matchName="scala.collection.mutable.ArrayOps.unzip"
problemName=MissingMethodProblem
},
{
matchName="scala.collection.mutable.ArrayOps.unzip3"
problemName=MissingMethodProblem
},
{
matchName="scala.collection.mutable.ArrayOps#ofFloat.unzip"
problemName=IncompatibleMethTypeProblem
},
{
matchName="scala.collection.mutable.ArrayOps#ofFloat.unzip3"
problemName=IncompatibleMethTypeProblem
},
{
matchName="scala.collection.mutable.ArrayOps#ofBoolean.unzip"
problemName=IncompatibleMethTypeProblem
},
{
matchName="scala.collection.mutable.ArrayOps#ofBoolean.unzip3"
problemName=IncompatibleMethTypeProblem
},
{
matchName="scala.collection.mutable.ArrayOps#ofRef.unzip"
problemName=IncompatibleMethTypeProblem
},
{
matchName="scala.collection.mutable.ArrayOps#ofRef.unzip3"
problemName=IncompatibleMethTypeProblem
},
{
matchName="scala.collection.mutable.ArrayOps#ofUnit.unzip"
problemName=IncompatibleMethTypeProblem
},
{
matchName="scala.collection.mutable.ArrayOps#ofUnit.unzip3"
problemName=IncompatibleMethTypeProblem
},
{
matchName="scala.collection.mutable.ArrayOps#ofDouble.unzip"
problemName=IncompatibleMethTypeProblem
},
{
matchName="scala.collection.mutable.ArrayOps#ofDouble.unzip3"
problemName=IncompatibleMethTypeProblem
}
]
}
101 changes: 100 additions & 1 deletion bincompat-forward.whitelist.conf
Expand Up @@ -4,4 +4,103 @@ filter {
# "scala.concurrent.impl"
# "scala.reflect.runtime"
]
}
// see SI-8372
problems=[
{
matchName="scala.collection.mutable.ArrayOps#ofChar.unzip"
problemName=IncompatibleMethTypeProblem
},
{
matchName="scala.collection.mutable.ArrayOps#ofChar.unzip3"
problemName=IncompatibleMethTypeProblem
},
{
matchName="scala.collection.mutable.ArrayOps#ofByte.unzip"
problemName=IncompatibleMethTypeProblem
},
{
matchName="scala.collection.mutable.ArrayOps#ofByte.unzip3"
problemName=IncompatibleMethTypeProblem
},
{
matchName="scala.collection.mutable.ArrayOps#ofShort.unzip"
problemName=IncompatibleMethTypeProblem
},
{
matchName="scala.collection.mutable.ArrayOps#ofShort.unzip3"
problemName=IncompatibleMethTypeProblem
},
{
matchName="scala.collection.mutable.ArrayOps#ofLong.unzip"
problemName=IncompatibleMethTypeProblem
},
{
matchName="scala.collection.mutable.ArrayOps#ofLong.unzip3"
problemName=IncompatibleMethTypeProblem
},
{
matchName="scala.collection.mutable.ArrayOps#ofInt.unzip"
problemName=IncompatibleMethTypeProblem
},
{
matchName="scala.collection.mutable.ArrayOps#ofInt.unzip3"
problemName=IncompatibleMethTypeProblem
},
{
matchName="scala.collection.mutable.ArrayOps.unzip"
problemName=MissingMethodProblem
},
{
matchName="scala.collection.mutable.ArrayOps.unzip3"
problemName=MissingMethodProblem
},
{
matchName="scala.collection.mutable.ArrayOps.unzip"
problemName=MissingMethodProblem
},
{
matchName="scala.collection.mutable.ArrayOps.unzip3"
problemName=MissingMethodProblem
},
{
matchName="scala.collection.mutable.ArrayOps#ofFloat.unzip"
problemName=IncompatibleMethTypeProblem
},
{
matchName="scala.collection.mutable.ArrayOps#ofFloat.unzip3"
problemName=IncompatibleMethTypeProblem
},
{
matchName="scala.collection.mutable.ArrayOps#ofBoolean.unzip"
problemName=IncompatibleMethTypeProblem
},
{
matchName="scala.collection.mutable.ArrayOps#ofBoolean.unzip3"
problemName=IncompatibleMethTypeProblem
},
{
matchName="scala.collection.mutable.ArrayOps#ofRef.unzip"
problemName=IncompatibleMethTypeProblem
},
{
matchName="scala.collection.mutable.ArrayOps#ofRef.unzip3"
problemName=IncompatibleMethTypeProblem
},
{
matchName="scala.collection.mutable.ArrayOps#ofUnit.unzip"
problemName=IncompatibleMethTypeProblem
},
{
matchName="scala.collection.mutable.ArrayOps#ofUnit.unzip3"
problemName=IncompatibleMethTypeProblem
},
{
matchName="scala.collection.mutable.ArrayOps#ofDouble.unzip"
problemName=IncompatibleMethTypeProblem
},
{
matchName="scala.collection.mutable.ArrayOps#ofDouble.unzip3"
problemName=IncompatibleMethTypeProblem
}
]
}
19 changes: 17 additions & 2 deletions src/library/scala/collection/mutable/ArrayOps.scala
Expand Up @@ -114,10 +114,16 @@ trait ArrayOps[T] extends Any with ArrayLike[T, Array[T]] with CustomParalleliza
* @tparam T2 the type of the second half of the element pairs
* @param asPair an implicit conversion which asserts that the element type
* of this Array is a pair.
* @param ct1 a class tag for T1 type parameter that is required to create an instance
* of Array[T1]
* @param ct2 a class tag for T2 type parameter that is required to create an instance
* of Array[T2]
* @return a pair of Arrays, containing, respectively, the first and second half
* of each element pair of this Array.
*/
def unzip[T1: ClassTag, T2: ClassTag](implicit asPair: T => (T1, T2)): (Array[T1], Array[T2]) = {
// implementation NOTE: ct1 and ct2 can't be written as context bounds because desugared
// implicits are put in front of asPair parameter that is supposed to guide type inference
def unzip[T1, T2](implicit asPair: T => (T1, T2), ct1: ClassTag[T1], ct2: ClassTag[T2]): (Array[T1], Array[T2]) = {
val a1 = new Array[T1](length)
val a2 = new Array[T2](length)
var i = 0
Expand All @@ -137,10 +143,19 @@ trait ArrayOps[T] extends Any with ArrayLike[T, Array[T]] with CustomParalleliza
* @tparam T3 the type of the third of three elements in the triple
* @param asTriple an implicit conversion which asserts that the element type
* of this Array is a triple.
* @param ct1 a class tag for T1 type parameter that is required to create an instance
* of Array[T1]
* @param ct2 a class tag for T2 type parameter that is required to create an instance
* of Array[T2]
* @param ct3 a class tag for T3 type parameter that is required to create an instance
* of Array[T3]
* @return a triple of Arrays, containing, respectively, the first, second, and third
* elements from each element triple of this Array.
*/
def unzip3[T1: ClassTag, T2: ClassTag, T3: ClassTag](implicit asTriple: T => (T1, T2, T3)): (Array[T1], Array[T2], Array[T3]) = {
// implementation NOTE: ct1, ct2, ct3 can't be written as context bounds because desugared
// implicits are put in front of asPair parameter that is supposed to guide type inference
def unzip3[T1, T2, T3](implicit asTriple: T => (T1, T2, T3), ct1: ClassTag[T1], ct2: ClassTag[T2],
ct3: ClassTag[T3]): (Array[T1], Array[T2], Array[T3]) = {
val a1 = new Array[T1](length)
val a2 = new Array[T2](length)
val a3 = new Array[T3](length)
Expand Down
4 changes: 2 additions & 2 deletions test/files/neg/t8372.check
@@ -1,7 +1,7 @@
t8372.scala:7: error: tpe T1 is an unresolved spliceable type
t8372.scala:7: error: No ClassTag available for T1
def unzip[T1, T2](a: Array[(T1, T2)]) = a.unzip
^
t8372.scala:9: error: tpe T1 is an unresolved spliceable type
t8372.scala:9: error: No ClassTag available for T1
def unzip3[T1, T2, T3](a: Array[(T1, T2, T3)]): (Array[T1], Array[T2], Array[T3]) = a.unzip3
^
two errors found

0 comments on commit ed74326

Please sign in to comment.