Skip to content

Commit 7d1d93e

Browse files
committed
Push `|' into corresponding RefinedTypes in approximateUnion
This gives in general a supertype, that's OK for approximation. See ee76fda for an explanation.
1 parent 93dd1cf commit 7d1d93e

File tree

2 files changed

+42
-25
lines changed

2 files changed

+42
-25
lines changed

src/dotty/tools/dotc/core/TypeOps.scala

Lines changed: 41 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -266,31 +266,50 @@ trait TypeOps { this: Context => // TODO: Make standalone object.
266266
val accu1 = if (accu exists (_ derivesFrom c)) accu else c :: accu
267267
if (cs == c.baseClasses) accu1 else dominators(rest, accu1)
268268
}
269+
def approximateOr(tp1: Type, tp2: Type)(implicit ctx: Context): Type = {
270+
def isClassRef(tp: Type): Boolean = tp match {
271+
case tp: TypeRef => tp.symbol.isClass
272+
case tp: RefinedType => isClassRef(tp.parent)
273+
case _ => false
274+
}
275+
def next(tp: TypeProxy) = tp.underlying match {
276+
case TypeBounds(_, hi) => hi
277+
case nx => nx
278+
}
279+
tp1 match {
280+
case tp1: RefinedType =>
281+
tp2 match {
282+
case tp2: RefinedType if tp1.refinedName == tp2.refinedName =>
283+
return tp1.derivedRefinedType(
284+
approximateUnion(OrType(tp1.parent, tp2.parent)),
285+
tp1.refinedName,
286+
(tp1.refinedInfo | tp2.refinedInfo).substRefinedThis(tp2, RefinedThis(tp1)))
287+
.ensuring { x => println(i"approx or $tp1 | $tp2 = $x"); true } // DEBUG
288+
case _ =>
289+
}
290+
case _ =>
291+
}
292+
tp1 match {
293+
case tp1: TypeProxy if !isClassRef(tp1) =>
294+
approximateUnion(next(tp1) | tp2)
295+
case _ =>
296+
tp2 match {
297+
case tp2: TypeProxy if !isClassRef(tp2) =>
298+
approximateUnion(tp1 | next(tp2))
299+
case _ =>
300+
val commonBaseClasses = tp.mapReduceOr(_.baseClasses)(intersect)
301+
val doms = dominators(commonBaseClasses, Nil)
302+
def baseTp(cls: ClassSymbol): Type =
303+
if (tp1.typeParams.nonEmpty) tp.baseTypeRef(cls)
304+
else tp.baseTypeWithArgs(cls)
305+
doms.map(baseTp).reduceLeft(AndType.apply)
306+
}
307+
}
308+
}
269309
if (ctx.featureEnabled(defn.LanguageModuleClass, nme.keepUnions)) tp
270310
else tp match {
271311
case tp: OrType =>
272-
def isClassRef(tp: Type): Boolean = tp match {
273-
case tp: TypeRef => tp.symbol.isClass
274-
case tp: RefinedType => isClassRef(tp.parent)
275-
case _ => false
276-
}
277-
def next(tp: TypeProxy) = tp.underlying match {
278-
case TypeBounds(_, hi) => hi
279-
case nx => nx
280-
}
281-
tp.tp1 match {
282-
case tp1: TypeProxy if !isClassRef(tp1) =>
283-
approximateUnion(next(tp1) | tp.tp2)
284-
case _ =>
285-
tp.tp2 match {
286-
case tp2: TypeProxy if !isClassRef(tp2) =>
287-
approximateUnion(tp.tp1 | next(tp2))
288-
case _ =>
289-
val commonBaseClasses = tp.mapReduceOr(_.baseClasses)(intersect)
290-
val doms = dominators(commonBaseClasses, Nil)
291-
doms.map(tp.baseTypeWithArgs).reduceLeft(AndType.apply)
292-
}
293-
}
312+
approximateOr(tp.tp1, tp.tp2)
294313
case tp @ AndType(tp1, tp2) =>
295314
tp derived_& (approximateUnion(tp1), approximateUnion(tp2))
296315
case tp: RefinedType =>

tests/pos/intersection.scala

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import dotty.language.keepUnions
12
object intersection {
23

34
class A
@@ -11,9 +12,6 @@ object intersection {
1112
val a: A & B => Unit = z
1213
val b: (A => Unit) | (B => Unit) = z
1314

14-
15-
16-
1715
type needsA = A => Nothing
1816
type needsB = B => Nothing
1917
}

0 commit comments

Comments
 (0)