Java Solaris Communities Sun Store Join SDN My Profile Why Join?
 
Bug Database
Bug Detail
Quick Lists
Top 25 Bugs
Top 25 RFE's
Recently Closed Bugs
Printable Page Printable Page


Bug Database
Bug ID: 6657499
Votes 0
Synopsis javac 1.6.0 fails to compile class with inner class
Category java:compiler
Reported Against
Release Fixed 7(b27)
State 10-Fix Delivered, bug
Priority: 3-Medium
Related Bugs 5009484
Submit Date 31-JAN-2008
Description
FULL PRODUCT VERSION :
[  xxxxx@xxxxx   genericsTest]$ java -version
java version "1.5.0_13"
Java(TM) 2 Runtime Environment, Standard Edition (build 1.5.0_13-b05)
Java HotSpot(TM) Server VM (build 1.5.0_13-b05, mixed mode)


ADDITIONAL OS VERSION INFORMATION :
Linux loddont 2.6.22.9-61.fc6PAE #1 SMP Thu Sep 27 18:27:50 EDT 2007 i686 i686 i386 GNU/Linux


A DESCRIPTION OF THE PROBLEM :
This appears to occur when you define a class inside a method and there are generic types in the outer class.  It appears that they do not pass to the nested class (sorry if thats the wrong terminology for a named class in a method).  I believe this is a bug because it used to compile and it seems inconsistent.  You can minimally reproduce this by trying to compile this lot:-

public interface Foo<T> {
  T foo();
}

public class Bar<T> implements Foo<T> {
  public T foo() {
    class FooImpl implements Foo<T> {
      public T foo() {
        return null;
      }
    }
    return new FooImpl().foo();
  }
}

You get this error with javac/1.6.0_4

[  xxxxx@xxxxx   genericsTest]$ /usr/java/jdk1.6.0_04/bin/javac -d classes src/*
src/Bar.java:9: incompatible types
found   : java.lang.Object
required: T
    return new FooImpl().foo();
                            ^
1 error

However, as indicated, java 1.5.0 is quite happy:-

[  xxxxx@xxxxx   genericsTest]$ /usr/java/jdk1.5.0/bin/javac -d classes src/*
[  xxxxx@xxxxx   genericsTest]$

It seems unlikely that this is the correct behaviour since if the type T is not available in the nested class, then I'd exect the line

    class FooImpl implements Foo<T> {

to fail to compile because T isn't defined.

I should mention that the eclipse compiler is quite happy with this construct.  Maybe they're wrong but I would still suggest that the javac compiler doesn't make much sense here as the generic type T is clearly visible in some sense.

STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
1) Create src dir and classes dir.
2) Put 'foo.java' and 'bar.java' in src dir.
3) javac -d classes src/*


REPRODUCIBILITY :
This bug can be reproduced always.

CUSTOMER SUBMITTED WORKAROUND :
The following modified version of Bar does compile with 1.6.0_4 and 1.5.0 oddly enough

public class Bar<T> implements Foo<T> {
  public T foo() {
    class FooImpl<T2 extends T> implements Foo<T> {
      public T foo() {
        return null;
      }
    }
    return new FooImpl<T>().foo();
  }
}

as does the slightly more sensible version

public class Bar<T> implements Foo<T> {
  public T foo() {
    class FooImpl<T2> implements Foo<T2> {
      public T2 foo() {
        return null;
      }
    }
    return new FooImpl<T>().foo();
  }
}

So you can always make the class external and/or add parameterised types.  I was only doing this because the class concerned was never likely to be of use outside the method so it seemed the best place for it.
Posted Date : 2008-01-31 10:18:00.0
Work Around
N/A
Evaluation
This bug is due to the interplay between resolution of types and local inner classes and not to generics as it may seem at first. When the type FooImpl is accessed within the body of foo(), javac looks for a suitable enclosing instance from which FooImpl can be accessed. However, since FooImpl is a local inner classes (which means that the owner of FooImpl is a method and not a class), the process of finding such an instance fails. This, in turn, trigger the erasure of the symbol to be resolved, causing all type variable to be replaced by their declared bounds. This explains why javac complains about finding a T instead of an Object (the declared bound of T - the signature of foo() has already been erased!). 

The problem has been introduced when fixing CR 5009484 in Mustang. A segment of code in Attr.java was added in order to access a given symbol through the most appropriate enclosing instance (the one in which the symbol is accessible, as not accessible symbols might hide accessible ones). However there's no point for performing an enclosing instance lookup when attributing a *TYPE*, since types are always acessible as toplevel types (inner classes get translated to toplevel classes) and no hiding occurs between class names (it's not possible for an inner class to have the same name as one of its enclosing classes).

The solution is in preventing the enclosing instance lookup when attributing a type.
Posted Date : 2008-02-28 13:50:45.0
Comments
  
  Include a link with my name & email   


PLEASE NOTE: JDK6 is formerly known as Project Mustang