summaryrefslogtreecommitdiff
path: root/src/reflect/scala/reflect/internal/tpe
diff options
context:
space:
mode:
authorJason Zaugg <jzaugg@gmail.com>2014-02-21 15:04:01 +0100
committerJason Zaugg <jzaugg@gmail.com>2014-02-21 15:04:01 +0100
commitd128f624bc4cf22dc0e277706690e98ed6f084b6 (patch)
treebab1f544f705a4df0fb126dd72e1159a36856b9b /src/reflect/scala/reflect/internal/tpe
parent25f23a443bc6831d1c8d7f6f57212a29e84bbaa5 (diff)
parent917c49416133bd067c203f907e9fe9112a081ff4 (diff)
downloadscala-d128f624bc4cf22dc0e277706690e98ed6f084b6.tar.gz
scala-d128f624bc4cf22dc0e277706690e98ed6f084b6.tar.bz2
scala-d128f624bc4cf22dc0e277706690e98ed6f084b6.zip
Merge pull request #3557 from adriaanm/t8224
SI-8224 Fix regression in f-bound aware LUBs
Diffstat (limited to 'src/reflect/scala/reflect/internal/tpe')
-rw-r--r--src/reflect/scala/reflect/internal/tpe/GlbLubs.scala69
1 files changed, 32 insertions, 37 deletions
diff --git a/src/reflect/scala/reflect/internal/tpe/GlbLubs.scala b/src/reflect/scala/reflect/internal/tpe/GlbLubs.scala
index 1c4d05ae32..876685e24a 100644
--- a/src/reflect/scala/reflect/internal/tpe/GlbLubs.scala
+++ b/src/reflect/scala/reflect/internal/tpe/GlbLubs.scala
@@ -14,11 +14,11 @@ private[internal] trait GlbLubs {
import TypesStats._
private final val printLubs = scala.sys.props contains "scalac.debug.lub"
+ private final val strictInference = settings.strictInference
/** In case anyone wants to turn off lub verification without reverting anything. */
private final val verifyLubs = true
-
private def printLubMatrix(btsMap: Map[Type, List[Type]], depth: Depth) {
import util.TableDef
import TableDef.Column
@@ -63,6 +63,26 @@ private[internal] trait GlbLubs {
}
}
+ // only called when strictInference
+ private def willViolateRecursiveBounds(tp: Type, ts: List[Type], tsElimSub: List[Type]) = {
+ val typeSym = ts.head.typeSymbol // we're uniform, the `.head` is as good as any.
+ def fbounds = findRecursiveBounds(ts) map (_._2)
+ def isRecursive = typeSym.typeParams exists fbounds.contains
+
+ isRecursive && (transposeSafe(tsElimSub map (_.normalize.typeArgs)) match {
+ case Some(arggsTransposed) =>
+ val mergedTypeArgs = (tp match { case et: ExistentialType => et.underlying; case _ => tp}).typeArgs
+ exists3(typeSym.typeParams, mergedTypeArgs, arggsTransposed) {
+ (param, arg, lubbedArgs) =>
+ val isExistential = arg.typeSymbol.isExistentiallyBound
+ val isInFBound = fbounds contains param
+ val wasLubbed = !lubbedArgs.exists(_ =:= arg)
+ (!isExistential && isInFBound && wasLubbed)
+ }
+ case None => false
+ })
+ }
+
/** Given a matrix `tsBts` whose columns are basetype sequences (and the symbols `tsParams` that should be interpreted as type parameters in this matrix),
* compute its least sorted upwards closed upper bound relative to the following ordering <= between lists of types:
*
@@ -88,7 +108,8 @@ private[internal] trait GlbLubs {
case _ => tp
}
// pretypes is a tail-recursion-preserving accumulator.
- @tailrec def loop(pretypes: List[Type], tsBts: List[List[Type]]): List[Type] = {
+ @tailrec
+ def loop(pretypes: List[Type], tsBts: List[List[Type]]): List[Type] = {
lubListDepth = lubListDepth.incr
if (tsBts.isEmpty || (tsBts exists typeListIsEmpty)) pretypes.reverse
@@ -110,28 +131,19 @@ private[internal] trait GlbLubs {
// 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) {
- 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
- }
- }
- else t
- }
val tails = tsBts map (_.tail)
- mergePrefixAndArgs(elimSub(ts1, depth) map elimHigherOrderTypeParam, Covariant, depth) match {
+ val ts1 = elimSub(ts0, depth) map elimHigherOrderTypeParam
+ mergePrefixAndArgs(ts1, Covariant, depth) match {
case NoType => loop(pretypes, tails)
- case tp => loop(tp :: pretypes, tails)
+ case tp if strictInference && willViolateRecursiveBounds(tp, ts0, ts1) =>
+ log(s"Breaking recursion in lublist, advancing frontier and discaring merged prefix/args from $tp")
+ loop(pretypes, tails)
+ case tp =>
+ loop(tp :: pretypes, tails)
}
- }
- else {
+ } else {
// frontier is not uniform yet, move it beyond the current minimal symbol;
- // lather, rinSe, repeat
+ // lather, rinse, repeat
val sym = minSym(ts0)
val newtps = tsBts map (ts => if (ts.head.typeSymbol == sym) ts.tail else ts)
if (printLubs) {
@@ -257,23 +269,6 @@ private[internal] trait GlbLubs {
private val _glbResults = new mutable.HashMap[(Depth, List[Type]), Type]
def glbResults = _glbResults
- /** 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 Nil => NothingTpe
case t :: Nil => t