Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement :settings in the REPL #13982

Merged
merged 1 commit into from Dec 13, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
4 changes: 2 additions & 2 deletions compiler/src/dotty/tools/dotc/core/MacroClassLoader.scala
Expand Up @@ -23,7 +23,7 @@ object MacroClassLoader {
private def makeMacroClassLoader(using Context): ClassLoader = trace("new macro class loader") {
val entries = ClassPath.expandPath(ctx.settings.classpath.value, expandStar=true)
val urls = entries.map(cp => java.nio.file.Paths.get(cp).toUri.toURL).toArray
val out = ctx.settings.outputDir.value.jpath.toUri.toURL // to find classes in case of suspended compilation
new java.net.URLClassLoader(urls :+ out, getClass.getClassLoader)
val out = Option(ctx.settings.outputDir.value.toURL) // to find classes in case of suspended compilation
new java.net.URLClassLoader(urls ++ out.toList, getClass.getClassLoader)
}
}
Expand Up @@ -18,7 +18,7 @@ import io.AbstractFile
import java.net.{URL, URLConnection, URLStreamHandler}
import java.util.Collections

class AbstractFileClassLoader(root: AbstractFile, parent: ClassLoader) extends ClassLoader(parent):
class AbstractFileClassLoader(val root: AbstractFile, parent: ClassLoader) extends ClassLoader(parent):
private def findAbstractFile(name: String) = root.lookupPath(name.split('/').toIndexedSeq, directory = false)

override protected def findResource(name: String) =
Expand Down
9 changes: 8 additions & 1 deletion compiler/src/dotty/tools/repl/ParseResult.scala
Expand Up @@ -80,6 +80,11 @@ case object Imports extends Command {
val command: String = ":imports"
}

case class Settings(arg: String) extends Command
object Settings {
val command: String = ":settings"
}

/** Reset the session to the initial state from when the repl program was
* started
*/
Expand All @@ -106,6 +111,7 @@ case object Help extends Command {
|:doc <expression> print the documentation for the given expression
|:imports show import history
|:reset reset the repl to its initial state, forgetting all session entries
|:settings <options> update compiler options, if possible
""".stripMargin
}

Expand All @@ -128,7 +134,8 @@ object ParseResult {
Imports.command -> (_ => Imports),
Load.command -> (arg => Load(arg)),
TypeOf.command -> (arg => TypeOf(arg)),
DocOf.command -> (arg => DocOf(arg))
DocOf.command -> (arg => DocOf(arg)),
Settings.command -> (arg => Settings(arg)),
dwijnand marked this conversation as resolved.
Show resolved Hide resolved
)

def apply(source: SourceFile)(implicit state: State): ParseResult = {
Expand Down
6 changes: 3 additions & 3 deletions compiler/src/dotty/tools/repl/Rendering.scala
Expand Up @@ -31,16 +31,16 @@ private[repl] class Rendering(parentClassLoader: Option[ClassLoader] = None) {

private val MaxStringElements: Int = 1000 // no need to mkString billions of elements

private var myClassLoader: ClassLoader = _
private var myClassLoader: AbstractFileClassLoader = _

private var myReplStringOf: Object => String = _


/** Class loader used to load compiled code */
private[repl] def classLoader()(using Context) =
if (myClassLoader != null) myClassLoader
if (myClassLoader != null && myClassLoader.root == ctx.settings.outputDir.value) myClassLoader
else {
val parent = parentClassLoader.getOrElse {
val parent = Option(myClassLoader).orElse(parentClassLoader).getOrElse {
val compilerClasspath = ctx.platform.classPath(using ctx).asURLs
// We can't use the system classloader as a parent because it would
// pollute the user classpath with everything passed to the JVM
Expand Down
19 changes: 19 additions & 0 deletions compiler/src/dotty/tools/repl/ReplDriver.scala
Expand Up @@ -5,8 +5,10 @@ import java.nio.charset.StandardCharsets

import dotty.tools.dotc.ast.Trees._
import dotty.tools.dotc.ast.{tpd, untpd}
import dotty.tools.dotc.config.CommandLineParser.tokenize
import dotty.tools.dotc.config.Properties.{javaVersion, javaVmName, simpleVersionString}
import dotty.tools.dotc.core.Contexts._
import dotty.tools.dotc.core.Decorators._
import dotty.tools.dotc.core.Phases.{unfusedPhases, typerPhase}
import dotty.tools.dotc.core.Denotations.Denotation
import dotty.tools.dotc.core.Flags._
Expand Down Expand Up @@ -414,6 +416,23 @@ class ReplDriver(settings: Array[String],
}
state

case Settings(arg) => arg match
case "" =>
given ctx: Context = state.context
for (s <- ctx.settings.userSetSettings(ctx.settingsState).sortBy(_.name))
out.println(s"${s.name} = ${if s.value == "" then "\"\"" else s.value}")
state
case _ =>
setup(tokenize(arg).toArray, rootCtx) match
case Some((files, ictx)) =>
dwijnand marked this conversation as resolved.
Show resolved Hide resolved
inContext(ictx) {
if files.nonEmpty then out.println(i"Ignoring spurious arguments: $files%, %")
ictx.base.initialize()(using ictx)
rootCtx = ictx
}
case _ =>
state.copy(context = rootCtx)

case Quit =>
// end of the world!
state
Expand Down
16 changes: 16 additions & 0 deletions compiler/test-resources/repl/settings-command
@@ -0,0 +1,16 @@
scala> def f(thread: Thread) = thread.stop()
there were 1 deprecation warning(s); re-run with -deprecation for details
def f(thread: Thread): Unit

scala>:settings -deprecation foo.scala
Ignoring spurious arguments: foo.scala

scala> def f(thread: Thread) = thread.stop()
1 warning found
-- Deprecation Warning: --------------------------------------------------------
1 | def f(thread: Thread) = thread.stop()
| ^^^^^^^^^^^
|method stop in class Thread is deprecated since : see corresponding Javadoc for more information.
def f(thread: Thread): Unit

scala>
18 changes: 18 additions & 0 deletions compiler/test-resources/repl/settings-outputDir
@@ -0,0 +1,18 @@
scala> java.nio.file.Files.exists(java.nio.file.Files.createDirectories(java.nio.file.Paths.get("target", "test-repl-settings-outDir")))
val res0: Boolean = true

scala> val x = 1
val x: Int = 1

scala>:settings -d target/test-repl-settings-outDir

scala> val y = 2
val y: Int = 2

scala> x
val res1: Int = 1

scala> y
val res2: Int = 2

scala> java.nio.file.Files.walk(java.nio.file.Paths.get("target", "test-repl-settings-outDir")).sorted(java.util.Comparator.reverseOrder).forEach(java.nio.file.Files.delete)