Skip to content

Commit cb5935e

Browse files
committed
Merge pull request #1053 from dotty-staging/fix-#1045
Fix #1045
2 parents 0c4eb33 + ae09ac2 commit cb5935e

File tree

5 files changed

+90
-25
lines changed

5 files changed

+90
-25
lines changed

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

+63-22
Original file line numberDiff line numberDiff line change
@@ -266,31 +266,72 @@ 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-
if (ctx.featureEnabled(defn.LanguageModuleClass, nme.keepUnions)) tp
270-
else tp match {
271-
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))
269+
def approximateOr(tp1: Type, tp2: Type): 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+
/** If `tp1` and `tp2` are typebounds, try to make one fit into the other
280+
* or to make them equal, by instantiating uninstantiated type variables.
281+
*/
282+
def homogenizedUnion(tp1: Type, tp2: Type): Type = {
283+
tp1 match {
284+
case tp1: TypeBounds =>
285+
tp2 match {
286+
case tp2: TypeBounds =>
287+
def fitInto(tp1: TypeBounds, tp2: TypeBounds): Unit = {
288+
val nestedCtx = ctx.fresh.setNewTyperState
289+
if (tp2.boundsInterval.contains(tp1.boundsInterval)(nestedCtx))
290+
nestedCtx.typerState.commit()
291+
}
292+
fitInto(tp1, tp2)
293+
fitInto(tp2, tp1)
288294
case _ =>
289-
val commonBaseClasses = tp.mapReduceOr(_.baseClasses)(intersect)
290-
val doms = dominators(commonBaseClasses, Nil)
291-
doms.map(tp.baseTypeWithArgs).reduceLeft(AndType.apply)
292295
}
296+
case _ =>
293297
}
298+
tp1 | tp2
299+
}
300+
301+
tp1 match {
302+
case tp1: RefinedType =>
303+
tp2 match {
304+
case tp2: RefinedType if tp1.refinedName == tp2.refinedName =>
305+
return tp1.derivedRefinedType(
306+
approximateUnion(OrType(tp1.parent, tp2.parent)),
307+
tp1.refinedName,
308+
homogenizedUnion(tp1.refinedInfo, tp2.refinedInfo).substRefinedThis(tp2, RefinedThis(tp1)))
309+
//.ensuring { x => println(i"approx or $tp1 | $tp2 = $x\n constr = ${ctx.typerState.constraint}"); true } // DEBUG
310+
case _ =>
311+
}
312+
case _ =>
313+
}
314+
tp1 match {
315+
case tp1: TypeProxy if !isClassRef(tp1) =>
316+
approximateUnion(next(tp1) | tp2)
317+
case _ =>
318+
tp2 match {
319+
case tp2: TypeProxy if !isClassRef(tp2) =>
320+
approximateUnion(tp1 | next(tp2))
321+
case _ =>
322+
val commonBaseClasses = tp.mapReduceOr(_.baseClasses)(intersect)
323+
val doms = dominators(commonBaseClasses, Nil)
324+
def baseTp(cls: ClassSymbol): Type =
325+
if (tp1.typeParams.nonEmpty) tp.baseTypeRef(cls)
326+
else tp.baseTypeWithArgs(cls)
327+
doms.map(baseTp).reduceLeft(AndType.apply)
328+
}
329+
}
330+
}
331+
if (ctx.featureEnabled(defn.LanguageModuleClass, nme.keepUnions)) tp
332+
else tp match {
333+
case tp: OrType =>
334+
approximateOr(tp.tp1, tp.tp2)
294335
case tp @ AndType(tp1, tp2) =>
295336
tp derived_& (approximateUnion(tp1), approximateUnion(tp2))
296337
case tp: RefinedType =>

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

+19
Original file line numberDiff line numberDiff line change
@@ -1199,6 +1199,15 @@ object Types {
11991199
* class B extends C[B] with D with E
12001200
*
12011201
* we approximate `A | B` by `C[A | B] with D`
1202+
*
1203+
* As a second measure we also homogenize refinements containing
1204+
* type variables. For instance, if `A` is an instantiatable type variable,
1205+
* then
1206+
*
1207+
* ArrayBuffer[Int] | ArrayBuffer[A]
1208+
*
1209+
* is approximated by instantiating `A` to `Int` and returning `ArrayBuffer[Int]`
1210+
* instead of `ArrayBuffer[_ >: Int | A <: Int & A]`
12021211
*/
12031212
def approximateUnion(implicit ctx: Context) = ctx.approximateUnion(this)
12041213

@@ -2848,6 +2857,11 @@ object Types {
28482857
case _ => super.| (that)
28492858
}
28502859

2860+
/** The implied bounds, where aliases are mapped to intervals from
2861+
* Nothing/Any
2862+
*/
2863+
def boundsInterval(implicit ctx: Context): TypeBounds = this
2864+
28512865
/** If this type and that type have the same variance, this variance, otherwise 0 */
28522866
final def commonVariance(that: TypeBounds): Int = (this.variance + that.variance) / 2
28532867

@@ -2885,6 +2899,11 @@ object Types {
28852899
else if (v < 0) derivedTypeAlias(this.lo & that.lo, v)
28862900
else super.| (that)
28872901
}
2902+
2903+
override def boundsInterval(implicit ctx: Context): TypeBounds =
2904+
if (variance == 0) this
2905+
else if (variance < 0) TypeBounds.lower(alias)
2906+
else TypeBounds.upper(alias)
28882907
}
28892908

28902909
class CachedTypeAlias(alias: Type, variance: Int, hc: Int) extends TypeAlias(alias, variance) {
File renamed without changes.

tests/pos/i1045.scala

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
import scala.collection._
2+
object T {
3+
val newSymbolMap: mutable.HashMap[String, mutable.HashMap[Int, Double]] = mutable.HashMap.empty
4+
val map = newSymbolMap.getOrElse("a", mutable.HashMap.empty)
5+
map.put(1, 0.0)
6+
newSymbolMap.put("a", map)
7+
}

tests/pos/intersection.scala

+1-3
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)