Skip to content

Commit c460627

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 1215dd2 commit c460627

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
@@ -1191,6 +1191,26 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling {
11911191
isSubRef(tp1, tp2) && isSubRef(tp2, tp1)
11921192
}
11931193

1194+
/** If the range `tp1..tp2` consist of a single type, that type, otherwise NoType`.
1195+
* This is the case if `tp1 =:= tp2`, but also if `tp1 <:< tp2`, `tp1` is a singleton type,
1196+
* and `tp2` derives from `scala.Singleton` (or vice-versa). Examples of the latter case:
1197+
*
1198+
* "name".type .. Singleton
1199+
* "name".type .. String & Singleton
1200+
* Singleton .. "name".type
1201+
* String & Singleton .. "name".type
1202+
*
1203+
* All consist of the single type `"name".type`.
1204+
*/
1205+
def singletonInterval(tp1: Type, tp2: Type): Type = {
1206+
def isSingletonBounds(lo: Type, hi: Type) =
1207+
lo.isSingleton && hi.derivesFrom(defn.SingletonClass) && isSubTypeWhenFrozen(lo, hi)
1208+
if (isSameTypeWhenFrozen(tp1, tp2)) tp1
1209+
else if (isSingletonBounds(tp1, tp2)) tp1
1210+
else if (isSingletonBounds(tp2, tp1)) tp2
1211+
else NoType
1212+
}
1213+
11941214
/** The greatest lower bound of two types */
11951215
def glb(tp1: Type, tp2: Type): Type = /*>|>*/ trace(s"glb(${tp1.show}, ${tp2.show})", subtyping, show = true) /*<|<*/ {
11961216
if (tp1 eq tp2) tp1
@@ -1279,9 +1299,10 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling {
12791299
case tparam :: tparamsRest =>
12801300
val arg1 :: args1Rest = args1
12811301
val arg2 :: args2Rest = args2
1302+
val common = singletonInterval(arg1, arg2)
12821303
val v = tparam.paramVariance
12831304
val lubArg =
1284-
if (isSameTypeWhenFrozen(arg1, arg2)) arg1
1305+
if (common.exists) common
12851306
else if (v > 0) lub(arg1.hiBound, arg2.hiBound, canConstrain)
12861307
else if (v < 0) glb(arg1.loBound, arg2.loBound)
12871308
else TypeBounds(glb(arg1.loBound, arg2.loBound),
@@ -1310,9 +1331,10 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling {
13101331
case tparam :: tparamsRest =>
13111332
val arg1 :: args1Rest = args1
13121333
val arg2 :: args2Rest = args2
1334+
val common = singletonInterval(arg1, arg2)
13131335
val v = tparam.paramVariance
13141336
val glbArg =
1315-
if (isSameTypeWhenFrozen(arg1, arg2)) arg1
1337+
if (common.exists) common
13161338
else if (v > 0) glb(arg1.hiBound, arg2.hiBound)
13171339
else if (v < 0) lub(arg1.loBound, arg2.loBound)
13181340
else if (arg1.isInstanceOf[TypeBounds] || arg2.isInstanceOf[TypeBounds])

0 commit comments

Comments
 (0)