Bug 474355 - generics varargs problem - ecj behavior differs from javac
Summary: generics varargs problem - ecj behavior differs from javac
Status: REOPENED
Alias: None
Product: JDT
Classification: Eclipse Project
Component: Core (show other bugs)
Version: 4.5   Edit
Hardware: PC Mac OS X
: P3 normal with 1 vote (vote)
Target Milestone: ---   Edit
Assignee: JDT-Core-Inbox CLA
QA Contact: Srikanth Sankaran CLA
URL:
Whiteboard: stalebug
Keywords:
Depends on:
Blocks:
 
Reported: 2015-08-05 15:51 EDT by Andrew Clement CLA
Modified: 2023-06-08 04:14 EDT (History)
7 users (show)

See Also:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Andrew Clement CLA 2015-08-05 15:51:59 EDT
This was raised against AspectJ but I think it is a JDT issue. This snippet of code:

import java.lang.Object;
import java.util.*;

public class GenericVarargsBug {

    public static void main(String... args) {
        List<byte[]> sth = new ArrayList<>();
        sth.add(new byte[]{23, 23});
        isItWorking(sth.get(0));
    }

    private static void isItWorking(Object... os) {
        System.out.println("yes");
    }
}

Compiles with javac (1.8 u45) and runs, printing 'yes'.

When compiled with Mars (4.5.0) it compiles OK but fails when you run it:

Exception in thread "main" java.lang.ClassCastException: [B cannot be cast to [Ljava.lang.Object;
	at GenericVarargsBug.main(GenericVarargsBug.java:9)

I haven't checked if it is addressed in JDT master.
Comment 1 Stephan Herrmann CLA 2015-08-05 20:12:20 EDT
The same behavior can be observed in versions 3.1.2 up-to and including HEAD (i.e., all versions that accept generics).

The compiler can't decide whether or not byte[] is compatible with Object[]. Cast to Object[] indicates we are attempting a fixed-args invocation, interpreting the varargs arg as an array arg. But then the value casted to Object[] is wrapped in a new Object[] (for a true varargs invocation), perhaps because the compiler now remembers that byte[] is *not* compatible with Object[]. Typecheck seems to be correct, just a dangling conversion messes things up.

Interesting mess actually, which probably went undetected through all these years, because mixing generics and arrays isn't really the style that is taught in school ;P
Comment 2 Ronald Soe-Win CLA 2015-11-30 23:27:28 EST
This sounds quite similar (albeit a different scenario) to the following - I wasn't sure whether to raise a new bug or to comment.

The following test harness fails on Test 2 with the error:

Exception in thread "main" java.lang.ClassCastException: java.lang.Object cannot be cast to [Ljava.lang.Object;
	at test.Test.main(Test.java:10)

Test Harness:

public class Test {
	public static void main(final String[] args)
	{

		final Object test1 = getParamaterisedObject();
		System.out.println("Test A result: " + varargTest(test1));

		System.out.println("Test B result: " + varargTest(getParamaterisedObject()));
	}

	public static int varargTest(final Object... o)
	{
		return 1;
	}

	@SuppressWarnings("unchecked")
	public static <T> T getParamaterisedObject()
	{
			return (T) new Object();
	}
}

Both tests run on 4.4.2, but the second test errors on 4.5.1.

Cheers,
Ron.
Comment 3 Manoj N Palat CLA 2018-05-16 01:38:21 EDT
Bulk move out of 4.8
Comment 4 Eclipse Genie CLA 2020-05-07 09:44:55 EDT
This bug hasn't had any activity in quite some time. Maybe the problem got resolved, was a duplicate of something else, or became less pressing for some reason - or maybe it's still relevant but just hasn't been looked at yet. As such, we're closing this bug.

If you have further information on the current state of the bug, please add it and reopen this bug. The information can be, for example, that the problem still occurs, that you still want the feature, that more information is needed, or that the bug is (for whatever reason) no longer relevant.

--
The automated Eclipse Genie.
Comment 5 momo CLA 2020-05-07 10:02:44 EDT
The bug still persists in Version 4.15:

Exception in thread "main" java.lang.ClassCastException: class [B cannot be cast to class [Ljava.lang.Object; ([B and [Ljava.lang.Object; are in module java.base of loader 'bootstrap')
	at Test.main(Test.java:8)
Comment 6 Olivier Thomann CLA 2020-05-07 11:41:47 EDT
Stephan, I am not a JLS spec expert. Eclipse compiler adds a checkcast when invoking the isWorking method. javac doesn't add that checkcast call.
I think it is worth investigating why this checkcast call is inserted.
FYI here are the bytecodes:
         0: new           #16                 // class java/util/ArrayList
         3: dup
         4: invokespecial #18                 // Method java/util/ArrayList."<init>":()V
         7: astore_1
         8: aload_1
         9: iconst_2
        10: newarray       byte
        12: dup
        13: iconst_0
        14: bipush        23
        16: bastore
        17: dup
        18: iconst_1
        19: bipush        23
        21: bastore
        22: invokeinterface #19,  2           // InterfaceMethod java/util/List.add:(Ljava/lang/Object;)Z
        27: pop
        28: iconst_1
        29: anewarray     #3                  // class java/lang/Object
        32: dup
        33: iconst_0
        34: aload_1
        35: iconst_0
        36: invokeinterface #25,  2           // InterfaceMethod java/util/List.get:(I)Ljava/lang/Object;
        41: checkcast     #29                 // class "[Ljava/lang/Object;"
        44: aastore
        45: invokestatic  #31                 // Method isItWorking:([Ljava/lang/Object;)V
        48: return

so javac doesn't add the checkcast at pc 41. Everything else is the same.

If I code what is actually done under the cover, we don't generate the checkcast anymore.
		Object[] r = new Object[1];
		r[0] = sth.get(0);
		isItWorking(r);

Reopening.
Comment 7 Stephan Herrmann CLA 2020-05-07 14:54:53 EDT
seems to be some problem of communication between resolve and generateCode. I acknowledged above that this is probably a bug, but for me this is not high priority. Independently of this bug I would strongly recommend against mixing generics plus arrays plus varargs.

There's actually a quite reasonable workaround to disambiguate the array-vs-varargs conflict:

        isItWorking((Object)sth.get(0));

Smth like this is always a good idea when passing an array as a single element into a varargs method.
Comment 8 Eclipse Genie CLA 2022-04-28 18:02:32 EDT
This bug hasn't had any activity in quite some time. Maybe the problem got resolved, was a duplicate of something else, or became less pressing for some reason - or maybe it's still relevant but just hasn't been looked at yet.

If you have further information on the current state of the bug, please add it. The information can be, for example, that the problem still occurs, that you still want the feature, that more information is needed, or that the bug is (for whatever reason) no longer relevant.

--
The automated Eclipse Genie.