Skip to content
Permalink
Browse files

SI-5683 Fail gracefully when transposing a ragged type arg matrix.

The code used to do this, until `transpose` starting throwing IAE
rather than AIOOBE.

Symptomatic treatment only: The reported crasher now infers ill-kinded
type args and reports an error.
  • Loading branch information
retronym committed May 26, 2012
1 parent 85cd96d commit 80d986997e58b5195654b6f9ca8cd81bc62f4bbf
@@ -6572,47 +6572,50 @@ trait Types extends api.Types { self: SymbolTable =>
else Some(typeRef(pre, sym, List(lub(args))))
}
}
else {
val args = map2(sym.typeParams, argss.transpose) { (tparam, as) =>
if (depth == 0) {
if (tparam.variance == variance) {
// Take the intersection of the upper bounds of the type parameters
// rather than falling all the way back to "Any", otherwise we end up not
// conforming to bounds.
val bounds0 = sym.typeParams map (_.info.bounds.hi) filterNot (_.typeSymbol == AnyClass)
if (bounds0.isEmpty) AnyClass.tpe
else intersectionType(bounds0 map (b => b.asSeenFrom(tps.head, sym)))
else transposeSafe(argss) match {
case None =>
// transpose freaked out because of irregular argss
// catching just in case (shouldn't happen, but also doesn't cost us)
// [JZ] It happens: see SI-5683.
debuglog("transposed irregular matrix!?" +(tps, argss))
None
case Some(argsst) =>
val args = map2(sym.typeParams, argsst) { (tparam, as) =>
if (depth == 0) {
if (tparam.variance == variance) {
// Take the intersection of the upper bounds of the type parameters
// rather than falling all the way back to "Any", otherwise we end up not
// conforming to bounds.
val bounds0 = sym.typeParams map (_.info.bounds.hi) filterNot (_.typeSymbol == AnyClass)
if (bounds0.isEmpty) AnyClass.tpe
else intersectionType(bounds0 map (b => b.asSeenFrom(tps.head, sym)))
}
else if (tparam.variance == -variance) NothingClass.tpe
else NoType
}
else if (tparam.variance == -variance) NothingClass.tpe
else NoType
}
else {
if (tparam.variance == variance) lub(as, decr(depth))
else if (tparam.variance == -variance) glb(as, decr(depth))
else {
val l = lub(as, decr(depth))
val g = glb(as, decr(depth))
if (l <:< g) l
if (tparam.variance == variance) lub(as, decr(depth))
else if (tparam.variance == -variance) glb(as, decr(depth))
else {
val l = lub(as, decr(depth))
val g = glb(as, decr(depth))
if (l <:< g) l
else { // Martin: I removed this, because incomplete. Not sure there is a good way to fix it. For the moment we
// just err on the conservative side, i.e. with a bound that is too high.
// if(!(tparam.info.bounds contains tparam)) //@M can't deal with f-bounds, see #2251

val qvar = commonOwner(as) freshExistential "" setInfo TypeBounds(g, l)
capturedParams += qvar
qvar.tpe
val qvar = commonOwner(as) freshExistential "" setInfo TypeBounds(g, l)
capturedParams += qvar
qvar.tpe
}
}
}
}
}
if (args contains NoType) None
else Some(existentialAbstraction(capturedParams.toList, typeRef(pre, sym, args)))
if (args contains NoType) None
else Some(existentialAbstraction(capturedParams.toList, typeRef(pre, sym, args)))
}
} catch {
case ex: MalformedType => None
case ex: IndexOutOfBoundsException => // transpose freaked out because of irregular argss
// catching just in case (shouldn't happen, but also doesn't cost us)
debuglog("transposed irregular matrix!?"+ (tps, argss))
None
}
case SingleType(_, sym) :: rest =>
val pres = tps map (_.prefix)
@@ -201,6 +201,12 @@ trait Collections {
}
true
}

final def transposeSafe[A](ass: List[List[A]]): Option[List[List[A]]] = try {
Some(ass.transpose)
} catch {
case _: IllegalArgumentException => None
}
}

object Collections extends Collections { }
@@ -0,0 +1,16 @@
t5683.scala:12: error: inferred kinds of the type arguments (Object,Int) do not conform to the expected kinds of the type parameters (type M,type B).
Object's type parameters do not match type M's expected parameters:
class Object has no type parameters, but type M has one
val crash: K[StringW,Int,Int] = k{ (y: Int) => null: W[String, Int] }
^
t5683.scala:12: error: type mismatch;
found : Int => Test.W[String,Int]
required: Int => M[B]
val crash: K[StringW,Int,Int] = k{ (y: Int) => null: W[String, Int] }
^
t5683.scala:12: error: type mismatch;
found : Test.K[M,Int,B]
required: Test.K[Test.StringW,Int,Int]
val crash: K[StringW,Int,Int] = k{ (y: Int) => null: W[String, Int] }
^
three errors found
@@ -0,0 +1,23 @@
object Test {
trait NT[X]
trait W[W, A] extends NT[Int]
type StringW[T] = W[String, T]
trait K[M[_], A, B]

def k[M[_], B](f: Int => M[B]): K[M, Int, B] = null

val okay1: K[StringW,Int,Int] = k{ (y: Int) => null: StringW[Int] }
val okay2 = k[StringW,Int]{ (y: Int) => null: W[String, Int] }

val crash: K[StringW,Int,Int] = k{ (y: Int) => null: W[String, Int] }

// remove `extends NT[Int]`, and the last line gives an inference error
// rather than a crash.
// test/files/pos/t5683.scala:12: error: no type parameters for method k: (f: Int => M[B])Test.K[M,Int,B] exist so that it can be applied to arguments (Int => Test.W[String,Int])
// --- because ---
// argument expression's type is not compatible with formal parameter type;
// found : Int => Test.W[String,Int]
// required: Int => ?M[?B]
// val crash: K[StringW,Int,Int] = k{ (y: Int) => null: W[String, Int] }
// ^
}

0 comments on commit 80d9869

Please sign in to comment.
You can’t perform that action at this time.