@@ -181,7 +181,7 @@ trait Implicits {
181
181
private val infoMapCache = new LinkedHashMap [Symbol , InfoMap ]
182
182
private val improvesCache = perRunCaches.newMap[(ImplicitInfo , ImplicitInfo ), Boolean ]()
183
183
private val implicitSearchId = { var id = 1 ; () => try id finally id += 1 }
184
-
184
+ private val shadowerUseOldImplementation = java.lang. Boolean .getBoolean( " scalac.implicit.shadow.old " )
185
185
def resetImplicits () {
186
186
implicitsCache.clear()
187
187
infoMapCache.clear()
@@ -257,6 +257,7 @@ trait Implicits {
257
257
258
258
var useCountArg : Int = 0
259
259
var useCountView : Int = 0
260
+ def useCount (isView : Boolean ): Int = if (isView) useCountView else useCountArg
260
261
261
262
/** Does type `tp` contain an Error type as parameter or result?
262
263
*/
@@ -985,7 +986,7 @@ trait Implicits {
985
986
986
987
/** Sorted list of eligible implicits.
987
988
*/
988
- val eligible = Shadower .using(isLocalToCallsite){ shadower =>
989
+ private def eligibleOld = Shadower .using(isLocalToCallsite){ shadower =>
989
990
val matches = iss flatMap { is =>
990
991
val result = is filter (info => checkValid(info.sym) && survives(info, shadower))
991
992
shadower addInfos is
@@ -995,6 +996,82 @@ trait Implicits {
995
996
// most frequent one first
996
997
matches sortBy (x => if (isView) - x.useCountView else - x.useCountArg)
997
998
}
999
+
1000
+ /** Sorted list of eligible implicits.
1001
+ */
1002
+ private def eligibleNew = {
1003
+ final case class Candidate (info : ImplicitInfo , level : Int )
1004
+ var matches : java.util.ArrayList [Candidate ] = null
1005
+ var matchesNames : java.util.HashSet [Name ] = null
1006
+
1007
+ var maxCandidateLevel = 0
1008
+
1009
+ {
1010
+ var i = 0
1011
+ // Collect candidates, the level at which each was found and build a set of their names
1012
+ var iss = this .iss
1013
+ while (! iss.isEmpty) {
1014
+ var is = iss.head
1015
+ while (! is.isEmpty) {
1016
+ val info = is.head
1017
+ if (checkValid(info.sym) && survives(info, NoShadower )) {
1018
+ if (matches == null ) {
1019
+ matches = new java.util.ArrayList (16 )
1020
+ matchesNames = new java.util.HashSet (16 )
1021
+ }
1022
+ matches.add(Candidate (info, i))
1023
+ matchesNames.add(info.name)
1024
+ maxCandidateLevel = i
1025
+ }
1026
+ is = is.tail
1027
+ }
1028
+ iss = iss.tail
1029
+ i += 1
1030
+ }
1031
+ }
1032
+
1033
+ if (matches == null )
1034
+ Nil // OPT common case: no candidates
1035
+ else {
1036
+ if (isLocalToCallsite) {
1037
+ // A second pass to filter out results that are shadowed by implicits in inner scopes.
1038
+ var i = 0
1039
+ var removed = false
1040
+ var iss = this .iss
1041
+ while (! iss.isEmpty && i < maxCandidateLevel) {
1042
+ var is = iss.head
1043
+ while (! is.isEmpty) {
1044
+ val info = is.head
1045
+ if (matchesNames.contains(info.name)) {
1046
+ var j = 0
1047
+ val numMatches = matches.size()
1048
+ while (j < numMatches) {
1049
+ val matchInfo = matches.get(j)
1050
+ if (matchInfo != null && matchInfo.info.name == info.name && matchInfo.level > i) {
1051
+ // Shadowed. For now set to null, so as not to mess up the indexing our current loop.
1052
+ matches.set(j, null )
1053
+ removed = true
1054
+ }
1055
+ j += 1
1056
+ }
1057
+ }
1058
+ is = is.tail
1059
+ }
1060
+ iss = iss.tail
1061
+ i += 1
1062
+ }
1063
+ if (removed) matches.removeIf(_ == null ) // remove for real now.
1064
+ }
1065
+ // most frequent one first. Sort in-place.
1066
+ matches.sort(((x, y) => java.lang.Integer .compare(y.info.useCount(isView), x.info.useCount(isView))))
1067
+ val result = new ListBuffer [ImplicitInfo ]
1068
+ matches.forEach(x => result += x.info)
1069
+ result.toList
1070
+ }
1071
+ }
1072
+
1073
+ val eligible = if (shadowerUseOldImplementation) eligibleOld else eligibleNew
1074
+
998
1075
if (eligible.nonEmpty)
999
1076
printTyping(tree, eligible.size + s " eligible for pt= $pt at ${fullSiteString(context)}" )
1000
1077
0 commit comments