-
Notifications
You must be signed in to change notification settings - Fork 2
Questionable Type Inference behavior #151
Description
I'm going to walk through a debugging session on the convert-common-image-types branch.
In AdaptationMatchingRoutine I am trying to match dependencies of a complex lifting op. The lifter matches fine, but the adaptor dependency has problems.
The dependency type is:
java.util.function.Function<org.scijava.function.Computers.Arity2<RAII1 extends net.imglib2.RandomAccessibleInterval<I1>, RAII2 extends
net.imglib2.RandomAccessibleInterval<I2>, RAIO extends net.imglib2.RandomAccessibleInterval<O>>, java.util.function.BiFunction<RAII1, RAII2, RAIO>>
and the matched Op type is:
org.scijava.ops.engine.adapt.functional.ComputersToFunctionsViaFunction.Computer2ToFunction2ViaFunction<I1, I2, O>
So as we recursively infer the type variables, the types were are inferring are:
0 = {TypeVariableImpl@9129} "RAII1"
1 = {TypeVariableImpl@9077} "RAII2"
2 = {TypeVariableImpl@9131} "RAIO"
and the inferFroms types are:
0 = {TypeVariableImpl@9098} "I1"
1 = {TypeVariableImpl@9185} "I2"
2 = {TypeVariableImpl@9187} "O"
This leads to this typeVarAssigns map that is checked in Types.typesSatisfyVariables:
{TypeVariableImpl@9077} "RAII2" -> {TypeVariableImpl@9185} "I2"
{TypeVariableImpl@9131} "RAIO" -> {TypeVariableImpl@9187} "O"
{TypeVariableImpl@9135} "I1" -> {Any@9184} "Any"
{TypeVariableImpl@9137} "O" -> {Any@9188} "Any"
{TypeVariableImpl@9129} "RAII1" -> {TypeVariableImpl@9098} "I1"
{TypeVariableImpl@9133} "I2" -> {Any@9186} "Any"
Note that the I1, I1 and O here are different from the inferFroms above.. these are the type parameters of the RAI1, RAI2 and RAIO type variables.
So then we check [Types.isAssignable](https://github.com/scijava/incubator/blob/54b8af3021886df2530a3d9b6dd861c879ba7a2f/scijava/scijava-types/src/main/java/org/scijava/types/Types.java#L2725-L2726) for each type` (the values in the assignment map) being assignable to the bound.
This leads to, for example, isAssignable with:
type = {TypeVariableImpl@9098} "I1"
toType = net.imglib2.RandomAccessibleInterval<Any>
We chain down to the ParameterizedType version of isAssignable, and then try to extract the arguments of type.
This leads us to this case logic in getTypeArguments which returns null. This is because type is an unbound type variable, so getImplicitBounds(type) returns Object, and isAssignable(Object, RandomAccessibleInterval) returns false.
Then back in isAssignable, we see the null return and say "we're not compatible".
However I think this is incorrect. Our type variable I1 is unbound and currently has no assignment in the Map<TypeVariable<?>, Type> of type assignments. We know it's unbound because its only "bound" was Object.
It seems to me that if type is a TypeVariable with a single Object bound and no assignment in the type map, then we should assign it to the toClass in the type map.
Since isAssignable seems like "the place" we do these mapping side effects maybe it should happen here, mapping type -> toParameterizedType:
{TypeVariableImpl@9098} "I1" -> net.imglib2.RandomAccessibleInterval<Any>