fieldにfieldが代入できないぜぇ ワイルドカードだろ〜?

概要

wild.field に wild.fieldが代入できなくなる

やり方

  1. 型変数TをもつクラスCを用意します。
  2. CはT型のフィールドfieldをもちます。
  3. C<?>型の変数wildを用意すると、wild.fieldにはwild.fieldが代入できません
package test;

public class CaptureConversionTest {

    static class C<T> {
        T field;
    }
    
    public static void main(final String[] args) {
        C<String> str = new C<String>();
        str.field = str.field;
        
        C<?> wild = str;
        // コンパイルエラー
//        wild.field = wild.field;
        // ヘルパメソッドに渡せばOK
        assignmentAux(wild);
    }
    
    private static <T> void assignmentAux(final C<T> something) {
        something.field = something.field;
    }

}

代入できない理由

2つのフィールド参照の式 (wild.field) でそれぞれ別々に捕捉変換 (capture conversion) が起こり、互換性のない型になるため。

参考: 捕捉変換に関する覚え書き - しげるメモ

Eclipseだとこんなエラーが出る。
2回目の捕捉変換でできた型から1回目の捕捉変換でできた型に変換できない ということ。

Type mismatch: cannot convert from capture#2-of ? to capture#1-of ?

Oracleコンパイラだとこんな感じ。

    [javac] C:\work\java\src\test\CaptureConversionTest.java:15: エラー: 互換性のない型
    [javac]         wild.field = wild.field;
    [javac]                          ^
    [javac]   期待値: CAP#2
    [javac]   検出値:    CAP#1
    [javac]   CAP#1,CAP#2が新しい型変数の場合:
    [javac]     ?のキャプチャからのCAP#1 extends Object
    [javac]     ?のキャプチャからのCAP#2 extends Object
    [javac] エラー1個

あれ?右辺の方が先に捕捉変換されている?