diff --git a/compiler/src/dotty/tools/dotc/typer/ErrorReporting.scala b/compiler/src/dotty/tools/dotc/typer/ErrorReporting.scala index ab72bdd2f5b8..34881ff8172a 100644 --- a/compiler/src/dotty/tools/dotc/typer/ErrorReporting.scala +++ b/compiler/src/dotty/tools/dotc/typer/ErrorReporting.scala @@ -4,14 +4,23 @@ package typer import ast._ import core._ -import Types._, ProtoTypes._, Contexts._, Decorators._, Denotations._, Symbols._ -import Implicits._, Flags._ +import Types._ +import ProtoTypes._ +import Contexts._ +import Decorators._ +import Denotations._ +import Symbols._ +import Implicits._ +import Flags._ import util.Spans._ import util.SourcePosition import java.util.regex.Matcher.quoteReplacement + import reporting.diagnostic.Message import reporting.diagnostic.messages._ +import scala.util.matching.Regex + object ErrorReporting { import tpd._ @@ -152,10 +161,14 @@ object ErrorReporting { */ def userDefinedErrorString(raw: String, paramNames: List[String], args: List[Type]): String = { def translate(name: String): Option[String] = { + println("<" + name + ">") val idx = paramNames.indexOf(name) - if (idx >= 0) Some(quoteReplacement(ex"${args(idx)}")) else None + if (idx >= 0) Some(ex"${args(idx)}") else None } - """\$\{\w*\}""".r.replaceSomeIn(raw, m => translate(m.matched.drop(2).init)) + println(raw) + """\$\{\s*([^}\s]+)\s*\}""".r.replaceAllIn(raw, (_: Regex.Match) match { + case Regex.Groups(v) => quoteReplacement(translate(v).getOrElse("")) + }) } def rewriteNotice: String = diff --git a/compiler/src/dotty/tools/dotc/typer/Implicits.scala b/compiler/src/dotty/tools/dotc/typer/Implicits.scala index 72d97dc4bb28..7163152aa447 100644 --- a/compiler/src/dotty/tools/dotc/typer/Implicits.scala +++ b/compiler/src/dotty/tools/dotc/typer/Implicits.scala @@ -3,10 +3,10 @@ package dotc package typer import core._ -import ast.{Trees, TreeTypeMap, untpd, tpd} +import ast.{TreeTypeMap, Trees, tpd, untpd} import util.Spans._ -import util.Stats.{track, record, monitored} -import printing.{Showable, Printer} +import util.Stats.{monitored, record, track} +import printing.{Printer, Showable} import printing.Texts._ import Contexts._ import Types._ @@ -28,13 +28,15 @@ import reporting.diagnostic.Message import Inferencing.fullyDefinedType import Trees._ import Hashable._ -import util.{Property, SourceFile, NoSource} +import util.{NoSource, Property, SourceFile} import config.Config import config.Printers.{implicits, implicitsDetailed} +import dotty.tools.dotc.core.Annotations.Annotation + import collection.mutable import reporting.trace -import annotation.tailrec +import annotation.tailrec import scala.annotation.internal.sharable /** Implicit resolution */ @@ -859,11 +861,16 @@ trait Implicits { self: Typer => def location(preposition: String) = if (where.isEmpty) "" else s" $preposition $where" + @tailrec def annotationOnType(cls: Symbol, tp: Type): Option[Annotation] = tp.widen match { + case AnnotatedType(tpe, ann) => if (ann matches cls) Some(ann) else annotationOnType(cls, tpe) + case _ => None + } + /** Extract a user defined error message from a symbol `sym` * with an annotation matching the given class symbol `cls`. */ def userDefinedMsg(sym: Symbol, cls: Symbol) = for { - ann <- sym.getAnnotation(cls) + ann <- annotationOnType(cls, pt).orElse(sym.getAnnotation(cls)) Trees.Literal(Constant(msg: String)) <- ann.argument(0) } yield msg diff --git a/tests/untried/neg/t2462b.check b/tests/neg-custom-args/fatal-warnings/t2462b.check similarity index 100% rename from tests/untried/neg/t2462b.check rename to tests/neg-custom-args/fatal-warnings/t2462b.check diff --git a/tests/neg-custom-args/fatal-warnings/t2462b.scala b/tests/neg-custom-args/fatal-warnings/t2462b.scala new file mode 100644 index 000000000000..6aa2290d3b1c --- /dev/null +++ b/tests/neg-custom-args/fatal-warnings/t2462b.scala @@ -0,0 +1,25 @@ +package test + +import scala.annotation.implicitNotFound + +@implicitNotFound(msg = "Cannot construct a collection of type ${Too} with elements of type ${Elem} based on a collection of type ${From}.") +trait Meh[-From, +To] + +@implicitNotFound(msg = "Cannot construct a collection of type ${To} ${Elem}.") +trait Meh2[-From, +To] + +class C[T] +trait T { + def m[Aaa](implicit theC: C[Aaa] @implicitNotFound("I see no C[${Uuh}]")) = ??? + def n[Aaa](implicit theC: C[Aaa] @implicitNotFound("I see no C[${Aaa}]")) = ??? +} + +trait U[X, Y[_], Z[_, ZZ]] { + class I[R] { + def m[S](implicit i: Int @implicitNotFound("${X} ${Y} ${ Z } ${R} ${S} -- ${XX} ${ZZ} ${ Nix }")) = ??? + } +} + +// error +// error +// error \ No newline at end of file diff --git a/tests/neg/t2462a.check b/tests/neg/t2462a.check new file mode 100644 index 000000000000..fdef75b9b8e0 --- /dev/null +++ b/tests/neg/t2462a.check @@ -0,0 +1,9 @@ +-- Error: tests/neg/t2462a.scala:2:44 ---------------------------------------------------------------------------------- +2 | List(1,2,3).map[Int, List[String]](x => 1) // error + | ^ + |Cannot construct a collection of type List[String] with elements of type Int based on a collection of type List[Int].. + |I found: + | + | scala.collection.immutable.List.canBuildFrom[Nothing] + | + |But method canBuildFrom in object List does not match type scala.collection.generic.CanBuildFrom[List[Int], Int, List[String]]. diff --git a/tests/neg/t2462a.scala b/tests/neg/t2462a.scala new file mode 100644 index 000000000000..92183b8d7cf1 --- /dev/null +++ b/tests/neg/t2462a.scala @@ -0,0 +1,3 @@ +object Test { + List(1,2,3).map[Int, List[String]](x => 1) // error +} diff --git a/tests/neg/t2462c.check b/tests/neg/t2462c.check new file mode 100644 index 000000000000..3d3e6686bd39 --- /dev/null +++ b/tests/neg/t2462c.check @@ -0,0 +1,20 @@ +-- Error: tests/neg/t2462c.scala:24:8 ---------------------------------------------------------------------------------- +24 | f[X$Y] // error + | ^ + | No C of X$Y +-- Error: tests/neg/t2462c.scala:30:13 --------------------------------------------------------------------------------- +30 | f[Foo[Int]] // error + | ^ + | No C of Foo[Int] +-- Error: tests/neg/t2462c.scala:33:13 --------------------------------------------------------------------------------- +33 | g[Foo[Int]] // error + | ^ + | No C of Foo[Int] +-- Error: tests/neg/t2462c.scala:36:13 --------------------------------------------------------------------------------- +36 | h[Foo[Int]] // error + | ^ + | No C of Foo[Int] +-- Error: tests/neg/t2462c.scala:40:19 --------------------------------------------------------------------------------- +40 | i.m[Option[Long]] // error + | ^ + | no implicit argument of type Int was found for parameter i of method m in class I diff --git a/tests/neg/t2462c.scala b/tests/neg/t2462c.scala new file mode 100644 index 000000000000..e0ce55bfc720 --- /dev/null +++ b/tests/neg/t2462c.scala @@ -0,0 +1,41 @@ + +import annotation._ + +@implicitNotFound("No C of ${ A }") +class C[A] + +trait X$Y +/* using the $$ separator for expanded names is unwise +trait X$$Y +trait X$$$Y +trait X$$$$Y + */ + +trait Foo[A] + +trait U[X, Y[_], Z[_, ZZ]] { + class I[R] { + def m[S](implicit i: Int @implicitNotFound("${X} ${Y} ${ Z } ${R} ${S} -- ${XX}.")) = ??? + } +} + +class Test { + def f[A: C] = ??? + f[X$Y] // error + /* using the $$ separator for expanded names is unwise + f[X$$Y] + f[X$$$Y] + f[X$$$$Y] + */ + f[Foo[Int]] // error + + def g[Aaa](implicit theC: C[Aaa]) = ??? + g[Foo[Int]] // error + + def h[Aaa](implicit theC: C[Aaa] @implicitNotFound("I see no C[${Aaa}]")) = ??? + h[Foo[Int]] // error + + val u = new U[String, List, ({type T[A, _] = List[C[_]]})#T] { } + val i = new u.I[Int] + i.m[Option[Long]] // error +} \ No newline at end of file diff --git a/tests/untried/neg/t2462a.check b/tests/untried/neg/t2462a.check deleted file mode 100644 index 86d74b86d406..000000000000 --- a/tests/untried/neg/t2462a.check +++ /dev/null @@ -1,4 +0,0 @@ -t2462a.scala:2: error: Cannot construct a collection of type List[String] with elements of type Int based on a collection of type List[Int]. - List(1,2,3).map[Int, List[String]](x => 1) - ^ -one error found diff --git a/tests/untried/neg/t2462a.scala b/tests/untried/neg/t2462a.scala deleted file mode 100644 index 5e49314d53b0..000000000000 --- a/tests/untried/neg/t2462a.scala +++ /dev/null @@ -1,3 +0,0 @@ -object Test { - List(1,2,3).map[Int, List[String]](x => 1) -} diff --git a/tests/untried/neg/t2462b.flags b/tests/untried/neg/t2462b.flags deleted file mode 100644 index 85d8eb2ba295..000000000000 --- a/tests/untried/neg/t2462b.flags +++ /dev/null @@ -1 +0,0 @@ --Xfatal-warnings diff --git a/tests/untried/neg/t2462b.scala b/tests/untried/neg/t2462b.scala deleted file mode 100644 index 576db4bd3f33..000000000000 --- a/tests/untried/neg/t2462b.scala +++ /dev/null @@ -1,9 +0,0 @@ -package test - -import scala.annotation.implicitNotFound - -@implicitNotFound(msg = "Cannot construct a collection of type ${Too} with elements of type ${Elem} based on a collection of type ${From}.") -trait Meh[-From, +To] - -@implicitNotFound(msg = "Cannot construct a collection of type ${To} ${Elem}.") -trait Meh2[-From, +To] diff --git a/tests/untried/neg/t2462c.check b/tests/untried/neg/t2462c.check deleted file mode 100644 index edeead55d60c..000000000000 --- a/tests/untried/neg/t2462c.check +++ /dev/null @@ -1,7 +0,0 @@ -t2462c.scala:18: error: No C of X$Y - f[X$Y] - ^ -t2462c.scala:24: error: No C of Foo[Int] - f[Foo[Int]] - ^ -two errors found diff --git a/tests/untried/neg/t2462c.flags b/tests/untried/neg/t2462c.flags deleted file mode 100644 index 85d8eb2ba295..000000000000 --- a/tests/untried/neg/t2462c.flags +++ /dev/null @@ -1 +0,0 @@ --Xfatal-warnings diff --git a/tests/untried/neg/t2462c.scala b/tests/untried/neg/t2462c.scala deleted file mode 100644 index acf04afba954..000000000000 --- a/tests/untried/neg/t2462c.scala +++ /dev/null @@ -1,25 +0,0 @@ - -import annotation._ - -@implicitNotFound("No C of ${ A }") -class C[A] - -trait X$Y -/* using the $$ separator for expanded names is unwise -trait X$$Y -trait X$$$Y -trait X$$$$Y - */ - -trait Foo[A] - -class Test { - def f[A: C] = ??? - f[X$Y] -/* using the $$ separator for expanded names is unwise - f[X$$Y] - f[X$$$Y] - f[X$$$$Y] - */ - f[Foo[Int]] -}