From 849b21ac3f2f5d260c910f7e3d88c487d0033fb1 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 | 43 +++++++++++++++---- 1 file changed, 35 insertions(+), 8 deletions(-) diff --git a/compiler/src/dotty/tools/repl/Rendering.scala b/compiler/src/dotty/tools/repl/Rendering.scala index cc1c4bf338ee..314198a1bf97 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,14 +84,12 @@ private[repl] class Rendering(parentClassLoader: Option[ClassLoader] = None): /** Return a String representation of a value we got from `classLoader()`. */ private[repl] def replStringOf(value: Object, prefixLength: Int)(using Context): String = { // pretty-print things with 100 cols 50 rows by default, - dotty.shaded.pprint.PPrinter.BlackWhite - .apply( - value, - width = 100, - height = 50, - initialOffset = prefixLength - ) - .plainText + pprintRender( + value, + width = 100, + height = 50, + initialOffset = prefixLength + ) } /** Load the value of the symbol using reflection.