From bbbe580d1e79c8c3fd578f1b1914cfc17c06257e Mon Sep 17 00:00:00 2001 From: Jamie Thompson Date: Wed, 1 Oct 2025 17:51:49 +0200 Subject: [PATCH] REPL - invoke pprint reflectively fixes https://github.com/scala/scala3/issues/24111 reflectively load the function each time, (i.e. don't cache). As this is a rare event (i.e user interaction), any cost is less of a concern. if cant load reflectively, then fallback to calling directly. --- compiler/src/dotty/tools/repl/Rendering.scala | 31 ++++++++++++++++++- 1 file changed, 30 insertions(+), 1 deletion(-) diff --git a/compiler/src/dotty/tools/repl/Rendering.scala b/compiler/src/dotty/tools/repl/Rendering.scala index 238353867516..7151db30f371 100644 --- a/compiler/src/dotty/tools/repl/Rendering.scala +++ b/compiler/src/dotty/tools/repl/Rendering.scala @@ -26,6 +26,35 @@ private[repl] class Rendering(parentClassLoader: Option[ClassLoader] = None): var myClassLoader: AbstractFileClassLoader = uninitialized + private def pprintRender(value: Any, width: Int, height: Int, initialOffset: Int)(using Context): String = { + def fallback() = + dotty.shaded.pprint.PPrinter.BlackWhite.apply( + value, width = width, height = height, initialOffset = initialOffset + ).plainText + try + val cl = classLoader() + val pprintCls = Class.forName("dotty.shaded.pprint.PPrinter$BlackWhite$", false, cl) + val fansiStrCls = Class.forName("dotty.shaded.fansi.Str", false, cl) + val BlackWhite = pprintCls.getField("MODULE$").get(null) + val BlackWhite_apply = pprintCls.getMethod("apply", + classOf[Any], // value + classOf[Int], // width + classOf[Int], // height + classOf[Int], // indentation + classOf[Int], // initialOffset + classOf[Boolean], // escape Unicode + classOf[Boolean], // show field names + ) + val FansiStr_plainText = fansiStrCls.getMethod("plainText") + val fansiStr = BlackWhite_apply.invoke( + BlackWhite, value, width, height, 2, initialOffset, false, true + ) + FansiStr_plainText.invoke(fansiStr).asInstanceOf[String] + catch + case _: ClassNotFoundException => fallback() + case _: NoSuchMethodException => fallback() + } + /** Class loader used to load compiled code */ private[repl] def classLoader()(using Context) = @@ -55,7 +84,7 @@ private[repl] class Rendering(parentClassLoader: Option[ClassLoader] = None): /** Return a String representation of a value we got from `classLoader()`. */ private[repl] def replStringOf(sym: Symbol, value: Object)(using Context): String = { // pretty-print things with 100 cols 50 rows by default, - dotty.shaded.pprint.PPrinter.BlackWhite.apply(value, width = 100, height = 50).plainText + pprintRender(value, width = 100, height = 50, initialOffset = 0 /* TODO: include offset */) } /** Load the value of the symbol using reflection.