Some Eclipse Foundation services are deprecated, or will be soon. Please ensure you've read this important communication.

Bug 364200

Summary: Error erroneously reported when using generics with wildcards
Product: [Eclipse Project] JDT Reporter: Joseph Gordon <joesgordon>
Component: CoreAssignee: Srikanth Sankaran <srikanth_sankaran>
Status: VERIFIED INVALID QA Contact:
Severity: normal    
Priority: P3 CC: jarthana, Olivier_Thomann, tim-eclipse
Version: 3.8   
Target Milestone: 3.8 M5   
Hardware: PC   
OS: Windows 7   
Whiteboard:

Description Joseph Gordon CLA 2011-11-18 16:34:55 EST
Build Identifier: 20110615-0604

Eclipse highlights code as a java error, but the java compiler does not. See the Steps to Reproduce for an example.

Reproducible: Always

Steps to Reproduce:
1. Create a class called 'GenericsTest' and paste the following within the class:

public interface A<X> {
    X get();
    void doStuff(X x);
}

public class Test {
    public <T extends A<?>> void foo(T t) {
        bar(t);
    }

    private <X> void bar(A<X> t) {
        X x = t.get();
        t.doStuff(x);
    }
}

2. Observe the error:

The method bar(GenericsTest.A<X>) in the type GenericsTest.Test is not applicable for the arguments (T)

3. Compile outside of eclipse with javac.

4. Observe no errors.
Comment 1 Olivier Thomann CLA 2011-11-18 16:40:39 EST
This compiles fine with javac 1.6, but fails to compile with javac 1.7:
Test.java:8: error: method bar in class Test cannot be applied to given types;
        bar(t);
        ^
  required: A<X>
  found: T
  reason: actual argument T cannot be converted to A<CAP#1> by method invocation conversion
  where X,T are type-variables:
    X extends Object declared in method <X>bar(A<X>)
    T extends A<?> declared in method <T>foo(T)
  where CAP#1 is a fresh type-variable:
    CAP#1 extends Object from capture of ?
1 error
Comment 2 Joseph Gordon CLA 2011-11-18 17:00:22 EST
@Oliver Thompson, thank you for letting me know (as I didn't). I was using 1.6.0_27 as the JDK, so Eclipse is still identifying an error that the selected JDK is not.

With respect to Java 7, this might be an error with that javac because

bar( ( A<?> )t );

works and is arguably redundant since t is a T and

T extends A<?>

or am I misunderstanding something. Thank you for your help!
Comment 3 Srikanth Sankaran CLA 2012-01-11 07:24:28 EST
I believe the eclipse compiler behavior is correct 
and is matched by JDK5 and JDK7 (latest). It would
appear the JDK6 behavior is a regression which has
since been fixed.

Basically, here is a brief explanation of what is
going on here:

Given the generic method bar and the call site as
given by bar(t), the inference algorithm has no
constrains to work with to infer the type of the
type variable X. So after considering the arguments
and expected return type etc, X is still unresolved
and per specification is resolved to be the published
lower bound - i.e X is inferred to be Object and the
method becomes void bar(A<Object>) t); Since the
actual parameters cannot be converted to formal
parameters, the inferred method has to be rejected
leaving us with no applicable candidates. Hence the
call must be rejected.

The reason the call bar( ( A<?> )t ); succeeds is that
in this case X is inferred to be "capture#1-of ?"
and the generic method parameterized with this substitution
becomes void bar(A<capture#1-of ?>) for which the
parameter compatibility holds.

Closing as INVALID.
Comment 4 Jay Arthanareeswaran CLA 2012-01-23 09:46:48 EST
Verified for 3.8M5