Community
Participate
Working Groups
Build ID: Build id: M20070212-1330 Steps To Reproduce: With compiler compliance level 5.0, public Set<String> getTypedSet() { return true ? Collections.emptySet() : null; } leads to "Type mismatch: cannot convert from Set<Object> to Set<String>". More information: public Set<String> getTypedSet() { return Collections.emptySet(); } works.
Reproduced with 3.3 M5eh. javac (1.5.0_11, 6_01_b03, 7_b06) behaves as we do. The reason is that the conditional expression prevents us to infer the type parameter for <T> Set<T> emptySet(). I'll double-check the spec. Note that the following test case provides a workaround: class X { public Set<String> getTypedSet() { return true ? Collections.<String>emptySet() : null; } } While the following fails as well: class X { public Set<String> getTypedSet() { return true ? Collections.emptySet() : Collections.emptySet(); } }
It's not exactly clear what's going on. Both public Set<String> getTypedSet() { if (true) return Collections.emptySet(); else return null; } and public Set<String> getTypedSet() { Set<String> s; if (true) s = Collections.emptySet(); else s = null; return s; } work.
In the examples of comment #2, the 'return <expression>' gives a clue that the expression should be of type Set<String>, which enables to infer the type parameter (T) as String. The same for the assignment to s. In the initial test case, the ternary operator "filters the clue out" somehow. I will search the spec for an explanation of that point, around the rules for type inference. (Since javac behaves as we do, I would expect the spec to tell us right.)
More formally, JLS 3 § 15.12.2.8 tells us that if a method, for which type inference has provided no type parameter after considering the types of the argument expressions, is in a context into which it will be subject to assignment conversion to a type S, then its parameter types are inferred using a S >> R constraint, where R stands for the method return type (it's a bit more complex than that in general, but this will do for this case). Else (if it will not be subject to assignment conversion), the type parameters are inferred 'under the assumption that the method result was assigned to a variable of type Object.'. § 5.2 tells us that assignment conversion occurs when an expression is assigned to a variable. It tells us nothing regarding either the return statement or the ?: conditional operator. $ 14.17 tells us that the expression of a return must assignable to the type of the enclosing method. Which tends to support the view that 'return <exp>' puts exp in a context into which it will be subject to an assignment conversion. Having said that, nothing in the spec commands that, placing 'e1 ? e2 : e3' in a context into which it will be subject to assignment conversion to a type S implies that e2 and e3 be placed in a context into which they would be subject to assignment conversion to the said type S. While we would be tempted to make that move on simple cases, the rules given in § 15.25 that command the ?: expression type are quite complex on non-trivial cases (they can involve applying lub to capture conversions of boxing conversions). My understanding is that the spec does not require that the property 'S >> e1 ? e2 : e3 imply S >> e2 and S >> e3' be leveraged at type inference time, leaving us with Object >> e2. Except if anything more positive can be found in the spec that would invalidate that analysis, given the fact that the reference implementation behaves as we do, I would support closing this bug as invalid. Philippe, Kent, what do you think?
Given noone vetos my proposal, closing as INVALID.
Comment 4 is accurate, our behavior is mandated by the spec. Note that cast expressions are not providing clues for inference either (I am arguing about this with them already). Maxime - can you pls add a regression test still ?
Released GenericTypeTest#1109 and 1110 in HEAD.