Skip to content

Commit 6a50e5c

Browse files
committed
REPL class loader is context class loader
1 parent c01d596 commit 6a50e5c

File tree

3 files changed

+23
-10
lines changed

3 files changed

+23
-10
lines changed

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

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ import dotty.tools.dotc.util.{SourceFile, SourcePosition}
2929
import dotty.tools.dotc.{CompilationUnit, Driver}
3030
import dotty.tools.dotc.config.CompilerCommand
3131
import dotty.tools.io._
32+
import dotty.tools.runner.ScalaClassLoader.*
3233
import org.jline.reader._
3334

3435
import scala.annotation.tailrec
@@ -62,7 +63,7 @@ case class State(objectIndex: Int,
6263
/** Main REPL instance, orchestrating input, compilation and presentation */
6364
class ReplDriver(settings: Array[String],
6465
out: PrintStream = Console.out,
65-
classLoader: Option[ClassLoader] = None) extends Driver {
66+
classLoader: Option[ClassLoader] = None) extends Driver:
6667

6768
/** Overridden to `false` in order to not have to give sources on the
6869
* commandline
@@ -161,15 +162,17 @@ class ReplDriver(settings: Array[String],
161162
else loop(interpret(res)(state))
162163
}
163164

164-
try withRedirectedOutput { loop(initialState) }
165+
try runBody { loop(initialState) }
165166
finally terminal.close()
166167
}
167168

168-
final def run(input: String)(implicit state: State): State = withRedirectedOutput {
169+
final def run(input: String)(implicit state: State): State = runBody {
169170
val parsed = ParseResult(input)(state)
170171
interpret(parsed)
171172
}
172173

174+
private def runBody(body: => State): State = rendering.classLoader()(using rootCtx).asContext(withRedirectedOutput(body))
175+
173176
// TODO: i5069
174177
final def bind(name: String, value: Any)(implicit state: State): State = state
175178

@@ -455,4 +458,5 @@ class ReplDriver(settings: Array[String],
455458
private def printDiagnostic(dia: Diagnostic)(implicit state: State) = dia.level match
456459
case interfaces.Diagnostic.INFO => out.println(dia.msg) // print REPL's special info diagnostics directly to out
457460
case _ => ReplConsoleReporter.doReport(dia)(using state.context)
458-
}
461+
462+
end ReplDriver

compiler/src/dotty/tools/runner/ScalaClassLoader.scala

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -14,12 +14,8 @@ import scala.annotation.tailrec
1414
import scala.util.control.Exception.catching
1515

1616
final class RichClassLoader(private val self: ClassLoader) extends AnyVal {
17-
/** Executing an action with this classloader as context classloader */
18-
private def asContext[T](action: => T): T = {
19-
val saved = Thread.currentThread.getContextClassLoader
20-
try { ScalaClassLoader.setContext(self) ; action }
21-
finally ScalaClassLoader.setContext(saved)
22-
}
17+
/** Execute an action with this classloader as context classloader. */
18+
private def asContext[T](action: => T): T = ScalaClassLoader.asContext(self)(action)
2319

2420
/** Load and link a class with this classloader */
2521
def tryToLoadClass[T <: AnyRef](path: String): Option[Class[T]] = tryClass(path, initialize = false)
@@ -74,4 +70,13 @@ object ScalaClassLoader {
7470
MethodHandles.lookup().findStatic(classOf[ClassLoader], "getPlatformClassLoader", MethodType.methodType(classOf[ClassLoader])).invoke().asInstanceOf[ClassLoader]
7571
catch case _: Throwable => null
7672
else null
73+
74+
extension (classLoader: ClassLoader)
75+
/** Execute an action with this classloader as context classloader. */
76+
def asContext[T](action: => T): T =
77+
val saved = Thread.currentThread.getContextClassLoader
78+
try
79+
setContext(classLoader)
80+
action
81+
finally setContext(saved)
7782
}

compiler/test/dotty/tools/repl/ReplCompilerTests.scala

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -241,6 +241,10 @@ class ReplCompilerTests extends ReplTest {
241241
... 28 elided
242242
*/
243243
}
244+
@Test def `i14281 context class loader must be REPL class loader` = fromInitialState { implicit state =>
245+
run("class C ; assert(classOf[C].getClassLoader eq Thread.currentThread.getContextClassLoader)")
246+
assertEquals(List("// defined class C"), lines())
247+
}
244248
}
245249

246250
object ReplCompilerTests {

0 commit comments

Comments
 (0)