Skip to content

Commit

Permalink
Improve incorrect classloader reporting in staging
Browse files Browse the repository at this point in the history
* do not println staging crashes to stdout
* enrich the errors coming from the compiler with additional
hints about using the correct classloader
  • Loading branch information
jchyb committed Apr 24, 2024
1 parent 3cad257 commit 1fc3916
Show file tree
Hide file tree
Showing 7 changed files with 52 additions and 2 deletions.
2 changes: 2 additions & 0 deletions compiler/src/dotty/tools/dotc/Run.scala
Original file line number Diff line number Diff line change
Expand Up @@ -661,4 +661,6 @@ object Run {
report.enrichErrorMessage(errorMessage)
else
errorMessage
def doNotEnrichErrorMessage: Unit =
if run != null then run.myEnrichedErrorMessage = true
}
4 changes: 3 additions & 1 deletion staging/src/scala/quoted/staging/QuoteCompiler.scala
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,9 @@ private class QuoteCompiler extends Compiler:

override def newRun(implicit ctx: Context): ExprRun =
reset()
new ExprRun(this, ctx.addMode(Mode.ReadPositions))
val run = new ExprRun(this, ctx.addMode(Mode.ReadPositions))
run.doNotEnrichErrorMessage
run

def outputClassName: TypeName = "Generated$Code$From$Quoted".toTypeName

Expand Down
16 changes: 15 additions & 1 deletion staging/src/scala/quoted/staging/QuoteDriver.scala
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import dotty.tools.dotc.quoted.QuotesCache
import dotty.tools.io.{AbstractFile, Directory, PlainDirectory, VirtualDirectory}
import dotty.tools.repl.AbstractFileClassLoader
import dotty.tools.dotc.reporting._
import dotty.tools.dotc.config.Settings.Setting.value
import dotty.tools.dotc.util.ClasspathFromClassloader
import scala.quoted._
import scala.quoted.staging.Compiler
Expand Down Expand Up @@ -40,7 +41,20 @@ private class QuoteDriver(appClassloader: ClassLoader) extends Driver:
setCompilerSettings(ctx1.fresh.setSetting(ctx1.settings.outputDir, outDir), settings)
}

new QuoteCompiler().newRun(ctx).compileExpr(exprBuilder) match
val compiledExpr =
try
new QuoteCompiler().newRun(ctx).compileExpr(exprBuilder)
catch case ex: dotty.tools.FatalError =>
val enrichedMessage =
s"""An unhandled exception was thrown in the staging compiler.
|This might be caused by using an incorrect classloader
|when creating the `staging.Compiler` instance with `staging.Compiler.make`.
|For details, please refer to the documentation.
|For non-enriched exceptions, compile with -Yno-enrich-error-messages.""".stripMargin
if ctx.settings.YnoEnrichErrorMessages.value(using ctx) then throw ex
else throw new Exception(enrichedMessage, ex)

compiledExpr match
case Right(value) =>
value.asInstanceOf[T]

Expand Down
1 change: 1 addition & 0 deletions tests/run-staging/i19170c.check
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
exception thrown, no additional printlns
16 changes: 16 additions & 0 deletions tests/run-staging/i19170c.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import scala.quoted.*

given staging.Compiler =
staging.Compiler.make(getClass.getClassLoader.getParent) // different classloader that 19170b.scala
class A(i: Int)

def f(i: Expr[Int])(using Quotes): Expr[A] = { '{ new A($i) } }

@main def Test = {
try
val g: Int => A = staging.run { '{ (i: Int) => ${ f('{i}) } } }
println(g(3))
catch case ex: Exception =>
assert(ex.getMessage().startsWith("An unhandled exception was thrown in the staging compiler."), ex.getMessage())
println("exception thrown, no additional printlns")
}
1 change: 1 addition & 0 deletions tests/run-staging/i19176b.check
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
exception thrown, no additional printlns
14 changes: 14 additions & 0 deletions tests/run-staging/i19176b.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import scala.quoted.*

given staging.Compiler =
staging.Compiler.make(getClass.getClassLoader.getParent) // we want to make sure the classloader is incorrect

class A

@main def Test =
try
val f: (A, Int) => Int = staging.run { '{ (q: A, x: Int) => x } }
f(new A, 3)
catch case ex: Exception =>
assert(ex.getMessage().startsWith("An unhandled exception was thrown in the staging compiler."), ex.getMessage())
println("exception thrown, no additional printlns")

0 comments on commit 1fc3916

Please sign in to comment.