Skip to content

Commit

Permalink
Fix #10098: Handle inheritance for implicitNotFound annotation
Browse files Browse the repository at this point in the history
  • Loading branch information
prolativ committed Nov 5, 2020
1 parent bf0b5b6 commit e5a1da5
Show file tree
Hide file tree
Showing 4 changed files with 50 additions and 6 deletions.
12 changes: 8 additions & 4 deletions compiler/src/dotty/tools/dotc/typer/ErrorReporting.scala
Original file line number Diff line number Diff line change
Expand Up @@ -250,7 +250,7 @@ class ImplicitSearchError(
*/
private def userDefinedMsg(sym: Symbol, cls: Symbol) = for {
ann <- sym.getAnnotation(cls)
Trees.Literal(Constant(msg: String)) <- ann.argument(0)
msg <- ann.argumentConstantString(0)
} yield msg

private def location(preposition: String) = if (where.isEmpty) "" else s" $preposition $where"
Expand Down Expand Up @@ -313,7 +313,7 @@ class ImplicitSearchError(
*
* def foo(implicit @annotation.implicitNotFound("Foo is missing") foo: Foo): Any = ???
*/
private def userDefinedImplicitNotFoundParamMessage = paramSymWithMethodCallTree.flatMap { (sym, applTree) =>
private def userDefinedImplicitNotFoundParamMessage: Option[String] = paramSymWithMethodCallTree.flatMap { (sym, applTree) =>
userDefinedMsg(sym, defn.ImplicitNotFoundAnnot).map { rawMsg =>
val (fn, targs, _) = tpd.decomposeCall(applTree)
val methodOwner = fn.symbol.owner
Expand All @@ -332,8 +332,12 @@ class ImplicitSearchError(
*
* def foo(implicit foo: Foo): Any = ???
*/
private def userDefinedImplicitNotFoundTypeMessage =
val classSym = pt.classSymbol
private def userDefinedImplicitNotFoundTypeMessage: Option[String] =
pt.baseClasses.iterator
.map(userDefinedImplicitNotFoundTypeMessage(_))
.find(_.isDefined).flatten

private def userDefinedImplicitNotFoundTypeMessage(classSym: ClassSymbol): Option[String] =
userDefinedMsg(classSym, defn.ImplicitNotFoundAnnot).map { rawMsg =>
val substituteType = (_: Type).asSeenFrom(pt, classSym)
formatAnnotationMessage(rawMsg, classSym, substituteType)
Expand Down
16 changes: 16 additions & 0 deletions tests/neg/i10098.check
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
-- Error: tests/neg/i10098.scala:20:32 ---------------------------------------------------------------------------------
20 | implicitly[Bar12[Int, String]] // error
| ^
| There's no Foo2[String, Int]
-- Error: tests/neg/i10098.scala:21:32 ---------------------------------------------------------------------------------
21 | implicitly[Bar21[Int, String]] // error
| ^
| There's no Foo1[String, Int]
-- Error: tests/neg/i10098.scala:22:32 ---------------------------------------------------------------------------------
22 | implicitly[Baz12[Int, String]] // error
| ^
| There's no Baz12[Int, String]
-- Error: tests/neg/i10098.scala:23:32 ---------------------------------------------------------------------------------
23 | implicitly[Baz21[Int, String]] // error
| ^
| There's no Baz21[Int, String]
24 changes: 24 additions & 0 deletions tests/neg/i10098.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import annotation.implicitNotFound

@implicitNotFound("There's no Foo1[${A}, ${B}]")
trait Foo1[A, B]

@implicitNotFound("There's no Foo2[${A}, ${B}]")
trait Foo2[A, B]

trait Bar12[C, D] extends Foo1[D, C] with Foo2[D, C]

trait Bar21[C, D] extends Foo2[D, C] with Foo1[D, C]

@implicitNotFound("There's no Baz12[${C}, ${D}]")
trait Baz12[C, D] extends Foo1[D, C] with Foo2[D, C]

@implicitNotFound("There's no Baz21[${C}, ${D}]")
trait Baz21[C, D] extends Foo2[D, C] with Foo1[D, C]

object Test {
implicitly[Bar12[Int, String]] // error
implicitly[Bar21[Int, String]] // error
implicitly[Baz12[Int, String]] // error
implicitly[Baz21[Int, String]] // error
}
4 changes: 2 additions & 2 deletions tests/neg/i4986c.scala
Original file line number Diff line number Diff line change
Expand Up @@ -16,15 +16,15 @@ class Outer[A] {

trait X$Y

@implicitNotFound("There's no U[${X}, ${Y}, ${Z}]")
@implicitNotFound(msg = "There's no U[${X}, ${Y}, ${Z}]")
trait U[X, Y[_], Z[_, ZZ]] {
class I[R] {
def m[S](implicit @implicitNotFound("${X}; ${Y}; ${ Z }; ${R}; ${S}; ${XX}") i: Int) = ???
}
}

class Test[A] {
def f(implicit @implicitNotFound("Missing X$Y for Test[${A}]") xy: X$Y) = ???
def f(implicit @implicitNotFound(msg = "Missing X$Y for Test[${A}]") xy: X$Y) = ???
def g[B: Outer] = ???
def h[B](implicit outer: Outer[B]) = ???
def i[B](implicit @implicitNotFound("Missing implicit outer param of type Outer[${B}] for Test[${A}]") outer: Outer[B]) = ???
Expand Down

0 comments on commit e5a1da5

Please sign in to comment.