aboutsummaryrefslogtreecommitdiff
path: root/src/dotty/tools/dotc/core/TypeOps.scala
diff options
context:
space:
mode:
authorMartin Odersky <odersky@gmail.com>2016-02-04 12:03:09 +0100
committerMartin Odersky <odersky@gmail.com>2016-02-04 12:03:15 +0100
commit7d1d93e95113802bee77b9d2b89475a56be46bf7 (patch)
tree994d5cf39aa3ab813d5b13f4b36bce2c8fcdda6c /src/dotty/tools/dotc/core/TypeOps.scala
parent93dd1cf1fdbf56ca3c153aa5a25fb4c48782acf5 (diff)
downloaddotty-7d1d93e95113802bee77b9d2b89475a56be46bf7.tar.gz
dotty-7d1d93e95113802bee77b9d2b89475a56be46bf7.tar.bz2
dotty-7d1d93e95113802bee77b9d2b89475a56be46bf7.zip
Push `|' into corresponding RefinedTypes in approximateUnion
This gives in general a supertype, that's OK for approximation. See ee76fda for an explanation.
Diffstat (limited to 'src/dotty/tools/dotc/core/TypeOps.scala')
-rw-r--r--src/dotty/tools/dotc/core/TypeOps.scala63
1 files changed, 41 insertions, 22 deletions
diff --git a/src/dotty/tools/dotc/core/TypeOps.scala b/src/dotty/tools/dotc/core/TypeOps.scala
index 70e8302d9..7121d94df 100644
--- a/src/dotty/tools/dotc/core/TypeOps.scala
+++ b/src/dotty/tools/dotc/core/TypeOps.scala
@@ -266,31 +266,50 @@ trait TypeOps { this: Context => // TODO: Make standalone object.
val accu1 = if (accu exists (_ derivesFrom c)) accu else c :: accu
if (cs == c.baseClasses) accu1 else dominators(rest, accu1)
}
+ def approximateOr(tp1: Type, tp2: Type)(implicit ctx: Context): Type = {
+ def isClassRef(tp: Type): Boolean = tp match {
+ case tp: TypeRef => tp.symbol.isClass
+ case tp: RefinedType => isClassRef(tp.parent)
+ case _ => false
+ }
+ def next(tp: TypeProxy) = tp.underlying match {
+ case TypeBounds(_, hi) => hi
+ case nx => nx
+ }
+ tp1 match {
+ case tp1: RefinedType =>
+ tp2 match {
+ case tp2: RefinedType if tp1.refinedName == tp2.refinedName =>
+ return tp1.derivedRefinedType(
+ approximateUnion(OrType(tp1.parent, tp2.parent)),
+ tp1.refinedName,
+ (tp1.refinedInfo | tp2.refinedInfo).substRefinedThis(tp2, RefinedThis(tp1)))
+ .ensuring { x => println(i"approx or $tp1 | $tp2 = $x"); true } // DEBUG
+ case _ =>
+ }
+ case _ =>
+ }
+ tp1 match {
+ case tp1: TypeProxy if !isClassRef(tp1) =>
+ approximateUnion(next(tp1) | tp2)
+ case _ =>
+ tp2 match {
+ case tp2: TypeProxy if !isClassRef(tp2) =>
+ approximateUnion(tp1 | next(tp2))
+ case _ =>
+ val commonBaseClasses = tp.mapReduceOr(_.baseClasses)(intersect)
+ val doms = dominators(commonBaseClasses, Nil)
+ def baseTp(cls: ClassSymbol): Type =
+ if (tp1.typeParams.nonEmpty) tp.baseTypeRef(cls)
+ else tp.baseTypeWithArgs(cls)
+ doms.map(baseTp).reduceLeft(AndType.apply)
+ }
+ }
+ }
if (ctx.featureEnabled(defn.LanguageModuleClass, nme.keepUnions)) tp
else tp match {
case tp: OrType =>
- def isClassRef(tp: Type): Boolean = tp match {
- case tp: TypeRef => tp.symbol.isClass
- case tp: RefinedType => isClassRef(tp.parent)
- case _ => false
- }
- def next(tp: TypeProxy) = tp.underlying match {
- case TypeBounds(_, hi) => hi
- case nx => nx
- }
- tp.tp1 match {
- case tp1: TypeProxy if !isClassRef(tp1) =>
- approximateUnion(next(tp1) | tp.tp2)
- case _ =>
- tp.tp2 match {
- case tp2: TypeProxy if !isClassRef(tp2) =>
- approximateUnion(tp.tp1 | next(tp2))
- case _ =>
- val commonBaseClasses = tp.mapReduceOr(_.baseClasses)(intersect)
- val doms = dominators(commonBaseClasses, Nil)
- doms.map(tp.baseTypeWithArgs).reduceLeft(AndType.apply)
- }
- }
+ approximateOr(tp.tp1, tp.tp2)
case tp @ AndType(tp1, tp2) =>
tp derived_& (approximateUnion(tp1), approximateUnion(tp2))
case tp: RefinedType =>