@@ -474,10 +474,11 @@ object Implicits {
474
474
import Implicits ._
475
475
476
476
/** Info relating to implicits that is kept for one run */
477
- trait ImplicitRunInfo {
477
+ trait ImplicitRunInfo :
478
478
self : Run =>
479
479
480
- private val implicitScopeCache = mutable.AnyRefMap [Type , OfTypeImplicits ]()
480
+ private val implicitScopeCache1 = mutable.AnyRefMap [Type , OfTypeImplicits ]()
481
+ private val implicitScopeCache2 = mutable.AnyRefMap [Type , OfTypeImplicits ]()
481
482
482
483
private val EmptyTermRefSet = new TermRefSet (using NoContext )
483
484
@@ -504,8 +505,7 @@ trait ImplicitRunInfo {
504
505
* a type variable, we need the current context, the current
505
506
* runinfo context does not do.
506
507
*/
507
- def implicitScope (rootTp : Type , liftingCtx : Context ): OfTypeImplicits = {
508
-
508
+ def implicitScope1 (rootTp : Type , liftingCtx : Context ): OfTypeImplicits = {
509
509
val seen : mutable.Set [Type ] = mutable.Set ()
510
510
val incomplete : mutable.Set [Type ] = mutable.Set ()
511
511
@@ -557,7 +557,7 @@ trait ImplicitRunInfo {
557
557
trace(i " collectCompanions( $tp) " , implicitsDetailed) {
558
558
record(" collectCompanions" )
559
559
560
- def iscopeRefs (t : Type ): TermRefSet = implicitScopeCache .get(t) match {
560
+ def iscopeRefs (t : Type ): TermRefSet = implicitScopeCache1 .get(t) match {
561
561
case Some (is) =>
562
562
is.companionRefs
563
563
case None =>
@@ -568,7 +568,7 @@ trait ImplicitRunInfo {
568
568
else {
569
569
seen += t
570
570
val is = iscope(t)
571
- if (! implicitScopeCache .contains(t)) incomplete += tp
571
+ if (! implicitScopeCache1 .contains(t)) incomplete += tp
572
572
is.companionRefs
573
573
}
574
574
}
@@ -629,19 +629,195 @@ trait ImplicitRunInfo {
629
629
if (canCache &&
630
630
((tp eq rootTp) || // first type traversed is always cached
631
631
! incomplete.contains(tp))) // other types are cached if they are not incomplete
632
- implicitScopeCache (tp) = result
632
+ implicitScopeCache1 (tp) = result
633
633
result
634
634
}
635
- if (canCache) implicitScopeCache .getOrElse(tp, computeIScope())
635
+ if (canCache) implicitScopeCache1 .getOrElse(tp, computeIScope())
636
636
else computeIScope()
637
637
}
638
638
639
639
iscope(rootTp)
640
640
}
641
641
642
+ private def isExcluded (sym : Symbol ) =
643
+ if migrateTo3 then false else sym.is(Package ) || sym.isPackageObject
644
+
645
+ /** Is `sym` an anchor type for which givens may exist? Anchor types are classes,
646
+ * opaque type aliases, and abstract types, but not type parameters or package objects.
647
+ */
648
+ private def isAnchor (sym : Symbol ) =
649
+ sym.isClass && ! isExcluded(sym)
650
+ || sym.isOpaqueAlias
651
+ || sym.is(Deferred , butNot = Param )
652
+
653
+ private def computeIScope (rootTp : Type ): OfTypeImplicits =
654
+
655
+ object collectParts extends TypeTraverser :
656
+
657
+ private var provisional : Boolean = _
658
+ private var parts : mutable.LinkedHashSet [Type ] = _
659
+ private val partSeen = TypeHashSet ()
660
+
661
+ def traversePrefix (pre : Type ): Unit = pre match
662
+ case pre : TermRef =>
663
+ if migrateTo3 then traverse(pre.info)
664
+ traversePrefix(pre.prefix)
665
+ case _ =>
666
+ traverse(pre)
667
+
668
+ def traverse (t : Type ) =
669
+ if partSeen.contains(t) then ()
670
+ else if implicitScopeCache2.contains(t) then parts += t
671
+ else
672
+ partSeen.addEntry(t)
673
+ t.dealias match
674
+ case t : TypeRef =>
675
+ if isAnchor(t.symbol) then
676
+ parts += t
677
+ traversePrefix(t.prefix)
678
+ else
679
+ traverse(t.underlying)
680
+ case t : TermRef =>
681
+ if ! isExcluded(t.symbol) then
682
+ traverse(t.info)
683
+ traversePrefix(t.prefix)
684
+ case t : ThisType if t.cls.is(Module ) && t.cls.isStaticOwner =>
685
+ traverse(t.cls.sourceModule.termRef)
686
+ case t : ConstantType =>
687
+ traverse(t.underlying)
688
+ case t : TypeParamRef =>
689
+ traverse(t.underlying)
690
+ if ctx.typerState.constraint.contains(t) then provisional = true
691
+ case t : TermParamRef =>
692
+ traverse(t.underlying)
693
+ case t =>
694
+ traverseChildren(t)
695
+
696
+ def apply (tp : Type ): (collection.Set [Type ], Boolean ) =
697
+ provisional = false
698
+ parts = mutable.LinkedHashSet ()
699
+ partSeen.clear()
700
+ traverse(tp)
701
+ (parts, provisional)
702
+ end collectParts
703
+
704
+ val seen = TypeHashSet ()
705
+ val incomplete = TypeHashSet ()
706
+
707
+ def collectCompanions (tp : Type , parts : collection.Set [Type ]): TermRefSet =
708
+ val companions = new TermRefSet
709
+
710
+ def iscopeRefs (t : Type ): TermRefSet =
711
+ implicitScopeCache2.get(t) match
712
+ case Some (is) =>
713
+ is.companionRefs
714
+ case None =>
715
+ if seen.contains(t) then
716
+ incomplete.addEntry(tp) // all references for `t` will be accounted for in `seen` so we return `EmptySet`.
717
+ EmptyTermRefSet // on the other hand, the refs of `tp` are now inaccurate, so `tp` is marked incomplete.
718
+ else
719
+ seen.addEntry(t)
720
+ val is = recur(t)
721
+ if ! implicitScopeCache2.contains(t) then incomplete.addEntry(tp)
722
+ is.companionRefs
723
+ end iscopeRefs
724
+
725
+ def addCompanion (pre : Type , companion : Symbol ) =
726
+ if companion.exists && ! companion.isAbsent() then
727
+ companions += TermRef (pre, companion)
728
+
729
+ def addCompanions (t : Type ) = implicitScopeCache2.get(t) match
730
+ case Some (iscope) =>
731
+ companions ++= iscope.companionRefs
732
+ case None => t match
733
+ case t : TypeRef =>
734
+ val sym = t.symbol
735
+ val pre = t.prefix
736
+ addPath(pre)
737
+ addCompanion(pre,
738
+ if sym.isClass then sym.companionModule
739
+ else pre.member(sym.name.toTermName)
740
+ .suchThat(companion => companion.is(Module ) && companion.owner == sym.owner)
741
+ .symbol)
742
+ if sym.isClass then
743
+ for p <- t.parents do companions ++= iscopeRefs(p)
744
+ else
745
+ companions ++= iscopeRefs(t.superType)
746
+ end addCompanions
747
+
748
+ def addPath (pre : Type ): Unit = pre.dealias match
749
+ case pre : ThisType if pre.cls.is(Module ) && pre.cls.isStaticOwner =>
750
+ addPath(pre.cls.sourceModule.termRef)
751
+ case pre : TermRef =>
752
+ if pre.symbol.is(Package ) then
753
+ if migrateTo3 then
754
+ addCompanion(pre, pre.member(nme.PACKAGE ).symbol)
755
+ addPath(pre.prefix)
756
+ else if ! pre.symbol.isPackageObject || migrateTo3 then
757
+ companions += pre
758
+ addPath(pre.prefix)
759
+ case _ =>
760
+
761
+ parts.foreach(addCompanions)
762
+ companions
763
+ end collectCompanions
764
+
765
+ def recur (tp : Type ): OfTypeImplicits =
766
+ val (parts, provisional) = collectParts(tp)
767
+ val companions = collectCompanions(tp, parts)
768
+ val result = OfTypeImplicits (tp, companions)(runContext)
769
+ if Config .cacheImplicitScopes
770
+ && tp.hash != NotCached
771
+ && ! provisional
772
+ && (tp eq rootTp) // first type traversed is always cached
773
+ || ! incomplete.contains(tp) // other types are cached if they are not incomplete
774
+ then implicitScopeCache2(tp) = result
775
+ result
776
+
777
+ recur(rootTp)
778
+ end computeIScope
779
+
780
+ def implicitScope2 (tp : Type )(using Context ): OfTypeImplicits =
781
+ // println(i"calling iscope of $tp at ${ctx.runId} / ${runContext.runId}")
782
+
783
+ object liftToAnchors extends TypeMap :
784
+ override def stopAtStatic = true
785
+ private val seen = TypeHashSet ()
786
+
787
+ def applyToUnderlying (t : TypeProxy ) =
788
+ if seen.contains(t) then
789
+ WildcardType
790
+ else
791
+ seen.addEntry(t)
792
+ apply(
793
+ t.underlying match
794
+ case TypeBounds (lo, hi) =>
795
+ if defn.isBottomTypeAfterErasure(lo) then hi
796
+ else AndType .make(lo, hi)
797
+ case u => u)
798
+
799
+ def apply (t : Type ) = t.dealias match
800
+ case t : TypeRef =>
801
+ if isAnchor(t.symbol) then t else applyToUnderlying(t)
802
+ case t : TypeVar => apply(t.underlying)
803
+ case t : ParamRef => applyToUnderlying(t)
804
+ case t : ConstantType => apply(t.underlying)
805
+ case t => mapOver(t)
806
+ end liftToAnchors
807
+
808
+ implicitScopeCache2.getOrElse(tp, {
809
+ val liftedTp = liftToAnchors(tp)
810
+ if liftedTp eq tp then computeIScope(tp)
811
+ else
812
+ val liftedIScope = implicitScopeCache2.getOrElse(liftedTp, computeIScope(liftedTp))
813
+ OfTypeImplicits (tp, liftedIScope.companionRefs)(runContext)
814
+ })
815
+ end implicitScope2
816
+
642
817
protected def reset (): Unit =
643
- implicitScopeCache.clear()
644
- }
818
+ implicitScopeCache1.clear()
819
+ implicitScopeCache2.clear()
820
+ end ImplicitRunInfo
645
821
646
822
/** The implicit resolution part of type checking */
647
823
trait Implicits { self : Typer =>
@@ -908,6 +1084,7 @@ trait Implicits { self: Typer =>
908
1084
implicits.println(i " committing ${result.tstate.constraint} yielding ${ctx.typerState.constraint} in ${ctx.typerState}" )
909
1085
result
910
1086
case result : SearchFailure if result.isAmbiguous =>
1087
+ // println(i"FAIL for $pt / $argument: $result0")
911
1088
val deepPt = pt.deepenProto
912
1089
if (deepPt ne pt) inferImplicit(deepPt, argument, span)
913
1090
else if (migrateTo3 && ! ctx.mode.is(Mode .OldOverloadingResolution ))
@@ -922,8 +1099,10 @@ trait Implicits { self: Typer =>
922
1099
}
923
1100
else result
924
1101
case NoMatchingImplicitsFailure =>
1102
+ // println(i"FAIL for $pt / $argument: $result0")
925
1103
SearchFailure (new NoMatchingImplicits (pt, argument, ctx.typerState.constraint))
926
1104
case _ =>
1105
+ // println(i"FAIL for $pt / $argument: $result0")
927
1106
result0
928
1107
}
929
1108
// If we are at the outermost implicit search then emit the implicit dictionary, if any.
@@ -1247,7 +1426,17 @@ trait Implicits { self: Typer =>
1247
1426
}
1248
1427
}
1249
1428
1250
- def implicitScope (tp : Type ): OfTypeImplicits = ctx.run.implicitScope(tp, ctx)
1429
+ def implicitScope (tp : Type ): OfTypeImplicits =
1430
+ val now = ctx.run.implicitScope2(tp)
1431
+ if false then
1432
+ val old = ctx.run.implicitScope1(tp, ctx)
1433
+ val olds = old.companionRefs.toList
1434
+ val nows = now.companionRefs.toList
1435
+ if olds != nows then println(
1436
+ i """ different implicit scopes for $tp
1437
+ |old: $olds%, %
1438
+ |new: $nows%, % """ )
1439
+ now
1251
1440
1252
1441
/** All available implicits, without ranking */
1253
1442
def allImplicits : Set [TermRef ] = {
0 commit comments