Skip to content

Commit b11e6d6

Browse files
committed
Handle Array classtags in the same way as others
The previous implicit definition of arrayTag in DottyPredef priorities arrayTag over all other classtag searches, which led to surprising results in `i1907a.scala`.
1 parent 2ce9328 commit b11e6d6

File tree

2 files changed

+28
-22
lines changed

2 files changed

+28
-22
lines changed

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

Lines changed: 28 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -507,7 +507,34 @@ trait Implicits { self: Typer =>
507507
* which is itself parameterized by another string,
508508
* indicating where the implicit parameter is needed
509509
*/
510-
def inferImplicitArg(formal: Type, error: (String => String) => Unit, pos: Position)(implicit ctx: Context): Tree =
510+
def inferImplicitArg(formal: Type, error: (String => String) => Unit, pos: Position)(implicit ctx: Context): Tree = {
511+
512+
/** If `formal` is of the form ClassTag[T], where `T` is a class type,
513+
* synthesize a class tag for `T`.
514+
*/
515+
def synthesizedClassTag(formal: Type, pos: Position)(implicit ctx: Context): Tree = {
516+
if (formal.isRef(defn.ClassTagClass))
517+
formal.argTypes match {
518+
case arg :: Nil =>
519+
fullyDefinedType(arg, "ClassTag argument", pos) match {
520+
case defn.ArrayOf(elemTp) =>
521+
val etag = inferImplicitArg(defn.ClassTagType.appliedTo(elemTp), error, pos)
522+
if (etag.isEmpty) etag else etag.select(nme.wrap)
523+
case tp if hasStableErasure(tp) =>
524+
ref(defn.ClassTagModule)
525+
.select(nme.apply)
526+
.appliedToType(tp)
527+
.appliedTo(clsOf(erasure(tp)))
528+
.withPos(pos)
529+
case tp =>
530+
EmptyTree
531+
}
532+
case _ =>
533+
EmptyTree
534+
}
535+
else EmptyTree
536+
}
537+
511538
inferImplicit(formal, EmptyTree, pos) match {
512539
case SearchSuccess(arg, _, _, _) =>
513540
arg
@@ -534,24 +561,6 @@ trait Implicits { self: Typer =>
534561
EmptyTree
535562
}
536563
}
537-
538-
/** If `formal` is of the form ClassTag[T], where `T` is a class type,
539-
* synthesize a class tag for `T`.
540-
*/
541-
def synthesizedClassTag(formal: Type, pos: Position)(implicit ctx: Context): Tree = {
542-
if (formal.isRef(defn.ClassTagClass))
543-
formal.argTypes match {
544-
case arg :: Nil =>
545-
val tp = fullyDefinedType(arg, "ClassTag argument", pos)
546-
if (hasStableErasure(tp))
547-
return ref(defn.ClassTagModule)
548-
.select(nme.apply)
549-
.appliedToType(tp)
550-
.appliedTo(clsOf(erasure(tp)))
551-
.withPos(pos)
552-
case _ =>
553-
}
554-
EmptyTree
555564
}
556565

557566
private def assumedCanEqual(ltp: Type, rtp: Type)(implicit ctx: Context) = {

library/src/dotty/DottyPredef.scala

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,6 @@ import scala.collection.Seq
99
object DottyPredef {
1010
implicit def typeTag[T]: TypeTag[T] = ???
1111

12-
implicit def arrayTag[T](implicit ctag: ClassTag[T]): ClassTag[Array[T]] =
13-
ctag.wrap
14-
1512
/** A fall-back implicit to compare values of any types.
1613
* The compiler will restrict implicit instances of `eqAny`. An instance
1714
* `eqAny[T, U]` is _valid_ if `T <: U` or `U <: T` or both `T` and `U` are

0 commit comments

Comments
 (0)