Java 10のコンパイラバグを見つけた

予定通りにJava10が出ましたね!Javaが予定通りにリリースされることが珍しすぎたのか、関東では雪になっていたようです。


Java10の変更点についてはこちらにまとめています。
Java 10新機能まとめ - Qiita
Java10のJEP以外の変更まとめ - Qiita


ところで、varが導入されたのでいろいろ試してたらコンパイラが落ちました。
次のようなコードを-g付でコンパイルすると落ちます。

import java.util.List;
public class Main {
  public static void main(String... args) {
    var m = List.of("a", 1);
    System.out.println(m);
  }
}


このように、正式リリースであるbuild 46でコンパイルするとこうなります。

src$ javac Main.java -g
コンパイラで例外が発生しました(10)。Bug Database (http://bugs.java.com)で重複がないかをご確認のうえ、Java bugレポート・ページ(http://bugreport.java.com)でJavaコンパイラに対するbugの登録をお願いいたします。レポートには、そのプログラムと下記の診断内容を含めてく ださい。ご協力ありがとうございます。
java.lang.AssertionError: Unexpected intersection type: java.lang.Object&java.io.Serializable&java.lang.Comparable<? extends java.lang.Object&java.io.Serializable&java.lang.Comparable<?>>
        at jdk.compiler/com.sun.tools.javac.jvm.ClassWriter.enterInner(ClassWriter.java:1043)
        at jdk.compiler/com.sun.tools.javac.jvm.ClassWriter$CWSignatureGenerator.classReference(ClassWriter.java:312)


最初、コンパイルを遅くするパターンあるかなと思って、そうするとList.of("a",1)をネストするのがよさそうだなとやってみると、NetBeansから実行させたときに落ちたのです。
javacやjshellでは通ったので、NetBeansのバグかなーと思ってたのだけど、ちょうどそこにIntelliJ IDEAをデモしてる@yusukeがいたので試してもらうと、こっちでも落ちました。Scala Matsuriだったので、そこにkmizuもやってきて、いろいろ話してたら、まあどうもComparatorがまずそうね、と。


なので、こういうのは大丈夫です。

var s = List.of("a");
var t = List.of("a", 1, List.of());
var u = List.of("a", 1, Optional.empty());

これ、それぞれどうなるか考えるのも楽しそう。


List.of("a",1)は なかなかやらないと思うけど、こういうのやりますよね。

var props = Map.of(
  "name", "naoki",
  "level", 3);


例外が出るコード周辺はこんな感じ

/**********************************************************************
 * Writing Objects
 **********************************************************************/
    /** Enter an inner class into the `innerClasses' set/queue.
     */
    void enterInner(ClassSymbol c) {
        if (c.type.isCompound()) {
            throw new AssertionError("Unexpected intersection type: " + c.type);
        }

http://hg.openjdk.java.net/jdk/jdk10/file/b09e56145e11/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/ClassWriter.java#l1041

なのでクラスファイルを出力するときにうっかりintersectionが消されずにやってきてるのかなーと思ったのだけど、bitterfoxさんがそこではクラスファイル出してませんよ、でもなんか型情報出そうとしてますね、と教えてくれたので、クラスファイルではなく型情報がつくと言えばデバッグ情報だと思って、-gをつけてみたらみごとに再現しました。


んで、久保田さんに報告したらと勧められて、MLに投げてみました。そのあたりの流れは、この前後のツイートで。


ということで、MLに投げた。ドキドキ。
bug: compiler crashes with `var s=List.of("a",1)`


で、bitterfoxさんがパッチを投げて、ライセンスヘッダなど修正をして、取り込まれる模様けど、もっと根本から解決する必要があるらしく、別のコードで対策するらしい(3/25修正)。
[JDK-8199910] Compiler crashes with -g option and variables of intersection type inferred by `var` - Java Bug System
RFR 8199910: Compiler crashes with -g option and variables of intersection type inferred by `var`
(5/3追記)10.0.1では修正されませんでしたね。11-eaでは修正されています。


ツイートは、こっちにもまとめています。
Java10コンパイラバグ


一度はJavaコンパイラを落としてみたいと思っていたのだけど、簡単なコードで落とせてびっくり。まあ、List.of("a",1,List.of())では問題ないとか、-gがついてなければ問題ないとか、あらかじめ見つけるのも難しそう。


Java10 たのしー

コンパイラ―原理・技法・ツール (Information & Computing)

コンパイラ―原理・技法・ツール (Information & Computing)