Here is some food for thought that might be relevant to discussions such as in #41. Low-level type systems generally need to at some point incorporate multi-value flow-sensitivity. That means that a branch taken on one value needs to be able to affect the operations you can do on other values on the context.
Here's an example for supporting Java/C# (that normally wouldn't be written this way but which would be produced by inlining):
int sum(Object arr) {
Integer[] ints = (Integer[]) arr;
int sum = 0;
for (int i = 0; i < ints.length; i++) {
Integer intref = ints[i];
sum += intref.int_value;
}
return sum;
}
At the low level, this turns into:
int sum(Object arr) {
ints = cast arr to Array;
elem_type = ints.elem_rtt;
assert elem_type == Integer.rtt;
sum = 0;
for (i = 0; i < ints.length; i++) {
intref = ints[i];
sum += intref.int_value;
}
return sum;
}
Notice that, in order for this to type check, after branching on elem_type == Integer.rtt we need to realize that this means the references contained in ints necessarily have an int_value field even though elem_type == Integer.rtt has no direct reference to ints.
Without multi-value flow-sensitivity, you can only get the following to type check:
int sum(Object arr) {
ints = cast arr to Array;
elem_type = ints.elem_rtt;
assert elem_type == Integer.rtt;
sum = 0;
for (i = 0; i < ints.length; i++) {
intref = cast ints[i] to Integer;
sum += intref.int_value;
}
return sum;
}
That is, we have to cast every reference retrieved from ints to Integer even after asserting that its element type is the correct type. To make matters worse, if you don't have multi-value flow-sensitivity, there's no way to enforce the expectation that a surface-level Integer[] only contains Integer references, so you'll have to cast the result of int[i] even when ints has surface-level type Integer[].
(Note: all of this is independent of covariant arrays, so feel free to ignore that additional complexity when pondering this food for thought.)
So when considering design options, you might want to think of which options better support multi-value flow-sensitivity.
Here is some food for thought that might be relevant to discussions such as in #41. Low-level type systems generally need to at some point incorporate multi-value flow-sensitivity. That means that a branch taken on one value needs to be able to affect the operations you can do on other values on the context.
Here's an example for supporting Java/C# (that normally wouldn't be written this way but which would be produced by inlining):
At the low level, this turns into:
Notice that, in order for this to type check, after branching on
elem_type == Integer.rttwe need to realize that this means the references contained inintsnecessarily have anint_valuefield even thoughelem_type == Integer.rtthas no direct reference toints.Without multi-value flow-sensitivity, you can only get the following to type check:
That is, we have to cast every reference retrieved from
intstoIntegereven after asserting that its element type is the correct type. To make matters worse, if you don't have multi-value flow-sensitivity, there's no way to enforce the expectation that a surface-levelInteger[]only containsIntegerreferences, so you'll have to cast the result ofint[i]even whenintshas surface-level typeInteger[].(Note: all of this is independent of covariant arrays, so feel free to ignore that additional complexity when pondering this food for thought.)
So when considering design options, you might want to think of which options better support multi-value flow-sensitivity.