@@ -22,7 +22,7 @@ package typechecker
22
22
import scala .annotation .{nowarn , tailrec }
23
23
import scala .collection .mutable , mutable .{LinkedHashMap , ListBuffer }
24
24
import scala .language .implicitConversions
25
- import scala .reflect .internal .util .{ReusableInstance , Statistics , TriState }
25
+ import scala .reflect .internal .util .{Statistics , TriState }
26
26
import scala .reflect .internal .TypesStats
27
27
import scala .tools .nsc .Reporting .WarningCategory .{Scala3Migration , WFlagSelfImplicit }
28
28
import symtab .Flags ._
@@ -88,11 +88,10 @@ trait Implicits extends splain.SplainData {
88
88
*/
89
89
def inferImplicit (tree : Tree , pt : Type , reportAmbiguous : Boolean , isView : Boolean , context : Context , saveAmbiguousDivergent : Boolean , pos : Position ): SearchResult = {
90
90
currentRun.profiler.beforeImplicitSearch(pt)
91
- try {
91
+ try
92
92
inferImplicit1(tree, pt, reportAmbiguous, isView, context, saveAmbiguousDivergent, pos)
93
- } finally {
93
+ finally
94
94
currentRun.profiler.afterImplicitSearch(pt)
95
- }
96
95
}
97
96
98
97
private def inferImplicit1 (tree : Tree , pt : Type , reportAmbiguous : Boolean , isView : Boolean , context : Context , saveAmbiguousDivergent : Boolean , pos : Position ): SearchResult = {
@@ -239,7 +238,7 @@ trait Implicits extends splain.SplainData {
239
238
private val improvesCache = perRunCaches.newMap[(ImplicitInfo , ImplicitInfo ), Boolean ]()
240
239
private val implicitSearchId = { var id = 1 ; () => try id finally id += 1 }
241
240
242
- private val shadowerUseOldImplementation = java.lang.Boolean .getBoolean(" scalac.implicit.shadow.old" )
241
+ // private val shadowerUseOldImplementation = java.lang.Boolean.getBoolean("scalac.implicit.shadow.old")
243
242
def resetImplicits (): Unit = {
244
243
implicitsCache.clear()
245
244
infoMapCache.clear()
@@ -943,8 +942,7 @@ trait Implicits extends splain.SplainData {
943
942
else if (itree3.isErroneous)
944
943
fail(" error typechecking implicit candidate" )
945
944
else if (isLocalToCallsite && ! hasMatchingSymbol(itree2))
946
- fail(" candidate implicit %s is shadowed by %s" .format(
947
- info.sym.fullLocationString, itree2.symbol.fullLocationString))
945
+ fail(s " candidate implicit ${info.sym.fullLocationString} is shadowed by ${itree2.symbol.fullLocationString}" )
948
946
else {
949
947
val tvars = undetParams map freshVar
950
948
val ptInstantiated = pt.instantiateTypeParams(undetParams, tvars)
@@ -1035,7 +1033,8 @@ trait Implicits extends splain.SplainData {
1035
1033
* - the symbol's type is initialized
1036
1034
* - the symbol comes from a classfile
1037
1035
* - the symbol comes from a different sourcefile than the current one
1038
- * - the symbol and the accessed symbol's definitions come before, and do not contain the closest enclosing definition, // see #3373
1036
+ * - the symbol comes earlier in the source file but is not an enclosing definition
1037
+ * - ditto for the accessed of an accessor (#3373)
1039
1038
* - the symbol's definition is a val, var, or def with an explicit result type
1040
1039
* The aim of this method is to prevent premature cyclic reference errors
1041
1040
* by computing the types of only those implicits for which one of these
@@ -1059,17 +1058,20 @@ trait Implicits extends splain.SplainData {
1059
1058
if (sym.hasAccessorFlag) {
1060
1059
val symAcc = sym.accessed // #3373
1061
1060
symAcc.pos.pointOrElse(0 ) < ownerPos &&
1062
- ! (owner.ownerChain exists (o => (o eq sym) || (o eq symAcc))) // probably faster to iterate only once, don't feel like duplicating hasTransOwner for this case
1063
- } else ! (owner hasTransOwner sym)) // faster than owner.ownerChain contains sym
1064
- }
1065
-
1066
- sym.isInitialized || {
1067
- val sourceFile = sym.sourceFile
1068
- sourceFile == null ||
1069
- (sourceFile ne context.unit.source.file) ||
1070
- hasExplicitResultType(sym) ||
1071
- comesBefore(sym, context.owner)
1061
+ ! owner.ownerChain.exists(o => (o eq sym) || (o eq symAcc))
1062
+ // probably faster to iterate only once, avoid duplicating hasTransOwner for this case
1063
+ }
1064
+ else ! owner.hasTransOwner(sym) // faster than owner.ownerChain contains sym
1065
+ )
1072
1066
}
1067
+ ( sym.isInitialized
1068
+ || hasExplicitResultType(sym)
1069
+ || (sym.sourceFile match {
1070
+ case null => true
1071
+ case sourceFile => sourceFile ne context.unit.source.file
1072
+ })
1073
+ || comesBefore(sym, context.owner)
1074
+ )
1073
1075
}
1074
1076
1075
1077
/** Prune ImplicitInfos down to either all the eligible ones or the best one.
@@ -1088,7 +1090,7 @@ trait Implicits extends splain.SplainData {
1088
1090
|| (! context.macrosEnabled && info.sym.isTermMacro)
1089
1091
)
1090
1092
1091
- /** True if a given ImplicitInfo (already known isValid) is eligible .
1093
+ /** True if a given ImplicitInfo that isValid is not ineligible and matches the expected type .
1092
1094
*/
1093
1095
@ nowarn(" cat=lint-inaccessible" )
1094
1096
def survives (info : ImplicitInfo , shadower : Shadower ) = (
@@ -1100,7 +1102,7 @@ trait Implicits extends splain.SplainData {
1100
1102
/** The implicits that are not valid because they come later in the source and
1101
1103
* lack an explicit result type. Used for error diagnostics only.
1102
1104
*/
1103
- val invalidImplicits = new ListBuffer [Symbol ]
1105
+ val invalidImplicits = ListBuffer .empty [Symbol ]
1104
1106
1105
1107
/** Tests for validity and updates invalidImplicits by side effect when false.
1106
1108
*/
@@ -1145,6 +1147,7 @@ trait Implicits extends splain.SplainData {
1145
1147
}
1146
1148
}
1147
1149
1150
+ /*
1148
1151
/** Sorted list of eligible implicits.
1149
1152
*/
1150
1153
private def eligibleOld = Shadower.using(isLocalToCallsite) { shadower =>
@@ -1220,13 +1223,26 @@ trait Implicits extends splain.SplainData {
1220
1223
}
1221
1224
if (removed) matches.removeIf(_ == null) // remove for real now.
1222
1225
}
1223
- val result = new ListBuffer [ImplicitInfo ]
1226
+ val result = ListBuffer.empty [ImplicitInfo]
1224
1227
matches.forEach(x => result += x.info)
1225
1228
result.toList
1226
1229
}
1227
1230
}
1231
+ */
1228
1232
1229
- val eligible : List [ImplicitInfo ] = if (shadowerUseOldImplementation) eligibleOld else eligibleNew
1233
+ val eligibleValidMatching : List [ImplicitInfo ] =
1234
+ iss.flatMap(_.filter(info => checkValid(info.sym) && survives(info, NoShadower )))
1235
+
1236
+ val eligible : List [ImplicitInfo ] = eligibleValidMatching
1237
+ /*
1238
+ val eligible: List[ImplicitInfo] = {
1239
+ val prev = eligibleNew
1240
+ if (!eligibleValidMatching.corresponds(prev)((a, b) => a.sym == b.sym))
1241
+ debuglog(s"Eligible diff: ${eligibleValidMatching.diff(prev)}")
1242
+ eligibleValidMatching
1243
+ }
1244
+ //val eligible: List[ImplicitInfo] = if (shadowerUseOldImplementation) eligibleOld else eligibleNew
1245
+ */
1230
1246
if (eligible.nonEmpty)
1231
1247
printTyping(tree, s " ${eligible.size} eligible for pt= $pt at ${fullSiteString(context)}" )
1232
1248
@@ -1270,8 +1286,9 @@ trait Implicits extends splain.SplainData {
1270
1286
foreach2(undetParams, savedInfos){ (up, si) => up.setInfo(si) }
1271
1287
}
1272
1288
}
1289
+ // Don't accumulate constraints from typechecking or type error message creation for failed candidates
1273
1290
if (typedFirstPending.isFailure)
1274
- undoLog.undoTo(mark) // Don't accumulate constraints from typechecking or type error message creation for failed candidates
1291
+ undoLog.undoTo(mark)
1275
1292
1276
1293
// Pass the errors to `DivergentImplicitRecovery` so that it can note
1277
1294
// the first `DivergentImplicitTypeError` that is being propagated
@@ -1302,13 +1319,13 @@ trait Implicits extends splain.SplainData {
1302
1319
// earlier elems may improve on later ones, but not the other way.
1303
1320
// So if there is any element not improved upon by the first it is an error.
1304
1321
rankImplicits(eligible, Nil ) match {
1305
- case Nil => ()
1322
+ case Nil =>
1306
1323
case (chosenResult, chosenInfo) :: rest =>
1307
- rest find { case (_, alt) => ! improves(chosenInfo, alt) } match {
1308
- case Some ((competingResult, competingInfo)) =>
1324
+ rest. find { case (_, alt) => ! improves(chosenInfo, alt) } match {
1325
+ case Some ((competingResult, competingInfo)) =>
1309
1326
AmbiguousImplicitError (chosenInfo, chosenResult.tree, competingInfo, competingResult.tree, " both" , " and" , " " )(isView, pt, tree)(context)
1310
1327
return AmbiguousSearchFailure // Stop the search once ambiguity is encountered, see t4457_2.scala
1311
- case _ =>
1328
+ case _ =>
1312
1329
if (isView) chosenInfo.useCountView += 1
1313
1330
else chosenInfo.useCountArg += 1
1314
1331
}
@@ -1757,15 +1774,41 @@ trait Implicits extends splain.SplainData {
1757
1774
val failstart = if (stats) statistics.startTimer(inscopeFailNanos) else null
1758
1775
val succstart = if (stats) statistics.startTimer(inscopeSucceedNanos) else null
1759
1776
1760
- var result = searchImplicit(context.implicitss, isLocalToCallsite = true )
1777
+ // looking up a "candidate" implicit from this context must yield the candidate if not shadowed
1778
+ // note that isAccessible is checked by isQualifyingImplicit //&& isAccessible(ii.sym, ii.pre)
1779
+ // if lookup fails, it's a stale symbol problem, not our problem (pos/t5639)
1780
+ def shadowed (ii : ImplicitInfo ): Boolean = {
1781
+ val shadowed = context.lookupSymbol(ii.name, _ => true ) match {
1782
+ case LookupSucceeded (qualifier, symbol) =>
1783
+ // ii.pre or skipPackageObject
1784
+ val pre = if (ii.pre.typeSymbol.isPackageObjectClass) ii.pre.typeSymbol.owner.module.info else ii.pre
1785
+ val ok = (
1786
+ symbol.alternatives.exists(_ == ii.sym)
1787
+ && (qualifier.isEmpty || qualifier.tpe =:= pre)
1788
+ )
1789
+ if (! ok && settings.isDebug) {
1790
+ val pretext = if (ii.pre != NoType ) s " in ${ii.pre}" else " "
1791
+ val qualtext = if (! qualifier.isEmpty) s " in ${qualifier.tpe}" else " "
1792
+ debuglog(s " Drop shadowed implicit ${ii.sym.fullLocationString}${pretext} for ${
1793
+ symbol.fullLocationString}${qualtext}" )
1794
+ }
1795
+ ! ok
1796
+ case failure =>
1797
+ debuglog(s " Not dropping implicit $ii or ${ii.sym.fullLocationString} on bad lookup $failure in ${
1798
+ context.owner}" )
1799
+ false
1800
+ }
1801
+ shadowed
1802
+ }
1803
+ val implicitss = context.implicitss.map(_.filterNot(shadowed)).filter(! _.isEmpty)
1804
+ var result = searchImplicit(implicitss, isLocalToCallsite = true )
1761
1805
1762
- if (stats) {
1806
+ if (stats)
1763
1807
if (result.isFailure) statistics.stopTimer(inscopeFailNanos, failstart)
1764
1808
else {
1765
1809
statistics.stopTimer(inscopeSucceedNanos, succstart)
1766
1810
statistics.incCounter(inscopeImplicitHits)
1767
1811
}
1768
- }
1769
1812
1770
1813
if (result.isFailure) {
1771
1814
val failstart = if (stats) statistics.startTimer(oftypeFailNanos) else null
@@ -1980,16 +2023,19 @@ trait Implicits extends splain.SplainData {
1980
2023
def isShadowed (name : Name ): Boolean
1981
2024
}
1982
2025
object Shadower {
1983
- private [this ] val localShadowerCache = ReusableInstance [LocalShadower ](new LocalShadower , enabled = isCompilerUniverse)
2026
+ /*
2027
+ private val localShadowerCache = ReusableInstance[LocalShadower](new LocalShadower, enabled = isCompilerUniverse)
1984
2028
1985
2029
def using[T](local: Boolean)(f: Shadower => T): T =
1986
2030
if (local) localShadowerCache.using { shadower =>
1987
2031
shadower.clear()
1988
2032
f(shadower)
1989
2033
}
1990
2034
else f(NoShadower)
2035
+ */
1991
2036
}
1992
2037
2038
+ /*
1993
2039
/** Used for exclude implicits from outer scopes that are shadowed by same-named implicits */
1994
2040
private final class LocalShadower extends Shadower {
1995
2041
// OPT: using j.l.HashSet as that retains the internal array on clear(), which makes it worth caching.
@@ -2000,6 +2046,7 @@ trait Implicits extends splain.SplainData {
2000
2046
def isShadowed(name: Name) = shadowed.contains(name)
2001
2047
def clear(): Unit = shadowed.clear()
2002
2048
}
2049
+ */
2003
2050
/** Used for the implicits of expected type, when no shadowing checks are needed. */
2004
2051
private object NoShadower extends Shadower {
2005
2052
def addInfos (infos : Infos ): Unit = {}
0 commit comments