United StatesChange Country, Oracle Worldwide Web Sites Communities I am a... I want to...
JDK-6611449 : Internal Error thrown during generic method/constructor invocation

Details
Type:
Bug
Submit Date:
2007-10-01
Status:
Closed
Updated Date:
2011-05-17
Project Name:
JDK
Resolved Date:
2011-05-17
Component:
tools
OS:
generic
Sub-Component:
javac
CPU:
generic
Priority:
P4
Resolution:
Fixed
Affected Versions:
7
Fixed Versions:

Related Reports
Relates:

Sub Tasks

Description
Description:
   
The following code fails during compilation with  "internal error".
<code>

public class TypeInferenceTest<S>{

    public  TypeInferenceTest() {

    this(1,1); //Throws internal error; cannot instanatiate ...
    //<Number>this(1,1); //Cannot find symbol
    //  <Integer>this(1); //Cannot find symbol
    // this(1); //Cannot find symbol
    }
    public <T extends S> TypeInferenceTest(T a, T b) {
        //.....
    }
    public <T extends S> TypeInferenceTest(T a) {
       //....
    }

    <T extends S> void met1(T a,T b){
       met2 (1,1);//Throws internal error; cannot instanatiate ...
       new TypeInferenceTest<Number> ().met2 (1,1); //Compiles fine -- Type Inference works
//       met2(1); // Cannot find symbol
    }
    <T extends S> void met2(T a,T b){
        //..
    }

    <T extends S> void met2(T a){
       //...
    }

}



</code>

Compilation result is :
<output>

TypeInferenceTest.java:5: internal error; cannot instantiate <T>TypeInferenceTest(T,T) at TypeInferenceTest<S> to ()
    this(1,1); //Throws internal error; cannot instanatiate ...
        ^
TypeInferenceTest.java:18: internal error; cannot instantiate <T>met2(T,T) at TypeInferenceTest<S> to (int,int)
       Integer i = met2 (1,1);//Throws internal error; cannot instanatiate ...
                        ^
2 errors


</output>

Tried in :
<version>
java version "1.7.0-internal"
Java(TM) SE Runtime Environment (build 1.7.0-internal-jprtadm_26_Sep_2007_03_43-b00)
Java HotSpot(TM) Server VM (build 11.0-b06, mixed mode)

uname -a
SunOS bonsai 5.11 snv_49 i86pc i386 i86pc

                                    

Comments
EVALUATION

The internal error is due to the fact that javac selects a method/constructor that is not applicable because of the declared bound of the type variable T extending S. Unfortunatelly, this incompatibility is detected only at a later point during the resolution process so that javac is forced to trigger an internal error (because it realizes that something wrong happened during resolution).

In particular, the interplay between boxing and type inference makes the resolution process to select an inapplicable method. Given a method declaration M1 and a list of actual argument types A1, A2 ... An, the resolution process is internally composed into two main steps:

1) An instantiation of M1 is found so that the formal parameters of M1 match against A1, A2 ... An.
2) If 1) fails repeat step 1) by substituting each primitive type (if any) in A1, A2 ... An with their corresponding boxed types.

As an example, suppose that M1 = <T extends String> void m(T t1,T t2) and that A1,A2 = {int,int}. Step 1) should fail, since no instance of T exists so that T==int. On the other hand, step 2 fails too, since T is inferred to be Integer which is not compliant wrt the declared bound of T (Integer <: String does NOT hold).

The actual behavior of javac differs from the one described above since javac makes step 1 succeed by basically inferring T itself for the type variable T. Such an inferred type is good for javac as it satisfies the declared bound of T (T <: T!), but then, at a later point, when javac checks that the selected method is effectively applicable (this is done by basically repeating step 2 - so enabling autoboxing), it suddenly realizes that the selected method is not compliant wrt the declared bound S of T. 

The solution to this problem is to fix javac so that step 1) fails as expected - this is equivalent to say that any type inference constraint referring a primitive type should be rewritten so that the primitive type is substituted by its boxing type, as described in JLS 15.12.2.7

"
...
Otherwise, if the constraint has the form A <<F
    * If A is a primitive type, then A is converted to a reference type U via boxing conversion and this algorithm is applied recursively to the constraint U << F.
...
"
                                     
2008-01-31
SUGGESTED FIX

http://sa.sfbay.sun.com/projects/langtools_data/7/6611449/
                                     
2008-01-31
EVALUATION

The use of "throws internal error" is mildly confusing; it "reports" an internal error. Either way, internal errors are not good.



gzilla[6611449]% /w/local/jdk/1.7.0/bin/javac TypeInferenceTest.java
TypeInferenceTest.java:6: internal error; cannot instantiate <T>TypeInferenceTest(T,T) at TypeInferenceTest<S> to ()
    this(1,1); //Throws internal error; cannot instanatiate ...
        ^
TypeInferenceTest.java:19: internal error; cannot instantiate <T>met2(T,T) at TypeInferenceTest<S> to (int,int)
       met2 (1,1);//Throws internal error; cannot instanatiate ...
            ^
2 errors
gzilla[6611449]%
                                     
2008-01-30



Hardware and Software, Engineered to Work Together