Skip to content

Commit ad94ab5

Browse files
Merge pull request #5797 from dotty-staging/create-interpreter
Add regression test for tasty reflect case study
2 parents 190f34b + 9a9bbbc commit ad94ab5

18 files changed

+795
-8
lines changed

compiler/src/dotty/tools/dotc/tastyreflect/FlagsOpsImpl.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ trait FlagsOpsImpl extends scala.tasty.reflect.FlagsOps with CoreImpl {
4040
def Contravariant: Flags = core.Flags.Contravariant
4141
def Scala2X: Flags = core.Flags.Scala2x
4242
def DefaultParameterized: Flags = core.Flags.DefaultParameterized
43-
def Stable: Flags = core.Flags.StableRealizable
43+
def StableRealizable: Flags = core.Flags.StableRealizable
4444
def Param: Flags = core.Flags.Param
4545
def ParamAccessor: Flags = core.Flags.ParamAccessor
4646
}

compiler/src/dotty/tools/dotc/tastyreflect/SymbolOpsImpl.scala

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,10 @@ trait SymbolOpsImpl extends scala.tasty.reflect.SymbolOps with CoreImpl {
7676
}
7777
}
7878

79+
def isDefinedInCurrentRun(implicit ctx: Context): Boolean = {
80+
symbol.topLevelClass.asClass.isDefinedInCurrentRun
81+
}
82+
7983
}
8084

8185
object IsPackageSymbol extends IsPackageSymbolModule {
@@ -171,6 +175,10 @@ trait SymbolOpsImpl extends scala.tasty.reflect.SymbolOps with CoreImpl {
171175

172176
def DefSymbolDeco(symbol: DefSymbol): DefSymbolAPI = new DefSymbolAPI {
173177
def tree(implicit ctx: Context): DefDef = FromSymbol.defDefFromSym(symbol)
178+
179+
def signature(implicit ctx: Context): Signature = {
180+
symbol.signature
181+
}
174182
}
175183

176184
object IsValSymbol extends IsValSymbolModule {
@@ -181,6 +189,11 @@ trait SymbolOpsImpl extends scala.tasty.reflect.SymbolOps with CoreImpl {
181189
def ValSymbolDeco(symbol: ValSymbol): ValSymbolAPI = new ValSymbolAPI {
182190
def tree(implicit ctx: Context): ValDef = FromSymbol.valDefFromSym(symbol)
183191

192+
def moduleClass(implicit ctx: Context): Option[ClassSymbol] = {
193+
val sym = symbol.moduleClass
194+
if (sym.exists) Some(sym.asClass) else None
195+
}
196+
184197
def companionClass(implicit ctx: Context): Option[ClassSymbol] = {
185198
val sym = symbol.companionClass
186199
if (sym.exists) Some(sym.asClass) else None

compiler/src/dotty/tools/dotc/tastyreflect/TypeOrBoundsOpsImpl.scala

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@ trait TypeOrBoundsOpsImpl extends scala.tasty.reflect.TypeOrBoundsOps with CoreI
1919
*/
2020
def widen(implicit ctx: Context): Type = tpe.widen
2121

22+
def classSymbol(implicit ctx: Context): Option[ClassSymbol] =
23+
if (tpe.classSymbol.exists) Some(tpe.classSymbol.asClass) else None
2224
}
2325

2426
def ConstantTypeDeco(x: ConstantType): Type.ConstantTypeAPI = new Type.ConstantTypeAPI {

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,7 @@ class BootstrappedOnlyCompilationTests extends ParallelTesting {
8181
@Test def runWithCompiler: Unit = {
8282
implicit val testGroup: TestGroup = TestGroup("runWithCompiler")
8383
compileFilesInDir("tests/run-with-compiler", withCompilerOptions) +
84+
compileDir("tests/run-with-compiler-custom-args/tasty-interpreter", withCompilerOptions) +
8485
compileFile("tests/run-with-compiler-custom-args/staged-streams_1.scala", withCompilerOptions without "-Yno-deep-subtypes")
8586
}.checkRuns()
8687

library/src/scala/tasty/reflect/FlagsOps.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -93,8 +93,8 @@ trait FlagsOps extends Core {
9393
/** Is this symbol a method with default parameters */
9494
def DefaultParameterized: Flags
9595

96-
/** Is this symbol member that is assumed to be stable */
97-
def Stable: Flags
96+
/** Is this symbol member that is assumed to be stable and realizable */
97+
def StableRealizable: Flags
9898

9999
/** Is this symbol a parameter */
100100
def Param: Flags

library/src/scala/tasty/reflect/Printers.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -126,7 +126,7 @@ trait Printers
126126
if (flags.is(Flags.Contravariant)) flagList += "Flags.Contravariant"
127127
if (flags.is(Flags.Scala2X)) flagList += "Flags.Scala2X"
128128
if (flags.is(Flags.DefaultParameterized)) flagList += "Flags.DefaultParameterized"
129-
if (flags.is(Flags.Stable)) flagList += "Flags.Stable"
129+
if (flags.is(Flags.StableRealizable)) flagList += "Flags.StableRealizable"
130130
if (flags.is(Flags.Param)) flagList += "Flags.Param"
131131
if (flags.is(Flags.ParamAccessor)) flagList += "Flags.ParamAccessor"
132132
flagList.result().mkString(" | ")
@@ -501,7 +501,7 @@ trait Printers
501501
if (flags.is(Flags.Contravariant)) flagList += "contravariant"
502502
if (flags.is(Flags.Scala2X)) flagList += "scala2x"
503503
if (flags.is(Flags.DefaultParameterized)) flagList += "defaultParameterized"
504-
if (flags.is(Flags.Stable)) flagList += "stable"
504+
if (flags.is(Flags.StableRealizable)) flagList += "stableRealizable"
505505
if (flags.is(Flags.Param)) flagList += "param"
506506
if (flags.is(Flags.ParamAccessor)) flagList += "paramAccessor"
507507
flagList.result().mkString("/*", " ", "*/")

library/src/scala/tasty/reflect/SymbolOps.scala

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ trait SymbolOps extends Core {
5151
/** Annotations attached to this symbol */
5252
def annots(implicit ctx: Context): List[Term]
5353

54+
def isDefinedInCurrentRun(implicit ctx: Context): Boolean
5455
}
5556
implicit def SymbolDeco(symbol: Symbol): SymbolAPI
5657

@@ -121,7 +122,7 @@ trait SymbolOps extends Core {
121122
}
122123

123124
trait TypeSymbolAPI {
124-
/** TypeDef tree of this defintion. */
125+
/** TypeDef tree of this definition. */
125126
def tree(implicit ctx: Context): TypeDef
126127
}
127128
implicit def TypeSymbolDeco(symbol: TypeSymbol): TypeSymbolAPI
@@ -136,6 +137,8 @@ trait SymbolOps extends Core {
136137
trait DefSymbolAPI {
137138
/** DefDef tree of this defintion. */
138139
def tree(implicit ctx: Context): DefDef
140+
141+
def signature(implicit ctx: Context): Signature
139142
}
140143
implicit def DefSymbolDeco(symbol: DefSymbol): DefSymbolAPI
141144

@@ -151,8 +154,9 @@ trait SymbolOps extends Core {
151154
def tree(implicit ctx: Context): ValDef
152155

153156
/** The class symbol of the companion module class */
154-
def companionClass(implicit ctx: Context): Option[ClassSymbol]
157+
def moduleClass(implicit ctx: Context): Option[ClassSymbol]
155158

159+
def companionClass(implicit ctx: Context): Option[ClassSymbol]
156160
}
157161
implicit def ValSymbolDeco(symbol: ValSymbol): ValSymbolAPI
158162

library/src/scala/tasty/reflect/TypeOrBoundsOps.scala

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ trait TypeOrBoundsOps extends Core {
4444
implicit def TypeLambdaDeco(x: TypeLambda): Type.TypeLambdaAPI
4545

4646
implicit def TypeBoundsDeco(bounds: TypeBounds): TypeBoundsAPI
47-
47+
4848
// ----- Types ----------------------------------------------------
4949

5050
def typeOf[T: scala.quoted.Type]: Type
@@ -53,6 +53,7 @@ trait TypeOrBoundsOps extends Core {
5353
def =:=(other: Type)(implicit ctx: Context): Boolean
5454
def <:<(other: Type)(implicit ctx: Context): Boolean
5555
def widen(implicit ctx: Context): Type
56+
def classSymbol(implicit ctx: Context): Option[ClassSymbol]
5657
}
5758

5859
val IsType: IsTypeModule
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
object IntepretedMain {
2+
def main(args: Array[String]): Unit = {
3+
val x1 = 42
4+
println(x1)
5+
println()
6+
7+
lazy val x2 = println("Hello")
8+
x2
9+
x2
10+
println()
11+
12+
def x3 = 42
13+
println(x3)
14+
println()
15+
16+
var x4: Int = 42
17+
x4 = 43
18+
println(x4)
19+
println()
20+
21+
if(x1 == 42)
22+
println("if")
23+
else
24+
println("else")
25+
println()
26+
27+
var x5 = 5
28+
while(x5 > 0){
29+
println(x5)
30+
x5 = x5 - 1
31+
}
32+
println()
33+
34+
def meth() = 42
35+
println(meth())
36+
println()
37+
38+
def methP(i: Int) = i
39+
println(methP(55))
40+
41+
println(Precompiled)
42+
println(Precompiled.staticMeth)
43+
println(Precompiled.staticVal)
44+
println(Precompiled.staticMeth1())
45+
println(Precompiled.staticMeth2(58))
46+
println(Precompiled.staticMeth3(new Object))
47+
println(Precompiled.staticMeth4(new Bar))
48+
println(Precompiled.staticMeth5(new Bar, 61))
49+
println(Precompiled.staticMeth4(new InterpretedBar))
50+
println(Precompiled.staticMeth5(new InterpretedBar, 62))
51+
52+
val x6: Any = 64
53+
println(x6.isInstanceOf[Int])
54+
println(x6.isInstanceOf[Long])
55+
println(x6.asInstanceOf[Int])
56+
57+
58+
val bar = new Bar
59+
println(bar.meth() + 5)
60+
println(bar.methA(66))
61+
62+
val ibar = new InterpretedBar
63+
println(ibar.meth() + 5)
64+
println(ibar.methA(67))
65+
}
66+
67+
def foo(x: Int): Unit = println(x)
68+
}
69+
70+
class InterpretedBar extends IFace {
71+
def meth(): Int = 62
72+
def methA(x: Int): Int = x + 1
73+
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
2+
class Bar extends IFace {
3+
def meth(): Int = 60
4+
def methA(x: Int): Int = x
5+
}
6+
7+
trait IFace {
8+
def meth(): Int
9+
def methA(x: Int): Int
10+
}
11+
12+
object Precompiled {
13+
def staticMeth = 55
14+
val staticVal = 56
15+
16+
// Todo
17+
def staticMeth1() = 57
18+
def staticMeth2(arg: Int) = arg
19+
def staticMeth3(arg: Object): Int = 59
20+
def staticMeth4(arg: IFace): Int = arg.meth()
21+
def staticMeth5(arg: IFace, x: Int): Int = arg.methA(x)
22+
23+
override def toString() = "precompiledModule"
24+
}
Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
import java.io.{ByteArrayOutputStream, File, PrintStream}
2+
3+
import dotty.tools.dotc.core.Contexts
4+
import dotty.tools.dotc.reporting.Reporter
5+
import dotty.tools.dotc.reporting.diagnostic.MessageContainer
6+
import dotty.tools.dotc.util.DiffUtil
7+
import dotty.tools.io.Path
8+
9+
import scala.io.Source
10+
import scala.tasty.file._
11+
import scala.tasty.interpreter.TastyInterpreter
12+
import scala.tasty.Reflection
13+
14+
object Test {
15+
def main(args: Array[String]): Unit = {
16+
17+
val actualOutput = interpret("")("IntepretedMain", "InterpretedBar")
18+
val expectedOutput =
19+
"""42
20+
|
21+
|Hello
22+
|
23+
|42
24+
|
25+
|43
26+
|
27+
|if
28+
|
29+
|5
30+
|4
31+
|3
32+
|2
33+
|1
34+
|
35+
|42
36+
|
37+
|55
38+
|precompiledModule
39+
|55
40+
|56
41+
|57
42+
|58
43+
|59
44+
|60
45+
|61
46+
|62
47+
|63
48+
|true
49+
|false
50+
|64
51+
|65
52+
|66
53+
|67
54+
|68
55+
|""".stripMargin
56+
57+
assert(expectedOutput == actualOutput,
58+
"\n>>>>>>>>>>>>>>>>>>\n" +
59+
DiffUtil.mkColoredCodeDiff(actualOutput, expectedOutput, true) +
60+
"<<<<<<<<<<<<<<<<<<"
61+
)
62+
63+
compileAndInterpret("HelloWorld.scala")
64+
compileAndInterpret("nullInstanceEval.scala")
65+
compileAndInterpret("t3327.scala")
66+
// compileAndInterpret("t5614.scala")
67+
// compileAndInterpret("t4054.scala")
68+
// compileAndInterpret("sort.scala")
69+
// compileAndInterpret("t0607.scala")
70+
// compileAndInterpret("i4073b.scala")
71+
// compileAndInterpret("i4430.scala")
72+
// compileAndInterpret("nullAsInstanceOf.scala")
73+
// compileAndInterpret("classof.scala")
74+
// compileAndInterpret("null-hash.scala")
75+
// compileAndInterpret("i3518.scala")
76+
// compileAndInterpret("withIndex.scala")
77+
// compileAndInterpret("unboxingBug.scala")
78+
// compileAndInterpret("traitInit.scala")
79+
}
80+
81+
def compileAndInterpret(testFileName: String) = {
82+
val reproter = new Reporter {
83+
def doReport(m: MessageContainer)(implicit ctx: Contexts.Context): Unit = println(m)
84+
}
85+
val out = java.nio.file.Paths.get("out/interpreted")
86+
if (!java.nio.file.Files.exists(out))
87+
java.nio.file.Files.createDirectory(out)
88+
dotty.tools.dotc.Main.process(Array("-classpath", System.getProperty("java.class.path"), "-d", out.toString, "tests/run/" + testFileName), reproter)
89+
90+
val actualOutput = interpret(out.toString)("Test")
91+
92+
val checkFile = java.nio.file.Paths.get("tests/run/" + testFileName.stripSuffix(".scala") + ".check")
93+
if (java.nio.file.Files.exists(checkFile)) {
94+
val expectedOutput = Source.fromFile(checkFile.toFile).getLines().mkString("", "\n", "\n")
95+
96+
assert(expectedOutput == actualOutput,
97+
"\n>>>>>>>>>>>>>>>>>>\n" +
98+
DiffUtil.mkColoredCodeDiff(actualOutput, expectedOutput, true) +
99+
"<<<<<<<<<<<<<<<<<<"
100+
)
101+
}
102+
}
103+
104+
def interpret(classpath: String*)(interpretedClasses: String*): String = {
105+
val ps = new ByteArrayOutputStream()
106+
try scala.Console.withOut(ps) {
107+
ConsumeTasty(classpath.mkString(java.io.File.pathSeparatorChar.toString), interpretedClasses.toList, new TastyInterpreter)
108+
} catch {
109+
case e: Throwable => throw new Exception(ps.toString, e)
110+
}
111+
ps.toString
112+
}
113+
}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
package scala.tasty.interpreter
2+
3+
import scala.tasty.Reflection
4+
import scala.tasty.file.TastyConsumer
5+
6+
class TastyInterpreter extends TastyConsumer {
7+
8+
final def apply(reflect: Reflection)(root: reflect.Tree): Unit = {
9+
import reflect._
10+
object Traverser extends TreeTraverser {
11+
12+
override def traverseTree(tree: Tree)(implicit ctx: Context): Unit = tree match {
13+
// TODO: check the correct sig and object enclosement for main
14+
case DefDef("main", _, _, _, Some(rhs)) =>
15+
val interpreter = new jvm.Interpreter(reflect)
16+
17+
interpreter.eval(rhs)(Map.empty)
18+
// TODO: recurse only for PackageDef, ClassDef
19+
case tree =>
20+
super.traverseTree(tree)
21+
}
22+
}
23+
Traverser.traverseTree(root)(reflect.rootContext)
24+
}
25+
}

0 commit comments

Comments
 (0)