Community
Participate
Working Groups
Created attachment 183139 [details] test projects I20101109-0800 I thought this was bug328775 coming back, but it appears to be a new regression since the issue happens for both 1.4 and 1.5 projects. Similar to bug328775 I have the following piece of code: public void start(BundleContext context) throws Exception { ServiceReference ref = context.getServiceReference("test"); Runnable r = context.getService(ref); <<< this should fail to compile } In this case we have a ref of type ServiceReference<?> returned from context.getServiceReference because a string was passed instead of a class. On java 1.4 the generics mean nothing and the context.getService(ref) call should erase to returning Object. On 1.5 ? is used so it should be Object as well. In all cases the compiler should not allow the assignment to a Runnable without an explicit cast. The attached projects show that no error is created by the compiler for both the 1.4 and 1.5 project. I'm not sure why this is behaving different from the code in bug328775 which seems quite similar. The two test projects still contain the old case from bug328775. You will notice that a compile error is still generated correctly for that testcase.
Running from HEAD for jdt.core also reproduces the issue.
(In reply to comment #0) > Created an attachment (id=183139) [details] > test projects > > I20101109-0800 > > I thought this was bug328775 coming back, but it appears to be a new regression Do you know of a version of JDT/Core since when this "regression" has come about ? At least initially, this looks like the right behavior. > public void start(BundleContext context) throws Exception { > ServiceReference ref = context.getServiceReference("test"); > Runnable r = context.getService(ref); <<< this should fail to compile > } > > In this case we have a ref of type ServiceReference<?> returned from > context.getServiceReference because a string was passed instead of a class. On > java 1.4 the generics mean nothing and the context.getService(ref) call should > erase to returning Object. On 1.5 ? is used so it should be Object as well. Let us talk about 1.5 first. The descriptor of the method getService looks like: <S> S getService(ServiceReference<S> reference); On 1.5 since the passed argument ref is of the raw type ServiceReference and the expected return type (in assignment context) is Runnable, the type parameter is inferred to be Runnable (alternately the formal parameter is inferred to be of type ServiceReference<Runnable>) and hence in that invocation context the generic method return S which is Runnable. There is nothing in the declaration of ServiceReference that says that ServiceReference<Runnable> is not a valid parameterized type. The warnings that the compiler does emit viz: - Type safety: Unchecked invocation getService(ServiceReference) of the generic method getService(ServiceReference<S>) of type BundleContext - Type safety: The expression of type ServiceReference needs unchecked conversion to conform to ServiceReference<Runnable> shed some light on what is going on here. So the getService call is NOT returning Object on 1.5, but is inferred to return Runnable. This is not and cannot be checked by the compiler. and hence the warning. On 1.4 the picture is similar. The way the projects are set up, the 1.4 build sees the 1.5 type of BundleContext with generics in its signature and this would again result in the return type being inferred to be Runnable. > In all cases the compiler should not allow the assignment to a Runnable without > an explicit cast. > > The attached projects show that no error is created by the compiler for both > the 1.4 and 1.5 project. I'm not sure why this is behaving different from the > code in bug328775 which seems quite similar. The two test projects still > contain the old case from bug328775. You will notice that a compile error is > still generated correctly for that testcase.
Would the following be an equivalent plain java test case ? // ------------------------8<------------------------- interface BundleContext { ServiceReference< ? > getServiceReference(String clazz); <S> S getService(ServiceReference<S> reference); } interface ServiceReference<S> extends Comparable<Object> { } interface Bundle extends Comparable<Bundle> { } public class Activator { public void start(BundleContext context) throws Exception { ServiceReference ref = context.getServiceReference("test"); Runnable r = context.getService(ref); } } // ------------------------8<------------------------- If so the behavior on this piece of code is the same between 3.6 and HEAD. On this test case javac5,6,7 give an error: Activator.java:13: incompatible types Runnable r = context.getService(ref); ^ required: Runnable found: Object 1 error However, we know for a fact that there are a number of nuances that differ in the way type inference is implemented in the two compilers resulting in the a number of open issues on both compiler's cases. See that eclipse 3.4, 3.5 and 3.6 M3 reject the above code with a dignostic very similar to javac. While 3.6 M5 onwards we compile it with only a warning. (I don't have M4 bits to test) So, if this is confirmed not to be a regression, I would leave the sleeping dog alone.
I think I understand your explanation, but what I found confusing is that in 1.4 there is no warning and no error. So I would expect the code to work at runtime. In 1.5, there is a unchecked warning where javac reports an error. As you say, there are cases where both compilers don't report these cases in a similar way. At least you have a warning, which can indicate a potential runtime issue. The 1.4 case still bothers me as the user has no idea that something is wrong until the runtime.
(In reply to comment #3) > > See that eclipse 3.4, 3.5 and 3.6 M3 reject the above code with > a dignostic very similar to javac. While 3.6 M5 onwards we compile > it with only a warning. (I don't have M4 bits to test) > > So, if this is confirmed not to be a regression, I would leave the > sleeping dog alone. But is this not considered a regression between 3.5.0 and 3.6.0?
(In reply to comment #4) > The 1.4 case still bothers me as the user has no idea that something is wrong > until the runtime. In Eclipse 3.6 the 1.4 case fails with a compile error for me.
(In reply to comment #4) > The 1.4 case still bothers me as the user has no idea that something is wrong > until the runtime. (In reply to comment #5) > But is this not considered a regression between 3.5.0 and 3.6.0? (In reply to comment #6) > In Eclipse 3.6 the 1.4 case fails with a compile error for me. OK, I'll take a deeper look and see what gives. I am still not sure there is a regression here (the 1.4 case change could be the right thing to do if the 1.5 behavior is correct), but a behavior change that needs to be understood better. I'll track it down to the bug fix that went in circa 3.6 M4 and study that in detail to see if the 1.5+ change is warranted in the first place.
This looks like an unintended side effect of the fix for bug# 277643. As can be seen there, we actually deliberately introduced spec non compliant behavior to match javac. Perhaps some nuance was not not mimicked properly. If I backout this particular fix, eclipse compiler behavior matches javac's behavior on the code snippet in comment# 3. Backing it out would break the fix for bug# 277643 of course and is not an option. This will require deeper investigation. I agree this needs to be looked into and cannot be closed as such.
This is the same problem as bug 330435. The patch posted there at bug 330435 comment 12 contains a junit test for the current problem. I'll raise a separate defect for the change in behavior seen at 1.5 post bug# 277643 *** This bug has been marked as a duplicate of bug 330435 ***
Verified using I20101207-0250 (4.1 I-build)