Skip to content

Commit 80d9869

Browse files
committed
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.
1 parent 85cd96d commit 80d9869

File tree

4 files changed

+77
-29
lines changed

4 files changed

+77
-29
lines changed

src/compiler/scala/reflect/internal/Types.scala

Lines changed: 32 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -6572,47 +6572,50 @@ trait Types extends api.Types { self: SymbolTable =>
65726572
else Some(typeRef(pre, sym, List(lub(args))))
65736573
}
65746574
}
6575-
else {
6576-
val args = map2(sym.typeParams, argss.transpose) { (tparam, as) =>
6577-
if (depth == 0) {
6578-
if (tparam.variance == variance) {
6579-
// Take the intersection of the upper bounds of the type parameters
6580-
// rather than falling all the way back to "Any", otherwise we end up not
6581-
// conforming to bounds.
6582-
val bounds0 = sym.typeParams map (_.info.bounds.hi) filterNot (_.typeSymbol == AnyClass)
6583-
if (bounds0.isEmpty) AnyClass.tpe
6584-
else intersectionType(bounds0 map (b => b.asSeenFrom(tps.head, sym)))
6575+
else transposeSafe(argss) match {
6576+
case None =>
6577+
// transpose freaked out because of irregular argss
6578+
// catching just in case (shouldn't happen, but also doesn't cost us)
6579+
// [JZ] It happens: see SI-5683.
6580+
debuglog("transposed irregular matrix!?" +(tps, argss))
6581+
None
6582+
case Some(argsst) =>
6583+
val args = map2(sym.typeParams, argsst) { (tparam, as) =>
6584+
if (depth == 0) {
6585+
if (tparam.variance == variance) {
6586+
// Take the intersection of the upper bounds of the type parameters
6587+
// rather than falling all the way back to "Any", otherwise we end up not
6588+
// conforming to bounds.
6589+
val bounds0 = sym.typeParams map (_.info.bounds.hi) filterNot (_.typeSymbol == AnyClass)
6590+
if (bounds0.isEmpty) AnyClass.tpe
6591+
else intersectionType(bounds0 map (b => b.asSeenFrom(tps.head, sym)))
6592+
}
6593+
else if (tparam.variance == -variance) NothingClass.tpe
6594+
else NoType
65856595
}
6586-
else if (tparam.variance == -variance) NothingClass.tpe
6587-
else NoType
6588-
}
6589-
else {
6590-
if (tparam.variance == variance) lub(as, decr(depth))
6591-
else if (tparam.variance == -variance) glb(as, decr(depth))
65926596
else {
6593-
val l = lub(as, decr(depth))
6594-
val g = glb(as, decr(depth))
6595-
if (l <:< g) l
6597+
if (tparam.variance == variance) lub(as, decr(depth))
6598+
else if (tparam.variance == -variance) glb(as, decr(depth))
6599+
else {
6600+
val l = lub(as, decr(depth))
6601+
val g = glb(as, decr(depth))
6602+
if (l <:< g) l
65966603
else { // Martin: I removed this, because incomplete. Not sure there is a good way to fix it. For the moment we
65976604
// just err on the conservative side, i.e. with a bound that is too high.
65986605
// if(!(tparam.info.bounds contains tparam)) //@M can't deal with f-bounds, see #2251
65996606

6600-
val qvar = commonOwner(as) freshExistential "" setInfo TypeBounds(g, l)
6601-
capturedParams += qvar
6602-
qvar.tpe
6607+
val qvar = commonOwner(as) freshExistential "" setInfo TypeBounds(g, l)
6608+
capturedParams += qvar
6609+
qvar.tpe
6610+
}
66036611
}
66046612
}
66056613
}
6606-
}
6607-
if (args contains NoType) None
6608-
else Some(existentialAbstraction(capturedParams.toList, typeRef(pre, sym, args)))
6614+
if (args contains NoType) None
6615+
else Some(existentialAbstraction(capturedParams.toList, typeRef(pre, sym, args)))
66096616
}
66106617
} catch {
66116618
case ex: MalformedType => None
6612-
case ex: IndexOutOfBoundsException => // transpose freaked out because of irregular argss
6613-
// catching just in case (shouldn't happen, but also doesn't cost us)
6614-
debuglog("transposed irregular matrix!?"+ (tps, argss))
6615-
None
66166619
}
66176620
case SingleType(_, sym) :: rest =>
66186621
val pres = tps map (_.prefix)

src/compiler/scala/reflect/internal/util/Collections.scala

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -201,6 +201,12 @@ trait Collections {
201201
}
202202
true
203203
}
204+
205+
final def transposeSafe[A](ass: List[List[A]]): Option[List[List[A]]] = try {
206+
Some(ass.transpose)
207+
} catch {
208+
case _: IllegalArgumentException => None
209+
}
204210
}
205211

206212
object Collections extends Collections { }

test/files/neg/t5683.check

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
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).
2+
Object's type parameters do not match type M's expected parameters:
3+
class Object has no type parameters, but type M has one
4+
val crash: K[StringW,Int,Int] = k{ (y: Int) => null: W[String, Int] }
5+
^
6+
t5683.scala:12: error: type mismatch;
7+
found : Int => Test.W[String,Int]
8+
required: Int => M[B]
9+
val crash: K[StringW,Int,Int] = k{ (y: Int) => null: W[String, Int] }
10+
^
11+
t5683.scala:12: error: type mismatch;
12+
found : Test.K[M,Int,B]
13+
required: Test.K[Test.StringW,Int,Int]
14+
val crash: K[StringW,Int,Int] = k{ (y: Int) => null: W[String, Int] }
15+
^
16+
three errors found

test/files/neg/t5683.scala

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
object Test {
2+
trait NT[X]
3+
trait W[W, A] extends NT[Int]
4+
type StringW[T] = W[String, T]
5+
trait K[M[_], A, B]
6+
7+
def k[M[_], B](f: Int => M[B]): K[M, Int, B] = null
8+
9+
val okay1: K[StringW,Int,Int] = k{ (y: Int) => null: StringW[Int] }
10+
val okay2 = k[StringW,Int]{ (y: Int) => null: W[String, Int] }
11+
12+
val crash: K[StringW,Int,Int] = k{ (y: Int) => null: W[String, Int] }
13+
14+
// remove `extends NT[Int]`, and the last line gives an inference error
15+
// rather than a crash.
16+
// 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])
17+
// --- because ---
18+
// argument expression's type is not compatible with formal parameter type;
19+
// found : Int => Test.W[String,Int]
20+
// required: Int => ?M[?B]
21+
// val crash: K[StringW,Int,Int] = k{ (y: Int) => null: W[String, Int] }
22+
// ^
23+
}

0 commit comments

Comments
 (0)