Skip to content

Commit 6b71880

Browse files
committed
fix #3797 Add support for @implicitAmbiguous
1 parent 3365ed3 commit 6b71880

File tree

3 files changed

+40
-15
lines changed

3 files changed

+40
-15
lines changed

compiler/src/dotty/tools/dotc/core/Definitions.scala

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -670,6 +670,8 @@ class Definitions {
670670
def ContravariantBetweenAnnot(implicit ctx: Context) = ContravariantBetweenAnnotType.symbol.asClass
671671
lazy val DeprecatedAnnotType = ctx.requiredClassRef("scala.deprecated")
672672
def DeprecatedAnnot(implicit ctx: Context) = DeprecatedAnnotType.symbol.asClass
673+
lazy val ImplicitAmbiguousAnnotType = ctx.requiredClassRef("scala.annotation.implicitAmbiguous")
674+
def ImplicitAmbiguousAnnot(implicit ctx: Context) = ImplicitAmbiguousAnnotType.symbol.asClass
673675
lazy val ImplicitNotFoundAnnotType = ctx.requiredClassRef("scala.annotation.implicitNotFound")
674676
def ImplicitNotFoundAnnot(implicit ctx: Context) = ImplicitNotFoundAnnotType.symbol.asClass
675677
lazy val InlineAnnotType = ctx.requiredClassRef("scala.inline")

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

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -159,11 +159,11 @@ object ErrorReporting {
159159
TypeMismatch(found2, expected2, whyNoMatchStr(found, expected), postScript)
160160
}
161161

162-
/** Format `raw` implicitNotFound argument, replacing all
163-
* occurrences of `${X}` where `X` is in `paramNames` with the
162+
/** Format `raw` implicitNotFound or implicitAmbiguous argument, replacing
163+
* all occurrences of `${X}` where `X` is in `paramNames` with the
164164
* corresponding shown type in `args`.
165165
*/
166-
def implicitNotFoundString(raw: String, paramNames: List[String], args: List[Type]): String = {
166+
def userDefinedErrorString(raw: String, paramNames: List[String], args: List[Type]): String = {
167167
def translate(name: String): Option[String] = {
168168
val idx = paramNames.indexOf(name)
169169
if (idx >= 0) Some(quoteReplacement(ex"${args(idx)}")) else None

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

Lines changed: 35 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ import Constants._
2626
import Applications._
2727
import ProtoTypes._
2828
import ErrorReporting._
29+
import Annotations.Annotation
2930
import reporting.diagnostic.{Message, MessageContainer}
3031
import Inferencing.fullyDefinedType
3132
import Trees._
@@ -696,22 +697,44 @@ trait Implicits { self: Typer =>
696697
}
697698
}
698699
def location(preposition: String) = if (where.isEmpty) "" else s" $preposition $where"
700+
def userDefinedMessage(annot: Annotation, params: List[String], args: List[Type]): Option[String] =
701+
for(Trees.Literal(Constant(raw: String)) <- annot.argument(0)) yield {
702+
err.userDefinedErrorString(
703+
raw,
704+
params,
705+
args)
706+
}
699707
arg.tpe match {
700708
case ambi: AmbiguousImplicits =>
701-
msg(s"ambiguous implicit arguments: ${ambi.explanation}${location("of")}")(
702-
s"ambiguous implicit arguments of type ${pt.show} found${location("for")}")
703-
case _ =>
704-
val userDefined =
705-
for {
706-
notFound <- pt.typeSymbol.getAnnotation(defn.ImplicitNotFoundAnnot)
707-
Trees.Literal(Constant(raw: String)) <- notFound.argument(0)
709+
val maybeAnnot = ambi.alt1.ref.symbol.getAnnotation(defn.ImplicitAmbiguousAnnot).map(
710+
(_, ambi.alt1)
711+
).orElse(
712+
ambi.alt2.ref.symbol.getAnnotation(defn.ImplicitAmbiguousAnnot).map(
713+
(_, ambi.alt2)
714+
)
715+
)
716+
val userDefined = maybeAnnot.flatMap { case (annot, alt) =>
717+
val params = alt.ref.underlying match {
718+
case lambda: TypeLambda => lambda.typeParams.map(_.paramName.unexpandedName.toString)
719+
case _ => Nil
708720
}
709-
yield {
710-
err.implicitNotFoundString(
711-
raw,
712-
pt.typeSymbol.typeParams.map(_.name.unexpandedName.toString),
713-
pt.argInfos)
721+
alt.tstate.commit()
722+
val args = alt.tree match {
723+
case TypeApply(_, targs) if params.nonEmpty =>
724+
targs.map(a => fullyDefinedType(a.typeOpt, "type parameter", a.pos))
725+
case _ =>
726+
Nil
714727
}
728+
userDefinedMessage(annot, params, args)
729+
}
730+
userDefined.map(msg(_)()).getOrElse(
731+
msg(s"ambiguous implicit arguments: ${ambi.explanation}${location("of")}")(
732+
s"ambiguous implicit arguments of type ${pt.show} found${location("for")}")
733+
)
734+
case _ =>
735+
val userDefined = pt.typeSymbol.getAnnotation(defn.ImplicitNotFoundAnnot).flatMap(
736+
userDefinedMessage(_, pt.typeSymbol.typeParams.map(_.name.unexpandedName.toString), pt.argInfos)
737+
)
715738
msg(userDefined.getOrElse(em"no implicit argument of type $pt was found${location("for")}"))()
716739
}
717740
}

0 commit comments

Comments
 (0)