Scala: dotty コンパイラを試す
Scala Days San Francisco のキーノートでも触れられた、Scala の新コンパイラ dotty を試す。
環境
- OS X Yosemite: Version 10.10.2
- Processor: 2.6 GHz Intel Core i7
- Memory 16GB 1600 MHz DDR3
- 以下インストール済み
- Oracle JDK 8 u40 (JDK 7 ではビルドできなかった)
- git: version 1.8.4.3
- sbt: version 0.13.0
インストール
まずは、作業ディレクトリに scala/scala および dotty のソースコードをダウンロード。
$ cd <YOUR_WORK_DIR> $ git clone git@github.com:scala/scala.git $ git clone git@github.com:lampepfl/dotty.git
Java コンパイラのバージョンを確認 (1.8.x であればOK)
$ javac -version javac 1.8.0_40
JDK 8 をインストールしているのにバージョンが古い場合は、環境変数などをチェック
$ export JAVA_HOME=`/System/Library/Frameworks/JavaVM.framework/Versions/A/Commands/java_home -v "1.8"` $ echo $JAVA_HOME /Library/Java/JavaVirtualMachines/jdk1.8.0_40.jdk/Contents/Home $ PATH=${JAVA_HOME}/bin:${PATH} $ javac -version javac 1.8.0_40
dotty をビルド
$ cd dotty $ sbt compile
100個ほど warn メッセージが表示されたが、Travis CI でも出ているので無視。所要時間は 58秒ほどだった。
sbt run を実行すると、usage が表示された。
$ set run
Usage: scalac <options> <source files> where possible standard options include: -Dproperty=value Pass -Dproperty=value directly to the runtime system. -J Pass directly to the runtime system. -bootclasspath Override location of bootstrap class files. -classpath Specify where to find user class files. -d destination for generated classfiles. -dependencyfile Set dependency tracking file. -deprecation Emit warning and location for usages of deprecated APIs. -encoding Specify character encoding used by source files. -explaintypes Explain type errors in more detail. -extdirs Override location of installed extensions. -feature Emit warning and location for usages of features that should be imported explicitly. -g Set level of generated debugging info. -help Print a synopsis of standard options -javabootclasspath Override java boot classpath. -javaextdirs Override java extdirs classpath. -language Enable one or more language features. -no-specialization Ignore @specialize annotations. -nobootcp Do not use the boot classpath for the scala jars. -nowarn Generate no warnings. -optimise Generates faster bytecode by applying optimisations to the program -pagewidth Set page width -print Print program with Scala-specific features removed. -sourcepath Specify location(s) of source files. -strict Use strict type rules, which means some formerly legal code does not typecheck anymore. -target Target platform for object files. All JVM 1.5 targets are deprecated. -toolcp Add to the runner classpath. -unchecked Enable additional warnings where generated code depends on assumptions. -uniqid Uniquely tag all identifiers in debugging output. -usejavacp Utilize the java.class.path in classpath resolution. -verbose Output messages about what the compiler is doing. -version Print product version and exit. @<file> A text file containing compiler arguments (options and source files)
UT を実行
$ sbt test ...snip... [info] Passed: Total 106, Failed 0, Errors 0, Passed 106
無事、全てのテストが通った。所要時間は 157秒。
REPL
Scala REPL で dotty の AST を試す。
$ ./bin/dotc -repl Welcome to Scala version 2.11.5 (Java HotSpot(TM) 64-Bit Server VM, Java 1.8.0_40). Type in expressions to have them evaluated. Type :help for more information. scala> import test.DottyTypeStealer._; import dotty.tools.dotc.core.Types._; import test.DottyTypeStealer._ import dotty.tools.dotc.core.Types._ scala> val s = stealType("object o { type X }", "o.X") s: (dotty.tools.dotc.core.Contexts.Context, List[dotty.tools.dotc.core.Types.Type]) = (Context( owner = module class , scope = Scopes() owner = module class , scope = Scopes() owner = module class , scope = Scopes() owner = module class , scope = Scopes() owner = module class , scope = Scopes() owner = module class , scope = Scopes() owner = val , scope = Scopes(module _root_) owner = val , scope = null owner = val , scope = null,List(TypeRef(TermRef(ThisType(TypeRef(NoPrefix,)),o),X))) scala> implicit val ctx = s._1 ctx: dotty.tools.dotc.core.Contexts.Context = Context( owner = module class , scope = Scopes() owner = module class , scope = Scopes() owner = module class , scope = Scopes() owner = module class , scope = Scopes() owner = module class , scope = Scopes() owner = module class , scope = Scopes() owner = val , scope = Scopes(module _root_) owner = val , scope = null owner = val , scope = null scala> val t = s._2(0) t: dotty.tools.dotc.core.Types.Type = TypeRef(TermRef(ThisType(TypeRef(NoPrefix,)),o),X) scala> val u = t.asInstanceOf[TypeRef].underlying u: dotty.tools.dotc.core.Types.Type = TypeBounds(TypeRef(ThisType(TypeRef(NoPrefix,scala)),Nothing), TypeRef(ThisType(TypeRef(NoPrefix,scala)),Any)) scala> t.show res0: String = o.X scala> u.show res1: String = ""
ただし、ここで動いているのはあくまでも Scala REPL であるため、dotty 固有の構文は受け付けられない。
Hello world
まずは、付属のサンプルコードを試してみたが、 ClassFormatError で実行できず。
$ cat ./examples/hello.scala package hello object world extends App { println("hello dotty!") } $ ./bin/dotc ./examples/hello.scala warning: encountered F-bounded higher-kinded type parameters for type scala$collection$generic$GenMapFactory$$CC; assuming they are invariant warning: encountered F-bounded higher-kinded type parameters for type scala$collection$generic$MapFactory$$CC; assuming they are invariant warning: encountered F-bounded higher-kinded type parameters for type scala$collection$generic$GenSetFactory$$CC; assuming they are invariant warning: encountered F-bounded higher-kinded type parameters for type scala$collection$generic$SetFactory$$CC; assuming they are invariant four warnings found $ ll hello total 16 -rw-r--r-- 1 user staff 1134 3 28 18:41 world$.class -rw-r--r-- 1 user staff 400 3 28 18:41 world.class $ scala hello.world java.lang.ClassFormatError: Illegal method name "initial$scala.DelayedInit" in class hello/world$ at java.lang.ClassLoader.defineClass1(Native Method) at java.lang.ClassLoader.defineClass(ClassLoader.java:760) at java.security.SecureClassLoader.defineClass(SecureClassLoader.java:142) at java.net.URLClassLoader.defineClass(URLClassLoader.java:467) at java.net.URLClassLoader.access$100(URLClassLoader.java:73) at java.net.URLClassLoader$1.run(URLClassLoader.java:368) at java.net.URLClassLoader$1.run(URLClassLoader.java:362) at java.security.AccessController.doPrivileged(Native Method) at java.net.URLClassLoader.findClass(URLClassLoader.java:361) at java.lang.ClassLoader.loadClass(ClassLoader.java:424) at java.lang.ClassLoader.loadClass(ClassLoader.java:357) at hello.world.main(hello.scala) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:497) at scala.reflect.internal.util.ScalaClassLoader$$anonfun$run$1.apply(ScalaClassLoader.scala:70) at scala.reflect.internal.util.ScalaClassLoader$class.asContext(ScalaClassLoader.scala:31) at scala.reflect.internal.util.ScalaClassLoader$URLClassLoader.asContext(ScalaClassLoader.scala:101) at scala.reflect.internal.util.ScalaClassLoader$class.run(ScalaClassLoader.scala:70) at scala.reflect.internal.util.ScalaClassLoader$URLClassLoader.run(ScalaClassLoader.scala:101) at scala.tools.nsc.CommonRunner$class.run(ObjectRunner.scala:22) at scala.tools.nsc.ObjectRunner$.run(ObjectRunner.scala:39) at scala.tools.nsc.CommonRunner$class.runAndCatch(ObjectRunner.scala:29) at scala.tools.nsc.ObjectRunner$.runAndCatch(ObjectRunner.scala:39) at scala.tools.nsc.MainGenericRunner.runTarget$1(MainGenericRunner.scala:65) at scala.tools.nsc.MainGenericRunner.run$1(MainGenericRunner.scala:87) at scala.tools.nsc.MainGenericRunner.process(MainGenericRunner.scala:98) at scala.tools.nsc.MainGenericRunner$.main(MainGenericRunner.scala:103) at scala.tools.nsc.MainGenericRunner.main(MainGenericRunner.scala)
App トレイトを使うのを避けたら、とりあえず動くようになった。
package hello object world { def main(args: Array[String]): Unit = { println("hello dotty!") } }
$ dotc ./src/01_hello_world.scala warning: encountered F-bounded higher-kinded type parameters for type scala$collection$generic$GenMapFactory$$CC; assuming they are invariant warning: encountered F-bounded higher-kinded type parameters for type scala$collection$generic$MapFactory$$CC; assuming they are invariant warning: encountered F-bounded higher-kinded type parameters for type scala$collection$generic$GenSetFactory$$CC; assuming they are invariant warning: encountered F-bounded higher-kinded type parameters for type scala$collection$generic$SetFactory$$CC; assuming they are invariant four warnings found $ scala hello.world hello dotty!
新機能を試す
プロシージャ構文の廃止
関数定義の = を省略すると、
package hello object world_ng { def main(args: Array[String]) { println("hello dotty!") } }
コンパイルエラーになる。
$ dotc ./src/02_hello_world_ng.scala ./src/02_hello_world_ng.scala:4: error: '=' expected but '{' found. def main(args: Array[String]) { ^ one error found
XMLリテラル
旧形式のXMLリテラルはコンパイルエラーになる。
package hello object xml_ng { def main(args: Array[String]): Unit = { println(XML Literal) } }
$ dotc ./src/03_xml_literals_ng.scala ./src/03_xml_literals_ng.scala:5: error: xml is not a member of scala.type println(XML Literal) ^ one error found
将来は xml"" で中置記法に対応するとのことだが、現時点ではまだ使えない模様。
package hello object xml_literals { def main(args: Array[String]): Unit = { println(xml"""XML Literal""") } }
$ dotc ./src/04_xml_literals.scala ./src/04_xml_literals.scala:5: error: xml is not a member of StringContext println(xml"""XML Literal""") ^ one error found
トレイト・パラメータ
トレイトがパラメータを取れるようになる。
package hello object trait_parameter { trait CoordLike(x: Double, y: Double) { def show() = println(s"($x, $y)") } object Coord extends CoordLike(1.0, 2.0) def main(args: Array[String]): Unit = { Coord.show() } }
コンパイルはできたが、残念ながら実行はできなかった。
$ dotc ./src/05_trait_parameter.scala warning: encountered F-bounded higher-kinded type parameters for type scala$collection$generic$GenMapFactory$$CC; assuming they are invariant warning: encountered F-bounded higher-kinded type parameters for type scala$collection$generic$MapFactory$$CC; assuming they are invariant warning: encountered F-bounded higher-kinded type parameters for type scala$collection$generic$GenSetFactory$$CC; assuming they are invariant warning: encountered F-bounded higher-kinded type parameters for type scala$collection$generic$SetFactory$$CC; assuming they are invariant four warnings found $ scala hello.trait_parameter java.lang.ClassFormatError: Illegal method name "initial$hello.trait_parameter$$CoordLike" in class hello/trait_parameter$$CoordLike
パッケージの指定(package hello)をなくしたら、今度は別のエラーが出た。
$ scala trait_parameter java.lang.ClassFormatError: Method x in class trait_parameter$$CoordLike has illegal modifiers: 0x402