@@ -885,7 +885,7 @@ trait Implicits {
885
885
* - find the most likely one
886
886
* - if it matches, forget about all others it improves upon
887
887
*/
888
- @ tailrec private def rankImplicits (pending : Infos , acc : Infos ) : Infos = pending match {
888
+ @ tailrec private def rankImplicits (pending : Infos , acc : List [( SearchResult , ImplicitInfo )]) : List [( SearchResult , ImplicitInfo )] = pending match {
889
889
case Nil => acc
890
890
case firstPending :: otherPending =>
891
891
def firstPendingImproves (alt : ImplicitInfo ) =
@@ -912,7 +912,7 @@ trait Implicits {
912
912
val pendingImprovingBest = undoLog undo {
913
913
otherPending filterNot firstPendingImproves
914
914
}
915
- rankImplicits(pendingImprovingBest, firstPending :: acc)
915
+ rankImplicits(pendingImprovingBest, (newBest, firstPending) :: acc)
916
916
}
917
917
}
918
918
@@ -928,14 +928,14 @@ trait Implicits {
928
928
// So if there is any element not improved upon by the first it is an error.
929
929
rankImplicits(eligible, Nil ) match {
930
930
case Nil => ()
931
- case chosen :: rest =>
932
- rest find ( alt => ! improves(chosen , alt)) match {
933
- case Some (competing ) =>
934
- AmbiguousImplicitError (chosen, competing , " both" , " and" , " " )(isView, pt, tree)(context)
931
+ case (chosenResult, chosenInfo) :: rest =>
932
+ rest find { case (_, alt) => ! improves(chosenInfo , alt) } match {
933
+ case Some ((competingResult, competingInfo) ) =>
934
+ AmbiguousImplicitError (chosenInfo, chosenResult.tree, competingInfo, competingResult.tree , " both" , " and" , " " )(isView, pt, tree)(context)
935
935
return AmbiguousSearchFailure // Stop the search once ambiguity is encountered, see t4457_2.scala
936
936
case _ =>
937
- if (isView) chosen .useCountView += 1
938
- else chosen .useCountArg += 1
937
+ if (isView) chosenInfo .useCountView += 1
938
+ else chosenInfo .useCountArg += 1
939
939
}
940
940
}
941
941
@@ -1448,9 +1448,9 @@ trait Implicits {
1448
1448
}
1449
1449
}
1450
1450
1451
- object ImplicitNotFoundMsg {
1452
- def unapply (sym : Symbol ): Option [(Message )] = sym.implicitNotFoundMsg match {
1453
- case Some (m) => Some (new Message (sym, m))
1451
+ class ImplicitAnnotationMsg ( f : Symbol => Option [ String ], clazz : Symbol , annotationName : String ) {
1452
+ def unapply (sym : Symbol ): Option [(Message )] = f( sym) match {
1453
+ case Some (m) => Some (new Message (sym, m, annotationName ))
1454
1454
case None if sym.isAliasType =>
1455
1455
// perform exactly one step of dealiasing
1456
1456
// this is necessary because ClassManifests are now aliased to ClassTags
@@ -1462,39 +1462,43 @@ trait Implicits {
1462
1462
// check the message's syntax: should be a string literal that may contain occurrences of the string "${X}",
1463
1463
// where `X` refers to a type parameter of `sym`
1464
1464
def check (sym : Symbol ): Option [String ] =
1465
- sym.getAnnotation(ImplicitNotFoundClass ).flatMap(_.stringArg(0 ) match {
1466
- case Some (m) => new Message (sym, m).validate
1467
- case None => Some (" Missing argument `msg` on implicitNotFound annotation." )
1465
+ sym.getAnnotation(clazz ).flatMap(_.stringArg(0 ) match {
1466
+ case Some (m) => new Message (sym, m, annotationName ).validate
1467
+ case None => Some (s " Missing argument `msg` on $annotationName annotation. " )
1468
1468
})
1469
+ }
1470
+
1471
+ object ImplicitNotFoundMsg extends ImplicitAnnotationMsg (_.implicitNotFoundMsg, ImplicitNotFoundClass , " implicitNotFound" )
1472
+
1473
+ object ImplicitAmbiguousMsg extends ImplicitAnnotationMsg (_.implicitAmbiguousMsg, ImplicitAmbiguousClass , " implicitAmbiguous" )
1469
1474
1475
+ class Message (sym : Symbol , msg : String , annotationName : String ) {
1470
1476
// http://dcsobral.blogspot.com/2010/01/string-interpolation-in-scala-with.html
1471
1477
private val Intersobralator = """ \$\{\s*([^}\s]+)\s*\}""" .r
1472
1478
1473
- class Message (sym : Symbol , msg : String ) {
1474
- private def interpolate (text : String , vars : Map [String , String ]) =
1475
- Intersobralator .replaceAllIn(text, (_ : Regex .Match ) match {
1476
- case Regex .Groups (v) => Regex quoteReplacement vars.getOrElse(v, " " )
1479
+ private def interpolate (text : String , vars : Map [String , String ]) =
1480
+ Intersobralator .replaceAllIn(text, (_ : Regex .Match ) match {
1481
+ case Regex .Groups (v) => Regex quoteReplacement vars.getOrElse(v, " " )
1477
1482
// #3915: need to quote replacement string since it may include $'s (such as the interpreter's $iw)
1478
- })
1483
+ })
1479
1484
1480
- private lazy val typeParamNames : List [String ] = sym.typeParams.map(_.decodedName)
1485
+ private lazy val typeParamNames : List [String ] = sym.typeParams.map(_.decodedName)
1481
1486
1482
- def format (paramName : Name , paramTp : Type ): String = format(paramTp.typeArgs map (_.toString))
1483
- def format (typeArgs : List [String ]): String =
1484
- interpolate(msg, Map ((typeParamNames zip typeArgs): _* )) // TODO: give access to the name and type of the implicit argument, etc?
1487
+ def format (paramName : Name , paramTp : Type ): String = format(paramTp.typeArgs map (_.toString))
1488
+ def format (typeArgs : List [String ]): String =
1489
+ interpolate(msg, Map ((typeParamNames zip typeArgs): _* )) // TODO: give access to the name and type of the implicit argument, etc?
1485
1490
1486
- def validate : Option [String ] = {
1487
- val refs = Intersobralator .findAllMatchIn(msg).map(_ group 1 ).toSet
1488
- val decls = typeParamNames.toSet
1491
+ def validate : Option [String ] = {
1492
+ val refs = Intersobralator .findAllMatchIn(msg).map(_ group 1 ).toSet
1493
+ val decls = typeParamNames.toSet
1489
1494
1490
- (refs &~ decls) match {
1491
- case s if s.isEmpty => None
1492
- case unboundNames =>
1493
- val singular = unboundNames.size == 1
1494
- val ess = if (singular) " " else " s"
1495
- val bee = if (singular) " is" else " are"
1496
- Some (s " The type parameter $ess ${unboundNames mkString " , " } referenced in the message of the @implicitNotFound annotation $bee not defined by $sym. " )
1497
- }
1495
+ (refs &~ decls) match {
1496
+ case s if s.isEmpty => None
1497
+ case unboundNames =>
1498
+ val singular = unboundNames.size == 1
1499
+ val ess = if (singular) " " else " s"
1500
+ val bee = if (singular) " is" else " are"
1501
+ Some (s " The type parameter $ess ${unboundNames mkString " , " } referenced in the message of the @ $annotationName annotation $bee not defined by $sym. " )
1498
1502
}
1499
1503
}
1500
1504
}
0 commit comments