SunのコンパイラとEclipse JDTで動きが違う(3)

酒の肴くらいにしかならない豆知識。メソッド呼び出し時の型推論とか - しげるメモの知識が前提のネタです。

下記のコードはjavacとJDTで動きが違います。

public class Assignable {
    public static void main(String[] args) throws Throwable {
        throw get(); // ここの評価が違う
    }
    static <T> T get() {
        return null;
    }
}

javacだとコンパイルエラーにはならず、JDTだとコンパイルエラーになる感じ。

...
  ThrowStatement:
    throw Expression ;

A throw statement can throw an exception type E iff the static type of the throw expression is E or a subtype of E, or the thrown expression can throw E.

The Expression in a throw statement must denote a variable or value of a reference type which is assignable (§5.2) to the type Throwable, or a compile-time error occurs.
...

14.18 The throw Statement

「the static type of the throw expression」の解釈が難しいところですが、「type which is assignable to the type Throwable」とあるので、throwの右側にある式は「Throwableに対する代入変換コンテキスト」であると推測できます。
前回の話とつなげると、「代入変換コンテキスト」であり、「メソッドの戻り値型に型推論されていない型変数が含まれる」場合、メソッドの戻り値型を代入変換コンテキストの代入先の型に代入可能であるという制約を型推論に導入します。
ExpressionはThrowableに対する代入変換コンテキストであるため、T get()のTはThrowableに代入可能であるように推論されるので、T->Throwableになるのが正解。今回はjavacのほうが正しそうです。

心の底からどうでもいいと思った。