Skip to content

Commit 18d5913

Browse files
authored
Merge pull request #1921 from dotty-staging/fix-#1907
Fix #1907: Improve error message
2 parents 99679cf + abbee9e commit 18d5913

File tree

9 files changed

+90
-43
lines changed

9 files changed

+90
-43
lines changed

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

Lines changed: 30 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -507,7 +507,36 @@ 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+
if (defn.isBottomClass(tp.typeSymbol))
525+
error(where => i"attempt to take ClassTag of undetermined type for $where")
526+
ref(defn.ClassTagModule)
527+
.select(nme.apply)
528+
.appliedToType(tp)
529+
.appliedTo(clsOf(erasure(tp)))
530+
.withPos(pos)
531+
case tp =>
532+
EmptyTree
533+
}
534+
case _ =>
535+
EmptyTree
536+
}
537+
else EmptyTree
538+
}
539+
511540
inferImplicit(formal, EmptyTree, pos) match {
512541
case SearchSuccess(arg, _, _, _) =>
513542
arg
@@ -534,24 +563,6 @@ trait Implicits { self: Typer =>
534563
EmptyTree
535564
}
536565
}
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
555566
}
556567

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

compiler/test/dotty/tools/dotc/CompilerTest.scala

Lines changed: 19 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -397,20 +397,25 @@ abstract class CompilerTest {
397397
/** Gives an error message for one line where the expected number of errors and
398398
* the number of compiler errors differ. */
399399
def compareLines(fileName: String, expectedLines: List[(Int, Int)], foundLines: List[(Int, Int)]) = {
400-
expectedLines.foreach({ case (line, expNr) =>
401-
foundLines.find(_._1 == line) match {
402-
case Some((_, `expNr`)) => // this line is ok
403-
case Some((_, foundNr)) => errorMsg(fileName, Some(line), expNr, foundNr)
404-
case None => errorMsg(fileName, Some(line), expNr, 0)
405-
}
406-
})
407-
foundLines.foreach({ case (line, foundNr) =>
408-
expectedLines.find(_._1 == line) match {
409-
case Some((_, `foundNr`)) => // this line is ok
410-
case Some((_, expNr)) => errorMsg(fileName, Some(line), expNr, foundNr)
411-
case None => errorMsg(fileName, Some(line), 0, foundNr)
412-
}
413-
})
400+
expectedLines foreach{
401+
case (line, expNr) =>
402+
foundLines.find(_._1 == line) match {
403+
case Some((_, `expNr`)) => // this line is ok
404+
case Some((_, foundNr)) => errorMsg(fileName, Some(line), expNr, foundNr)
405+
case None =>
406+
println(s"expected lines = $expectedLines%, %")
407+
println(s"found lines = $foundLines%, %")
408+
errorMsg(fileName, Some(line), expNr, 0)
409+
}
410+
}
411+
foundLines foreach {
412+
case (line, foundNr) =>
413+
expectedLines.find(_._1 == line) match {
414+
case Some((_, `foundNr`)) => // this line is ok
415+
case Some((_, expNr)) => errorMsg(fileName, Some(line), expNr, foundNr)
416+
case None => errorMsg(fileName, Some(line), 0, foundNr)
417+
}
418+
}
414419
}
415420

416421
// ========== PARTEST HELPERS =============

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

tests/neg/i1802.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,8 @@ object Exception {
1414
def apply(x: Throwable): T = f(downcast(x).get)
1515
}
1616

17-
def mkThrowableCatcher[T](isDef: Throwable => Boolean, f: Throwable => T) = mkCatcher(isDef, f)
17+
def mkThrowableCatcher[T](isDef: Throwable => Boolean, f: Throwable => T) = mkCatcher(isDef, f) // error: undetermined ClassTag
1818

19-
implicit def throwableSubtypeToCatcher[Ex <: Throwable: ClassTag, T](pf: PartialFunction[Ex, T]) = // error: cyclic reference
19+
implicit def throwableSubtypeToCatcher[Ex <: Throwable: ClassTag, T](pf: PartialFunction[Ex, T]) =
2020
mkCatcher(pf.isDefinedAt _, pf.apply _)
2121
}

tests/neg/i1907.scala

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
import java.io.File
2+
3+
object Test {
4+
Some(new File("."))
5+
.map(_.listFiles).getOrElse(Array.empty) // error: undetermined ClassTag
6+
.map(_.listFiles)
7+
}

tests/neg/undet-classtag.scala

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
import scala.reflect.ClassTag
2+
3+
object Test {
4+
def f[T: reflect.ClassTag](x: T) = ???
5+
6+
f(???) // error: undetermined ClassTag
7+
}
8+
9+
// SI 9754
10+
object Program {
11+
def test[T: ClassTag](x: T) = {
12+
val arr = new Array[T](1)
13+
println(arr.getClass)
14+
println(x.getClass)
15+
arr(0) = x
16+
}
17+
18+
def main(args: Array[String]): Unit = {
19+
test(new Array[Nothing](0)) // error: undetermined ClassTag
20+
}
21+
}
22+
23+
// SI 5353
24+
object t5353 {
25+
if (false) Array("qwe") else Array() // error: undetermined ClassTag
26+
}
27+

tests/pos/t3859.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
class Test {
2-
def foo: Unit = bar(Array(): _*)
2+
def foo: Unit = bar(Array[AnyRef](): _*)
33
def bar(values: AnyRef*): Unit = ()
44
}

tests/pos/t5859.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,9 @@ class A {
77
f(List[AnyRef](): _*)
88
f(List(): _*)
99
f(Nil: _*)
10-
f(Array(): _*)
10+
// f(Array(): _*) // undetermined ClassTag
1111
f(Array[AnyRef](): _*)
1212
f(List(1))
1313
f(List(1), Nil: _*)
14-
f(List(1), Array(): _*)
14+
// f(List(1), Array(): _*) // undetermined ClassTag
1515
}

tests/run/array-addition.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@ object Test {
44
def main(args: Array[String]): Unit = {
55
prettyPrintArray(Array(1,2,3) :+ 4)
66
prettyPrintArray(1 +: Array(2,3,4))
7-
prettyPrintArray(Array() :+ 1)
8-
prettyPrintArray(1 +: Array())
7+
prettyPrintArray(Array[Int]() :+ 1)
8+
prettyPrintArray(1 +: Array[Int]())
99
}
1010
}
1111

0 commit comments

Comments
 (0)