Skip to content

Commit c40ec10

Browse files
committed
Add a way to know thew classloader of the class at the callsite
1 parent 55ca222 commit c40ec10

File tree

9 files changed

+69
-33
lines changed

9 files changed

+69
-33
lines changed

compiler/src/dotty/tools/dotc/consumetasty/ConsumeTasty.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ object ConsumeTasty {
1616
new TastyFromClass(tastyConsumer)
1717
}
1818

19-
val currentClasspath = QuoteDriver.currentClasspath
19+
val currentClasspath = QuoteDriver.currentClasspath(getClass.getClassLoader)
2020
import java.io.File.{ pathSeparator => sep }
2121
val args = "-from-tasty" :: "-Yretain-trees" :: "-classpath" :: s"$classpath$sep$currentClasspath" :: classes
2222
(new Consume).process(args.toArray)

compiler/src/dotty/tools/dotc/quoted/QuoteCompiler.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ class QuoteCompiler extends Compiler {
3737
new ExprRun(this, ctx.addMode(Mode.ReadPositions))
3838
}
3939

40-
def outputClassName: TypeName = "Quoted".toTypeName
40+
def outputClassName: TypeName = "Generated$Code$From$Quoted".toTypeName
4141

4242
/** Frontend that receives a scala.quoted.Expr or scala.quoted.Type as input */
4343
class QuotedFrontend(putInClass: Boolean) extends Phase {

compiler/src/dotty/tools/dotc/quoted/QuoteDriver.scala

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,11 @@ import scala.quoted.{Expr, Type}
1111
import scala.quoted.Toolbox
1212
import java.net.URLClassLoader
1313

14-
class QuoteDriver extends Driver {
14+
/** Driver to compile quoted code
15+
*
16+
* @param appClassloader classloader of the application that generated the quotes
17+
*/
18+
class QuoteDriver(appClassloader: ClassLoader) extends Driver {
1519
import tpd._
1620

1721
private[this] val contextBase: ContextBase = new ContextBase
@@ -32,7 +36,9 @@ class QuoteDriver extends Driver {
3236
val driver = new QuoteCompiler
3337
driver.newRun(ctx).compileExpr(expr)
3438

35-
val classLoader = new AbstractFileClassLoader(outDir, this.getClass.getClassLoader)
39+
assert(!ctx.reporter.hasErrors)
40+
41+
val classLoader = new AbstractFileClassLoader(outDir, appClassloader)
3642

3743
val clazz = classLoader.loadClass(driver.outputClassName.toString)
3844
val method = clazz.getMethod("apply")
@@ -82,7 +88,7 @@ class QuoteDriver extends Driver {
8288

8389
override def initCtx: Context = {
8490
val ictx = contextBase.initialCtx
85-
ictx.settings.classpath.update(QuoteDriver.currentClasspath)(ictx)
91+
ictx.settings.classpath.update(QuoteDriver.currentClasspath(appClassloader))(ictx)
8692
ictx
8793
}
8894

@@ -94,9 +100,9 @@ class QuoteDriver extends Driver {
94100

95101
object QuoteDriver {
96102

97-
def currentClasspath: String = {
103+
def currentClasspath(cl: ClassLoader): String = {
98104
val classpath0 = System.getProperty("java.class.path")
99-
this.getClass.getClassLoader match {
105+
cl match {
100106
case cl: URLClassLoader =>
101107
// Loads the classes loaded by this class loader
102108
// When executing `run` or `test` in sbt the classpath is not in the property java.class.path

compiler/src/dotty/tools/dotc/quoted/ToolboxImpl.scala

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,15 @@ import scala.quoted.Exprs.{LiftedExpr, TastyTreeExpr}
99
object ToolboxImpl {
1010
import tpd._
1111

12-
def make(settings: scala.quoted.Toolbox.Settings): scala.quoted.Toolbox = new scala.quoted.Toolbox {
12+
/** Create a new instance of the toolbox using the the classloader of the application.
13+
*
14+
* @param appClassloader classloader of the application that generated the quotes
15+
* @param settings toolbox settings
16+
* @return A new instance of the toolbox
17+
*/
18+
def make(settings: scala.quoted.Toolbox.Settings, appClassloader: ClassLoader): scala.quoted.Toolbox = new scala.quoted.Toolbox {
1319

14-
private[this] val driver: QuoteDriver = new QuoteDriver()
20+
private[this] val driver: QuoteDriver = new QuoteDriver(appClassloader)
1521

1622
def run[T](expr: Expr[T]): T = expr match {
1723
case expr: LiftedExpr[T] =>
@@ -26,4 +32,5 @@ object ToolboxImpl {
2632

2733
def show[T](tpe: Type[T]): String = synchronized(driver.show(tpe, settings))
2834
}
35+
2936
}

compiler/test-resources/repl/i6007

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,7 @@
11
scala> import quoted.Toolbox.Default._
2-
32
scala> val v = '{ (if true then Some(1) else None).map(v => v+1) }
43
val v: quoted.Expr[Option[Int]] = Expr(<pickled tasty>)
5-
64
scala> v.show
7-
val res0: String = if (true) scala.Some.apply[scala.Int](1) else scala.None.map[scala.Int](((v: scala.Int) => v.+(1)))
8-
5+
val res0: String = (if (true) scala.Some.apply[scala.Int](1) else scala.None).map[scala.Int](((v: scala.Int) => v.+(1)))
96
scala> v.run
10-
val res1: Option[Int] = Some(2)
7+
val res1: Option[Int] = Some(2)

library/src/scala/quoted/Toolbox.scala

Lines changed: 27 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -16,15 +16,35 @@ object Toolbox {
1616
implicit def make(implicit settings: Settings): Toolbox = Toolbox.make
1717
}
1818

19-
def make(implicit settings: Settings): Toolbox = {
20-
val cl = getClass.getClassLoader
21-
println(">>>>>")
22-
cl.asInstanceOf[java.net.URLClassLoader].getURLs().toList.foreach(println)
19+
/** Create a new instance of the toolbox.
20+
*
21+
* This instance of the toolbox tries to recover the classloader of the application based on
22+
* the classloader of the class that call make. This may not always be the correct classloader,
23+
* in which case the classloader must be passed explicitly.
24+
*
25+
* @param settings TODO
26+
* @return A new instance of the toolbox
27+
*/
28+
@forceInline def make(implicit settings: Settings): Toolbox = {
29+
// Get the name of the class at call site
30+
val className = new Throwable().getStackTrace.head.getClassName
31+
// We inline to make forName use the classloader of the class at call site
32+
val clazz = Class.forName(className)
33+
val cl = clazz.getClassLoader
34+
make(cl)
35+
}
2336

37+
/** Create a new instance of the toolbox using the the classloader of the application.
38+
*
39+
* @param appClassloader classloader of the application that generated the quotes
40+
* @param settings toolbox settings
41+
* @return A new instance of the toolbox
42+
*/
43+
def make(appClassloader: ClassLoader)(implicit settings: Settings): Toolbox = {
2444
try {
25-
val toolboxImplCls = cl.loadClass("dotty.tools.dotc.quoted.ToolboxImpl")
26-
val makeMeth = toolboxImplCls.getMethod("make", classOf[Settings])
27-
makeMeth.invoke(null, settings).asInstanceOf[Toolbox]
45+
val toolboxImplCls = appClassloader.loadClass("dotty.tools.dotc.quoted.ToolboxImpl")
46+
val makeMeth = toolboxImplCls.getMethod("make", classOf[Settings], classOf[ClassLoader])
47+
makeMeth.invoke(null, settings, appClassloader).asInstanceOf[Toolbox]
2848
}
2949
catch {
3050
case ex: ClassNotFoundException =>

sbt-dotty/sbt-test/sbt-dotty/quoted-example-project/src/main/scala/hello/Hello.scala

Lines changed: 16 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -5,29 +5,35 @@ import scala.quoted._
55

66
object Main {
77

8-
// Needed to run or show quotes
98
implicit val toolbox: scala.quoted.Toolbox = scala.quoted.Toolbox.make
109

1110
def main(args: Array[String]): Unit = {
1211
val square = stagedPower(2)
13-
println("3^2 = " + square(3))
14-
println("4.1^2 = " + square(4.1))
15-
println()
12+
13+
assert(Math.pow(3, 2) == square(3))
14+
15+
square(3)
16+
square(4)
17+
18+
assert(Math.pow(4, 2) == square(4))
19+
1620
val cube = stagedPower(3)
17-
println("2.4^3 = " + cube(2.4))
18-
println()
21+
cube(2)
22+
23+
24+
assert(Math.pow(2, 3) == cube(2))
25+
26+
1927

2028
val toTheFourth = stagedPower(4)
21-
println("3^4 = " + toTheFourth(3))
22-
println()
29+
assert(Math.pow(3, 4) == toTheFourth(3))
2330
}
2431

2532
def stagedPower(n: Int): Double => Double = {
2633
// Code representing the labmda where the recursion is unrolled based on the value of n
2734
val code = '{ (x: Double) => ${powerCode(n, '{x})}}
2835

29-
println(s"staged power for n=" + n + ":")
30-
println(code.show)
36+
code.show
3137

3238
// Evaluate the contents of the code and return it's value
3339
code.run
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
Foo
22
false
33
Bar
4-
class Quoted$A$1
4+
class Generated$Code$From$Quoted$A$1

tests/run-with-compiler/quote-run-with-settings.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ object Test {
1919
println()
2020

2121
val outDir = Paths.get("out/out-quoted-1")
22-
val classFile = outDir.resolve("Quoted.class")
22+
val classFile = outDir.resolve("Generated$Code$From$Quoted.class")
2323

2424
Files.deleteIfExists(classFile)
2525

0 commit comments

Comments
 (0)