Bug 129190 - [1.5][compiler] Contrary behaviour to Sun's compiler concerning typed classes, non-static inner classes and inheritence
Summary: [1.5][compiler] Contrary behaviour to Sun's compiler concerning typed classes...
Status: VERIFIED FIXED
Alias: None
Product: JDT
Classification: Eclipse Project
Component: Core (show other bugs)
Version: 3.2   Edit
Hardware: PC Windows XP
: P3 critical (vote)
Target Milestone: 3.2 M6   Edit
Assignee: Philipe Mulet CLA
QA Contact:
URL:
Whiteboard:
Keywords:
Depends on:
Blocks:
 
Reported: 2006-02-23 12:23 EST by Tobias Riemenschneider CLA
Modified: 2006-03-28 06:25 EST (History)
0 users

See Also:


Attachments
patch for properly inferring through enclosing param type (2.20 KB, patch)
2006-03-02 09:17 EST, Philipe Mulet CLA
no flags Details | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description Tobias Riemenschneider CLA 2006-02-23 12:23:21 EST
3.2M5 shows completely contrary behaviour to Sun's javac when compiling the following pieces of code.
<<<< File 1
class Outer<O> {
  class Inner {}

  static void method(Outer<?>.Inner x) {}
}
>>>>
<<<< File 2
class ExtendedOuter<E> extends Outer<E> {
  class ExtendedInner extends Inner {
    {
      Outer.method(this);
    }
  }
}
>>>>
Every source file contains a typed class with an inner class and the outer/inner class of the second file extends the outer/inner class of the first file. The point of interest is the signature of the static method in Outer. When declaring the signature as shown above, 3.2M5 compiles the classes without errors, while javac produces the following error
<<<<
ExtendedOuter.java:4: method(Outer<capture of ?>.Inner) in Outer cannot be applied to (ExtendedOuter<E>.ExtendedInner)
                        Outer.method(this);
                             ^
1 error
>>>>
When changing the static method's signature to
<<<<
  static void method(Outer.Inner x) {}
>>>>
or
<<<<
  static <T> void method(Outer<T>.Inner x) {}
>>>>
javac compiles the pieces of code without error, but 3.2M5 produces the following error
<<<<
ExtendedOuter.java    The method method(Outer<O>.Inner) in the type Outer is not applicable for the arguments (ExtendedOuter<E>.ExtendedInner)
>>>>
Next strange behaviour of 3.2M5 is, when both pieces of code are put into one file, the declaration
<<<<
  static void method(Outer<?>.Inner x) {}
>>>>
and
<<<<
  static void method(Outer.Inner x) {}
>>>>
compiles without error and only the declaration
<<<<
  static <T> void method(Outer<T>.Inner x) {}
>>>>
produces an error (while javac's estimation of the different pieces of code is still the same).

I'm quite not sure if it's an Eclipse bug or a javac bug, but the different behaviour of Eclipse using one and two files respectively looks like an Eclipse problem.
Comment 1 Philipe Mulet CLA 2006-02-24 07:50:37 EST
Please explain why this is 'critical' ?
Comment 2 Tobias Riemenschneider CLA 2006-02-24 09:37:20 EST
(In reply to comment #1)
> Please explain why this is 'critical' ?
We (research group database systems [http://dbs.mathematik.uni-marburg.de] of Philipps-University Marburg [http://www.uni-marburg.de]) use Eclipse for developing our research projects PIPES [http://dbs.mathematik.uni-marburg.de/Home/Research/Projects/PIPES] and XXL [http://dbs.mathematik.uni-marburg.de/Home/Research/Projects/XXL]. For several conferences (e.g. ICDE [
http://icde06.cc.gatech.edu/] and EDBT [http://www.edbt2006.de]) we need code that is compatible with Java - but it cannot be developed using Eclipse. Even worse, Eclipse shows a completely contrary behaviour to Sun's compiler, i.e., code that is Java-compatible isn't accepted by Eclipse and code that is 'Eclipse'-compatible isn't accepted by Java.

As a workaround we must develop our projects using Eclipse and in a second step verify the code produced by Eclipse for being Java-compatible and fixing the bugs made by Elipse, before publishing code fragments and the whole library respectively. That causes an additional expenditure of time and it is rather difficult for our research group to compensate it.
Comment 3 Philipe Mulet CLA 2006-02-24 17:11:51 EST
I understand. Is this the only pattern you saw ? 
Comment 4 Philipe Mulet CLA 2006-02-24 17:25:49 EST
I believe this is a bug in javac 1.5. No capture should be involved in this process.

FYI - javac from jdk1.6b73 does also accept the code as expected.

Added regression test: GenericTypeTest#test924
Comment 5 Philipe Mulet CLA 2006-02-24 17:56:09 EST
Glancing through their bug database, they seem to have a couple of issues with generic member types. Some of them got fixed in 6.0 only.
Seems to be one of these (couldn't find a specific bug for it though).

You should report this to them.

Closing as invalid, since our behavior is legite.
Comment 6 Philipe Mulet CLA 2006-02-27 18:51:50 EST
Simpler testcase:
import java.util.*;
public class X {
	public void foo() {
		List<? extends List<Object>> RESULT = null;
		List<? extends Object> lst = null;
		RESULT = Collections.singletonList(
                           Collections.singletonList(
                              lst.get(0)));
	}
}

Comment 7 Philipe Mulet CLA 2006-02-27 18:52:35 EST
oops wrong bug for previous comment addition
Comment 8 Tobias Riemenschneider CLA 2006-03-01 12:11:17 EST
I've compared javac's behaviour (1.6.0-beta2-b73) with 3.2M5a's behaviour and I still think there's a bug related to 3.2M5a. While javac compiles the different versions mentioned in the report without any compile time error, 3.2M5a rejects some versions as being wrong. Below I will provide a complete list of the different cases and compare javac's and 3.2M5a's behaviour.

The third case shown below is rejected by 3.2M5a although - as mentioned in comment #4 - no capture should be involved in this process, while javac accepts all cases.

(1) First method definition:
> Test.java >>>
class Outer<O> {
  class Inner {}

  static void method(Outer.Inner x) {}
}

class ExtendedOuter<E> extends Outer<E> {
  class ExtendedInner extends Inner {
    {
      Outer.method(this);
    }
  }
}
< Test.java <<<
Both, javac and 3.2M5a accept the piece of code.

(2) Second method definition:
> Test.java >>>
class Outer<O> {
  class Inner {}

  static void method(Outer<?>.Inner x) {}
}

class ExtendedOuter<E> extends Outer<E> {
  class ExtendedInner extends Inner {
    {
      Outer.method(this);
    }
  }
}
< Test.java <<<
Both, javac and 3.2M5a accept the piece of code.

(3) Third method definition:
> Test.java >>>
class Outer<O> {
  class Inner {}

  static <I> void method(Outer<I>.Inner x) {}
}

class ExtendedOuter<E> extends Outer<E> {
  class ExtendedInner extends Inner {
    {
      Outer.method(this);
    }
  }
}
< Test.java <<<
3.2M5a rejects the method as being not applicable for the given argument, while javac accepts it.
Comment 9 Philipe Mulet CLA 2006-03-02 09:10:45 EST
Agreed. The latter scenario should be accepted.

Problem lies in our inference when dealing with enclosing parameterized types.
Added GenericTypeTest#test937-939
Comment 10 Philipe Mulet CLA 2006-03-02 09:17:28 EST
Created attachment 35608 [details]
patch for properly inferring through enclosing param type
Comment 11 Philipe Mulet CLA 2006-03-02 09:21:01 EST
Good find Tobias. 
Released fix to HEAD.

If you find subsequent issues, please file them as new bug reports.
Comment 12 David Audel CLA 2006-03-28 06:25:18 EST
Verified for 3.2 M6 using build I20060328-0010