From 1c3ad971a63432d9d4f80ec1e32fc27429bbc235 Mon Sep 17 00:00:00 2001 From: odersky Date: Fri, 14 Nov 2025 16:27:24 +0100 Subject: [PATCH] Optimize and harden isCaptureChecking tests - Base it only on ids, no phase dereferencing needed - Make sure checkCapturesPhaseId is not confused with current id even if checkCapturesPhase does not exist and current phase is not set. --- .../src/dotty/tools/dotc/cc/CaptureOps.scala | 18 +++++++----------- .../src/dotty/tools/dotc/core/Phases.scala | 9 +++++++++ 2 files changed, 16 insertions(+), 11 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/cc/CaptureOps.scala b/compiler/src/dotty/tools/dotc/cc/CaptureOps.scala index ca55fef08758..354103e4344f 100644 --- a/compiler/src/dotty/tools/dotc/cc/CaptureOps.scala +++ b/compiler/src/dotty/tools/dotc/cc/CaptureOps.scala @@ -22,20 +22,16 @@ private val Captures: Key[CaptureSet] = Key() /** Are we at checkCaptures phase? */ def isCaptureChecking(using Context): Boolean = - ctx.phaseId == Phases.checkCapturesPhase.id + ctx.phaseId == Phases.checkCapturesPhaseId /** Are we in the CheckCaptures or Setup phase? */ def isCaptureCheckingOrSetup(using Context): Boolean = - val ccPhase = Phases.checkCapturesPhase - ccPhase.exists - && { - val ccId = ccPhase.id - val ctxId = ctx.phaseId - ctxId == ccId - || ctxId == ccId - 1 && ccState.iterationId > 0 - // Note: just checking phase id is not enough since Setup would - // also be the phase after pattern matcher. - } + val ccId = Phases.checkCapturesPhaseId + val ctxId = ctx.phaseId + ctxId == ccId + || ctxId == ccId - 1 && ccState.iterationId > 0 + // Note: just checking phase id is not enough since Setup would + // also be the phase after pattern matcher. /** A dependent function type with given arguments and result type * TODO Move somewhere else where we treat all function type related ops together. diff --git a/compiler/src/dotty/tools/dotc/core/Phases.scala b/compiler/src/dotty/tools/dotc/core/Phases.scala index df102c514fdf..b8522246eac8 100644 --- a/compiler/src/dotty/tools/dotc/core/Phases.scala +++ b/compiler/src/dotty/tools/dotc/core/Phases.scala @@ -216,6 +216,9 @@ object Phases { else this.fusedPhases = this.phases + if myCheckCapturesPhase.exists then + myCheckCapturesPhaseId = myCheckCapturesPhase.id + config.println(s"Phases = ${phases.toList}") config.println(s"nextDenotTransformerId = ${nextDenotTransformerId.toList}") } @@ -257,6 +260,10 @@ object Phases { private var myGenBCodePhase: Phase = uninitialized private var myCheckCapturesPhase: Phase = uninitialized + private var myCheckCapturesPhaseId: Int = -2 + // -1 means undefined, 0 means NoPhase, we make sure that we don't get a false hit + // if ctx.phaseId is either of these. + final def parserPhase: Phase = myParserPhase final def typerPhase: Phase = myTyperPhase final def postTyperPhase: Phase = myPostTyperPhase @@ -285,6 +292,7 @@ object Phases { final def flattenPhase: Phase = myFlattenPhase final def genBCodePhase: Phase = myGenBCodePhase final def checkCapturesPhase: Phase = myCheckCapturesPhase + final def checkCapturesPhaseId: Int = myCheckCapturesPhaseId private def setSpecificPhases() = { def phaseOfClass(pclass: Class[?]) = phases.find(pclass.isInstance).getOrElse(NoPhase) @@ -570,6 +578,7 @@ object Phases { def flattenPhase(using Context): Phase = ctx.base.flattenPhase def genBCodePhase(using Context): Phase = ctx.base.genBCodePhase def checkCapturesPhase(using Context): Phase = ctx.base.checkCapturesPhase + def checkCapturesPhaseId(using Context): Int = ctx.base.checkCapturesPhaseId def unfusedPhases(using Context): Array[Phase] = ctx.base.phases