summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPaul Phillips <paulp@improving.org>2012-08-10 16:19:19 -0700
committerPaul Phillips <paulp@improving.org>2012-08-11 08:29:22 -0700
commitdb46c71e8830639bc79e6363332a06642fd3d8cc (patch)
tree52b5457a53bac5119522611cbbc4d40da1a1f76b
parent48d9fb7307fb6519fe786a7d9be97996c5812fb7 (diff)
downloadscala-db46c71e8830639bc79e6363332a06642fd3d8cc.tar.gz
scala-db46c71e8830639bc79e6363332a06642fd3d8cc.tar.bz2
scala-db46c71e8830639bc79e6363332a06642fd3d8cc.zip
Improvement for SI-2251, failure to lub f-bounds.
After a great struggle, I realized that the major reason that code like this still doesn't compile: List(Stream(), List()) is that we were poisoning the computed lub in mergePrefixAndArgs by throwing in Any when the max recursion depth was reached. I modified it to return NoType instead, which allowed me to teach lublist to recognize what has happened and fall back to a weaker type, one which does not contain recursive bounds. This enables the lubbing process to complete. The most elusive lub, defeated. Notice also that the refinement members are correctly parameterized on Nothing, rather than on Any as has often been the case. scala> List(Stream(), List()) res0: List[scala.collection.immutable.LinearSeq[Nothing] with scala.collection.AbstractSeq[Nothing]{def companion: scala.collection.generic.GenericCompanion[scala.collection.immutable.LinearSeq with scala.collection.AbstractSeq]; def reverse: scala.collection.immutable.LinearSeq[Nothing] with scala.collection.AbstractSeq[Nothing]{def companion: scala.collection.generic.GenericCompanion[scala.collection.immutable.LinearSeq with scala.collection.AbstractSeq]; def reverse: scala.collection.immutable.LinearSeq[Nothing] with scala.collection.AbstractSeq[Nothing]{def reverse: scala.collection.immutable.LinearSeq[Nothing] with scala.collection.AbstractSeq[Nothing]; def dropRight(n: Int): scala.collection.immutable.LinearSeq[Nothing] with scala.collection.AbstractSeq[Nothing]; def takeRight(n: ...
-rw-r--r--src/reflect/scala/reflect/internal/Types.scala127
-rw-r--r--test/files/neg/lubs.check9
-rw-r--r--test/files/pos/ticket2251.scala14
-rw-r--r--test/files/run/lub-visibility.check2
-rw-r--r--test/files/run/t2251.check1
-rw-r--r--test/files/run/t2251.scala19
-rw-r--r--test/files/run/t2251b.check11
-rw-r--r--test/files/run/t2251b.scala48
8 files changed, 178 insertions, 53 deletions
diff --git a/src/reflect/scala/reflect/internal/Types.scala b/src/reflect/scala/reflect/internal/Types.scala
index 7df34a14e2..f519a2d4a6 100644
--- a/src/reflect/scala/reflect/internal/Types.scala
+++ b/src/reflect/scala/reflect/internal/Types.scala
@@ -6219,25 +6219,26 @@ trait Types extends api.Types { self: SymbolTable =>
* @See baseTypeSeq for a definition of sorted and upwards closed.
*/
private def lubList(ts: List[Type], depth: Int): List[Type] = {
- // Matching the type params of one of the initial types means dummies.
- val initialTypeParams = ts map (_.typeParams)
- def isHotForTs(xs: List[Type]) = initialTypeParams contains xs.map(_.typeSymbol)
-
+ var lubListDepth = 0
+ // This catches some recursive situations which would otherwise
+ // befuddle us, e.g. pos/hklub0.scala
+ def isHotForTs(xs: List[Type]) = ts exists (_.typeParams == xs.map(_.typeSymbol))
def elimHigherOrderTypeParam(tp: Type) = tp match {
- case TypeRef(pre, sym, args) if args.nonEmpty && isHotForTs(args) => tp.typeConstructor
- case _ => tp
+ case TypeRef(_, _, args) if args.nonEmpty && isHotForTs(args) =>
+ logResult("Retracting dummies from " + tp + " in lublist")(tp.typeConstructor)
+ case _ => tp
}
- var lubListDepth = 0
- def loop(tsBts: List[List[Type]]): List[Type] = {
+ // pretypes is a tail-recursion-preserving accumulator.
+ @annotation.tailrec def loop(pretypes: List[Type], tsBts: List[List[Type]]): List[Type] = {
lubListDepth += 1
- if (tsBts.isEmpty || tsBts.exists(_.isEmpty)) Nil
- else if (tsBts.tail.isEmpty) tsBts.head
+ if (tsBts.isEmpty || tsBts.exists(_.isEmpty)) pretypes.reverse
+ else if (tsBts.tail.isEmpty) pretypes.reverse ++ tsBts.head
else {
// ts0 is the 1-dimensional frontier of symbols cutting through 2-dimensional tsBts.
// Invariant: all symbols "under" (closer to the first row) the frontier
// are smaller (according to _.isLess) than the ones "on and beyond" the frontier
- val ts0 = tsBts map (_.head)
+ val ts0 = tsBts map (_.head)
// Is the frontier made up of types with the same symbol?
val isUniformFrontier = (ts0: @unchecked) match {
@@ -6250,23 +6251,23 @@ trait Types extends api.Types { self: SymbolTable =>
// merging, strip targs that refer to bound tparams (when we're computing the lub of type
// constructors.) Also filter out all types that are a subtype of some other type.
if (isUniformFrontier) {
- if (settings.debug.value || printLubs) {
- val fbounds = findRecursiveBounds(ts0)
- if (fbounds.nonEmpty) {
- println("Encountered " + fbounds.size + " recursive bounds while lubbing " + ts0.size + " types.")
- for ((p0, p1) <- fbounds) {
- val desc = if (p0 == p1) "its own bounds" else "the bounds of " + p1
-
- println(" " + p0.fullLocationString + " appears in " + desc)
- println(" " + p1 + " " + p1.info.bounds)
+ val fbounds = findRecursiveBounds(ts0) map (_._2)
+ val tcLubList = typeConstructorLubList(ts0)
+ def isRecursive(tp: Type) = tp.typeSymbol.typeParams exists fbounds.contains
+
+ val ts1 = ts0 map { t =>
+ if (isRecursive(t)) {
+ tcLubList map (t baseType _.typeSymbol) find (t => !isRecursive(t)) match {
+ case Some(tp) => logResult(s"Breaking recursion in lublist, substituting weaker type.\n Was: $t\n Now")(tp)
+ case _ => t
}
- println("")
}
+ else t
}
val tails = tsBts map (_.tail)
- mergePrefixAndArgs(elimSub(ts0 map elimHigherOrderTypeParam, depth), 1, depth) match {
- case Some(tp) => tp :: loop(tails)
- case _ => loop(tails)
+ mergePrefixAndArgs(elimSub(ts1, depth) map elimHigherOrderTypeParam, 1, depth) match {
+ case Some(tp) => loop(tp :: pretypes, tails)
+ case _ => loop(pretypes, tails)
}
}
else {
@@ -6283,7 +6284,7 @@ trait Types extends api.Types { self: SymbolTable =>
printLubMatrix((ts zip tsBts).toMap, lubListDepth)
}
- loop(newtps)
+ loop(pretypes, newtps)
}
}
}
@@ -6292,7 +6293,7 @@ trait Types extends api.Types { self: SymbolTable =>
if (printLubs)
printLubMatrix((ts zip initialBTSes).toMap, depth)
- loop(initialBTSes)
+ loop(Nil, initialBTSes)
}
/** The minimal symbol (wrt Symbol.isLess) of a list of types */
@@ -6427,6 +6428,23 @@ trait Types extends api.Types { self: SymbolTable =>
private val lubResults = new mutable.HashMap[(Int, List[Type]), Type]
private val glbResults = new mutable.HashMap[(Int, List[Type]), Type]
+ /** Given a list of types, finds all the base classes they have in
+ * common, then returns a list of type constructors derived directly
+ * from the symbols (so any more specific type information is ignored.)
+ * The list is filtered such that every type constructor in the list
+ * expects the same number of type arguments, which is chosen based
+ * on the deepest class among the common baseclasses.
+ */
+ def typeConstructorLubList(ts: List[Type]): List[Type] = {
+ val bcs = ts.flatMap(_.baseClasses).distinct sortWith (_ isLess _)
+ val tcons = bcs filter (clazz => ts forall (_.typeSymbol isSubClass clazz))
+
+ tcons map (_.typeConstructor) match {
+ case Nil => Nil
+ case t :: ts => t :: ts.filter(_.typeParams.size == t.typeParams.size)
+ }
+ }
+
def lub(ts: List[Type]): Type = ts match {
case List() => NothingClass.tpe
case List(t) => t
@@ -6434,8 +6452,20 @@ trait Types extends api.Types { self: SymbolTable =>
Statistics.incCounter(lubCount)
val start = Statistics.pushTimer(typeOpsStack, lubNanos)
try {
- lub(ts, lubDepth(ts))
- } finally {
+ val res = lub(ts, lubDepth(ts))
+ // If the number of unapplied type parameters in all incoming
+ // types is consistent, and the lub does not match that, return
+ // the type constructor of the calculated lub instead. This
+ // is because lubbing type constructors tends to result in types
+ // which have been applied to dummies or Nothing.
+ ts.map(_.typeParams.size).distinct match {
+ case x :: Nil if res.typeParams.size != x =>
+ logResult(s"Stripping type args from lub because $res is not consistent with $ts")(res.typeConstructor)
+ case _ =>
+ res
+ }
+ }
+ finally {
lubResults.clear()
glbResults.clear()
Statistics.popTimer(typeOpsStack, start)
@@ -6469,13 +6499,13 @@ trait Types extends api.Types { self: SymbolTable =>
}
}
def lub1(ts0: List[Type]): Type = {
- val (ts, tparams) = stripExistentialsAndTypeVars(ts0)
+ val (ts, tparams) = stripExistentialsAndTypeVars(ts0)
val lubBaseTypes: List[Type] = lubList(ts, depth)
- val lubParents = spanningTypes(lubBaseTypes)
- val lubOwner = commonOwner(ts)
- val lubBase = intersectionType(lubParents, lubOwner)
+ val lubParents = spanningTypes(lubBaseTypes)
+ val lubOwner = commonOwner(ts)
+ val lubBase = intersectionType(lubParents, lubOwner)
val lubType =
- if (phase.erasedTypes || depth == 0) lubBase
+ if (phase.erasedTypes || depth == 0 ) lubBase
else {
val lubRefined = refinedType(lubParents, lubOwner)
val lubThisType = lubRefined.typeSymbol.thisType
@@ -6492,6 +6522,7 @@ trait Types extends api.Types { self: SymbolTable =>
val syms = narrowts map (t =>
t.nonPrivateMember(proto.name).suchThat(sym =>
sym.tpe matches prototp.substThis(lubThisType.typeSymbol, t)))
+
if (syms contains NoSymbol) NoSymbol
else {
val symtypes =
@@ -6518,10 +6549,8 @@ trait Types extends api.Types { self: SymbolTable =>
// add a refinement symbol for all non-class members of lubBase
// which are refined by every type in ts.
for (sym <- lubBase.nonPrivateMembers ; if !excludeFromLub(sym)) {
- try {
- val lsym = lubsym(sym)
- if (lsym != NoSymbol) addMember(lubThisType, lubRefined, lsym, depth)
- } catch {
+ try lubsym(sym) andAlso (addMember(lubThisType, lubRefined, _, depth))
+ catch {
case ex: NoCommonType =>
}
}
@@ -6765,18 +6794,16 @@ trait Types extends api.Types { self: SymbolTable =>
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
+ val args = map2(sym.typeParams, argsst) { (tparam, as0) =>
+ val as = as0.distinct
+ if (as.size == 1) as.head
+ else if (depth == 0) {
+ log("Giving up merging args: can't unify %s under %s".format(as.mkString(", "), tparam.fullLocationString))
+ // Don't return "Any" (or "Nothing") when we have to give up due to
+ // recursion depth. Return NoType, which prevents us from poisoning
+ // lublist's results. It can recognize the recursion and deal with it, but
+ // only if we aren't returning invalid types.
+ NoType
}
else {
if (tparam.variance == variance) lub(as, decr(depth))
@@ -6785,7 +6812,7 @@ trait Types extends api.Types { self: SymbolTable =>
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
+ 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
diff --git a/test/files/neg/lubs.check b/test/files/neg/lubs.check
index 77ab20102c..affbd4983c 100644
--- a/test/files/neg/lubs.check
+++ b/test/files/neg/lubs.check
@@ -1,5 +1,10 @@
+lubs.scala:10: error: type mismatch;
+ found : test1.A[test1.A[Object]]
+ required: test1.A[test1.A[test1.A[Any]]]
+ val x3: A[A[A[Any]]] = f
+ ^
lubs.scala:11: error: type mismatch;
- found : test1.A[test1.A[test1.A[Any]]]
+ found : test1.A[test1.A[Object]]
required: test1.A[test1.A[test1.A[test1.A[Any]]]]
val x4: A[A[A[A[Any]]]] = f
^
@@ -13,4 +18,4 @@ lubs.scala:25: error: type mismatch;
required: test2.A{type T >: Null <: test2.A{type T >: Null <: test2.A{type T >: Null <: test2.A}}}
val x4: A { type T >: Null <: A { type T >: Null <: A { type T >: Null <: A } } } = f
^
-three errors found
+four errors found
diff --git a/test/files/pos/ticket2251.scala b/test/files/pos/ticket2251.scala
index b3afee4ea9..c220e85350 100644
--- a/test/files/pos/ticket2251.scala
+++ b/test/files/pos/ticket2251.scala
@@ -22,4 +22,18 @@ lub of List(D, C) is B[_2] forSome { type _2 >: D with C{} <: B[_1] forSome { ty
// should be: B[X] forSome {type X <: B[X]} -- can this be done automatically? for now, just detect f-bounded polymorphism and fall back to more coarse approximation
val data: List[A] = List(new C, new D)
+
+ val data2 = List(new C, new D)
+
+ val data3: List[B[X] forSome { type X <: B[_ <: A] }] = List(new C, new D)
+
+ // Not yet --
+ // val data4: List[B[X] forSome { type X <: B[X] }] = List(new C, new D)
+ // <console>:7: error: type mismatch;
+ // found : List[B[_ >: D with C <: B[_ >: D with C <: A]]]
+ // required: List[B[X] forSome { type X <: B[X] }]
+ // val data4: List[B[X] forSome { type X <: B[X] }] = List(new C, new D)
+
+ // works
+ val data5 = List[B[X] forSome { type X <: B[X] }](new C, new D)
}
diff --git a/test/files/run/lub-visibility.check b/test/files/run/lub-visibility.check
index 3461d1bf6b..f3a6bef215 100644
--- a/test/files/run/lub-visibility.check
+++ b/test/files/run/lub-visibility.check
@@ -8,7 +8,7 @@ scala> // should infer List[scala.collection.immutable.Seq[Nothing]]
scala> // but reverted that for SI-5534.
scala> val x = List(List(), Vector())
-x: List[scala.collection.immutable.Seq[Nothing] with scala.collection.AbstractSeq[Nothing]{def companion: scala.collection.generic.GenericCompanion[scala.collection.immutable.Seq with scala.collection.AbstractSeq{def dropRight(n: Int): scala.collection.immutable.Seq[Any] with scala.collection.AbstractSeq[Any]; def takeRight(n: Int): scala.collection.immutable.Seq[Any] with scala.collection.AbstractSeq[Any]; def drop(n: Int): scala.collection.immutable.Seq[Any] with scala.collection.AbstractSeq[Any]; def take(n: Int): scala.collection.immutable.Seq[Any] with scala.collection.AbstractSeq[Any]; def slice(from: Int,until: Int): scala.collection.immutable.Seq[Any] with scala.collection.AbstractSeq[Any]}]; def dropRight(n: Int): scala.collection.immutable.Seq[Nothing] with scala.collection.Ab...
+x: List[scala.collection.immutable.Seq[Nothing] with scala.collection.AbstractSeq[Nothing]{def companion: scala.collection.generic.GenericCompanion[scala.collection.immutable.Seq with scala.collection.AbstractSeq]; def dropRight(n: Int): scala.collection.immutable.Seq[Nothing] with scala.collection.AbstractSeq[Nothing]{def companion: scala.collection.generic.GenericCompanion[scala.collection.immutable.Seq with scala.collection.AbstractSeq]; def dropRight(n: Int): scala.collection.immutable.Seq[Nothing] with scala.collection.AbstractSeq[Nothing]{def dropRight(n: Int): scala.collection.immutable.Seq[Nothing] with scala.collection.AbstractSeq[Nothing]; def takeRight(n: Int): scala.collection.immutable.Seq[Nothing] with scala.collection.AbstractSeq[Nothing]; def drop(n: Int): scala.collecti...
scala>
scala>
diff --git a/test/files/run/t2251.check b/test/files/run/t2251.check
new file mode 100644
index 0000000000..55ad2a5857
--- /dev/null
+++ b/test/files/run/t2251.check
@@ -0,0 +1 @@
+Set(List(List(C), Stream(D, ?)))
diff --git a/test/files/run/t2251.scala b/test/files/run/t2251.scala
new file mode 100644
index 0000000000..00c5619b49
--- /dev/null
+++ b/test/files/run/t2251.scala
@@ -0,0 +1,19 @@
+class A
+trait B[T <: B[T]] extends A
+class C extends B[C] { override def toString = "C" }
+class D extends B[D] { override def toString = "D" }
+
+class E {
+ val ys = List(List(new C), Stream(new D))
+}
+
+object Test {
+ def trav = List(List(), Stream())
+
+ def main(args: Array[String]): Unit = {
+ val f = (new E).ys _
+ var xs: Set[List[_ <: Seq[B[_]]]] = Set()
+ xs += f()
+ println(xs)
+ }
+}
diff --git a/test/files/run/t2251b.check b/test/files/run/t2251b.check
new file mode 100644
index 0000000000..42b0be457a
--- /dev/null
+++ b/test/files/run/t2251b.check
@@ -0,0 +1,11 @@
+TypeTag[List[scala.collection.immutable.LinearSeq[B[_ >: D with C <: B[_ >: D with C <: A]]] with scala.collection.AbstractSeq[B[_ >: D with C <: B[_ >: D with C <: A]]]{def companion: scala.collection.generic.GenericCompanion[scala.collection.immutable.LinearSeq with scala.collection.AbstractSeq]; def reverse: scala.collection.immutable.LinearSeq[B[_ >: D with C <: A]] with scala.collection.AbstractSeq[B[_ >: D with C <: A]]{def companion: scala.collection.generic.GenericCompanion[scala.collection.immutable.LinearSeq with scala.collection.AbstractSeq]; def reverse: scala.collection.immutable.LinearSeq[A] with scala.collection.AbstractSeq[A]; def dropRight(n: Int): scala.collection.immutable.LinearSeq[A] with scala.collection.AbstractSeq[A]; def takeRight(n: Int): scala.collection.immutable.LinearSeq[A] with scala.collection.AbstractSeq[A]; def drop(n: Int): scala.collection.immutable.LinearSeq[A] with scala.collection.AbstractSeq[A]; def take(n: Int): scala.collection.immutable.LinearSeq[A] with scala.collection.AbstractSeq[A]; def slice(from: Int,until: Int): scala.collection.immutable.LinearSeq[A] with scala.collection.AbstractSeq[A]}; def dropRight(n: Int): scala.collection.immutable.LinearSeq[B[_ >: D with C <: A]] with scala.collection.AbstractSeq[B[_ >: D with C <: A]]{def companion: scala.collection.generic.GenericCompanion[scala.collection.immutable.LinearSeq with scala.collection.AbstractSeq]; def reverse: scala.collection.immutable.LinearSeq[A] with scala.collection.AbstractSeq[A]; def dropRight(n: Int): scala.collection.immutable.LinearSeq[A] with scala.collection.AbstractSeq[A]; def takeRight(n: Int): scala.collection.immutable.LinearSeq[A] with scala.collection.AbstractSeq[A]; def drop(n: Int): scala.collection.immutable.LinearSeq[A] with scala.collection.AbstractSeq[A]; def take(n: Int): scala.collection.immutable.LinearSeq[A] with scala.collection.AbstractSeq[A]; def slice(from: Int,until: Int): scala.collection.immutable.LinearSeq[A] with scala.collection.AbstractSeq[A]}; def takeRight(n: Int): scala.collection.immutable.LinearSeq[B[_ >: D with C <: A]] with scala.collection.AbstractSeq[B[_ >: D with C <: A]]{def companion: scala.collection.generic.GenericCompanion[scala.collection.immutable.LinearSeq with scala.collection.AbstractSeq]; def reverse: scala.collection.immutable.LinearSeq[A] with scala.collection.AbstractSeq[A]; def dropRight(n: Int): scala.collection.immutable.LinearSeq[A] with scala.collection.AbstractSeq[A]; def takeRight(n: Int): scala.collection.immutable.LinearSeq[A] with scala.collection.AbstractSeq[A]; def drop(n: Int): scala.collection.immutable.LinearSeq[A] with scala.collection.AbstractSeq[A]; def take(n: Int): scala.collection.immutable.LinearSeq[A] with scala.collection.AbstractSeq[A]; def slice(from: Int,until: Int): scala.collection.immutable.LinearSeq[A] with scala.collection.AbstractSeq[A]}; def drop(n: Int): scala.collection.immutable.LinearSeq[B[_ >: D with C <: A]] with scala.collection.AbstractSeq[B[_ >: D with C <: A]]{def companion: scala.collection.generic.GenericCompanion[scala.collection.immutable.LinearSeq with scala.collection.AbstractSeq]; def reverse: scala.collection.immutable.LinearSeq[A] with scala.collection.AbstractSeq[A]; def dropRight(n: Int): scala.collection.immutable.LinearSeq[A] with scala.collection.AbstractSeq[A]; def takeRight(n: Int): scala.collection.immutable.LinearSeq[A] with scala.collection.AbstractSeq[A]; def drop(n: Int): scala.collection.immutable.LinearSeq[A] with scala.collection.AbstractSeq[A]; def take(n: Int): scala.collection.immutable.LinearSeq[A] with scala.collection.AbstractSeq[A]; def slice(from: Int,until: Int): scala.collection.immutable.LinearSeq[A] with scala.collection.AbstractSeq[A]}; def take(n: Int): scala.collection.immutable.LinearSeq[B[_ >: D with C <: A]] with scala.collection.AbstractSeq[B[_ >: D with C <: A]]{def companion: scala.collection.generic.GenericCompanion[scala.collection.immutable.LinearSeq with scala.collection.AbstractSeq]; def reverse: scala.collection.immutable.LinearSeq[A] with scala.collection.AbstractSeq[A]; def dropRight(n: Int): scala.collection.immutable.LinearSeq[A] with scala.collection.AbstractSeq[A]; def takeRight(n: Int): scala.collection.immutable.LinearSeq[A] with scala.collection.AbstractSeq[A]; def drop(n: Int): scala.collection.immutable.LinearSeq[A] with scala.collection.AbstractSeq[A]; def take(n: Int): scala.collection.immutable.LinearSeq[A] with scala.collection.AbstractSeq[A]; def slice(from: Int,until: Int): scala.collection.immutable.LinearSeq[A] with scala.collection.AbstractSeq[A]}; def slice(from: Int,until: Int): scala.collection.immutable.LinearSeq[B[_ >: D with C <: A]] with scala.collection.AbstractSeq[B[_ >: D with C <: A]]{def companion: scala.collection.generic.GenericCompanion[scala.collection.immutable.LinearSeq with scala.collection.AbstractSeq]; def reverse: scala.collection.immutable.LinearSeq[A] with scala.collection.AbstractSeq[A]; def dropRight(n: Int): scala.collection.immutable.LinearSeq[A] with scala.collection.AbstractSeq[A]; def takeRight(n: Int): scala.collection.immutable.LinearSeq[A] with scala.collection.AbstractSeq[A]; def drop(n: Int): scala.collection.immutable.LinearSeq[A] with scala.collection.AbstractSeq[A]; def take(n: Int): scala.collection.immutable.LinearSeq[A] with scala.collection.AbstractSeq[A]; def slice(from: Int,until: Int): scala.collection.immutable.LinearSeq[A] with scala.collection.AbstractSeq[A]}; def splitAt(n: Int): (scala.collection.immutable.LinearSeq[A] with scala.collection.AbstractSeq[A], scala.collection.immutable.LinearSeq[A] with scala.collection.AbstractSeq[A])}]]
+TypeTag[List[scala.collection.immutable.Iterable[B[_ >: F with E with D with C <: B[_ >: F with E with D with C <: A]]] with F with Int => Any]]
+TypeTag[List[scala.collection.immutable.Seq[B[_ >: D with C <: B[_ >: D with C <: A]]] with scala.collection.AbstractSeq[B[_ >: D with C <: B[_ >: D with C <: A]]]{def companion: scala.collection.generic.GenericCompanion[scala.collection.immutable.Seq with scala.collection.AbstractSeq]; def dropRight(n: Int): scala.collection.immutable.Seq[B[_ >: D with C <: A]] with scala.collection.AbstractSeq[B[_ >: D with C <: A]]{def companion: scala.collection.generic.GenericCompanion[scala.collection.immutable.Seq with scala.collection.AbstractSeq]; def dropRight(n: Int): scala.collection.immutable.Seq[A] with scala.collection.AbstractSeq[A]; def takeRight(n: Int): scala.collection.immutable.Seq[A] with scala.collection.AbstractSeq[A]; def drop(n: Int): scala.collection.immutable.Seq[A] with scala.collection.AbstractSeq[A]; def take(n: Int): scala.collection.immutable.Seq[A] with scala.collection.AbstractSeq[A]; def slice(from: Int,until: Int): scala.collection.immutable.Seq[A] with scala.collection.AbstractSeq[A]; def init: scala.collection.immutable.Seq[A] with scala.collection.AbstractSeq[A]}; def takeRight(n: Int): scala.collection.immutable.Seq[B[_ >: D with C <: A]] with scala.collection.AbstractSeq[B[_ >: D with C <: A]]{def companion: scala.collection.generic.GenericCompanion[scala.collection.immutable.Seq with scala.collection.AbstractSeq]; def dropRight(n: Int): scala.collection.immutable.Seq[A] with scala.collection.AbstractSeq[A]; def takeRight(n: Int): scala.collection.immutable.Seq[A] with scala.collection.AbstractSeq[A]; def drop(n: Int): scala.collection.immutable.Seq[A] with scala.collection.AbstractSeq[A]; def take(n: Int): scala.collection.immutable.Seq[A] with scala.collection.AbstractSeq[A]; def slice(from: Int,until: Int): scala.collection.immutable.Seq[A] with scala.collection.AbstractSeq[A]; def init: scala.collection.immutable.Seq[A] with scala.collection.AbstractSeq[A]}; def drop(n: Int): scala.collection.immutable.Seq[B[_ >: D with C <: A]] with scala.collection.AbstractSeq[B[_ >: D with C <: A]]{def companion: scala.collection.generic.GenericCompanion[scala.collection.immutable.Seq with scala.collection.AbstractSeq]; def dropRight(n: Int): scala.collection.immutable.Seq[A] with scala.collection.AbstractSeq[A]; def takeRight(n: Int): scala.collection.immutable.Seq[A] with scala.collection.AbstractSeq[A]; def drop(n: Int): scala.collection.immutable.Seq[A] with scala.collection.AbstractSeq[A]; def take(n: Int): scala.collection.immutable.Seq[A] with scala.collection.AbstractSeq[A]; def slice(from: Int,until: Int): scala.collection.immutable.Seq[A] with scala.collection.AbstractSeq[A]; def init: scala.collection.immutable.Seq[A] with scala.collection.AbstractSeq[A]}; def take(n: Int): scala.collection.immutable.Seq[B[_ >: D with C <: A]] with scala.collection.AbstractSeq[B[_ >: D with C <: A]]{def companion: scala.collection.generic.GenericCompanion[scala.collection.immutable.Seq with scala.collection.AbstractSeq]; def dropRight(n: Int): scala.collection.immutable.Seq[A] with scala.collection.AbstractSeq[A]; def takeRight(n: Int): scala.collection.immutable.Seq[A] with scala.collection.AbstractSeq[A]; def drop(n: Int): scala.collection.immutable.Seq[A] with scala.collection.AbstractSeq[A]; def take(n: Int): scala.collection.immutable.Seq[A] with scala.collection.AbstractSeq[A]; def slice(from: Int,until: Int): scala.collection.immutable.Seq[A] with scala.collection.AbstractSeq[A]; def init: scala.collection.immutable.Seq[A] with scala.collection.AbstractSeq[A]}; def slice(from: Int,until: Int): scala.collection.immutable.Seq[B[_ >: D with C <: A]] with scala.collection.AbstractSeq[B[_ >: D with C <: A]]{def companion: scala.collection.generic.GenericCompanion[scala.collection.immutable.Seq with scala.collection.AbstractSeq]; def dropRight(n: Int): scala.collection.immutable.Seq[A] with scala.collection.AbstractSeq[A]; def takeRight(n: Int): scala.collection.immutable.Seq[A] with scala.collection.AbstractSeq[A]; def drop(n: Int): scala.collection.immutable.Seq[A] with scala.collection.AbstractSeq[A]; def take(n: Int): scala.collection.immutable.Seq[A] with scala.collection.AbstractSeq[A]; def slice(from: Int,until: Int): scala.collection.immutable.Seq[A] with scala.collection.AbstractSeq[A]; def init: scala.collection.immutable.Seq[A] with scala.collection.AbstractSeq[A]}; def splitAt(n: Int): (scala.collection.immutable.Seq[A] with scala.collection.AbstractSeq[A], scala.collection.immutable.Seq[A] with scala.collection.AbstractSeq[A]); def init: scala.collection.immutable.Seq[B[_ >: D with C <: A]] with scala.collection.AbstractSeq[B[_ >: D with C <: A]]{def companion: scala.collection.generic.GenericCompanion[scala.collection.immutable.Seq with scala.collection.AbstractSeq]; def dropRight(n: Int): scala.collection.immutable.Seq[A] with scala.collection.AbstractSeq[A]; def takeRight(n: Int): scala.collection.immutable.Seq[A] with scala.collection.AbstractSeq[A]; def drop(n: Int): scala.collection.immutable.Seq[A] with scala.collection.AbstractSeq[A]; def take(n: Int): scala.collection.immutable.Seq[A] with scala.collection.AbstractSeq[A]; def slice(from: Int,until: Int): scala.collection.immutable.Seq[A] with scala.collection.AbstractSeq[A]; def init: scala.collection.immutable.Seq[A] with scala.collection.AbstractSeq[A]}}]]
+TypeTag[List[scala.collection.Set[_ >: G with F <: B[_ >: G with F <: B[_ >: G with F <: A]]]]]
+TypeTag[List[scala.collection.Set[_ >: G with F <: B[_ >: G with F <: B[_ >: G with F <: A]]]]]
+TypeTag[List[scala.collection.Set[_ >: G with F <: B[_ >: G with F <: B[_ >: G with F <: A]]]]]
+TypeTag[List[Seq[B[_ >: G with F <: B[_ >: G with F <: A]]]]]
+TypeTag[List[scala.collection.Map[_ >: F with C <: B[_ >: F with C <: B[_ >: F with C <: A]], B[_ >: G with D <: B[_ >: G with D <: A]]]]]
+TypeTag[List[scala.collection.AbstractSeq[B[_ >: G with F <: B[_ >: G with F <: A]]] with scala.collection.LinearSeq[B[_ >: G with F <: B[_ >: G with F <: A]]]{def companion: scala.collection.generic.GenericCompanion[scala.collection.AbstractSeq with scala.collection.LinearSeq]; def dropRight(n: Int): scala.collection.AbstractSeq[B[_ >: G with F <: A]] with scala.collection.LinearSeq[B[_ >: G with F <: A]]{def companion: scala.collection.generic.GenericCompanion[scala.collection.AbstractSeq with scala.collection.LinearSeq]; def dropRight(n: Int): scala.collection.AbstractSeq[A] with scala.collection.LinearSeq[A]; def drop(n: Int): scala.collection.AbstractSeq[A] with scala.collection.LinearSeq[A]; def take(n: Int): scala.collection.AbstractSeq[A] with scala.collection.LinearSeq[A]; def slice(from: Int,until: Int): scala.collection.AbstractSeq[A] with scala.collection.LinearSeq[A]}; def drop(n: Int): scala.collection.AbstractSeq[B[_ >: G with F <: A]] with scala.collection.LinearSeq[B[_ >: G with F <: A]]{def companion: scala.collection.generic.GenericCompanion[scala.collection.AbstractSeq with scala.collection.LinearSeq]; def dropRight(n: Int): scala.collection.AbstractSeq[A] with scala.collection.LinearSeq[A]; def drop(n: Int): scala.collection.AbstractSeq[A] with scala.collection.LinearSeq[A]; def take(n: Int): scala.collection.AbstractSeq[A] with scala.collection.LinearSeq[A]; def slice(from: Int,until: Int): scala.collection.AbstractSeq[A] with scala.collection.LinearSeq[A]}; def take(n: Int): scala.collection.AbstractSeq[B[_ >: G with F <: A]] with scala.collection.LinearSeq[B[_ >: G with F <: A]]{def companion: scala.collection.generic.GenericCompanion[scala.collection.AbstractSeq with scala.collection.LinearSeq]; def dropRight(n: Int): scala.collection.AbstractSeq[A] with scala.collection.LinearSeq[A]; def drop(n: Int): scala.collection.AbstractSeq[A] with scala.collection.LinearSeq[A]; def take(n: Int): scala.collection.AbstractSeq[A] with scala.collection.LinearSeq[A]; def slice(from: Int,until: Int): scala.collection.AbstractSeq[A] with scala.collection.LinearSeq[A]}; def slice(from: Int,until: Int): scala.collection.AbstractSeq[B[_ >: G with F <: A]] with scala.collection.LinearSeq[B[_ >: G with F <: A]]{def companion: scala.collection.generic.GenericCompanion[scala.collection.AbstractSeq with scala.collection.LinearSeq]; def dropRight(n: Int): scala.collection.AbstractSeq[A] with scala.collection.LinearSeq[A]; def drop(n: Int): scala.collection.AbstractSeq[A] with scala.collection.LinearSeq[A]; def take(n: Int): scala.collection.AbstractSeq[A] with scala.collection.LinearSeq[A]; def slice(from: Int,until: Int): scala.collection.AbstractSeq[A] with scala.collection.LinearSeq[A]}}]]
+TypeTag[List[Seq[B[_ >: G with F <: B[_ >: G with F <: A]]]]]
+TypeTag[List[Seq[B[_ >: G with F <: B[_ >: G with F <: A]]]]]
diff --git a/test/files/run/t2251b.scala b/test/files/run/t2251b.scala
new file mode 100644
index 0000000000..b67b3aec1e
--- /dev/null
+++ b/test/files/run/t2251b.scala
@@ -0,0 +1,48 @@
+class A
+trait B[T <: B[T]] extends A
+class B1[T <: B1[T]] extends B[T]
+class C extends B[C] { override def toString = "C" }
+class D extends B[D] { override def toString = "D" }
+class E extends B[E] { override def toString = "E" }
+class F extends B[F] { override def toString = "F" }
+class G extends B1[G] { override def toString = "G" }
+
+object Test {
+ import scala.collection.{ mutable, immutable }
+ import scala.collection.immutable.{ Vector }
+ import scala.reflect.runtime.universe._
+ def what[T: TypeTag](x: T) = println(typeTag[T])
+
+ def main(args: Array[String]): Unit = {
+ what(List(List(new C), Stream(new D)))
+ what(List(List(new C), Stream(new D), Vector(new E), Set(new F)))
+ what(List(immutable.Vector(new C), Stream(new D)))
+ what(List(collection.Set(new F), mutable.Set(new G)))
+ what(List(collection.Set(new F), immutable.Set(new G)))
+ what(List(mutable.Set(new F), immutable.Set(new G)))
+ what(List(mutable.Seq(new F), immutable.Seq(new G)))
+ what(List(mutable.Map(new C -> new D), immutable.Map(new F -> new G)))
+ what(List(mutable.MutableList(new F), immutable.List(new G)))
+ what(List(mutable.Seq(new F), collection.Seq(new G)))
+ what(List(mutable.LinearSeq(new F), collection.IndexedSeq(new G)))
+ }
+}
+
+
+// class D extends B[D] { override def toString = "D" }
+
+
+// class E {
+// val ys = List(List(new C), Stream(new D))
+// }
+
+// object Test {
+// def trav = List(List(), Stream())
+
+// def main(args: Array[String]): Unit = {
+// val f = (new E).ys _
+// var xs: Set[List[_ <: Seq[B[_]]]] = Set()
+// xs += f()
+// println(xs)
+// }
+// }