diff --git a/compiler/src/dotty/tools/dotc/core/Periods.scala b/compiler/src/dotty/tools/dotc/core/Periods.scala index 019c5932b3c9..60226eb59fe0 100644 --- a/compiler/src/dotty/tools/dotc/core/Periods.scala +++ b/compiler/src/dotty/tools/dotc/core/Periods.scala @@ -1,6 +1,10 @@ -package dotty.tools.dotc.core +package dotty.tools +package dotc +package core import Contexts.* +import printing.* +import Texts.* import Phases.unfusedPhases object Periods { @@ -35,7 +39,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 +101,25 @@ 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 +138,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..ac13f0161c70 100644 --- a/compiler/src/dotty/tools/dotc/printing/Formatting.scala +++ b/compiler/src/dotty/tools/dotc/printing/Formatting.scala @@ -24,6 +24,17 @@ 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 + + import Shown.runCtxShow + sealed abstract class Show[-T]: /** Show a value T by returning a "shown" result. */ def show(x: T): Shown @@ -31,10 +42,9 @@ 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 + 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 /** The base implementation, passing the argument to StringFormatter which will try to `.show` it. */ object ShowAny extends Show[Any]: @@ -54,16 +64,26 @@ object Formatting { object Show extends ShowImplicits1: inline def apply[A](using inline z: Show[A]): Show[A] = z + given [X: Show]: Show[Option[X]] with + def show(x: Option[X]) = + CtxShow(x.map(toStr)) + end given + 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 [K: Show, V: Show]: Show[Map[K, V]] with + def show(x: Map[K, V]) = + CtxShow(x.map((k, v) => s"${toStr(k)} => ${toStr(v)}")) + end given 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]) + end given 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 Show[FlagSet] with def show(x: FlagSet) = x.flagsString @@ -79,7 +99,13 @@ 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(s"Range(${toStr(lo.toList)}, ${toStr(hi.toList)})") + end given given Show[Showable] = ShowAny given Show[Shown] = ShowAny @@ -101,11 +127,6 @@ object Formatting { given Show[util.Spans.Span] = ShowAny 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 end Show end ShownDef export ShownDef.{ Show, Shown } @@ -122,7 +143,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)) diff --git a/compiler/src/dotty/tools/dotc/transform/patmat/Space.scala b/compiler/src/dotty/tools/dotc/transform/patmat/Space.scala index 9bf852084cfe..012f2affffc1 100644 --- a/compiler/src/dotty/tools/dotc/transform/patmat/Space.scala +++ b/compiler/src/dotty/tools/dotc/transform/patmat/Space.scala @@ -115,7 +115,7 @@ object SpaceEngine { def decompose(typ: Typ)(using Context): List[Typ] = typ.decompose /** Simplify space such that a space equal to `Empty` becomes `Empty` */ - def computeSimplify(space: Space)(using Context): Space = trace(s"simplify($space)")(space match { + def computeSimplify(space: Space)(using Context): Space = trace(i"simplify($space)")(space match { case Prod(tp, fun, spaces) => val sps = spaces.mapconserve(simplify) if sps.contains(Empty) then Empty @@ -166,7 +166,7 @@ object SpaceEngine { } /** Is `a` a subspace of `b`? Equivalent to `simplify(simplify(a) - simplify(b)) == Empty`, but faster */ - def computeIsSubspace(a: Space, b: Space)(using Context): Boolean = trace(s"isSubspace($a, $b)") { + def computeIsSubspace(a: Space, b: Space)(using Context): Boolean = trace(i"isSubspace($a, $b)") { val a2 = simplify(a) val b2 = simplify(b) if (a ne a2) || (b ne b2) then isSubspace(a2, b2) @@ -195,7 +195,7 @@ object SpaceEngine { } /** Intersection of two spaces */ - def intersect(a: Space, b: Space)(using Context): Space = trace(s"$a & $b") { + def intersect(a: Space, b: Space)(using Context): Space = trace(i"intersect($a & $b)") { (a, b) match { case (Empty, _) | (_, Empty) => Empty case (_, Or(ss)) => Or(ss.map(intersect(a, _)).filter(_ ne Empty)) @@ -220,7 +220,7 @@ object SpaceEngine { } /** The space of a not covered by b */ - def minus(a: Space, b: Space)(using Context): Space = trace(s"$a - $b") { + def minus(a: Space, b: Space)(using Context): Space = trace(i"minus($a - $b)") { (a, b) match { case (Empty, _) => Empty case (_, Empty) => a