Skip to content

Commit 30e689c

Browse files
authored
Merge pull request scala#6257 from joroKr21/solve-wildcards
Eliminate TypeVars and Wildcards early in glb/lub
2 parents b1273e1 + 6bbef4e commit 30e689c

File tree

3 files changed

+43
-20
lines changed

3 files changed

+43
-20
lines changed

src/reflect/scala/reflect/internal/tpe/GlbLubs.scala

Lines changed: 26 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -158,31 +158,37 @@ private[internal] trait GlbLubs {
158158
rest filter (t => !first.typeSymbol.isSubClass(t.typeSymbol)))
159159
}
160160

161+
/** From a list of types, retain only maximal types as determined by the partial order `po`. */
162+
private def maxTypes(ts: List[Type])(po: (Type, Type) => Boolean): List[Type] = {
163+
def loop(ts: List[Type]): List[Type] = ts match {
164+
case t :: ts1 =>
165+
val ts2 = loop(ts1.filterNot(po(_, t)))
166+
if (ts2.exists(po(t, _))) ts2 else t :: ts2
167+
case Nil => Nil
168+
}
169+
170+
// The order here matters because type variables and
171+
// wildcards can act both as subtypes and supertypes.
172+
val (ts2, ts1) = ts.partition(_ exists {
173+
case tv: TypeVar => !tv.isGround
174+
case t => t.isWildcard
175+
})
176+
177+
loop(ts1 ::: ts2)
178+
}
179+
161180
/** Eliminate from list of types all elements which are a supertype
162181
* of some other element of the list. */
163-
private def elimSuper(ts: List[Type]): List[Type] = ts match {
164-
case List() | List(_) => ts
165-
case t :: ts1 =>
166-
val rest = elimSuper(ts1 filter (t1 => !(t <:< t1)))
167-
if (rest exists (t1 => t1 <:< t)) rest else t :: rest
168-
}
182+
private def elimSuper(ts: List[Type]): List[Type] =
183+
maxTypes(ts)((t1, t2) => t2 <:< t1)
169184

170185
/** Eliminate from list of types all elements which are a subtype
171186
* of some other element of the list. */
172-
private def elimSub(ts: List[Type], depth: Depth): List[Type] = {
173-
def elimSub0(ts: List[Type]): List[Type] = ts match {
174-
case List() => ts
175-
case List(t) => ts
176-
case t :: ts1 =>
177-
val rest = elimSub0(ts1 filter (t1 => !isSubType(t1, t, depth.decr)))
178-
if (rest exists (t1 => isSubType(t, t1, depth.decr))) rest else t :: rest
179-
}
180-
val ts0 = elimSub0(ts)
181-
if (ts0.isEmpty || ts0.tail.isEmpty) ts0
182-
else {
183-
val ts1 = ts0 mapConserve (t => elimAnonymousClass(t.dealiasWiden))
184-
if (ts1 eq ts0) ts0
185-
else elimSub(ts1, depth)
187+
@tailrec private def elimSub(ts: List[Type], depth: Depth): List[Type] = {
188+
val ts1 = maxTypes(ts)(isSubType(_, _, depth.decr))
189+
if (ts1.lengthCompare(1) <= 0) ts1 else {
190+
val ts2 = ts1.mapConserve(t => elimAnonymousClass(t.dealiasWiden))
191+
if (ts1 eq ts2) ts1 else elimSub(ts2, depth)
186192
}
187193
}
188194

test/files/pos/t10686.scala

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
object Test {
2+
def ltr[A](implicit ev: (Int, A) =:= (Int, String)) = null
3+
def rtl[A](implicit ev: (Int, String) =:= (Int, A)) = null
4+
ltr
5+
rtl
6+
}

test/files/pos/t10740.scala

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
object Test {
2+
case class Inv[A](x: A)
3+
def diff1[A](i: Inv[A], j: Inv[_ <: A]) = 1
4+
def diff2[A](i: Inv[_ >: A], j: Inv[A]) = 2
5+
def diff3[A](i: Inv[_ >: A], j: Inv[_ <: A]) = 3
6+
val i = Inv(Option(42))
7+
val j = Inv(Some(42))
8+
diff1(i, j)
9+
diff2(i, j)
10+
diff3(i, j)
11+
}

0 commit comments

Comments
 (0)