Skip to content

Commit ddbd04e

Browse files
committed
Fix handling of special implicit searches for ClassTag, quoted.Type, Eq
They did not work if the searched-for type was an uninstantiated TypeVar that had the class as an upper bound. Getting them to work is surprisingly subtle.
1 parent b7fa358 commit ddbd04e

File tree

4 files changed

+57
-11
lines changed

4 files changed

+57
-11
lines changed

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

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -863,6 +863,30 @@ object Types {
863863
}
864864
}
865865

866+
/** Like basetype, but follow context bounds */
867+
final def contextualBaseType(cls: ClassSymbol)(implicit ctx: Context): Type = {
868+
def loop(tp: Type): Type = tp match {
869+
case tp: TypeRef =>
870+
val sym = tp.symbol
871+
if (sym.isClass) tp.baseType(cls) else loop(tp.superType): @tailrec
872+
case tp: AppliedType =>
873+
tp.baseType(cls)
874+
case tp: TypeParamRef =>
875+
loop(ctx.typeComparer.bounds(tp).hi): @tailrec
876+
case tp: TypeProxy =>
877+
loop(tp.superType): @tailrec
878+
case tp: AndType =>
879+
loop(tp.tp1) & loop(tp.tp2): @tailrec
880+
case tp: OrType =>
881+
loop(tp.tp1) | loop(tp.tp2): @tailrec
882+
case tp: JavaArrayType =>
883+
if (cls == defn.ObjectClass) cls.typeRef else NoType
884+
case _ =>
885+
NoType
886+
}
887+
loop(this)
888+
}
889+
866890
def & (that: Type)(implicit ctx: Context): Type = track("&") {
867891
ctx.typeComparer.glb(this, that)
868892
}

compiler/src/dotty/tools/dotc/typer/Implicits.scala

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -650,17 +650,20 @@ trait Implicits { self: Typer =>
650650
ref(lazyImplicit))
651651
else
652652
arg
653-
case fail @ SearchFailure(tree) =>
654-
if (fail.isAmbiguous)
655-
tree
656-
else if (formalValue.isRef(defn.ClassTagClass))
657-
synthesizedClassTag(formalValue).orElse(tree)
658-
else if (formalValue.isRef(defn.QuotedTypeClass))
659-
synthesizedTypeTag(formalValue).orElse(tree)
660-
else if (formalValue.isRef(defn.EqClass))
661-
synthesizedEq(formalValue).orElse(tree)
653+
case fail @ SearchFailure(failed) =>
654+
def trySpecialCase(cls: ClassSymbol, handler: Type => Tree, ifNot: => Tree) = {
655+
val base = formalValue.contextualBaseType(cls)
656+
if (base <:< formalValue) {
657+
// With the subtype test we enforce that the searched type `formalValue` is of the right form
658+
handler(base).orElse(ifNot)
659+
}
660+
else ifNot
661+
}
662+
if (fail.isAmbiguous) failed
662663
else
663-
tree
664+
trySpecialCase(defn.ClassTagClass, synthesizedClassTag,
665+
trySpecialCase(defn.QuotedTypeClass, synthesizedTypeTag,
666+
trySpecialCase(defn.EqClass, synthesizedEq, failed)))
664667
}
665668
}
666669

tests/run/inlineForeach.scala

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,22 @@ object Test {
3535
zs
3636
}
3737

38+
implicit class intArrayOps(arr: Array[Int]) {
39+
inline def foreach(inline op: Int => Unit): Unit = {
40+
var i = 0
41+
while (i < arr.length) {
42+
op(arr(i))
43+
i += 1
44+
}
45+
}
46+
}
47+
48+
def sum(ints: Array[Int]): Int = {
49+
var t = 0
50+
for (n <- ints) t += n
51+
t
52+
}
53+
3854
def main(args: Array[String]) = {
3955
1.until(10).foreach(i => println(i))
4056
1.until(10).foreach(println(_))
@@ -44,5 +60,8 @@ object Test {
4460
for (k1 <- 1 to 10)
4561
for (k2 <- 1 to 10)
4662
println(s"$k1")
63+
64+
val xs = Array(1, 2, 3, 4)
65+
assert(sum(xs) == 10, sum(xs))
4766
}
4867
}

tests/run/patmatch-classtag.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ object dotc {
1818
object Impl extends API {
1919
type CaseDef = dotc.CaseDef
2020

21-
val tagForCaseDef: ClassTag[dotc.CaseDef] = implicitly[ClassTag[dotc.CaseDef]]
21+
val tagForCaseDef: ClassTag[dotc.CaseDef] = implicitly
2222

2323
object CaseDef extends CaseDefCompanion {
2424
def apply(str: String): CaseDef = dotc.CaseDef(str)

0 commit comments

Comments
 (0)