Skip to content

Commit a94bc8a

Browse files
authored
Merge pull request scala#8109 from retronym/topic/rework-implicit-shadower
Introduce a new implementation of implicit shadowing
2 parents 4951026 + 3d1ab81 commit a94bc8a

File tree

1 file changed

+79
-2
lines changed

1 file changed

+79
-2
lines changed

src/compiler/scala/tools/nsc/typechecker/Implicits.scala

+79-2
Original file line numberDiff line numberDiff line change
@@ -181,7 +181,7 @@ trait Implicits {
181181
private val infoMapCache = new LinkedHashMap[Symbol, InfoMap]
182182
private val improvesCache = perRunCaches.newMap[(ImplicitInfo, ImplicitInfo), Boolean]()
183183
private val implicitSearchId = { var id = 1 ; () => try id finally id += 1 }
184-
184+
private val shadowerUseOldImplementation = java.lang.Boolean.getBoolean("scalac.implicit.shadow.old")
185185
def resetImplicits() {
186186
implicitsCache.clear()
187187
infoMapCache.clear()
@@ -257,6 +257,7 @@ trait Implicits {
257257

258258
var useCountArg: Int = 0
259259
var useCountView: Int = 0
260+
def useCount(isView: Boolean): Int = if (isView) useCountView else useCountArg
260261

261262
/** Does type `tp` contain an Error type as parameter or result?
262263
*/
@@ -985,7 +986,7 @@ trait Implicits {
985986

986987
/** Sorted list of eligible implicits.
987988
*/
988-
val eligible = Shadower.using(isLocalToCallsite){ shadower =>
989+
private def eligibleOld = Shadower.using(isLocalToCallsite){ shadower =>
989990
val matches = iss flatMap { is =>
990991
val result = is filter (info => checkValid(info.sym) && survives(info, shadower))
991992
shadower addInfos is
@@ -995,6 +996,82 @@ trait Implicits {
995996
// most frequent one first
996997
matches sortBy (x => if (isView) -x.useCountView else -x.useCountArg)
997998
}
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+
9981075
if (eligible.nonEmpty)
9991076
printTyping(tree, eligible.size + s" eligible for pt=$pt at ${fullSiteString(context)}")
10001077

0 commit comments

Comments
 (0)