|
Quick Lists
|
|
Bug ID:
|
6369608
|
|
Votes
|
0
|
|
Synopsis
|
inference: Inferred types not substituted in bounds of unconstrained type variables
|
|
Category
|
java:specification
|
|
Reported Against
|
|
|
Release Fixed
|
|
|
State
|
6-Fix Understood,
bug
|
|
Priority:
|
4-Low
|
|
Related Bugs
|
6369605
,
6371674
,
6650759
,
6811943
|
|
Submit Date
|
06-JAN-2006
|
|
Description
|
See https://bugs.eclipse.org/bugs/show_bug.cgi?id=121369
Apparently, the specification requires a compiler must infer
List<T>, not List<Object> for U in a call to Foo.foo() in this
example:
class Foo {
static <T, U extends java.util.List<T>> void foo() {
return;
}
}
Posted Date : 2006-01-06 13:38:47.0
A further issue with uninferred type variables:
Can you explain how javac is accepting the following code if not doing what I am suggesting below?
public <E, S extends java.util.Collection<E>> S test1(S param){ return null; }
public void test2() { test1(new Vector<String>()); }
15.12.2.7 determines that: S = Vector<String>.
Then 15.12.2.8 kicks in to infer unconstrained E.
* S >> R' means: Object >> Vector<String>
* Bi[T1 = B(T1) ... Tn = B(Tn)] >> Ti means: Collection<E> >> S
Stepping back for an instant; what are we doing here? S already got inferred, so why would it try to infer it over again? Where is the fact that S = Vector<String> appearing then?
I think the spec should rather say
Bi[T1 = B(T1) ... Tn = B(Tn)] >> B(Ti) (note 'B(Ti)' instead of 'Ti')
but then the algorithm described in 15.12.2.7 wouldn't yield anything as:
Collection<E> >> Vector<String>
doesn't yield any data (as no formal argument on right side).
This is why I would suggest injecting:
Vector<String> << Collection<E>
If you don't do this, how can you infer E to be String instead of Object?
(E=Object would invalidate the bound contract for S, as Vector<String> is not <: Collection<Object>.)
If you change the line:
test1(new Vector<String>());
into:
String s = (String) test1(new Vector<String>());
you can see that javac did infer S to be Vector<String> as per error message tells.
To be clear my spec suggestion is that instead of 15.12.2.8 only saying:
* additional constraints Bi[T1 = B(T1) ... Tn = B(Tn)] >> Ti,
where Bi is the declared bound of Ti,
It would also hint from bounds of already inferred type variables, since
these may contain references to underconstrained variables.
* additional constraints B(Ti) << Bi[T1 = B(T1) ... Tn = B(Tn)],
where Bi is the declared bound of Ti,
Posted Date : 2007-06-20 00:17:30.0
|
|
Work Around
|
N/A
|
|
Evaluation
|
Given:
static <T, U extends java.util.List<T>> void foo() { return; }
Foo.foo();
the JLS does infer U to be List<T>, and then T to be Object. As Philippe says, U should be List<Object>. 15.12.2.8 should say:
"Any remaining type variable Tr that has not yet been inferred is then inferred to have type Object. If a previously inferred type Tp uses Tr, then Tp is now inferred to be Tp[Tr=Object]."
Sidebar: Philippe seems to imply that the example above gives a different inference result than:
static <T, U extends java.util.List<T>> U foo() { return null; }
String s = (String) Foo.foo();
but javac 1.6 infers Object for both T and U in both examples. Here, we compute U=glb(String, List<T>), so Object is the only possibility.
In the F-bounded case of:
static <T, U extends java.util.List<U>> U foo() { return null; }
String s = (String) Foo.foo();
we have U<:String and U<:List<U>, and need to compute U=glb(String,List<U>), which is ill-formed. The worst case would be:
static <T extends java.util.List<U>, U extends java.util.List<T>> ...
as we would have computations which rely on each other:
T=glb(..., List<U>)
U=glb(..., List<T>)
Ideally, T and U would both become List<Object>, or Object at worst. I propose this additional modification to 15.12.2.8:
"Any equality constraints are resolved, and then, for each remaining constraint of the form Ti<:Uk, the argument Ti is inferred to be glb(U'1..U'k) where U'i is Ui with any uninferred Tj (j<>i) replaced with Object."
Posted Date : 2007-06-19 16:12:36.0
There's a recurrent pattern in the JDK that would be invalidated by inferring T as List<Object>:
enum MyEnum {}
class Test {
Class<?> returnClass = null;
void test() {
Object value = Enum.valueOf((Class)Test.class, "");
}
}
Note that the signature of Enum.valueOf is:
<T extends Enum<T>> T valueOf(Class<T>, String)
In this case 15.12.2.7 fails (as the first argument type is raw) - no type is inferred from actual arguments; 15.12.2.8 derives the following set of constraints for T:
T <: Enum<T> (from declared bound)
T <: Object (from expected return type)
This lead to T = glb(Enum<T>, Object) = Enum<T>. If we replace T by Object, then we end up with Enum<Object> which no longer respect the constraints on T (inferred type for T=X should be a subtype of Enum<X>). As a result this method call cannot be type-checked.
One way out is to replace any F-bounded type variable on the RHS with ? thus giving:
T <: Enum<?>
T <: Object
Another way out of this is to infer T = #1, where ub(#1) = Enum<#1>
This has the advantage of (i) not being a straight type-variable trying to escape its context and (ii) respecting the bound constraints; in fact we have that
#1 <: [T:=#1] Enum<T> = Enum<#1>
ub(#1) = Enum<#1> <: Enum<#1> -> OK!
Posted Date : 2008-09-02 18:38:31.0
|
|
Comments
|
Submitted On 25-JUN-2007
mulet
Re: "Sidebar: Philippe seems to imply that ..."
I wasn't implying that, maybe only poorly phrasing my thoughts. Basically, by forcing an error to dump inferred types, some things become more visible.
Both cases should indeed yield the same thing. The trick is that javac infers U to be Object, where Eclipse compiler infers U to be List<Object>.
Note: the cast conversion doesn't create any constraint for inference, hence there is no: U=glb(String,List<T>).
Submitted On 25-JUN-2007
mulet
To be clear: "maybe only poorly phrasing my thoughts" - I am only speaking of myself poorly phrasing. <g>
Submitted On 03-SEP-2008
mulet
BTW - shouldn't a cast imply a type expectation in the long run ? Syntax for cast is quite a bit more natural to use than prefixing invocation with type arguments.
PLEASE NOTE: JDK6 is formerly known as Project Mustang
|
|
|
 |