Community
Participate
Working Groups
I20110307-2110 package xy; import java.util.ArrayList; import java.util.Collections; public class C { void foo(ArrayList<String> al) { Collections.fill(al, "Hi"); } } In 3.6, inlining the 'fill' method worked fine (except for the invisible FILL_THRESHOLD constant). In HEAD, the result is this, with 2 unnecessary casts that contain the unavailable type variable T: int size = ((List<? super T>) al).size(); if (size < Collections.FILL_THRESHOLD || al instanceof RandomAccess) { for (int i=0; i<size; i++) (al).set(i, (T) "Hi"); } else { ListIterator<? super String> itr = (al).listIterator(); for (int i=0; i<size; i++) { itr.next(); itr.set("Hi"); } }
Problem is not completely new (already present in 3.7 M4). Deepak, can you please have a look?
It is present in 3.7 M1 as well, most likely caused by bug 267386. Though in M1 the snippet from comment 0 results in 5 unnecessary casts :)
Fix will probably go in ASTNodes.getExplicitCast(Expression, Expression) (which is called from SourceProvider.replaceParameterWithExpression(...)) or somewhere deep inside TypeRules.canAssign(ITypeBinding, ITypeBinding)...
Simpler example. Inline fill1() and fill2() ---------------------------------------------------------------- package xy; import java.util.ArrayList; import java.util.List; import java.util.ListIterator; public class C { void foo(ArrayList<String> al) { fill1(al); fill2("Hi"); } public static <T> void fill1(List<? super T> list) { ListIterator<? super T> it = list.listIterator(); } public static <T> void fill2(T object) { List<T> list = new ArrayList<T>(); list.add(object); } } ---------------------------------------------------------------
I guess the problem is that ASTNodes.getExplicitCast(*) doesn't have enough information. It is missing the actual type argument <String> for the type parameter <T> in the reference, so it can't know the actual type arguments to perform the analysis with. I guess we have to take the MethodInvocation for the 'fill' method, resolve the method binding, and perform the substitutions to replace the type parameter (from methodBinding.getMethodDeclaration().getTypeParameters()) with the actual argument (from methodBinding.getTypeArguments()). The support for these substitutions will have to be added to the TypeEnvironment.
As a first solution for 3.7, we can also just detect the problem and avoid the cast if the result contains type variables that are not defined in the context of the receiver. That's much easier to implement, would not affect the other fixes we applied in 3.7, and would just bring us back into 3.6 state in the more exotic cases.
Created attachment 193578 [details] Workaround We currently have a regression compared to 3.6. This patch avoids casts if the reference type contains type variables. A more complicated fix could go into 3.8 if this turns out to be an issue in practice.
Fixed in HEAD.