@@ -477,7 +477,8 @@ import Implicits._
477
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,18 +629,171 @@ 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
+ def implicitScope2 (rootTp : Type )(using Context ): OfTypeImplicits =
643
+
644
+ def isExcluded (sym : Symbol ) =
645
+ if migrateTo3 then false else sym.is(Package ) || sym.isPackageObject
646
+
647
+ /** Is `sym` an anchor type for which givens may exist? Anchor types are classes,
648
+ * opaque type aliases, and abstract types, but not type parameters or package objects.
649
+ */
650
+ def isAnchor (sym : Symbol ) =
651
+ sym.isClass && ! isExcluded(sym)
652
+ || sym.isOpaqueAlias
653
+ || sym.is(Deferred , butNot = Param )
654
+
655
+ object liftToAnchors extends TypeMap :
656
+ private val partSeen = TypeHashSet ()
657
+ override def stopAtStatic = true
658
+ def apply (t : Type ) = t.dealias match
659
+ case t : TypeRef => if isAnchor(t.symbol) then t else apply(t.superType)
660
+ case t : TypeVar => apply(t.underlying)
661
+ case t : ParamRef => apply(t.underlying)
662
+ case t : ConstantType => apply(t.underlying)
663
+ case t => mapOver(t)
664
+
665
+ object collectParts extends TypeTraverser :
666
+
667
+ private var provisional : Boolean = _
668
+ private var parts : mutable.LinkedHashSet [Type ] = _
669
+ private val partSeen = TypeHashSet ()
670
+
671
+ def traversePrefix (pre : Type ): Unit = pre match
672
+ case pre : TermRef =>
673
+ if migrateTo3 then traverse(pre.info)
674
+ traversePrefix(pre.prefix)
675
+ case _ =>
676
+ traverse(pre)
677
+
678
+ def traverse (t : Type ) =
679
+ if partSeen.contains(t) then ()
680
+ else if implicitScopeCache2.contains(t) then parts += t
681
+ else
682
+ partSeen.addEntry(t)
683
+ t.dealias match
684
+ case t : TypeRef =>
685
+ if isAnchor(t.symbol) then
686
+ parts += t
687
+ traversePrefix(t.prefix)
688
+ else
689
+ traverse(t.underlying)
690
+ case t : TermRef =>
691
+ if ! isExcluded(t.symbol) then
692
+ traverse(t.info)
693
+ traversePrefix(t.prefix)
694
+ case t : ThisType if t.cls.is(Module ) && t.cls.isStaticOwner =>
695
+ traverse(t.cls.sourceModule.termRef)
696
+ case t : ConstantType =>
697
+ traverse(t.underlying)
698
+ case t : TypeParamRef =>
699
+ traverse(t.underlying)
700
+ if ctx.typerState.constraint.contains(t) then provisional = true
701
+ case t : TermParamRef =>
702
+ traverse(t.underlying)
703
+ case t =>
704
+ traverseChildren(t)
705
+
706
+ def apply (tp : Type ): (collection.Set [Type ], Boolean ) =
707
+ provisional = false
708
+ parts = mutable.LinkedHashSet ()
709
+ partSeen.clear()
710
+ traverse(tp)
711
+ (parts, provisional)
712
+ end collectParts
713
+
714
+ val seen = TypeHashSet ()
715
+ val incomplete = TypeHashSet ()
716
+
717
+ def collectCompanions (tp : Type , parts : collection.Set [Type ]): TermRefSet =
718
+
719
+ def iscopeRefs (t : Type ): TermRefSet =
720
+ implicitScopeCache2.get(t) match
721
+ case Some (is) =>
722
+ is.companionRefs
723
+ case None =>
724
+ if seen.contains(t) then
725
+ incomplete.addEntry(tp) // all references for `t` will be accounted for in `seen` so we return `EmptySet`.
726
+ EmptyTermRefSet // on the other hand, the refs of `tp` are now inaccurate, so `tp` is marked incomplete.
727
+ else
728
+ seen.addEntry(t)
729
+ val is = computeIScope(t)
730
+ if ! implicitScopeCache2.contains(t) then incomplete.addEntry(tp)
731
+ is.companionRefs
732
+ end iscopeRefs
733
+
734
+ val companions = new TermRefSet
735
+
736
+ def addCompanion (pre : Type , companion : Symbol ) =
737
+ if companion.exists && ! companion.isAbsent() then
738
+ companions += TermRef (pre, companion)
739
+
740
+ def addCompanions (t : Type ) = implicitScopeCache2.get(t) match
741
+ case Some (iscope) =>
742
+ companions ++= iscope.companionRefs
743
+ case None => t match
744
+ case t : TypeRef =>
745
+ val sym = t.symbol
746
+ val pre = t.prefix
747
+ addPath(pre)
748
+ addCompanion(pre,
749
+ if sym.isClass then sym.companionModule
750
+ else pre.member(sym.name.toTermName)
751
+ .suchThat(companion => companion.is(Module ) && companion.owner == sym.owner)
752
+ .symbol)
753
+ if sym.isClass then
754
+ for p <- t.parents do companions ++= iscopeRefs(p)
755
+ else
756
+ companions ++= iscopeRefs(t.superType)
757
+ end addCompanions
758
+
759
+ def addPath (pre : Type ): Unit = pre.dealias match
760
+ case pre : ThisType if pre.cls.is(Module ) && pre.cls.isStaticOwner =>
761
+ addPath(pre.cls.sourceModule.termRef)
762
+ case pre : TermRef =>
763
+ if pre.symbol.is(Package ) then
764
+ if migrateTo3 then
765
+ addCompanion(pre, pre.member(nme.PACKAGE ).symbol)
766
+ addPath(pre.prefix)
767
+ else if ! pre.symbol.isPackageObject || migrateTo3 then
768
+ companions += pre
769
+ addPath(pre.prefix)
770
+ case _ =>
771
+
772
+ parts.foreach(addCompanions)
773
+ companions
774
+ end collectCompanions
775
+
776
+ def computeIScope (tp : Type ): OfTypeImplicits =
777
+ val (parts, provisional) = collectParts(tp)
778
+ val result = new OfTypeImplicits (tp, collectCompanions(tp, parts))(runContext)
779
+ if Config .cacheImplicitScopes
780
+ && tp.hash != NotCached
781
+ && ! provisional
782
+ && (tp eq rootTp) // first type traversed is always cached
783
+ || ! incomplete.contains(tp) // other types are cached if they are not incomplete
784
+ then implicitScopeCache2(tp) = result
785
+ result
786
+
787
+ /** The implicit scope of type `tp` */
788
+ def iscope (tp : Type ): OfTypeImplicits =
789
+ implicitScopeCache2.getOrElse(tp, computeIScope(tp))
790
+
791
+ iscope(rootTp)
792
+ end implicitScope2
793
+
642
794
protected def reset (): Unit =
643
- implicitScopeCache.clear()
795
+ implicitScopeCache1.clear()
796
+ implicitScopeCache2.clear()
644
797
}
645
798
646
799
/** The implicit resolution part of type checking */
@@ -908,6 +1061,7 @@ trait Implicits { self: Typer =>
908
1061
implicits.println(i " committing ${result.tstate.constraint} yielding ${ctx.typerState.constraint} in ${ctx.typerState}" )
909
1062
result
910
1063
case result : SearchFailure if result.isAmbiguous =>
1064
+ // println(i"FAIL for $pt / $argument: $result0")
911
1065
val deepPt = pt.deepenProto
912
1066
if (deepPt ne pt) inferImplicit(deepPt, argument, span)
913
1067
else if (migrateTo3 && ! ctx.mode.is(Mode .OldOverloadingResolution ))
@@ -922,8 +1076,10 @@ trait Implicits { self: Typer =>
922
1076
}
923
1077
else result
924
1078
case NoMatchingImplicitsFailure =>
1079
+ // println(i"FAIL for $pt / $argument: $result0")
925
1080
SearchFailure (new NoMatchingImplicits (pt, argument, ctx.typerState.constraint))
926
1081
case _ =>
1082
+ // println(i"FAIL for $pt / $argument: $result0")
927
1083
result0
928
1084
}
929
1085
// If we are at the outermost implicit search then emit the implicit dictionary, if any.
@@ -1247,7 +1403,17 @@ trait Implicits { self: Typer =>
1247
1403
}
1248
1404
}
1249
1405
1250
- def implicitScope (tp : Type ): OfTypeImplicits = ctx.run.implicitScope(tp, ctx)
1406
+ def implicitScope (tp : Type ): OfTypeImplicits =
1407
+ val now = ctx.run.implicitScope2(tp)
1408
+ if false then
1409
+ val old = ctx.run.implicitScope1(tp, ctx)
1410
+ val olds = old.companionRefs.toList
1411
+ val nows = now.companionRefs.toList
1412
+ if olds != nows then println(
1413
+ i """ different implicit scopes for $tp
1414
+ |old: $olds%, %
1415
+ |new: $nows%, % """ )
1416
+ now
1251
1417
1252
1418
/** All available implicits, without ranking */
1253
1419
def allImplicits : Set [TermRef ] = {
0 commit comments