Community
Participate
Working Groups
The following snippet compiles fine using the build-in compiler in Eclipse 3.5.2 and 3.6 but yields an error using javac 1.6.0_21 and 1.5.0_22 import java.awt.event.ActionListener; import java.util.ArrayList; public class Test { public Test() { } public <T extends ActionListener> void test(Class<T> clazz) { boolean b = clazz == ArrayList.class; } } The message is Test.java:7: incomparable types: java.lang.Class<T> and java.lang.Class<java.util.ArrayList> boolean b = clazz == ArrayList.class; Seems to me that javac is right since ArrayList is not a subclass of ActionListener.
Indeed, this is a bug in eclipse. Will follow up.
Slightly shorter test case: interface I {} public class Test { <T extends I> void main(Class<T> clazz) { boolean b = clazz == Test.class || // eclipse - !Error, javac - Error I.class == Test.class; // Both compilers complain here } }
Also interesting is: interface I {} public class Test { <T extends I> void main(Class<T> clazz, Test t) { boolean b = clazz == t.getClass() || // eclipse mum, javac mum I.class == t.getClass(); // eclipse mum, javac scream } } Again, at the outset, javac behaviour seems to be correct.
Also interesting is that eclipse compiles the following without error: import java.util.List; interface I {} public class Test { <T extends I> void main(List<T> clazz, List<Test> testList) { boolean b = clazz == testList; } } while javac complains. but if you make Test a final class, eclipse also complains. In the exact same contexts, eclipse has no hesitation in flagging an assignment as being illegal.
Here is another very interesting case: interface List<E> {} interface I {} public class X implements I { void main(List<I> li, X t) { boolean b = I.class == t.getClass(); // javac complains here b = li == t.getList(); // javac does not complain here } List<? extends Object> getList() { return null; } } which indicates that javac recognizes I.class to be a constant class literal expresssion.
(In reply to comment #4) > Also interesting is that eclipse compiles the following without error: > > import java.util.List; > > interface I {} > > public class Test { > <T extends I> void main(List<T> clazz, List<Test> testList) { > boolean b = clazz == testList; > } > } > > while javac complains. I have raised Bug 323473 to track this.
Created attachment 177385 [details] Proposed patch
All tests pass, Jay, please review. TIA.
The problem here basically is that the eclipse compiler was not recognizing (in the comparison context) that an expression such as ArrayList.class is a compile time constant, it being a class literal and that the type of that expression is frozen cannot refer to any subtypes whatsoever.
Patch looks good. Sorry about the delay, Srikanth.
Released in HEAD for 3.7 M2.
Verified for 3.7M2 using I20100914-0100
Reopening since this causes more serious problems (see bug 330869). Will look to fix this for M4.
This seems to be a big twilight zone, best reflected in Philippe's comment: bug 148046 comment 1. The JLS arbitrarily defines what criteria can be used to "prove" two types distinct. This is different from what javac checks, is different from what common sense may conclude, which is different from ... For the issue at hand JLS 4.5.1 has this simple rule: "Two type arguments are provably distinct if neither of the arguments is a type variable or wildcard, and the two arguments are not the same type." According to that rule we have no reason to report an error for any of the examples that involve a type variable. I made a quick test by adding to the top of isProvablyDistinctTypeArgument() if (isTypeVariable() || otherArgument.isTypeVariable()) return false; This changed the outcome of 2 tests in GenericsRegressionTest - test322531d() and test322531f() and 10 distinct tests in GenericTypeTest In all cases common sense seems to agree with our compiler, but I doubt that these are in line with the JLS. Other related bugs are bug 158870, bug 89940 and bug 90437, which introduced the method TypeBinding.isProvableDistinctSubType(), and many more related issues I'm sure. Srikanth, what's your strategy in this mine field? Is it time to make strictness configurable (JLS - emulate javac - best effort)? Might be cleanest but also a significant effort I'm afraid.
(In reply to comment #14) > This seems to be a big twilight zone, best reflected in Philippe's comment: > bug 148046 comment 1. > The JLS arbitrarily defines what criteria can be used to "prove" two types > distinct. This is different from what javac checks, is different from > what common sense may conclude, which is different from ... > > For the issue at hand JLS 4.5.1 has this simple rule: > "Two type arguments are provably distinct if neither of the arguments is a > type variable or wildcard, and the two arguments are not the same type." > > According to that rule we have no reason to report an error for any of the > examples that involve a type variable. I agree that there is room for discretion in these cases. What I would like to do here is to address those cases where the distinction can be discerned fairly obviously and match up eclipse behavior with javac, but this is going to have to wait as I don't have time right now. I'll revisit this later and see what is the best course of action.
(In reply to comment #14) > This seems to be a big twilight zone, best reflected in Philippe's comment: > bug 148046 comment 1. > The JLS arbitrarily defines what criteria can be used to "prove" two types > distinct. This is different from what javac checks, is different from > what common sense may conclude, which is different from ... > > For the issue at hand JLS 4.5.1 has this simple rule: > "Two type arguments are provably distinct if neither of the arguments is a > type variable or wildcard, and the two arguments are not the same type." See JLS spec bug 6557279 and sun compiler bug 6932571.
(In reply to comment #16) > See JLS spec bug 6557279 and sun compiler bug 6932571. Do you have a working link to the spec bug? All I get on oracles pages is: "This bug is not available."
(In reply to comment #17) > (In reply to comment #16) > > See JLS spec bug 6557279 and sun compiler bug 6932571. > > Do you have a working link to the spec bug? > All I get on oracles pages is: "This bug is not available." Yes, this link looks broken now - Here is the text from notes I had made earlier: JLS 4.5.1.1 should be clarified along these lines: "Two type arguments are provably distinct if one of the following is true: - Neither argument is a type variable or wildcard, and the two arguments are not the same type. - One type argument is a type variable or wildcard, with an upper bound (from capture conversion, if necessary) is S; and the other type argument T is not a type variable or wildcard; and neither |S|<:|T| nor |T|<:|S|. - Each type argument is a type variable or wildcard, with upper bounds (from capture conversion, if necessary) of S and T; and neither |S|<:|T| nor |T|<:|S|."
Stephan, Olivier, > JLS 4.5.1.1 should be clarified along these lines: > "Two type arguments are provably distinct if one of the following is true: > - Neither argument is a type variable or wildcard, and the two arguments are > not the same type. > - One type argument is a type variable or wildcard, with an upper bound (from > capture conversion, if necessary) is S; and the other type argument T is not a > type variable or wildcard; and neither |S|<:|T| nor |T|<:|S|. > - Each type argument is a type variable or wildcard, with upper bounds (from > capture conversion, if necessary) of S and T; and neither |S|<:|T| nor > |T|<:|S|." I have been staring at this text for a long time now - does not this make List<? extends Number> and List<Object> not provably distinct ? For: "Two parameterized types are provably distinct if either of the following conditions hold: • They are invocations of distinct generic type declarations. • Any of their type arguments are provably distinct." Bullet 1 obviously holds. Looking at bullet 2, Argument#1 = "? extends Number" and Argument#2 = Object S = UpperBound(Argument#1) = Number T = Object. |S| <: |T| What silly mistake/oversight am I committing here ?
(In reply to comment #19) Hi Srikanth, "Sorrry" I can't find a mistake in your reasoning. Here's how I interpret the situation: the currently valid version of the JLS is a strawman in this regard: as soon as we see a type variable or a wildcard we are not allowed to mark any parameterized types as provably distinct. EOS. The "improvement" you quote (let's assume it has any authorization, to me it is little more than a rumour) takes the smallest possible step in the desired direction: if we encounter any type variable or wildcard, those must be really really different for the overall types to be considered provably distinct. So while List<Number> is provably distinct from List<Object>, the "new spec" indeed doesn't consider List<? extends Number> or List<E extends Number> as provably distinct from List<Object>. Sure, if we have wildcard/typevariable with an upper bound and a class type above the upper bound those can never be unified, but the "new spec" simply doesn't exploit this fact and thus it is probably much weaker than the current implementation of javac. Sure the spec would become longer if all cases would be aggressively spelled out to mark as provably distinct as many pairs of types as possible. If one type argument is a typevariable or wildcard with an upper bound, maybe different cases would need to be created for the other type argument (class type vs. interface type) to determine whether two-way incompatibility or one-way incompatibility must be required etc. I'm sure between us we could prove lots of pairs of types distinct, which the JLS shyly accepts as may-be-this-may-be-that. My question is: do we see strong activity towards a really improved spec? Otherwise, why not indeed consider different levels of type checking: - strict JLS (weakest) - approximate javac (medium) - best effort (strongest) I admit the medium level would be difficult to maintain, because all depends on practical experiments, and the evolution of javac may be diffictul to trace. But I don't see how one fixed algorithm can ever serve all masters.
(In reply to comment #20) > (In reply to comment #19) > Here's how I interpret the situation: the currently valid version of the JLS > is a strawman in this regard: as soon as we see a type variable or a wildcard > we are not allowed to mark any parameterized types as provably distinct. EOS. > > The "improvement" you quote (let's assume it has any authorization, > to me it is little more than a rumour) takes the smallest possible step > in the desired direction: if we encounter any type variable or wildcard, > those must be really really different for the overall types to be considered > provably distinct. Thanks for taking a look and re-affirming the observation. When I saw the spec bug being fixed, I rather naively expected javac7 of the latest vintage to comply to this version. In the end as you say, this _is_ only the smallest possible step in the desired direction and is not a panacea for the all the behavior differences between javac & ecj due to each one's idiosyncratic interpretation of distinctness of types and type arguments. > My question is: do we see strong activity towards a really improved spec? There are some behavior differences between javac7 and javac6 which in tandem with the spec bug seemed to indicate such activity, but it now looks just a smoke screen. > Otherwise, why not indeed consider different levels of type checking: > - strict JLS (weakest) > - approximate javac (medium) > - best effort (strongest) We have some use cases and user scenarios where compatibility is paramount and that really narrows down the choice to the medium level, > I admit the medium level would be difficult to maintain, because all depends > on practical experiments, and the evolution of javac may be diffictul to > trace. But I don't see how one fixed algorithm can ever serve all masters. Sigh.
(In reply to comment #21) > > Otherwise, why not indeed consider different levels of type checking: > > - strict JLS (weakest) > > - approximate javac (medium) > > - best effort (strongest) > > We have some use cases and user scenarios where compatibility > is paramount and that really narrows down the choice to the > medium level, I wasn't suggesting to abandon the medium level, but to make strictness configurable. I don't mind making medium the default, but give people a choice to push the compiler either way. Or are you saying that *everybody* leave it at the (muddled) medium? Maybe having the option to revert to medium, people get the courage to use best effort during day-to-day business?
(In reply to comment #22) > (In reply to comment #21) > > > Otherwise, why not indeed consider different levels of type checking: > > > - strict JLS (weakest) > > > - approximate javac (medium) > > > - best effort (strongest) [...] > I wasn't suggesting to abandon the medium level, but to make strictness > configurable. I don't mind making medium the default, but give people a > choice to push the compiler either way. > > Or are you saying that *everybody* leave it at the (muddled) medium? Strict JLS mode is not going to serve any useful purpose given how underspecified things are. If we make medium the default (which is the only real choice we have), we anyway have the onerous burden of divining javac's interpretation by little more than staring into tea leaves. And you want to complicate things further by adding yet another mode ? :) On a more serious note, I agree there is no gainsaying the value of a strict mode, but it is a project for another day.
Another test case from https://bugs.eclipse.org/bugs/show_bug.cgi?id=170064 public class Test { public static class Foo<T>{ } public static class Bar<T> extends Foo<T>{ } public <Z,E extends Foo<Z>> Class<E> test(){ return (Class<E>) Bar.class; } }
*** Bug 170064 has been marked as a duplicate of this bug. ***
Another test case from bug 323473 interface List<E> {} interface I {} public class X { <T extends I> void main(List<T> clazz, List<X> xList) { boolean b = clazz == xList || xList == clazz; } }
*** Bug 323473 has been marked as a duplicate of this bug. ***
Despite all the intricacies, I believe comment 0 should be fixable on our side => during 4.10 time permitting.
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.