diff options
-rw-r--r-- | src/dotty/tools/dotc/core/Definitions.scala | 2 | ||||
-rw-r--r-- | src/dotty/tools/dotc/typer/ErrorReporting.scala | 12 | ||||
-rw-r--r-- | src/dotty/tools/dotc/typer/Typer.scala | 11 | ||||
-rw-r--r-- | tests/neg/EqualityStrawman1.scala | 9 |
4 files changed, 30 insertions, 4 deletions
diff --git a/src/dotty/tools/dotc/core/Definitions.scala b/src/dotty/tools/dotc/core/Definitions.scala index 5376ed591..9128bd3a5 100644 --- a/src/dotty/tools/dotc/core/Definitions.scala +++ b/src/dotty/tools/dotc/core/Definitions.scala @@ -449,6 +449,8 @@ class Definitions { def ContravariantBetweenAnnot(implicit ctx: Context) = ContravariantBetweenAnnotType.symbol.asClass lazy val DeprecatedAnnotType = ctx.requiredClassRef("scala.deprecated") def DeprecatedAnnot(implicit ctx: Context) = DeprecatedAnnotType.symbol.asClass + lazy val ImplicitNotFoundAnnotType = ctx.requiredClassRef("scala.annotation.implicitNotFound") + def ImplicitNotFoundAnnot(implicit ctx: Context) = ImplicitNotFoundAnnotType.symbol.asClass lazy val InvariantBetweenAnnotType = ctx.requiredClassRef("dotty.annotation.internal.InvariantBetween") def InvariantBetweenAnnot(implicit ctx: Context) = InvariantBetweenAnnotType.symbol.asClass lazy val MigrationAnnotType = ctx.requiredClassRef("scala.annotation.migration") diff --git a/src/dotty/tools/dotc/typer/ErrorReporting.scala b/src/dotty/tools/dotc/typer/ErrorReporting.scala index d6a87acf6..69c12e5f5 100644 --- a/src/dotty/tools/dotc/typer/ErrorReporting.scala +++ b/src/dotty/tools/dotc/typer/ErrorReporting.scala @@ -116,6 +116,18 @@ object ErrorReporting { | found : $found | required: $expected""".stripMargin + whyNoMatchStr(found, expected) } + + /** Format `raw` implicitNotFound argument, replacing all + * occurrences of `${X}` where `X` is in `paramNames` with the + * corresponding shown type in `args`. + */ + def implicitNotFoundString(raw: String, paramNames: List[String], args: List[Type]): String = { + def translate(name: String): Option[String] = { + val idx = paramNames.indexOf(name) + if (idx >= 0) Some(args(idx).show) else None + } + """\$\{\w*\}""".r.replaceSomeIn(raw, m => translate(m.matched.drop(2).init)) + } } def err(implicit ctx: Context): Errors = new Errors diff --git a/src/dotty/tools/dotc/typer/Typer.scala b/src/dotty/tools/dotc/typer/Typer.scala index b95acc7ca..f263d3093 100644 --- a/src/dotty/tools/dotc/typer/Typer.scala +++ b/src/dotty/tools/dotc/typer/Typer.scala @@ -1541,7 +1541,16 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit case failure: SearchFailure => val arg = synthesizedClassTag(formal) if (!arg.isEmpty) arg - else implicitArgError(d"no implicit argument of type $formal found for $where" + failure.postscript) + else { + var msg = d"no implicit argument of type $formal found for $where" + failure.postscript + for (notFound <- formal.typeSymbol.getAnnotation(defn.ImplicitNotFoundAnnot); + Literal(Constant(raw: String)) <- notFound.argument(0)) + msg = err.implicitNotFoundString( + raw, + formal.typeSymbol.typeParams.map(_.name.unexpandedName.toString), + formal.argInfos) + implicitArgError(msg) + } } } if (errors.nonEmpty) { diff --git a/tests/neg/EqualityStrawman1.scala b/tests/neg/EqualityStrawman1.scala index 8c9b435e4..b1b6c0380 100644 --- a/tests/neg/EqualityStrawman1.scala +++ b/tests/neg/EqualityStrawman1.scala @@ -1,20 +1,23 @@ package strawman.equality +import annotation.implicitNotFound object EqualityStrawman1 { trait Eq[-T] - trait Impossible + + @implicitNotFound("cannot compare value of type ${T} with a value outside its equality class") + trait Impossible[T] object Eq extends Eq[Any] trait Base { def === (other: Any): Boolean = this.equals(other) - def === (other: CondEquals)(implicit ce: Impossible): Boolean = ??? + def === [T <: CondEquals](other: T)(implicit ce: Impossible[T]): Boolean = ??? } trait CondEquals extends Base { def === [T >: this.type <: CondEquals](other: T)(implicit ce: Eq[T]): Boolean = this.equals(other) - def === (other: Any)(implicit ce: Impossible): Boolean = ??? + def === [T](other: T)(implicit ce: Impossible[T]): Boolean = ??? } trait Equals[-T] extends CondEquals |