Bug 159738 - [1.5][compiler] Missing class casts in generated byte code for generic method
Summary: [1.5][compiler] Missing class casts in generated byte code for generic method
Status: VERIFIED FIXED
Alias: None
Product: JDT
Classification: Eclipse Project
Component: Core (show other bugs)
Version: 3.2.1   Edit
Hardware: PC Windows XP
: P3 normal (vote)
Target Milestone: 3.3 M3   Edit
Assignee: Philipe Mulet CLA
QA Contact:
URL:
Whiteboard:
Keywords:
Depends on:
Blocks:
 
Reported: 2006-10-04 11:35 EDT by Ed Merks CLA
Modified: 2006-10-30 11:58 EST (History)
1 user (show)

See Also:


Attachments
Proposed patch (10.62 KB, patch)
2006-10-27 18:46 EDT, 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 Ed Merks CLA 2006-10-04 11:35:53 EDT
Consider this toy example:

import java.util.Map;

class GenericType <E extends Object & Comparable<E> & Map.Entry<String, E>>
{
  public void doSomething(E e)
  {
    System.out.println(e.compareTo(e.getValue()));
  }  
}

class ConcreteType
{
  public void doSomething(Object obj)
  {
    System.out.println(((Comparable)obj).compareTo(((Map.Entry)obj).getValue()));
  }  
}

public class Foo
{
  public static void main(String[] args)
  {
    new GenericType().doSomething("a1");
    new ConcreteType().doSomething("aa");
  }
}

The purpose of this test was to understand the byte code generated for the first doSomething method, which we imagine must look just like the byte code for the second doSomething method.  But looking at the byte code, that wasn't the case.  So then we tried to run the example, expecting to get a class cast exception for both.  But instead we get this:

Exception in thread "main" java.lang.IncompatibleClassChangeError
	at GenericType.doSomething(Foo.java:7)
	at Foo.main(Foo.java:23)

When we compile with Sun javac, we get class cast exceptions as expected. 

This leads me to conclude that the CHECKCAST code is not generated properly by the Eclipse compiler.
Comment 1 Philipe Mulet CLA 2006-10-04 12:03:18 EDT
Indeed, our code produces:
[IncompatibleClassChangeError:1][ClassCastException:2]
where javac's produces:
[ClassCastException:1][ClassCastException:2]

Suspect a generic cast optimization which is proving wrong here.
--------

import java.util.Map;

class GenericType<E extends Object & Comparable<E> & Map.Entry<String, E>> {
	public void doSomething(E e) {
		System.out.println(e.compareTo(e.getValue()));
	}
}

class ConcreteType {
	public void doSomething(Object obj) {
		System.out.println(((Comparable) obj).compareTo(((Map.Entry) obj).getValue()));
	}
}

public class X {
	public static void main(String[] args) {
		try {
			new GenericType().doSomething("a1");
		} catch(Throwable e) {
			System.out.print("[" + e.getClass().getSimpleName() + ":1]");
		}
		try {
			new ConcreteType().doSomething("a2");
		} catch(Throwable e) {
			System.out.print("[" + e.getClass().getSimpleName() + ":2]");
		}
	}
}
Comment 2 Philipe Mulet CLA 2006-10-04 12:09:11 EDT
GenericType#doSomething()

eclipse=====================
  // Method descriptor #17 (Ljava/lang/Object;)V
  // Signature: (TE;)V
  // Stack: 3, Locals: 2
  public void doSomething(Object e);
     0  getstatic System.out : PrintStream [20]
     3  aload_1 [e]
     4  aload_1 [e]
     5  invokeinterface Map$Entry.getValue() : Object [26] [nargs: 1]
    10  invokeinterface Comparable.compareTo(Object) : int [32] [nargs: 2]
    15  invokevirtual PrintStream.println(int) : void [38]
    18  return

javac=======================
  // Method descriptor #15 (Ljava/lang/Object;)V
  // Signature: (TE;)V
  // Stack: 3, Locals: 2
  public void doSomething(Object arg0);
     0  getstatic System.out : PrintStream [2]
     3  aload_1
     4  checkcast Comparable [3]
     7  aload_1
     8  checkcast Map$Entry [4]
    11  invokeinterface Map$Entry.getValue() : Object [5] [nargs: 1]
    16  invokeinterface Comparable.compareTo(Object) : int [6] [nargs: 2]
    21  invokevirtual PrintStream.println(int) : void [7]
    24  return
Comment 3 Philipe Mulet CLA 2006-10-05 18:15:44 EDT
also see bug 141289
Comment 4 Philipe Mulet CLA 2006-10-05 19:13:37 EDT
Our support for inserted generic cast on multi-bound scenario is only dealing with fieldref/methodref receivers.

Extra cast should be on codegen of msgSend, when rcv type doesn't match expectation (secondary bound issue), whatever the receiver expression may be (not just field/method).

Should construct testcase with ternary or local or cast expression etc...
Comment 5 Philipe Mulet CLA 2006-10-27 18:46:25 EDT
Created attachment 52900 [details]
Proposed patch
Comment 6 Philipe Mulet CLA 2006-10-27 19:50:44 EDT
Added GenericTypeTest#test1057

Released for 3.3M3.
Fixed
Comment 7 David Audel CLA 2006-10-30 11:58:15 EST
Verified for 3.3 M3 using build I20061030-0010