Skip to content

Commit 350733e

Browse files
committed
REPL - invoke pprint reflectively
fixes #24111 reset the print function each time the classloader resets, if cant load reflectively, then fallback to calling directly.
1 parent a7bbe58 commit 350733e

File tree

1 file changed

+43
-1
lines changed

1 file changed

+43
-1
lines changed

compiler/src/dotty/tools/repl/Rendering.scala

Lines changed: 43 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,47 @@ private[repl] class Rendering(parentClassLoader: Option[ClassLoader] = None):
2626

2727
var myClassLoader: AbstractFileClassLoader = uninitialized
2828

29+
private var pprintState: ((Any, Int, Int, Int) => String) | Null = null
30+
private def pprintRender(value: Any, width: Int, height: Int, initialOffset: Int)(using Context): String = {
31+
def fallback = (value: Any, width: Int, height: Int, initialOffset: Int) =>
32+
dotty.shaded.pprint.PPrinter.BlackWhite.apply(
33+
value, width = 100, height = 50, initialOffset = initialOffset
34+
).plainText
35+
val cl = classLoader()
36+
val firstTry = pprintState
37+
val lambda =
38+
if firstTry == null then
39+
val loaded: (Any, Int, Int, Int) => String = try
40+
val pprintCls = Class.forName("dotty.shaded.pprint.PPrinter$BlackWhite$", false, cl)
41+
val BlackWhite = pprintCls.getField("MODULE$").get(null)
42+
val BlackWhite_apply = pprintCls.getMethod("apply",
43+
classOf[Any], // value
44+
classOf[Int], // width
45+
classOf[Int], // height
46+
classOf[Int], // indentation
47+
classOf[Int], // initialOffset
48+
classOf[Boolean], // escape Unicode
49+
classOf[Boolean], // show field names
50+
)
51+
val fansiStrCls = Class.forName("dotty.shaded.fansi.Str", false, cl)
52+
val FansiStr_plainText = fansiStrCls.getMethod("plainText")
53+
{(value: Any, width: Int, height: Int, initialOffset: Int) =>
54+
val fansiStr = BlackWhite_apply.invoke(
55+
BlackWhite, value, width, height, 2, initialOffset, false, true
56+
)
57+
FansiStr_plainText.invoke(fansiStr).asInstanceOf[String]
58+
}
59+
catch
60+
case _: ClassNotFoundException => fallback
61+
case _: NoSuchMethodException => fallback
62+
pprintState = loaded
63+
loaded
64+
else firstTry
65+
end lambda
66+
67+
lambda(value, width, height, initialOffset)
68+
}
69+
2970

3071
/** Class loader used to load compiled code */
3172
private[repl] def classLoader()(using Context) =
@@ -44,6 +85,7 @@ private[repl] class Rendering(parentClassLoader: Option[ClassLoader] = None):
4485
}
4586

4687
myClassLoader = new AbstractFileClassLoader(ctx.settings.outputDir.value, parent)
88+
pprintState = null // reset pprint if we change classloader
4789
myClassLoader
4890
}
4991

@@ -55,7 +97,7 @@ private[repl] class Rendering(parentClassLoader: Option[ClassLoader] = None):
5597
/** Return a String representation of a value we got from `classLoader()`. */
5698
private[repl] def replStringOf(sym: Symbol, value: Object)(using Context): String = {
5799
// pretty-print things with 100 cols 50 rows by default,
58-
dotty.shaded.pprint.PPrinter.BlackWhite.apply(value, width = 100, height = 50).plainText
100+
pprintRender(value, width = 100, height = 50, initialOffset = 0 /* TODO: include offset */)
59101
}
60102

61103
/** Load the value of the symbol using reflection.

0 commit comments

Comments
 (0)