@@ -68,6 +68,11 @@ class TypeComparer(@constructorOnly initctx: Context) extends ConstraintHandling
68
68
private var myInstance : TypeComparer = this
69
69
def currentInstance : TypeComparer = myInstance
70
70
71
+ /** All capturing types in the original `tp1` enclosing the currently
72
+ * compared type.
73
+ */
74
+ private var enclosingCapturing1 : List [AnnotatedType ] = Nil
75
+
71
76
/** Is a subtype check in progress? In that case we may not
72
77
* permanently instantiate type variables, because the corresponding
73
78
* constraint might still be retracted and the instantiation should
@@ -256,7 +261,7 @@ class TypeComparer(@constructorOnly initctx: Context) extends ConstraintHandling
256
261
report.log(explained(_.isSubType(tp1, tp2, approx)))
257
262
}
258
263
// Eliminate LazyRefs before checking whether we have seen a type before
259
- val normalize = new TypeMap {
264
+ val normalize = new TypeMap with CaptureSet . IdempotentCaptRefMap {
260
265
val DerefLimit = 10
261
266
var derefCount = 0
262
267
def apply (t : Type ) = t match {
@@ -538,17 +543,23 @@ class TypeComparer(@constructorOnly initctx: Context) extends ConstraintHandling
538
543
539
544
res
540
545
541
- case CapturingType (parent1, refs1) =>
542
- if tp2.isAny then true
543
- else if subCaptures(refs1, tp2.captureSet, frozenConstraint).isOK && sameBoxed(tp1, tp2, refs1)
544
- || ! ctx.mode.is(Mode .CheckBoundsOrSelfType ) && tp1.isAlwaysPure
545
- then
546
- val tp2a =
547
- if tp1.isBoxedCapturing && ! parent1.isBoxedCapturing
548
- then tp2.unboxed
549
- else tp2
550
- recur(parent1, tp2a)
551
- else thirdTry
546
+ case tp1 @ CapturingType (parent1, refs1) =>
547
+ def compareCapturing =
548
+ if tp2.isAny then true
549
+ else if subCaptures(refs1, tp2.captureSet, frozenConstraint).isOK && sameBoxed(tp1, tp2, refs1)
550
+ || ! ctx.mode.is(Mode .CheckBoundsOrSelfType ) && tp1.isAlwaysPure
551
+ then
552
+ val tp2a =
553
+ if tp1.isBoxedCapturing && ! parent1.isBoxedCapturing
554
+ then tp2.unboxed
555
+ else tp2
556
+ try
557
+ enclosingCapturing1 = tp1 :: enclosingCapturing1
558
+ recur(parent1, tp2a)
559
+ finally
560
+ enclosingCapturing1 = enclosingCapturing1.tail
561
+ else thirdTry
562
+ compareCapturing
552
563
case tp1 : AnnotatedType if ! tp1.isRefining =>
553
564
recur(tp1.parent, tp2)
554
565
case tp1 : MatchType =>
@@ -660,10 +671,12 @@ class TypeComparer(@constructorOnly initctx: Context) extends ConstraintHandling
660
671
case (info1 : MethodType , info2 : MethodType ) =>
661
672
matchingMethodParams(info1, info2, precise = false )
662
673
&& isSubInfo(info1.resultType, info2.resultType.subst(info2, info1))
663
- case (info1 @ CapturingType (parent1, refs1), info2 : Type ) =>
674
+ case (info1 @ CapturingType (parent1, refs1), info2 : Type )
675
+ if info2.stripCapturing.isInstanceOf [MethodOrPoly ] =>
664
676
subCaptures(refs1, info2.captureSet, frozenConstraint).isOK && sameBoxed(info1, info2, refs1)
665
677
&& isSubInfo(parent1, info2)
666
- case (info1 : Type , CapturingType (parent2, refs2)) =>
678
+ case (info1 : Type , CapturingType (parent2, refs2))
679
+ if info1.stripCapturing.isInstanceOf [MethodOrPoly ] =>
667
680
val refs1 = info1.captureSet
668
681
(refs1.isAlwaysEmpty || subCaptures(refs1, refs2, frozenConstraint).isOK) && sameBoxed(info1, info2, refs1)
669
682
&& isSubInfo(info1, parent2)
@@ -672,7 +685,7 @@ class TypeComparer(@constructorOnly initctx: Context) extends ConstraintHandling
672
685
673
686
if defn.isFunctionType(tp2) then
674
687
if tp2.derivesFrom(defn.PolyFunctionClass ) then
675
- return isSubInfo(tp1.member (nme.apply).info, tp2.refinedInfo)
688
+ return isSubInfo(tp1.ccMember (nme.apply).info, tp2.refinedInfo)
676
689
else
677
690
tp1w.widenDealias match
678
691
case tp1 : RefinedType =>
@@ -2028,7 +2041,7 @@ class TypeComparer(@constructorOnly initctx: Context) extends ConstraintHandling
2028
2041
* rebase both itself and the member info of `tp` on a freshly created skolem type.
2029
2042
*/
2030
2043
def hasMatchingMember (name : Name , tp1 : Type , tp2 : RefinedType ): Boolean =
2031
- trace(i " hasMatchingMember( $tp1 . $name :? ${tp2.refinedInfo}), mbr: ${tp1.member (name).info}" , subtyping) {
2044
+ trace(i " hasMatchingMember( $tp1 . $name :? ${tp2.refinedInfo}), mbr: ${tp1.ccMember (name).info}" , subtyping) {
2032
2045
2033
2046
// If the member is an abstract type and the prefix is a path, compare the member itself
2034
2047
// instead of its bounds. This case is needed situations like:
@@ -2118,9 +2131,30 @@ class TypeComparer(@constructorOnly initctx: Context) extends ConstraintHandling
2118
2131
|| (tp1.isStable && m.symbol.isStableMember && isSubType(TermRef (tp1, m.symbol), tp2.refinedInfo))
2119
2132
end qualifies
2120
2133
2121
- tp1.member (name).hasAltWithInline(qualifies)
2134
+ tp1.ccMember (name).hasAltWithInline(qualifies)
2122
2135
}
2123
2136
2137
+ extension (qual : Type )
2138
+ /** Add all directly enclosing capture sets to `qual` and select `name` on the
2139
+ * resulting type. A capture set is directly enclosing if there is an enclosing
2140
+ * capturing type with the set and all types between `qual` and that type
2141
+ * are RefinedTypes or CapturingTypes.
2142
+ */
2143
+ def ccMember (name : Name ): Denotation =
2144
+ def isEnclosing (tp : Type ): Boolean = tp match
2145
+ case RefinedType (parent, _, _) => isEnclosing(parent)
2146
+ case CapturingType (parent, _) => isEnclosing(parent)
2147
+ case _ => tp eq qual
2148
+
2149
+ def addCaptures (tp : Type , encls : List [AnnotatedType ]): Type = encls match
2150
+ case (ct @ CapturingType (parent, refs)) :: encls1 if isEnclosing(parent) =>
2151
+ addCaptures(CapturingType (tp, refs, ct.isBoxedCapturing), encls1)
2152
+ case _ =>
2153
+ tp
2154
+
2155
+ addCaptures(qual, enclosingCapturing1).member(name)
2156
+ end ccMember
2157
+
2124
2158
final def ensureStableSingleton (tp : Type ): SingletonType = tp.stripTypeVar match {
2125
2159
case tp : SingletonType if tp.isStable => tp
2126
2160
case tp : ValueType => SkolemType (tp)
@@ -3397,7 +3431,7 @@ class ExplainingTypeComparer(initctx: Context) extends TypeComparer(initctx) {
3397
3431
}
3398
3432
3399
3433
override def hasMatchingMember (name : Name , tp1 : Type , tp2 : RefinedType ): Boolean =
3400
- traceIndented(s " hasMatchingMember( ${show(tp1)} . $name, ${show(tp2.refinedInfo)}), member = ${show(tp1.member (name).info)}" ) {
3434
+ traceIndented(s " hasMatchingMember( ${show(tp1)} . $name, ${show(tp2.refinedInfo)}), member = ${show(tp1.ccMember (name).info)}" ) {
3401
3435
super .hasMatchingMember(name, tp1, tp2)
3402
3436
}
3403
3437
0 commit comments