Skip to content

Commit 41c4fce

Browse files
committed
More precise characterization of singleton bounds
Avoids needlessly complicated inferred types such as C[_ >: 1.type <: Singleton] by detecting that that this is equivalent to `C[1.type]`.
1 parent 03fb30d commit 41c4fce

File tree

1 file changed

+24
-2
lines changed

1 file changed

+24
-2
lines changed

compiler/src/dotty/tools/dotc/core/TypeComparer.scala

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1189,6 +1189,26 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling {
11891189
isSubRef(tp1, tp2) && isSubRef(tp2, tp1)
11901190
}
11911191

1192+
/** If the range `tp1..tp2` consist of a single type, that type, otherwise NoType`.
1193+
* This is the case if `tp1 =:= tp2`, but also if `tp1 <:< tp2`, `tp1` is a singleton type,
1194+
* and `tp2` derives from `scala.Singleton` (or vice-versa). Examples of the latter case:
1195+
*
1196+
* "name".type .. Singleton
1197+
* "name".type .. String & Singleton
1198+
* Singleton .. "name".type
1199+
* String & Singleton .. "name".type
1200+
*
1201+
* All consist of the single type `"name".type`.
1202+
*/
1203+
def singletonInterval(tp1: Type, tp2: Type): Type = {
1204+
def isSingletonBounds(lo: Type, hi: Type) =
1205+
lo.isSingleton && hi.derivesFrom(defn.SingletonClass) && isSubTypeWhenFrozen(lo, hi)
1206+
if (isSameTypeWhenFrozen(tp1, tp2)) tp1
1207+
else if (isSingletonBounds(tp1, tp2)) tp1
1208+
else if (isSingletonBounds(tp2, tp1)) tp2
1209+
else NoType
1210+
}
1211+
11921212
/** The greatest lower bound of two types */
11931213
def glb(tp1: Type, tp2: Type): Type = /*>|>*/ trace(s"glb(${tp1.show}, ${tp2.show})", subtyping, show = true) /*<|<*/ {
11941214
if (tp1 eq tp2) tp1
@@ -1277,9 +1297,10 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling {
12771297
case tparam :: tparamsRest =>
12781298
val arg1 :: args1Rest = args1
12791299
val arg2 :: args2Rest = args2
1300+
val common = singletonInterval(arg1, arg2)
12801301
val v = tparam.paramVariance
12811302
val lubArg =
1282-
if (isSameTypeWhenFrozen(arg1, arg2)) arg1
1303+
if (common.exists) common
12831304
else if (v > 0) lub(arg1.hiBound, arg2.hiBound, canConstrain)
12841305
else if (v < 0) glb(arg1.loBound, arg2.loBound)
12851306
else TypeBounds(glb(arg1.loBound, arg2.loBound),
@@ -1308,9 +1329,10 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling {
13081329
case tparam :: tparamsRest =>
13091330
val arg1 :: args1Rest = args1
13101331
val arg2 :: args2Rest = args2
1332+
val common = singletonInterval(arg1, arg2)
13111333
val v = tparam.paramVariance
13121334
val glbArg =
1313-
if (isSameTypeWhenFrozen(arg1, arg2)) arg1
1335+
if (common.exists) common
13141336
else if (v > 0) glb(arg1.hiBound, arg2.hiBound)
13151337
else if (v < 0) lub(arg1.loBound, arg2.loBound)
13161338
else if (arg1.isInstanceOf[TypeBounds] || arg2.isInstanceOf[TypeBounds])

0 commit comments

Comments
 (0)