Autoboxing and generics type inference typically passes addresses, not values
Following up on #991 (closed), I'm observing numerous issues with code generation when using value types and generic methods.
Some of these will accidentally work in common cases (e.g. passing a value to a Gee container as a memory address, then getting it back out again), but if you want to work with the value that is passed in, then you're out of luck.
public void test<T>(T value) {
if (typeof(T) == typeof(int)) {
int int_val = (int) ((int?) value);
print("%d\n", int_val);
}
}
void main() {
const int FORTY_TWO = 42;
int forty_two = 42;
int? forty_two_boxed = 42;
//
// Plain calls, requires both autoboxing and type inference
//
test(42);
// Invalid, just casts the value to a pointer:
// test (G_TYPE_INT, NULL, NULL, (gpointer) ((gintptr) 42));
test(FORTY_TWO);
// Invalid, just casts the value to a pointer:
// test (G_TYPE_INT, NULL, NULL, (gpointer) ((gintptr) FORTY_TWO));
test(forty_two);
// Invalid, just casts the value to a pointer:
// test (G_TYPE_INT, NULL, NULL, (gpointer) ((gintptr) forty_two));
//
// Explicit boxing, type inference
//
test((int?) 42);
// Invalid, just casts the value to a pointer:
// test (G_TYPE_INT, (GBoxedCopyFunc) _int_dup, (GDestroyNotify) g_free, (gint*) 42);
test((int?) FORTY_TWO);
// Invalid, just casts the value to a pointer:
// test (G_TYPE_INT, (GBoxedCopyFunc) _int_dup, (GDestroyNotify) g_free, (gint*) FORTY_TWO);
test((int?) forty_two);
// Invalid, just casts the value to a pointer:
// test (G_TYPE_INT, (GBoxedCopyFunc) _int_dup, (GDestroyNotify) g_free, (gint*) forty_two);
test(forty_two_boxed);
// Valid, since the value is already a pointer
// test (G_TYPE_INT, (GBoxedCopyFunc) _int_dup, (GDestroyNotify) g_free, forty_two_boxed);
//
// Autoboxing, explicit typing
//
test<int?>(42);
// Valid, variable address is passed in:
// _tmp2_ = 42;
// test (G_TYPE_INT, (GBoxedCopyFunc) _int_dup, (GDestroyNotify) g_free, &_tmp2_);
test<int?>(FORTY_TWO);
// Valid, variable address is passed in:
// _tmp3_ = FORTY_TWO;
// test (G_TYPE_INT, (GBoxedCopyFunc) _int_dup, (GDestroyNotify) g_free, &_tmp3_);
test<int?>(forty_two);
// Valid, variable address is passed in:
// test (G_TYPE_INT, (GBoxedCopyFunc) _int_dup, (GDestroyNotify) g_free, &forty_two);
//
// Explicit boxing, explicit typing
//
test<int?>((int?) 42);
// Invalid, just casts the value to a pointer:
// test (G_TYPE_INT, (GBoxedCopyFunc) _int_dup, (GDestroyNotify) g_free, (gint*) 42);
test<int?>((int?) FORTY_TWO);
// Invalid, just casts the value to a pointer:
// test (G_TYPE_INT, (GBoxedCopyFunc) _int_dup, (GDestroyNotify) g_free, (gint*) FORTY_TWO);
test<int?>((int?) forty_two);
// Invalid, just casts the value to a pointer:
// test (G_TYPE_INT, (GBoxedCopyFunc) _int_dup, (GDestroyNotify) g_free, (gint*) forty_two);
test<int?>(forty_two_boxed);
// Valid, since the value is already a pointer
// test (G_TYPE_INT, (GBoxedCopyFunc) _int_dup, (GDestroyNotify) g_free, forty_two_boxed);
}