diff --git a/compiler/src/dotty/tools/dotc/core/Periods.scala b/compiler/src/dotty/tools/dotc/core/Periods.scala index 019c5932b3c9..9743f972b73d 100644 --- a/compiler/src/dotty/tools/dotc/core/Periods.scala +++ b/compiler/src/dotty/tools/dotc/core/Periods.scala @@ -1,7 +1,10 @@ -package dotty.tools.dotc.core +package dotty.tools +package dotc +package core import Contexts.* import Phases.unfusedPhases +import printing.*, Texts.* object Periods { @@ -35,7 +38,7 @@ object Periods { * * // Dmitry: sign == 0 isn't actually always true, in some cases phaseId == -1 is used for shifts, that easily creates code < 0 */ - class Period(val code: Int) extends AnyVal { + class Period(val code: Int) extends AnyVal with Showable { /** The run identifier of this period. */ def runId: RunId = code >>> (PhaseWidth * 2) @@ -97,7 +100,24 @@ object Periods { this.firstPhaseId min that.firstPhaseId, this.lastPhaseId max that.lastPhaseId) - override def toString: String = s"Period($firstPhaseId..$lastPhaseId, run = $runId)" + def toText(p: Printer): Text = inContext(p.printerContext)(this match + case Nowhere => "Nowhere" + case InitialPeriod => "InitialPeriod" + case InvalidPeriod => "InvalidPeriod" + case Period(NoRunId, 0, PhaseMask) => s"Period(NoRunId.all)" + case Period(runId, 0, PhaseMask) => s"Period($runId.all)" + case Period(runId, p1, pn) if p1 == pn => s"Period($runId.$p1(${ctx.base.phases(p1)}))" + case Period(runId, p1, pn) => s"Period($runId.$p1(${ctx.base.phases(p1)})-$pn(${ctx.base.phases(pn)}))" + ) + + override def toString: String = this match + case Nowhere => "Nowhere" + case InitialPeriod => "InitialPeriod" + case InvalidPeriod => "InvalidPeriod" + case Period(NoRunId, 0, PhaseMask) => s"Period(NoRunId.all)" + case Period(runId, 0, PhaseMask) => s"Period($runId.all)" + case Period(runId, p1, pn) if p1 == pn => s"Period($runId.$p1)" + case Period(runId, p1, pn) => s"Period($runId.$p1-$pn)" def ==(that: Period): Boolean = this.code == that.code def !=(that: Period): Boolean = this.code != that.code @@ -116,6 +136,17 @@ object Periods { /** The interval consisting of all periods of given run id */ def allInRun(rid: RunId): Period = apply(rid, 0, PhaseMask) + + def unapply(p: Period): Extractor = new Extractor(p.code) + + final class Extractor(private val code: Int) extends AnyVal { + private def p = new Period(code) + def isEmpty: false = false + def get: this.type = this + def _1 = p.runId + def _2 = p.firstPhaseId + def _3 = p.lastPhaseId + } } inline val NowhereCode = 0 diff --git a/compiler/src/dotty/tools/dotc/printing/Formatting.scala b/compiler/src/dotty/tools/dotc/printing/Formatting.scala index 02f470324e8a..c1b528221204 100644 --- a/compiler/src/dotty/tools/dotc/printing/Formatting.scala +++ b/compiler/src/dotty/tools/dotc/printing/Formatting.scala @@ -24,6 +24,15 @@ object Formatting { object Shown: given [A: Show]: Conversion[A, Shown] = Show[A].show(_) + extension (s: Shown) + def runCtxShow(using Context): Shown = s match + case cs: CtxShow => cs.run + case _ => s + + def toStr(x: Shown)(using Context): String = x match + case seq: Seq[?] => seq.map(toStr).mkString("[", ", ", "]") + case res => res.tryToShow + sealed abstract class Show[-T]: /** Show a value T by returning a "shown" result. */ def show(x: T): Shown @@ -31,10 +40,7 @@ object Formatting { trait CtxShow: def run(using Context): Shown - extension (s: Shown) - def ctxShow(using Context): Shown = s match - case cs: CtxShow => cs.run - case _ => s + import Shown.runCtxShow /** The base implementation, passing the argument to StringFormatter which will try to `.show` it. */ object ShowAny extends Show[Any]: @@ -55,15 +61,21 @@ object Formatting { inline def apply[A](using inline z: Show[A]): Show[A] = z given [X: Show]: Show[Seq[X]] with - def show(x: Seq[X]) = new CtxShow: - def run(using Context) = x.map(show1) + def show(x: Seq[X]) = CtxShow(x.map(toStr)) given [H: Show, T <: Tuple: Show]: Show[H *: T] with - def show(x: H *: T) = new CtxShow: - def run(using Context) = show1(x.head) *: Show[T].show(x.tail).ctxShow.asInstanceOf[Tuple] + def show(x: H *: T) = CtxShow(toStr(x.head) *: toShown(x.tail).asInstanceOf[Tuple]) given [X: Show]: Show[X | Null] with - def show(x: X | Null) = if x == null then "null" else Show[X].show(x.nn) + def show(x: X | Null) = if x == null then "null" else CtxShow(toStr(x.nn)) + + given [X: Show]: Show[Option[X]] with + def show(x: Option[X]) = x match + case Some(x) => CtxShow("Some(" + toStr(x) + ")") + case _ => "None" + + given [K: Show, V: Show]: Show[Map[K, V]] with + def show(x: Map[K, V]) = CtxShow(x.map((k, v) => toStr(k) + " => " + toStr(v))) given Show[FlagSet] with def show(x: FlagSet) = x.flagsString @@ -79,7 +91,12 @@ object Formatting { case ast.TreeInfo.Impure => "PurityLevel.Impure" case ast.TreeInfo.PurePath => "PurityLevel.PurePath" case ast.TreeInfo.IdempotentPath => "PurityLevel.IdempotentPath" - case _ => s"PurityLevel(${x.x})" + case _ => s"PurityLevel(${x.x.toBinaryString})" + + given Show[Atoms] with + def show(x: Atoms) = x match + case Atoms.Unknown => "Unknown" + case Atoms.Range(lo, hi) => CtxShow("Range(" + toStr(lo.toList) + ", " + toStr(hi.toList) + ")") given Show[Showable] = ShowAny given Show[Shown] = ShowAny @@ -92,6 +109,7 @@ object Formatting { given Show[Throwable] = ShowAny given Show[StringBuffer] = ShowAny given Show[CompilationUnit] = ShowAny + given Show[Periods.Period] = ShowAny given Show[Phases.Phase] = ShowAny given Show[TyperState] = ShowAny given Show[config.ScalaVersion] = ShowAny @@ -102,10 +120,9 @@ object Formatting { given Show[tasty.TreeUnpickler#OwnerTree] = ShowAny given Show[typer.ForceDegree.Value] = ShowAny - private def show1[A: Show](x: A)(using Context) = show2(Show[A].show(x).ctxShow) - private def show2(x: Shown)(using Context): String = x match - case seq: Seq[?] => seq.map(show2).mkString("[", ", ", "]") - case res => res.tryToShow + private inline def CtxShow(inline x: Context ?=> Shown) = new CtxShow { def run(using Context) = x(using ctx) } + private def toStr[A: Show](x: A)(using Context): String = Shown.toStr(toShown(x)) + private def toShown[A: Show](x: A)(using Context): Shown = Show[A].show(x).runCtxShow end Show end ShownDef export ShownDef.{ Show, Shown } @@ -122,7 +139,7 @@ object Formatting { class StringFormatter(protected val sc: StringContext) { protected def showArg(arg: Any)(using Context): String = arg.tryToShow - private def treatArg(arg: Shown, suffix: String)(using Context): (String, String) = arg.ctxShow match { + private def treatArg(arg: Shown, suffix: String)(using Context): (String, String) = arg.runCtxShow match { case arg: Seq[?] if suffix.indexOf('%') == 0 && suffix.indexOf('%', 1) != -1 => val end = suffix.indexOf('%', 1) val sep = StringContext.processEscapes(suffix.substring(1, end))