@@ -296,7 +296,10 @@ sealed abstract class CaptureSet extends Showable:
296296 val elems1 = elems.filter(p)
297297 if elems1 == elems then this
298298 else Const (elems.filter(p))
299- else Filtered (asVar, p)
299+ else
300+ this match
301+ case self : Filtered => Filtered (self.source, ref => self.p(ref) && p(ref))
302+ case _ => Filtered (asVar, p)
300303
301304 /** Capture set obtained by applying `tm` to all elements of the current capture set
302305 * and joining the results. If the current capture set is a variable, the same
@@ -326,7 +329,13 @@ sealed abstract class CaptureSet extends Showable:
326329 if isConst then
327330 if mappedElems == elems then this
328331 else Const (mappedElems)
329- else BiMapped (asVar, tm, mappedElems)
332+ else
333+ def unfused = BiMapped (asVar, tm, mappedElems)
334+ this match
335+ case self : BiMapped => self.bimap.fuse(tm) match
336+ case Some (fused : BiTypeMap ) => BiMapped (self.source, fused, mappedElems)
337+ case _ => unfused
338+ case _ => unfused
330339 case tm : IdentityCaptRefMap =>
331340 this
332341 case tm : AvoidMap if this .isInstanceOf [HiddenSet ] =>
@@ -749,6 +758,25 @@ object CaptureSet:
749758
750759 override def propagateSolved (provisional : Boolean )(using Context ) =
751760 if source.isConst && ! isConst then markSolved(provisional)
761+
762+ // ----------- Longest path recording -------------------------
763+
764+ /** Summarize for set displaying in a path */
765+ def summarize : String = getClass.toString
766+
767+ /** The length of the path of DerivedVars ending in this set */
768+ def pathLength : Int = source match
769+ case source : DerivedVar => source.pathLength + 1
770+ case _ => 1
771+
772+ /** The path of DerivedVars ending in this set */
773+ def path : List [DerivedVar ] = source match
774+ case source : DerivedVar => this :: source.path
775+ case _ => this :: Nil
776+
777+ if ctx.settings.YccLog .value || util.Stats .enabled then
778+ ctx.run.nn.recordPath(pathLength, path)
779+
752780 end DerivedVar
753781
754782 /** A variable that changes when `source` changes, where all additional new elements are mapped
@@ -852,7 +880,7 @@ object CaptureSet:
852880 * Parameters as in Mapped.
853881 */
854882 final class BiMapped private [CaptureSet ]
855- (val source : Var , bimap : BiTypeMap , initialElems : Refs )(using @ constructorOnly ctx : Context )
883+ (val source : Var , val bimap : BiTypeMap , initialElems : Refs )(using @ constructorOnly ctx : Context )
856884 extends DerivedVar (source.owner, initialElems):
857885
858886 override def tryInclude (elem : CaptureRef , origin : CaptureSet )(using Context , VarState ): CompareResult =
@@ -881,11 +909,12 @@ object CaptureSet:
881909
882910 override def isMaybeSet : Boolean = bimap.isInstanceOf [MaybeMap ]
883911 override def toString = s " BiMapped $id( $source, elems = $elems) "
912+ override def summarize = bimap.getClass.toString
884913 end BiMapped
885914
886915 /** A variable with elements given at any time as { x <- source.elems | p(x) } */
887916 class Filtered private [CaptureSet ]
888- (val source : Var , p : Context ?=> CaptureRef => Boolean )(using @ constructorOnly ctx : Context )
917+ (val source : Var , val p : Context ?=> CaptureRef => Boolean )(using @ constructorOnly ctx : Context )
889918 extends DerivedVar (source.owner, source.elems.filter(p)):
890919
891920 override def tryInclude (elem : CaptureRef , origin : CaptureSet )(using Context , VarState ): CompareResult =
@@ -1298,10 +1327,21 @@ object CaptureSet:
12981327 case t : CaptureRef if t.isTrackableRef => mapRef(t)
12991328 case _ => mapOver(t)
13001329
1301- lazy val inverse = new BiTypeMap :
1330+ override def fuse (next : BiTypeMap )(using Context ) = next match
1331+ case next : Inverse if next.inverse.getClass == getClass => assert(false ); Some (IdentityTypeMap )
1332+ case next : NarrowingCapabilityMap if next.getClass == getClass => assert(false )
1333+ case _ => None
1334+
1335+ class Inverse extends BiTypeMap :
13021336 def apply (t : Type ) = t // since f(c) <: c, this is the best inverse
13031337 def inverse = NarrowingCapabilityMap .this
13041338 override def toString = NarrowingCapabilityMap .this .toString ++ " .inverse"
1339+ override def fuse (next : BiTypeMap )(using Context ) = next match
1340+ case next : NarrowingCapabilityMap if next.inverse.getClass == getClass => assert(false ); Some (IdentityTypeMap )
1341+ case next : NarrowingCapabilityMap if next.getClass == getClass => assert(false )
1342+ case _ => None
1343+
1344+ lazy val inverse = Inverse ()
13051345 end NarrowingCapabilityMap
13061346
13071347 /** Maps `x` to `x?` */
0 commit comments