| Summary: | [1.5][compiler] Type handling on concrete inner class of super class is incorrect | ||
|---|---|---|---|
| Product: | [Eclipse Project] JDT | Reporter: | Steven Tamm <stamm> |
| Component: | Core | Assignee: | Philipe Mulet <philippe_mulet> |
| Status: | CLOSED FIXED | QA Contact: | |
| Severity: | critical | ||
| Priority: | P3 | CC: | philippe_mulet |
| Version: | 3.1 | ||
| Target Milestone: | 3.1 RC2 | ||
| Hardware: | PC | ||
| OS: | Windows XP | ||
| Whiteboard: | |||
Your example doesn't compile for quite a few other errors. Syntax error, unexpected static modifiers. Please correct your testcase to only expose the issue described in this PR; then reopen. I had assumed incorrectly that you would have pasted each of the classes into
three separate files, which would automatically add in the import. You cannot
reproduce the bug in a single class because of its use of statics. I.e. if you
place them all in the same class, it works correctly. Here is the example that
works correctly:
// Reduction.java
import java.util.*;
public class Reduction {
abstract static public class UserClass<K extends KeyClass> {
protected class DataHolder {
private final Map<K, Object> singleData = new HashMap<K,Object>();
public void put(K key, Object value) {this.singleData.put(key, value); }
}
private final DataHolder data = new DataHolder();
public Object get(K key) { return data.singleData.get(key); }
protected void loadHook(DataHolder data) {}
}
abstract static public class KeyClass {
public abstract String getName();
public static class Named extends KeyClass {
private final String paramName;
protected Named(String paramName) {this.paramName = paramName;}
@Override public final String getName() {return this.paramName;
}
}
}
public static class ChildClass extends UserClass<ChildClass.Key> {
public static class Key extends KeyClass.Named {
public static final Key instance = new Key("1");
private Key(String n) { super(n); }
}
@Override protected void loadHook(DataHolder data) {
}
}
}
However, when it is placed in three separate files, it doesn't work
//UserClass.java
import java.util.*;
abstract public class UserClass<K extends KeyClass> {
protected class DataHolder {
private final Map<K, Object> singleData = new HashMap<K,Object>();
public void put(K key, Object value) {this.singleData.put(key, value); }
}
private final DataHolder data = new DataHolder();
public Object get(K key) { return data.singleData.get(key); }
protected void loadHook(DataHolder data) {}
}
//KeyClass.java
abstract public class KeyClass {
public abstract String getName();
public static class Named extends KeyClass {
private final String paramName;
protected Named(String paramName) {this.paramName = paramName;}
@Override public final String getName() {return this.paramName;
}
}
}
//ChildClass.java
public class ChildClass extends UserClass<ChildClass.Key> {
public static class Key extends KeyClass.Named {
public static final Key instance = new Key("1");
private Key(String n) { super(n); }
}
@Override protected void loadHook(DataHolder data) {
}
}
This works fine when compiled from source... its a binary issue with
parameterized types.
The testcase can be reduced to 2 files:
public class UserClass<K> {
protected class DataHolder {}
protected void loadHook(DataHolder data) {}
}
public class ChildClass extends UserClass<Object> {
@Override protected void loadHook(DataHolder data) {}
}
When ChildClass is compiled & picks up UserClass as a binary, we end up
comparing 2 parameterized types:
protected class DataHolder
extends NULL TYPENULL SUPERINTERFACES
enclosing type : UserClass<java.lang.Object>NULL FIELDSNULL METHODS
and for the inherited method:
protected class DataHolder
extends NULL TYPENULL SUPERINTERFACES
enclosing type : UserClass#RAWNULL FIELDSNULL METHODS
Feels my bug. Added GenericTypeTest#test709. Problem was along the same line as bug 96085, but on a different path. Fixed by using LookupEnvironment#convertToRawType(...) during UnresolvedReferenceBinding resolution. Fixed Verified for 3.1 RC2 using build N20050607-0010 +JDT/Core HEAD Verified with I20050610-0010 |
There are three main classes, an class called UserClass which is parameterized based on KeyClass, and a child class that extends UserClass concretized with a child inner class: abstract public class UserClass<K extends KeyClass> { protected class DataHolder { private final Map<K, Object> singleData = new HashMap<K,Object>(); public void put(K key, Object value) {this.singleData.put(key, value); } } private final DataHolder data = new DataHolder(); public Object get(K key) { return data.singleData.get(key); } protected void loadHook(DataHolder data) {} } abstract public class KeyClass { public abstract String getName(); public static class Named extends KeyClass { private final String paramName; protected Named(String paramName) {this.paramName = paramName;} @Override public final String getName() {return this.paramName; } } } public class ChildClass extends UserClass<ChildClass.Key> { public static class Key extends KeyClass.Named { public static final Key instance = new Key("1"); private Key(String n) { super(n); } } @Override protected void loadHook(DataHolder data) { } } The @Override in the last class causese Name clash: The method loadHook(UserClass<ChildClass.Key>.DataHolder) of type ChildClass has the same erasure as loadHook(UserClass.DataHolder) of type UserClass<K> but does not override it If you remove the @Override, it works but gives a warning. It compiles correctly in javac. This behavior is a regression from M6.