Bug 330264 - [compiler] fails to error on invalid cast.
Summary: [compiler] fails to error on invalid cast.
Status: VERIFIED DUPLICATE of bug 330435
Alias: None
Product: JDT
Classification: Eclipse Project
Component: Core (show other bugs)
Version: 3.7   Edit
Hardware: PC Mac OS X - Carbon (unsup.)
: P3 normal (vote)
Target Milestone: 3.7 M4   Edit
Assignee: Srikanth Sankaran CLA
QA Contact:
URL:
Whiteboard:
Keywords:
Depends on:
Blocks:
 
Reported: 2010-11-15 11:47 EST by Thomas Watson CLA
Modified: 2010-12-07 12:06 EST (History)
1 user (show)

See Also:


Attachments
test projects (6.23 KB, application/octet-stream)
2010-11-15 11:47 EST, Thomas Watson CLA
no flags Details

Note You need to log in before you can comment on or make changes to this bug.
Description Thomas Watson CLA 2010-11-15 11:47:43 EST
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.
Comment 1 Thomas Watson CLA 2010-11-15 12:01:19 EST
Running from HEAD for jdt.core also reproduces the issue.
Comment 2 Srikanth Sankaran CLA 2010-11-15 23:35:20 EST
(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.
Comment 3 Srikanth Sankaran CLA 2010-11-16 00:13:07 EST
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.
Comment 4 Olivier Thomann CLA 2010-11-16 09:40:04 EST
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.
Comment 5 Thomas Watson CLA 2010-11-16 10:42:05 EST
(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?
Comment 6 Thomas Watson CLA 2010-11-16 10:52:49 EST
(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.
Comment 7 Srikanth Sankaran CLA 2010-11-16 20:32:09 EST
(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.
Comment 8 Srikanth Sankaran CLA 2010-11-18 07:08:34 EST
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.
Comment 9 Srikanth Sankaran CLA 2010-11-18 19:12:18 EST
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 ***
Comment 10 Olivier Thomann CLA 2010-12-07 12:06:07 EST
Verified using I20101207-0250 (4.1 I-build)