[Checkers] Method Type Parameters
Mahmood Ali
mahmood at MIT.EDU
Sat Mar 15 01:37:21 EDT 2008
Hi guys,
I will be working on resolving type parameters next. I am having some
trouble designing this, so I would like to get your input on it.
Consider us having
static <T> T get(T t1, T t2) { return null; }
__THE PROBLEM__
Resolving a type variable in a method invocation may require a type
inference if the used does not supply/declare them (e.g.
Collections.<Date>emptySet()). From my understanding of the JLS Sec.
15.12.2, there are three stages:
1. Resolving type variables based on type parameters: With a first
order approximation, we simply find the least upper bound on all the
uses of the type parameters. So if I call get(date, integer), I will
get lub(date, integer) as a return type. That doesn't always work, but
Javac provide you with this information.
2. Resolving type variables based on their assignment context. If a
type variable is not resolved based on parameters and the return type
is used in an assignment (or pseudo-assignment), we match the type
variable to the desired type, so the type of Collections.emptySet() is
Set<Integer> when it is assigned to Set<Integer> variable or Set<Date>
when it's a assigned to Set<Date> variable. In other words, the
return type is not only on the method invocation tree only, but also
on the context that it is in.
3. Any yet unresolved type variables are specified as
java.lang.Object. So Collections.emptySet() in a non-assignment
context is resolved to Set<Object>
__MY APPROACH__
It is relatively easy to find the un-annotated type of the type
variable, simply by using the Javac Types API, so we merely need to
find the right annotations for the type.
STEP ONE: BASED ON TYPE PARAMETERS:
Once we know how the type variable is resolved, we can simply find all
the uses of the parameters and find the lub in a similar fashion to
conditional expression type inference. I would simply refactor the
code for inferring conditional expressions to return to me the correct
type.
STEP TWO: BASED ON CONTEXT: HARDEST PART
We will have to figure out what it gets assigned to, if the type
variable is unbounded. One way of doing it is to use a TreePath and
climb the tree to find whether it is an assignment context or not, and
what the required type is. Please note that this should be recursive,
as the assignment could actually be to a parameter in a method
invocation that requires type inference (e.g. get(Integer, get(Date,
String))).
STEP THREE: Assign to Object (or actually to the supertype of T if one
is specified):
Whatever left from the second step gets assigned of Object.
Unfortunately, that means that actually need to perform step two
before resolving Object, as it is not sufficient to see that the Javac
Type is Object. Consider the following case
Set<@Null Object> set = Collections.emptySet();
Collections.emptySet();
The second statement will get Set<Object> due to unresolved E, while
the first one is assigned to Object due to step two and should
actually be @Null Object.
However, I don't know if will ever need to infere the type of return
type of a method invocation that are not part of an assignment context
(since otherwise, we won't need to type check the return type anyway).
__Engineering Techniques__
We can do the first type of inference and postpone the second one for
later, and simply require the users to explicitly set the type variable.
What do you guys thing?
More information about the checkers
mailing list