Skip to content

Commit 9b8c2ff

Browse files
committed
Fix scala#8020: Create dotty-tasty-consumer library
1 parent 7d756f4 commit 9b8c2ff

File tree

34 files changed

+189
-136
lines changed

34 files changed

+189
-136
lines changed

.drone.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ steps:
4040
depends_on: [ clone ]
4141
commands:
4242
- cp -R . /tmp/2/ && cd /tmp/2/
43-
- ./project/scripts/sbt ";dotty-bootstrapped/compile ;dotty-bootstrapped/test ;dotty-staging/test ;sjsSandbox/run;sjsSandbox/test;sjsJUnitTests/test ;configureIDE"
43+
- ./project/scripts/sbt ";dotty-bootstrapped/compile ;dotty-bootstrapped/test ;dotty-staging/test ;dotty-tasty-consumer/test ;dotty-tastydoc/test ;sjsSandbox/run;sjsSandbox/test;sjsJUnitTests/test ;configureIDE"
4444
- ./project/scripts/bootstrapCmdTests
4545

4646
- name: community_build

build.sbt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ val `dotty-library-bootstrappedJS` = Build.`dotty-library-bootstrappedJS`
1111
val `dotty-sbt-bridge` = Build.`dotty-sbt-bridge`
1212
val `dotty-sbt-bridge-tests` = Build.`dotty-sbt-bridge-tests`
1313
val `dotty-staging` = Build.`dotty-staging`
14+
val `dotty-tasty-consumer` = Build.`dotty-tasty-consumer`
1415
val `dotty-language-server` = Build.`dotty-language-server`
1516
val `dotty-bench` = Build.`dotty-bench`
1617
val `dotty-bench-bootstrapped` = Build.`dotty-bench-bootstrapped`

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

Lines changed: 0 additions & 55 deletions
This file was deleted.
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
package dotty.tools.dotc.util
2+
3+
import java.net.URLClassLoader
4+
import java.nio.file.Paths
5+
6+
import dotty.tools.repl.AbstractFileClassLoader
7+
8+
object ClasspathFromClassloader {
9+
10+
/** Attempt to recreate a classpath from a classloader.
11+
*
12+
* BEWARE: with exotic enough classloaders, this may not work at all or do
13+
* the wrong thing.
14+
*/
15+
def apply(cl: ClassLoader): String = {
16+
val classpathBuff = List.newBuilder[String]
17+
def collectClassLoaderPaths(cl: ClassLoader): Unit = {
18+
if (cl != null) {
19+
cl match {
20+
case cl: URLClassLoader =>
21+
// This is wrong if we're in a subclass of URLClassLoader
22+
// that filters loading classes from its parent ¯\_(ツ)_/¯
23+
collectClassLoaderPaths(cl.getParent)
24+
// Parent classloaders are searched before their child, so the part of
25+
// the classpath coming from the child is added at the _end_ of the
26+
// classpath.
27+
classpathBuff ++=
28+
cl.getURLs.iterator.map(url => Paths.get(url.toURI).toAbsolutePath.toString)
29+
case _ =>
30+
// HACK: We can't just collect the classpath from arbitrary parent
31+
// classloaders since the current classloader might intentionally
32+
// filter loading classes from its parent (for example
33+
// BootFilteredLoader in the sbt launcher does this and we really
34+
// don't want to include the scala-library that sbt depends on
35+
// here), but we do need to look at the parent of the REPL
36+
// classloader, so we special case it. We can't do this using a type
37+
// test since the REPL classloader class itself is normally loaded
38+
// with a different classloader.
39+
if (cl.getClass.getName == classOf[AbstractFileClassLoader].getName)
40+
collectClassLoaderPaths(cl.getParent)
41+
}
42+
}
43+
}
44+
collectClassLoaderPaths(cl)
45+
classpathBuff.result().mkString(java.io.File.pathSeparator)
46+
}
47+
}

compiler/test/dotty/Properties.scala

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,9 @@ object Properties {
5353
/** dotty-staging jar */
5454
def dottyStaging: String = sys.props("dotty.tests.classes.dottyStaging")
5555

56+
/** dotty-tasty-consumer jar */
57+
def dottyTastyConsumer: String = sys.props("dotty.tests.classes.dottyTastyConsumer")
58+
5659
/** tasty-core jar */
5760
def tastyCore: String = sys.props("dotty.tests.classes.tastyCore")
5861

compiler/test/dotty/tools/dotc/BootstrappedOnlyCompilationTests.scala

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -127,7 +127,8 @@ class BootstrappedOnlyCompilationTests extends ParallelTesting {
127127
aggregateTests(
128128
compileFilesInDir("tests/run-with-compiler", withCompilerOptions),
129129
compileFilesInDir("tests/run-staging", withStagingOptions),
130-
compileDir("tests/run-with-compiler-custom-args/tasty-interpreter", withCompilerOptions)
130+
compileFilesInDir("tests/run-custom-args/tasty-consumer", withTastyConsumerOptions),
131+
compileDir("tests/run-custom-args/tasty-interpreter", withTastyConsumerOptions),
131132
).checkRuns()
132133
}
133134

compiler/test/dotty/tools/vulpix/TestConfiguration.scala

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,9 @@ object TestConfiguration {
3939
lazy val withStagingClasspath =
4040
withCompilerClasspath + File.pathSeparator + mkClasspath(List(Properties.dottyStaging))
4141

42+
lazy val withTastyConsumerClasspath =
43+
withCompilerClasspath + File.pathSeparator + mkClasspath(List(Properties.dottyTastyConsumer))
44+
4245
def mkClasspath(classpaths: List[String]): String =
4346
classpaths.map({ p =>
4447
val file = new java.io.File(p)
@@ -54,6 +57,8 @@ object TestConfiguration {
5457
defaultOptions.withClasspath(withCompilerClasspath).withRunClasspath(withCompilerClasspath)
5558
lazy val withStagingOptions =
5659
defaultOptions.withClasspath(withStagingClasspath).withRunClasspath(withStagingClasspath)
60+
lazy val withTastyConsumerOptions =
61+
defaultOptions.withClasspath(withTastyConsumerClasspath).withRunClasspath(withTastyConsumerClasspath)
5762
val allowDeepSubtypes = defaultOptions without "-Yno-deep-subtypes"
5863
val allowDoubleBindings = defaultOptions without "-Yno-double-bindings"
5964
val picklingOptions = defaultOptions and (

dist/bin/common

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,7 @@ DOTTY_COMP=$(find_lib "*dotty-compiler*")
108108
DOTTY_INTF=$(find_lib "*dotty-interfaces*")
109109
DOTTY_LIB=$(find_lib "*dotty-library*")
110110
DOTTY_STAGING=$(find_lib "*dotty-staging*")
111+
DOTTY_CONSUME_TASTY=$(find_lib "*dotty-consume-tasty*")
111112
TASTY_CORE=$(find_lib "*tasty-core*")
112113
SCALA_ASM=$(find_lib "*scala-asm*")
113114
SCALA_LIB=$(find_lib "*scala-library*")

dist/bin/dotr

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,7 @@ elif [ $execute_repl == true ] || [ ${#residual_args[@]} -ne 0 ]; then
102102
echo "warning: multiple classpaths are found, dotr only use the last one."
103103
fi
104104
if [ $with_compiler == true ]; then
105-
cp_arg+="$PSEP$DOTTY_COMP$PSEP$TASTY_CORE$PSEP$DOTTY_INTF$PSEP$SCALA_ASM$PSEP$DOTTY_STAGING"
105+
cp_arg+="$PSEP$DOTTY_COMP$PSEP$TASTY_CORE$PSEP$DOTTY_INTF$PSEP$SCALA_ASM$PSEP$DOTTY_STAGING$PSEP$DOTTY_CONSUME_TASTY"
106106
fi
107107
eval exec "\"$JAVACMD\"" "$DEBUG" "-classpath \"$cp_arg\"" "${jvm_options[@]}" "${residual_args[@]}"
108108
else

docs/docs/reference/metaprogramming/tasty-inspect.md

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,10 @@ layout: doc-page
33
title: "TASTy Inspection"
44
---
55

6+
```scala
7+
libraryDependencies += "ch.epfl.lamp" %% "dotty-tasty-consumer" % scalaVersion.value
8+
```
9+
610
TASTy files contain the full typed tree of a class including source positions
711
and documentation. This is ideal for tools that analyze or extract semantic
812
information of the code. To avoid the hassle of working directly with the TASTy
@@ -16,6 +20,9 @@ To inspect the TASTy Reflect trees of a TASTy file a consumer can be defined in
1620
the following way.
1721

1822
```scala
23+
import scala.tasty.Reflection
24+
import scala.tasty.file._
25+
1926
class Consumer extends TastyConsumer {
2027
final def apply(reflect: Reflection)(root: reflect.Tree): Unit = {
2128
import reflect._
@@ -33,4 +40,12 @@ object Test {
3340
ConsumeTasty("", List("foo.Bar"), new Consumer)
3441
}
3542
}
36-
```
43+
```
44+
45+
Note that if we need to run the main (in an object called `Test`) after
46+
compilation we need make available the compiler to the runtime:
47+
48+
```shell
49+
dotc -with-compiler -d out Test.scala
50+
dotr -with-compiler -classpath out Test
51+
```

library/src/scala/tasty/file/ConsumeTasty.scala

Lines changed: 0 additions & 26 deletions
This file was deleted.

project/Build.scala

Lines changed: 26 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -595,9 +595,10 @@ object Build {
595595
val asm = findArtifactPath(externalDeps, "scala-asm")
596596
val dottyCompiler = jars("dotty-compiler")
597597
val dottyStaging = jars("dotty-staging")
598+
val dottyTastyConsumer = jars("dotty-tasty-consumer")
598599
val dottyInterfaces = jars("dotty-interfaces")
599600
val tastyCore = jars("tasty-core")
600-
run(insertClasspathInArgs(args1, List(dottyCompiler, dottyInterfaces, asm, dottyStaging, tastyCore).mkString(File.pathSeparator)))
601+
run(insertClasspathInArgs(args1, List(dottyCompiler, dottyInterfaces, asm, dottyStaging, dottyTastyConsumer, tastyCore).mkString(File.pathSeparator)))
601602
} else run(args)
602603
},
603604

@@ -671,9 +672,10 @@ object Build {
671672
}
672673
val dottyInterfaces = jars("dotty-interfaces")
673674
val dottyStaging = jars("dotty-staging")
675+
val dottyTastyConsumer = jars("dotty-tasty-consumer")
674676
val tastyCore = jars("tasty-core")
675677
val asm = findArtifactPath(externalDeps, "scala-asm")
676-
extraClasspath ++= Seq(dottyCompiler, dottyInterfaces, asm, dottyStaging, tastyCore)
678+
extraClasspath ++= Seq(dottyCompiler, dottyInterfaces, asm, dottyStaging, dottyTastyConsumer, tastyCore)
677679
}
678680

679681
val fullArgs = main :: insertClasspathInArgs(args, extraClasspath.mkString(File.pathSeparator))
@@ -715,14 +717,18 @@ object Build {
715717
)
716718

717719
lazy val bootstrapedDottyCompilerSettings = commonDottyCompilerSettings ++ Seq(
718-
javaOptions += {
720+
javaOptions ++= {
719721
val jars = packageAll.value
720-
"-Ddotty.tests.classes.dottyStaging=" + jars("dotty-staging")
722+
Seq(
723+
"-Ddotty.tests.classes.dottyStaging=" + jars("dotty-staging"),
724+
"-Ddotty.tests.classes.dottyTastyConsumer=" + jars("dotty-tasty-consumer"),
725+
)
721726
},
722727
packageAll := {
723728
packageAll.in(`dotty-compiler`).value ++ Seq(
724729
"dotty-compiler" -> packageBin.in(Compile).value.getAbsolutePath,
725730
"dotty-staging" -> packageBin.in(LocalProject("dotty-staging"), Compile).value.getAbsolutePath,
731+
"dotty-tasty-consumer" -> packageBin.in(LocalProject("dotty-tasty-consumer"), Compile).value.getAbsolutePath,
726732
"tasty-core" -> packageBin.in(LocalProject("tasty-core-bootstrapped"), Compile).value.getAbsolutePath,
727733
)
728734
}
@@ -803,6 +809,19 @@ object Build {
803809
javaOptions := (javaOptions in `dotty-compiler-bootstrapped`).value
804810
)
805811

812+
lazy val `dotty-tasty-consumer` = project.in(file("tasty-consumer")).
813+
withCommonSettings(Bootstrapped).
814+
// We want the compiler to be present in the compiler classpath when compiling this project but not
815+
// when compiling a project that depends on dotty-tasty-consumer (see sbt-dotty/sbt-test/sbt-dotty/tasty-consumer-example-project),
816+
// but we always need it to be present on the JVM classpath at runtime.
817+
dependsOn(dottyCompiler(Bootstrapped) % "provided").
818+
dependsOn(dottyCompiler(Bootstrapped) % "compile->runtime").
819+
dependsOn(dottyCompiler(Bootstrapped) % "test->test").
820+
settings(commonBootstrappedSettings).
821+
settings(
822+
javaOptions := (javaOptions in `dotty-compiler-bootstrapped`).value
823+
)
824+
806825
lazy val `dotty-sbt-bridge` = project.in(file("sbt-bridge/src")).
807826
// We cannot depend on any bootstrapped project to compile the bridge, since the
808827
// bridge is needed to compile these projects.
@@ -1106,6 +1125,7 @@ object Build {
11061125
publishLocal in `dotty-library-bootstrapped`,
11071126
publishLocal in `tasty-core-bootstrapped`,
11081127
publishLocal in `dotty-staging`,
1128+
publishLocal in `dotty-tasty-consumer`,
11091129
publishLocal in `scala-library`,
11101130
publishLocal in `scala-reflect`,
11111131
publishLocal in `dotty-doc-bootstrapped`,
@@ -1315,7 +1335,7 @@ object Build {
13151335
// FIXME: we do not aggregate `bin` because its tests delete jars, thus breaking other tests
13161336
def asDottyRoot(implicit mode: Mode): Project = project.withCommonSettings.
13171337
aggregate(`dotty-interfaces`, dottyLibrary, dottyCompiler, tastyCore, dottyDoc, `dotty-sbt-bridge`).
1318-
bootstrappedAggregate(`scala-library`, `scala-compiler`, `scala-reflect`, scalap, `dotty-language-server`, `dotty-staging`).
1338+
bootstrappedAggregate(`scala-library`, `scala-compiler`, `scala-reflect`, scalap, `dotty-language-server`, `dotty-staging`, `dotty-tasty-consumer`).
13191339
dependsOn(tastyCore).
13201340
dependsOn(dottyCompiler).
13211341
dependsOn(dottyLibrary).
@@ -1354,6 +1374,7 @@ object Build {
13541374
def asDottyTastydoc(implicit mode: Mode): Project = project.withCommonSettings.
13551375
aggregate(`dotty-tastydoc-input`).
13561376
dependsOn(dottyCompiler).
1377+
dependsOn(`dotty-tasty-consumer`).
13571378
settings(commonDocSettings)
13581379

13591380
def asDottyTastydocInput(implicit mode: Mode): Project = project.withCommonSettings.
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
package hello
2+
3+
import scala.tasty.Reflection
4+
import scala.tasty.file._
5+
6+
object Main extends App {
7+
8+
9+
class Consumer extends TastyConsumer {
10+
final def apply(reflect: Reflection)(root: reflect.Tree): Unit = {
11+
import reflect._
12+
val tastyStr = root.show
13+
println(tastyStr)
14+
}
15+
}
16+
17+
ConsumeTasty("", List("lib.Foo"), new Consumer)
18+
19+
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
lazy val dottyVersion = sys.props("plugin.scalaVersion")
2+
3+
lazy val lib = project
4+
.in(file("lib"))
5+
.settings(
6+
scalaVersion := dottyVersion
7+
)
8+
9+
lazy val app = project
10+
.in(file("app"))
11+
.settings(
12+
scalaVersion := dottyVersion,
13+
libraryDependencies += "ch.epfl.lamp" %% "dotty-tasty-consumer" % scalaVersion.value,
14+
)
15+
.dependsOn(lib)
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
package lib
2+
3+
class Foo {
4+
def foo(x: Int) = x
5+
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
addSbtPlugin("ch.epfl.lamp" % "sbt-dotty" % sys.props("plugin.version"))
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
> app/run

0 commit comments

Comments
 (0)