Skip to content

Commit 981f8e6

Browse files
committed
Do not resume into TypeComparer for capture vars
1 parent 6e12872 commit 981f8e6

File tree

1 file changed

+18
-11
lines changed

1 file changed

+18
-11
lines changed

compiler/src/dotty/tools/dotc/core/TypeComparer.scala

+18-11
Original file line numberDiff line numberDiff line change
@@ -320,20 +320,24 @@ class TypeComparer(@constructorOnly initctx: Context) extends ConstraintHandling
320320
/**
321321
* Assumes that isCapSet(tp) is true.
322322
*/
323-
def canonicalizeToCapSet(tp: Type): Type = tp match
324-
case ct @ CapturingType(_,_) => ct
325-
case tp: TypeRef if tp.symbol eq defn.Caps_CapSet => CapturingType(tp, CaptureSet.empty)
326-
case tp: SingletonType => canonicalizeToCapSet(tp.underlying)
327-
case tp: CaptureRef => CapturingType(defn.Caps_CapSet.typeRef, CaptureSet(tp))
328-
323+
def captureSet(tp: Type): CaptureSet = tp match
324+
case CapturingType(_,c) => c
325+
case tp: TypeRef if tp.symbol eq defn.Caps_CapSet => CaptureSet.empty
326+
case tp: SingletonType => captureSet(tp.underlying)
327+
case tp: CaptureRef => CaptureSet(tp)
329328

330329
/** In capture checking, implements the logic to compare type variables which represent
331330
* capture variables.
332331
*
333332
* Note: should only be called in a context where tp1 or tp2 is a type variable representing a capture variable.
333+
*
334+
* @return -1 if tp1 or tp2 is not a capture variables, 1 if both tp1 and tp2 are capture variables and tp1 is a subcapture of tp2,
335+
* 0 if both tp1 and tp2 are capture variables but tp1 is not a subcapture of tp2.
334336
*/
335-
def tryHandleCaptureVars: Boolean =
336-
isCaptureCheckingOrSetup && isCapSet(tp1) && isCapSet(tp2) && recur(canonicalizeToCapSet(tp1), canonicalizeToCapSet(tp2)) // TODO: we could probably just call subcapturing right away here and terminate early
337+
inline def tryHandleCaptureVars: Int =
338+
if !(isCaptureCheckingOrSetup && isCapSet(tp1) && isCapSet(tp2)) then -1
339+
else if (captureSet(tp1).subCaptures(captureSet(tp2), true).isOK) then 1
340+
else 0
337341

338342
def firstTry: Boolean = tp2 match {
339343
case tp2: NamedType =>
@@ -383,8 +387,9 @@ class TypeComparer(@constructorOnly initctx: Context) extends ConstraintHandling
383387
&& isSubPrefix(tp1.prefix, tp2.prefix)
384388
&& tp1.signature == tp2.signature
385389
&& !(sym1.isClass && sym2.isClass) // class types don't subtype each other
386-
|| tryHandleCaptureVars
387-
|| thirdTryNamed(tp2)
390+
|| {val cv = tryHandleCaptureVars
391+
if (cv < 0) then thirdTryNamed(tp2)
392+
else cv > 0 }
388393
case _ =>
389394
secondTry
390395
end compareNamed
@@ -899,7 +904,9 @@ class TypeComparer(@constructorOnly initctx: Context) extends ConstraintHandling
899904
def compareCapturing: Boolean =
900905
val refs1 = tp1.captureSet
901906
try
902-
if tp1.isInstanceOf[TypeRef] && tryHandleCaptureVars then return true
907+
if tp1.isInstanceOf[TypeRef] then
908+
val cv = tryHandleCaptureVars
909+
if (cv >= 0) then return (cv != 0)
903910
if refs1.isAlwaysEmpty then recur(tp1, parent2)
904911
else
905912
// The singletonOK branch is because we sometimes have a larger capture set in a singleton

0 commit comments

Comments
 (0)