Skip to content

Commit 0155d65

Browse files
Backport "Add formatters for Option, Map, Period, and Atoms" to LTS (#20915)
Backports #19658 to the LTS branch. PR submitted by the release tooling. [skip ci]
2 parents 7c12968 + 45cef44 commit 0155d65

File tree

3 files changed

+77
-23
lines changed

3 files changed

+77
-23
lines changed

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

+36-3
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
1-
package dotty.tools.dotc.core
1+
package dotty.tools
2+
package dotc
3+
package core
24

35
import Contexts.*
6+
import printing.*
7+
import Texts.*
48
import Phases.unfusedPhases
59

610
object Periods {
@@ -35,7 +39,7 @@ object Periods {
3539
*
3640
* // Dmitry: sign == 0 isn't actually always true, in some cases phaseId == -1 is used for shifts, that easily creates code < 0
3741
*/
38-
class Period(val code: Int) extends AnyVal {
42+
class Period(val code: Int) extends AnyVal with Showable {
3943

4044
/** The run identifier of this period. */
4145
def runId: RunId = code >>> (PhaseWidth * 2)
@@ -97,7 +101,25 @@ object Periods {
97101
this.firstPhaseId min that.firstPhaseId,
98102
this.lastPhaseId max that.lastPhaseId)
99103

100-
override def toString: String = s"Period($firstPhaseId..$lastPhaseId, run = $runId)"
104+
def toText(p: Printer): Text =
105+
inContext(p.printerContext):
106+
this match
107+
case Nowhere => "Nowhere"
108+
case InitialPeriod => "InitialPeriod"
109+
case InvalidPeriod => "InvalidPeriod"
110+
case Period(NoRunId, 0, PhaseMask) => s"Period(NoRunId.all)"
111+
case Period(runId, 0, PhaseMask) => s"Period($runId.all)"
112+
case Period(runId, p1, pn) if p1 == pn => s"Period($runId.$p1(${ctx.base.phases(p1)}))"
113+
case Period(runId, p1, pn) => s"Period($runId.$p1(${ctx.base.phases(p1)})-$pn(${ctx.base.phases(pn)}))"
114+
115+
override def toString: String = this match
116+
case Nowhere => "Nowhere"
117+
case InitialPeriod => "InitialPeriod"
118+
case InvalidPeriod => "InvalidPeriod"
119+
case Period(NoRunId, 0, PhaseMask) => s"Period(NoRunId.all)"
120+
case Period(runId, 0, PhaseMask) => s"Period($runId.all)"
121+
case Period(runId, p1, pn) if p1 == pn => s"Period($runId.$p1)"
122+
case Period(runId, p1, pn) => s"Period($runId.$p1-$pn)"
101123

102124
def ==(that: Period): Boolean = this.code == that.code
103125
def !=(that: Period): Boolean = this.code != that.code
@@ -116,6 +138,17 @@ object Periods {
116138
/** The interval consisting of all periods of given run id */
117139
def allInRun(rid: RunId): Period =
118140
apply(rid, 0, PhaseMask)
141+
142+
def unapply(p: Period): Extractor = new Extractor(p.code)
143+
144+
final class Extractor(private val code: Int) extends AnyVal {
145+
private def p = new Period(code)
146+
def isEmpty: false = false
147+
def get: this.type = this
148+
def _1 = p.runId
149+
def _2 = p.firstPhaseId
150+
def _3 = p.lastPhaseId
151+
}
119152
}
120153

121154
inline val NowhereCode = 0

compiler/src/dotty/tools/dotc/printing/Formatting.scala

+37-16
Original file line numberDiff line numberDiff line change
@@ -24,17 +24,27 @@ object Formatting {
2424
object Shown:
2525
given [A: Show]: Conversion[A, Shown] = Show[A].show(_)
2626

27+
extension (s: Shown)
28+
def runCtxShow(using Context): Shown = s match
29+
case cs: CtxShow => cs.run
30+
case _ => s
31+
32+
def toStr(x: Shown)(using Context): String = x match
33+
case seq: Seq[?] => seq.map(toStr).mkString("[", ", ", "]")
34+
case res => res.tryToShow
35+
36+
import Shown.runCtxShow
37+
2738
sealed abstract class Show[-T]:
2839
/** Show a value T by returning a "shown" result. */
2940
def show(x: T): Shown
3041

3142
trait CtxShow:
3243
def run(using Context): Shown
3344

34-
extension (s: Shown)
35-
def ctxShow(using Context): Shown = s match
36-
case cs: CtxShow => cs.run
37-
case _ => s
45+
private inline def CtxShow(inline x: Context ?=> Shown) = new CtxShow { def run(using Context) = x(using ctx) }
46+
private def toStr[A: Show](x: A)(using Context): String = Shown.toStr(toShown(x))
47+
private def toShown[A: Show](x: A)(using Context): Shown = Show[A].show(x).runCtxShow
3848

3949
/** The base implementation, passing the argument to StringFormatter which will try to `.show` it. */
4050
object ShowAny extends Show[Any]:
@@ -54,16 +64,26 @@ object Formatting {
5464
object Show extends ShowImplicits1:
5565
inline def apply[A](using inline z: Show[A]): Show[A] = z
5666

67+
given [X: Show]: Show[Option[X]] with
68+
def show(x: Option[X]) =
69+
CtxShow(x.map(toStr))
70+
end given
71+
5772
given [X: Show]: Show[Seq[X]] with
58-
def show(x: Seq[X]) = new CtxShow:
59-
def run(using Context) = x.map(show1)
73+
def show(x: Seq[X]) = CtxShow(x.map(toStr))
74+
75+
given [K: Show, V: Show]: Show[Map[K, V]] with
76+
def show(x: Map[K, V]) =
77+
CtxShow(x.map((k, v) => s"${toStr(k)} => ${toStr(v)}"))
78+
end given
6079

6180
given [H: Show, T <: Tuple: Show]: Show[H *: T] with
62-
def show(x: H *: T) = new CtxShow:
63-
def run(using Context) = show1(x.head) *: Show[T].show(x.tail).ctxShow.asInstanceOf[Tuple]
81+
def show(x: H *: T) =
82+
CtxShow(toStr(x.head) *: toShown(x.tail).asInstanceOf[Tuple])
83+
end given
6484

6585
given [X: Show]: Show[X | Null] with
66-
def show(x: X | Null) = if x == null then "null" else Show[X].show(x.nn)
86+
def show(x: X | Null) = if x == null then "null" else CtxShow(toStr(x.nn))
6787

6888
given Show[FlagSet] with
6989
def show(x: FlagSet) = x.flagsString
@@ -79,7 +99,13 @@ object Formatting {
7999
case ast.TreeInfo.Impure => "PurityLevel.Impure"
80100
case ast.TreeInfo.PurePath => "PurityLevel.PurePath"
81101
case ast.TreeInfo.IdempotentPath => "PurityLevel.IdempotentPath"
82-
case _ => s"PurityLevel(${x.x})"
102+
case _ => s"PurityLevel(${x.x.toBinaryString})"
103+
104+
given Show[Atoms] with
105+
def show(x: Atoms) = x match
106+
case Atoms.Unknown => "Unknown"
107+
case Atoms.Range(lo, hi) => CtxShow(s"Range(${toStr(lo.toList)}, ${toStr(hi.toList)})")
108+
end given
83109

84110
given Show[Showable] = ShowAny
85111
given Show[Shown] = ShowAny
@@ -101,11 +127,6 @@ object Formatting {
101127
given Show[util.Spans.Span] = ShowAny
102128
given Show[tasty.TreeUnpickler#OwnerTree] = ShowAny
103129
given Show[typer.ForceDegree.Value] = ShowAny
104-
105-
private def show1[A: Show](x: A)(using Context) = show2(Show[A].show(x).ctxShow)
106-
private def show2(x: Shown)(using Context): String = x match
107-
case seq: Seq[?] => seq.map(show2).mkString("[", ", ", "]")
108-
case res => res.tryToShow
109130
end Show
110131
end ShownDef
111132
export ShownDef.{ Show, Shown }
@@ -122,7 +143,7 @@ object Formatting {
122143
class StringFormatter(protected val sc: StringContext) {
123144
protected def showArg(arg: Any)(using Context): String = arg.tryToShow
124145

125-
private def treatArg(arg: Shown, suffix: String)(using Context): (String, String) = arg.ctxShow match {
146+
private def treatArg(arg: Shown, suffix: String)(using Context): (String, String) = arg.runCtxShow match {
126147
case arg: Seq[?] if suffix.indexOf('%') == 0 && suffix.indexOf('%', 1) != -1 =>
127148
val end = suffix.indexOf('%', 1)
128149
val sep = StringContext.processEscapes(suffix.substring(1, end))

compiler/src/dotty/tools/dotc/transform/patmat/Space.scala

+4-4
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,7 @@ object SpaceEngine {
115115
def decompose(typ: Typ)(using Context): List[Typ] = typ.decompose
116116

117117
/** Simplify space such that a space equal to `Empty` becomes `Empty` */
118-
def computeSimplify(space: Space)(using Context): Space = trace(s"simplify($space)")(space match {
118+
def computeSimplify(space: Space)(using Context): Space = trace(i"simplify($space)")(space match {
119119
case Prod(tp, fun, spaces) =>
120120
val sps = spaces.mapconserve(simplify)
121121
if sps.contains(Empty) then Empty
@@ -166,7 +166,7 @@ object SpaceEngine {
166166
}
167167

168168
/** Is `a` a subspace of `b`? Equivalent to `simplify(simplify(a) - simplify(b)) == Empty`, but faster */
169-
def computeIsSubspace(a: Space, b: Space)(using Context): Boolean = trace(s"isSubspace($a, $b)") {
169+
def computeIsSubspace(a: Space, b: Space)(using Context): Boolean = trace(i"isSubspace($a, $b)") {
170170
val a2 = simplify(a)
171171
val b2 = simplify(b)
172172
if (a ne a2) || (b ne b2) then isSubspace(a2, b2)
@@ -194,7 +194,7 @@ object SpaceEngine {
194194
}
195195

196196
/** Intersection of two spaces */
197-
def intersect(a: Space, b: Space)(using Context): Space = trace(s"$a & $b") {
197+
def intersect(a: Space, b: Space)(using Context): Space = trace(i"intersect($a & $b)") {
198198
(a, b) match {
199199
case (Empty, _) | (_, Empty) => Empty
200200
case (_, Or(ss)) => Or(ss.map(intersect(a, _)).filter(_ ne Empty))
@@ -219,7 +219,7 @@ object SpaceEngine {
219219
}
220220

221221
/** The space of a not covered by b */
222-
def minus(a: Space, b: Space)(using Context): Space = trace(s"$a - $b") {
222+
def minus(a: Space, b: Space)(using Context): Space = trace(i"minus($a - $b)") {
223223
(a, b) match {
224224
case (Empty, _) => Empty
225225
case (_, Empty) => a

0 commit comments

Comments
 (0)