Skip to content

Commit 5f05c4b

Browse files
committed
Merge pull request #174 from dotty-staging/reb
Pattern matcher
2 parents e0b290c + 3211985 commit 5f05c4b

File tree

120 files changed

+8063
-2056
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

120 files changed

+8063
-2056
lines changed
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
package dotty.tools.benchmarks
2+
3+
import java.lang.annotation.Annotation
4+
import java.lang.reflect.Method
5+
6+
import org.junit.runner.Request
7+
import org.junit.runner.notification.RunNotifier
8+
import org.scalameter.PerformanceTest.OnlineRegressionReport
9+
import org.scalameter.api._
10+
import org.scalameter.reporting.RegressionReporter.Tester
11+
12+
import scala.collection.mutable.ListBuffer
13+
14+
15+
abstract class TestsToBenchmarkConverter
16+
(targetClass: Class[_],
17+
filterAnnot: Class[_ <: java.lang.annotation.Annotation] = classOf[org.junit.Test].asInstanceOf[Class[_ <: java.lang.annotation.Annotation]])
18+
extends OnlineRegressionReport {
19+
20+
// accept all the results, do not fail
21+
override def tester: Tester = new Tester.Accepter
22+
23+
override def executor: Executor = LocalExecutor(warmer, aggregator, measurer)
24+
val testNames = getMethodsAnnotatedWith(targetClass, filterAnnot).map(_.getName).sorted
25+
26+
27+
val tests = testNames.map{name =>
28+
val runner = Request.method(targetClass, name).getRunner
29+
(name, Gen.single("test")(name).map(Request.method(targetClass, _).getRunner))}.toMap
30+
//Gen.enumeration("test")(testNames:_*)
31+
32+
performance of targetClass.getSimpleName config (Context(reports.resultDir -> "./tmp")) in {
33+
for (test <- testNames)
34+
measure.method(test) in {
35+
using(tests(test)) curve test in {
36+
r =>
37+
val dummy = new RunNotifier()
38+
r.run(dummy)
39+
}
40+
}
41+
}
42+
43+
def getMethodsAnnotatedWith(clazz: Class[_], annotation: Class[_ <: java.lang.annotation.Annotation]): List[Method] = {
44+
val methods = ListBuffer[Method]()
45+
var klass: Class[_] = clazz
46+
while (klass ne classOf[AnyRef]) {
47+
val allMethods = klass.getDeclaredMethods
48+
import scala.collection.JavaConversions._
49+
for (method <- allMethods) {
50+
if (annotation == null || method.isAnnotationPresent(annotation)) {
51+
val annotInstance: Annotation = method.getAnnotation(annotation)
52+
methods.add(method)
53+
}
54+
}
55+
klass = klass.getSuperclass
56+
}
57+
methods.toList
58+
}
59+
}
60+
61+
object dotcTests extends TestsToBenchmarkConverter(classOf[dotc.tests])

project/Build.scala

Lines changed: 49 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,12 @@
1+
import sbt.Keys._
12
import sbt._
2-
import Keys._
3-
import Process._
43

54
object DottyBuild extends Build {
65

76
val TRAVIS_BUILD = "dotty.travis.build"
87

98
val agentOptions = List(
10-
// "-agentlib:jdwp=transport=dt_socket,server=y,suspend=y,address=5005",
9+
// "-agentlib:jdwp=transport=dt_socket,server=y,suspend=y,address=5005"
1110
// "-agentpath:/home/dark/opt/yjp-2013-build-13072/bin/linux-x86-64/libyjpagent.so"
1211
)
1312

@@ -74,4 +73,51 @@ object DottyBuild extends Build {
7473
)
7574

7675
lazy val dotty = Project(id = "dotty", base = file("."), settings = defaults)
76+
77+
lazy val benchmarkSettings = Defaults.defaultSettings ++ Seq(
78+
79+
// to get Scala 2.11
80+
resolvers += Resolver.sonatypeRepo("releases"),
81+
82+
baseDirectory in (Test,run) := (baseDirectory in dotty).value,
83+
84+
85+
libraryDependencies ++= Seq("com.storm-enroute" %% "scalameter" % "0.6" % Test,
86+
"com.novocode" % "junit-interface" % "0.11-RC1"),
87+
testFrameworks += new TestFramework("org.scalameter.ScalaMeterFramework"),
88+
89+
// scalac options
90+
scalacOptions in Global ++= Seq("-feature", "-deprecation", "-language:_"),
91+
92+
javacOptions ++= Seq("-Xlint:unchecked", "-Xlint:deprecation"),
93+
94+
fork in Test := true,
95+
parallelExecution in Test := false,
96+
97+
// http://grokbase.com/t/gg/simple-build-tool/135ke5y90p/sbt-setting-jvm-boot-paramaters-for-scala
98+
javaOptions <++= (dependencyClasspath in Runtime, packageBin in Compile) map { (attList, bin) =>
99+
// put the Scala {library, reflect, compiler} in the classpath
100+
val path = for {
101+
file <- attList.map(_.data)
102+
path = file.getAbsolutePath
103+
prefix = if(path.endsWith(".jar")) "p" else "a"
104+
} yield "-Xbootclasspath/"+ prefix +":" + path
105+
// dotty itself needs to be in the bootclasspath
106+
val fullpath = ("-Xbootclasspath/a:" + bin) :: path.toList
107+
// System.err.println("BOOTPATH: " + fullpath)
108+
109+
val travis_build = // propagate if this is a travis build
110+
if (sys.props.isDefinedAt(TRAVIS_BUILD))
111+
List(s"-D$TRAVIS_BUILD=${sys.props(TRAVIS_BUILD)}")
112+
else
113+
List()
114+
val res = agentOptions ::: travis_build ::: fullpath
115+
println("Running with javaOptions: " +res)
116+
res
117+
}
118+
)
119+
120+
121+
lazy val benchmarks = Project(id = "dotty-bench", settings = benchmarkSettings,
122+
base = file("bench")) dependsOn(dotty % "compile->test")
77123
}

src/dotty/tools/dotc/Compiler.scala

Lines changed: 40 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import Contexts._
66
import Periods._
77
import Symbols._
88
import Scopes._
9-
import typer.{FrontEnd, Typer, Mode, ImportInfo}
9+
import typer.{FrontEnd, Typer, Mode, ImportInfo, RefChecks}
1010
import reporting.ConsoleReporter
1111
import dotty.tools.dotc.core.Phases.Phase
1212
import dotty.tools.dotc.transform._
@@ -16,25 +16,54 @@ import dotty.tools.dotc.core.Denotations.SingleDenotation
1616

1717
class Compiler {
1818

19+
/** Meta-ordering constraint:
20+
*
21+
* DenotTransformers that change the signature of their denotation's info must go
22+
* after erasure. The reason is that denotations are permanently referred to by
23+
* TermRefs which contain a signature. If the signature of a symbol would change,
24+
* all refs to it would become outdated - they could not be dereferenced in the
25+
* new phase.
26+
*
27+
* As an example, addGetters would change a field
28+
*
29+
* val x: T
30+
*
31+
* to a method
32+
*
33+
* def x: T
34+
*
35+
* but this would affect the signature of `x` (goes from NotAMethod to a method
36+
* signature). So we can't do this before erasure.
37+
*
38+
* After erasure, signature changing denot-transformers are OK because erasure
39+
* will make sure that only term refs with fixed SymDenotations survive beyond it. This
40+
* is possible because:
41+
*
42+
* - splitter has run, so every ident or select refers to a unique symbol
43+
* - after erasure, asSeenFrom is the identity, so every reference has a
44+
* plain SymDenotation, as opposed to a UniqueRefDenotation.
45+
*/
1946
def phases: List[List[Phase]] =
2047
List(
2148
List(new FrontEnd),
22-
List(new Companions),
49+
List(new FirstTransform,
50+
new SyntheticMethods),
2351
List(new SuperAccessors),
24-
// pickling and refchecks goes here
25-
List(new ElimRepeated, new ElimLocals),
26-
List(new ExtensionMethods),
27-
List(new TailRec),
52+
// pickling goes here
53+
List(new RefChecks,
54+
new ElimRepeated,
55+
new ElimLocals,
56+
new ExtensionMethods,
57+
new TailRec),
2858
List(new PatternMatcher,
29-
new LazyValTranformContext().transformer,
59+
new ExplicitOuter,
60+
new LazyValsTransform,
3061
new Splitter),
31-
List(new Nullarify,
32-
new TypeTestsCasts,
62+
List(new ElimByName,
3363
new InterceptedMethods,
3464
new Literalize),
3565
List(new Erasure),
36-
List(new UncurryTreeTransform
37-
/* , new Constructors */)
66+
List(new CapturedVars)
3867
)
3968

4069
var runId = 1

src/dotty/tools/dotc/ElimLocals.scala

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,12 @@ import DenotTransformers.SymTransformer
66
import Phases.Phase
77
import Contexts.Context
88
import SymDenotations.SymDenotation
9-
import TreeTransforms.TreeTransform
9+
import TreeTransforms.MiniPhaseTransform
1010
import Flags.Local
1111

1212
/** Widens all private[this] and protected[this] qualifiers to just private/protected */
13-
class ElimLocals extends TreeTransform with SymTransformer { thisTransformer =>
14-
override def name = "elimlocals"
13+
class ElimLocals extends MiniPhaseTransform with SymTransformer { thisTransformer =>
14+
override def phaseName = "elimLocals"
1515

1616
def transformSym(ref: SymDenotation)(implicit ctx: Context) =
1717
dropLocal(ref)

src/dotty/tools/dotc/Flatten.scala

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
package dotty.tools.dotc
2+
package transform
3+
4+
import core._
5+
import DenotTransformers.SymTransformer
6+
import Phases.Phase
7+
import Contexts.Context
8+
import SymDenotations.SymDenotation
9+
import TreeTransforms.MiniPhaseTransform
10+
11+
class Flatten extends MiniPhaseTransform with SymTransformer { thisTransformer =>
12+
override def phaseName = "flatten"
13+
14+
def transformSym(ref: SymDenotation)(implicit ctx: Context) = ???
15+
}

src/dotty/tools/dotc/Run.scala

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,12 @@ class Run(comp: Compiler)(implicit ctx: Context) {
2828
compileSources(sources)
2929
}
3030

31+
/** TODO: There's a fundamental design problem here: We assmble phases using `squash`
32+
* when we first build the compiler. But we modify them with -Yskip, -Ystop
33+
* on each run. That modification needs to either trasnform the tree structure,
34+
* or we need to assmeble phases on each run, and take -Yskip, -Ystop into
35+
* account. I think the latter would be preferable.
36+
*/
3137
def compileSources(sources: List[SourceFile]) = Stats.monitorHeartBeat {
3238
if (sources forall (_.exists)) {
3339
units = sources map (new CompilationUnit(_))
@@ -36,18 +42,19 @@ class Run(comp: Compiler)(implicit ctx: Context) {
3642
ctx.settings.YstopAfter.value.containsPhase(phase.prev)
3743
val phasesToRun = ctx.allPhases.init
3844
.takeWhile(!stoppedBefore(_))
39-
.filterNot(ctx.settings.Yskip.value.containsPhase(_))
40-
for (phase <- phasesToRun) {
45+
.filterNot(ctx.settings.Yskip.value.containsPhase(_)) // TODO: skip only subphase
46+
for (phase <- phasesToRun)
4147
if (!ctx.reporter.hasErrors) {
4248
phase.runOn(units)
4349
def foreachUnit(op: Context => Unit)(implicit ctx: Context): Unit =
4450
for (unit <- units) op(ctx.fresh.setPhase(phase.next).setCompilationUnit(unit))
4551
if (ctx.settings.Xprint.value.containsPhase(phase))
4652
foreachUnit(printTree)
47-
if (ctx.settings.Ycheck.value.containsPhase(phase) && !ctx.reporter.hasErrors)
48-
foreachUnit(TreeChecker.check)
53+
if (ctx.settings.Ycheck.value.containsPhase(phase) && !ctx.reporter.hasErrors) {
54+
assert(phase.isCheckable, s"phase $phase is not checkable")
55+
foreachUnit(TreeChecker.check(phasesToRun, _))
56+
}
4957
}
50-
}
5158
}
5259
}
5360

0 commit comments

Comments
 (0)