-
Notifications
You must be signed in to change notification settings - Fork 1.1k
Add expression compiler #22597
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
Add expression compiler #22597
Conversation
37985f6
to
839713b
Compare
Looks like the tests are not compiling due to usage of newer JDK API? |
I need to configure sbt-jdi-tools to enable JDI on JDK 8. |
55e7262
to
df7f853
Compare
d60954c
to
b207244
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Review of the tests and testing infrastructure so far (everything except the actual compiler/src/
things).
sjs-compiler-tests/test/scala/dotty/tools/dotc/ScalaJSCompilationTests.scala
Outdated
Show resolved
Hide resolved
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
And here's the rest.
11e4259
to
587896a
Compare
debugMode allows to connect to runner processes with JDI
Each time we disconnect the debugger, the child process opens a new port that we must read to connect a new debugger
We use ParallelTesting.cleanup instead
587896a
to
9fcf8f1
Compare
val errorWithNewPos = new Diagnostic.Error(error.msg, newPos) | ||
reportError(stripColor(messageAndPos(errorWithNewPos))) | ||
case _ => | ||
// TODO report the warnings in the expression |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should we report warnings? Maybe let's add a follow up issue later if this really necessary, but I would say it's not.
override def phaseName: String = InsertExpression.name | ||
override def isCheckable: Boolean = false | ||
|
||
// TODO move reflection methods (callMethod, getField, etc) to scala3-library |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's maybe create an issue?
This PR migrates the expression compiler from scalacenter/scala-debug-adapter to the scala3 repository. This change was agreed upon a few months ago during a core meeting to simplify the release process. By doing so, we eliminate the need to release parts of scalacenter/scala-debug-adapter during each Scala 3 release.
The
ExpressionCompiler
andExpressionCompilerBridge
are now parts of the main compiler module. This integration streamlines usage for external tools like sbt, Metals, Bloop, IJ Scala plugin. They can now rely on the compiler JAR directly without needing to download additional artifacts.The expression compiler
The expression compiler extends the main compiler with 3 phases:
InsertExpression:
def evaluate: Any
method.ExtractExpression:
Typer
, the pickler phases,ExtensionMethods
andElimByName
.LambdaLift
to prevent interference: the expression itself can change how lambdas are lifted. Notably it can contains lambda that needs to be lifted to the expression class.ResolveReflectEval:
reflectEval
calls into actual reflective calls based onReflectEvalStrategy
metadata.Usage of the expression compiler
The expression compiler powers the debug console in Metals and the IJ Scala plugin, enabling evaluation of arbitrary Scala expressions at runtime (even macros). The expression compiler produce class files that can be loaded the running Scala program, to compute the evaluation output.
The
ExpressionCompilerBridge
can be invoked by reflection with the following parameters:outputDir: Path
: Directory where compiled classes are writtenclassPath: String
: Classpath used during compilationoptions: Array[String]
: Compiler optionssourceFile: Path
: Source file where the expression is evaluatedconfig: ExpressionCompilerConfig
:packageName
: Package name of the current evaluation frameoutputClassName: String
: Name of the main generated class, to be loaded by the debuggeebreakpointLine: Int
: Line number where the expression is evaluatedexpression: String
: Expression to compilelocalVariables: Set[String]
: Set of visible local variables (used for checking evaluation of captured variables)errorReporter: Consumer[String]
: Callback for reporting errorsThe
ExpressionCompilerConfig
is designed as a factory class to allow binary-compatible evolution across versions, enabling cross-compatibility between different debugger and compiler versions.The debug tests
A significant part of this PR is the migration of ScalaEvaluationTests, notably the integration with the vulpix test infrastructure:
dotty.tools.vulpix.RunnerOrchestration
:debugMode
to start runners with JVM debugging optionsdebugMain
method to connect a debugger, start a main method and execute the debug stepsdotty.tools.debug.Debugger
: a lightweight implementation of a JVM debuggerdotty.tools.debug.ExpressionEvaluator
: to compile and evaluate expressions insidedotty.tools.debug.Debugger
dotty.tools.debug.DebugStepAssert
: to describe a debug scenario as a series of steps (break
,step
,next
andeval
)dotty.tools.debug.DebugTests
test class:tests/debug
.check
file as a series ofDebugStepAssert
debugMain
, and executes the debug stepsI migrated all relevant tests from ScalaEvaluationTests to
tests/debug
folder. Thanks to Vulpix parallel execution, the 47 debug tests now complete in approximately 30-40 seconds.