@@ -390,9 +390,10 @@ trait Implicits {
390
390
* Detect infinite search trees for implicits.
391
391
*
392
392
* @param info The given implicit info describing the implicit definition
393
+ * @param isLocal Is the implicit in the local scope of the call site?
393
394
* @pre `info.tpe` does not contain an error
394
395
*/
395
- private def typedImplicit (info : ImplicitInfo , ptChecked : Boolean ): SearchResult = {
396
+ private def typedImplicit (info : ImplicitInfo , ptChecked : Boolean , isLocal : Boolean ): SearchResult = {
396
397
(context.openImplicits find { case (tp, tree1) => tree1.symbol == tree.symbol && dominates(pt, tp)}) match {
397
398
case Some (pending) =>
398
399
// println("Pending implicit "+pending+" dominates "+pt+"/"+undetParams) //@MDEBUG
@@ -401,7 +402,7 @@ trait Implicits {
401
402
try {
402
403
context.openImplicits = (pt, tree) :: context.openImplicits
403
404
// println(" "*context.openImplicits.length+"typed implicit "+info+" for "+pt) //@MDEBUG
404
- typedImplicit0(info, ptChecked)
405
+ typedImplicit0(info, ptChecked, isLocal )
405
406
} catch {
406
407
case ex : DivergentImplicit =>
407
408
// println("DivergentImplicit for pt:"+ pt +", open implicits:"+context.openImplicits) //@MDEBUG
@@ -534,7 +535,7 @@ trait Implicits {
534
535
case _ => false
535
536
}
536
537
537
- private def typedImplicit0 (info : ImplicitInfo , ptChecked : Boolean ): SearchResult = {
538
+ private def typedImplicit0 (info : ImplicitInfo , ptChecked : Boolean , isLocal : Boolean ): SearchResult = {
538
539
incCounter(plausiblyCompatibleImplicits)
539
540
printTyping (
540
541
ptBlock(" typedImplicit0" ,
@@ -549,17 +550,24 @@ trait Implicits {
549
550
)
550
551
551
552
if (ptChecked || matchesPt(info))
552
- typedImplicit1(info)
553
+ typedImplicit1(info, isLocal )
553
554
else
554
555
SearchFailure
555
556
}
556
557
557
- private def typedImplicit1 (info : ImplicitInfo ): SearchResult = {
558
+ private def typedImplicit1 (info : ImplicitInfo , isLocal : Boolean ): SearchResult = {
558
559
incCounter(matchingImplicits)
559
560
560
561
val itree = atPos(pos.focus) {
561
- if (info.pre == NoPrefix ) Ident (info.name)
562
- else {
562
+ // workaround for deficient context provided by ModelFactoryImplicitSupport#makeImplicitConstraints
563
+ val isScalaDoc = context.tree == EmptyTree
564
+
565
+ if (isLocal && ! isScalaDoc) {
566
+ // SI-4270 SI-5376 Always use an unattributed Ident for implicits in the local scope,
567
+ // rather than an attributed Select, to detect shadowing.
568
+ Ident (info.name)
569
+ } else {
570
+ assert(info.pre != NoPrefix , info)
563
571
// SI-2405 Not info.name, which might be an aliased import
564
572
val implicitMemberName = info.sym.name
565
573
Select (gen.mkAttributedQualifier(info.pre), implicitMemberName)
@@ -607,8 +615,8 @@ trait Implicits {
607
615
608
616
if (context.hasErrors)
609
617
fail(" hasMatchingSymbol reported threw error(s)" )
610
- else if (! hasMatchingSymbol(itree1))
611
- fail(" candidate implicit %s is shadowed by other implicit %s" .format(
618
+ else if (isLocal && ! hasMatchingSymbol(itree1))
619
+ fail(" candidate implicit %s is shadowed by %s" .format(
612
620
info.sym.fullLocationString, itree1.symbol.fullLocationString))
613
621
else {
614
622
val tvars = undetParams map freshVar
@@ -683,17 +691,6 @@ trait Implicits {
683
691
}
684
692
}
685
693
686
- // #3453: in addition to the implicit symbols that may shadow the implicit with
687
- // name `name`, this method tests whether there's a non-implicit symbol with name
688
- // `name` in scope. Inspired by logic in typedIdent.
689
- private def nonImplicitSynonymInScope (name : Name ) = {
690
- // the implicit ones are handled by the `shadowed` set above
691
- context.scope.lookupEntry(name) match {
692
- case x : ScopeEntry => reallyExists(x.sym) && ! x.sym.isImplicit
693
- case _ => false
694
- }
695
- }
696
-
697
694
/** Should implicit definition symbol `sym` be considered for applicability testing?
698
695
* This is the case if one of the following holds:
699
696
* - the symbol's type is initialized
@@ -737,14 +734,15 @@ trait Implicits {
737
734
/** Prune ImplicitInfos down to either all the eligible ones or the best one.
738
735
*
739
736
* @param iss list of list of infos
740
- * @param shadowed set in which to record names that are shadowed by implicit infos
741
- * If it is null, no shadowing.
737
+ * @param isLocal if true, `iss` represents in-scope implicits, which must respect the normal rules of
738
+ * shadowing. The head of the list `iss` must represent implicits from the closest
739
+ * enclosing scope, and so on.
742
740
*/
743
- class ImplicitComputation (iss : Infoss , shadowed : util.HashSet [Name ]) {
741
+ class ImplicitComputation (iss : Infoss , isLocal : Boolean ) {
742
+ private val shadowed = util.HashSet [Name ](512 )
744
743
private var best : SearchResult = SearchFailure
745
744
private def isShadowed (name : Name ) = (
746
- (shadowed != null )
747
- && (shadowed(name) || nonImplicitSynonymInScope(name))
745
+ isLocal && shadowed(name)
748
746
)
749
747
private def isIneligible (info : ImplicitInfo ) = (
750
748
info.isCyclicOrErroneous
@@ -788,9 +786,7 @@ trait Implicits {
788
786
val eligible = {
789
787
val matches = iss flatMap { is =>
790
788
val result = is filter (info => checkValid(info.sym) && survives(info))
791
- if (shadowed ne null )
792
- shadowed addEntries (is map (_.name))
793
-
789
+ if (isLocal) shadowed addEntries (is map (_.name))
794
790
result
795
791
}
796
792
@@ -812,7 +808,7 @@ trait Implicits {
812
808
case Nil => acc
813
809
case i :: is =>
814
810
def tryImplicitInfo (i : ImplicitInfo ) =
815
- try typedImplicit(i, true )
811
+ try typedImplicit(i, ptChecked = true , isLocal )
816
812
catch divergenceHandler
817
813
818
814
tryImplicitInfo(i) match {
@@ -842,7 +838,7 @@ trait Implicits {
842
838
843
839
/** Returns all eligible ImplicitInfos and their SearchResults in a map.
844
840
*/
845
- def findAll () = mapFrom(eligible)(typedImplicit(_, false ))
841
+ def findAll () = mapFrom(eligible)(typedImplicit(_, ptChecked = false , isLocal ))
846
842
847
843
/** Returns the SearchResult of the best match.
848
844
*/
@@ -891,7 +887,7 @@ trait Implicits {
891
887
*/
892
888
def applicableInfos (iss : Infoss , isLocal : Boolean ): Map [ImplicitInfo , SearchResult ] = {
893
889
val start = startCounter(subtypeAppInfos)
894
- val computation = new ImplicitComputation (iss, if ( isLocal) util. HashSet [ Name ]( 512 ) else null ) { }
890
+ val computation = new ImplicitComputation (iss, isLocal) { }
895
891
val applicable = computation.findAll()
896
892
897
893
stopCounter(subtypeAppInfos, start)
@@ -909,7 +905,7 @@ trait Implicits {
909
905
*/
910
906
def searchImplicit (implicitInfoss : Infoss , isLocal : Boolean ): SearchResult =
911
907
if (implicitInfoss.forall(_.isEmpty)) SearchFailure
912
- else new ImplicitComputation (implicitInfoss, if ( isLocal) util. HashSet [ Name ]( 128 ) else null ) findBest()
908
+ else new ImplicitComputation (implicitInfoss, isLocal) findBest()
913
909
914
910
/** Produce an implicict info map, i.e. a map from the class symbols C of all parts of this type to
915
911
* the implicit infos in the companion objects of these class symbols C.
@@ -1397,19 +1393,22 @@ trait Implicits {
1397
1393
def allImplicitsPoly (tvars : List [TypeVar ]): List [(SearchResult , List [TypeConstraint ])] = {
1398
1394
def resetTVars () = tvars foreach { _.constr = new TypeConstraint }
1399
1395
1400
- def eligibleInfos (iss : Infoss , isLocal : Boolean ) = new ImplicitComputation (iss, if (isLocal) util.HashSet [Name ](512 ) else null ).eligible
1401
- val allEligibleInfos = (eligibleInfos(context.implicitss, true ) ++ eligibleInfos(implicitsOfExpectedType, false )).toList
1402
-
1403
- allEligibleInfos flatMap { ii =>
1404
- // each ImplicitInfo contributes a distinct set of constraints (generated indirectly by typedImplicit)
1405
- // thus, start each type var off with a fresh for every typedImplicit
1406
- resetTVars()
1407
- // any previous errors should not affect us now
1408
- context.flushBuffer()
1409
- val res = typedImplicit(ii, false )
1410
- if (res.tree ne EmptyTree ) List ((res, tvars map (_.constr)))
1411
- else Nil
1396
+ def eligibleInfos (iss : Infoss , isLocal : Boolean ) = {
1397
+ val eligible = new ImplicitComputation (iss, isLocal).eligible
1398
+ eligible.toList.flatMap {
1399
+ (ii : ImplicitInfo ) =>
1400
+ // each ImplicitInfo contributes a distinct set of constraints (generated indirectly by typedImplicit)
1401
+ // thus, start each type var off with a fresh for every typedImplicit
1402
+ resetTVars()
1403
+ // any previous errors should not affect us now
1404
+ context.flushBuffer()
1405
+
1406
+ val res = typedImplicit(ii, ptChecked = false , isLocal)
1407
+ if (res.tree ne EmptyTree ) List ((res, tvars map (_.constr)))
1408
+ else Nil
1409
+ }
1412
1410
}
1411
+ eligibleInfos(context.implicitss, isLocal = true ) ++ eligibleInfos(implicitsOfExpectedType, isLocal = false )
1413
1412
}
1414
1413
}
1415
1414
0 commit comments