diff --git a/bootstrap_compiler/typecheck.c b/bootstrap_compiler/typecheck.c
index 41b4e264..1910b611 100644
--- a/bootstrap_compiler/typecheck.c
+++ b/bootstrap_compiler/typecheck.c
@@ -1014,6 +1014,16 @@ static const Type *cast_array_members_to_a_common_type(const FunctionOrMethodTyp
Append(&compatible_with_all, *t);
}
+ if (compatible_with_all.len > 1) {
+ // Remove void* if exists, so that type of ["hello", NULL] becomes byte*[2]
+ for (int i = 0; i < compatible_with_all.len; i++) {
+ if (compatible_with_all.ptr[i] == voidPtrType) {
+ compatible_with_all.ptr[i] = compatible_with_all.ptr[--compatible_with_all.len];
+ break;
+ }
+ }
+ }
+
if (compatible_with_all.len != 1) {
List(char) namestr = {0};
for (const Type **t = distinct.ptr; t < End(distinct); t++) {
diff --git a/compiler/build_cf_graph.jou b/compiler/build_cf_graph.jou
index 90b684e0..05ad82c4 100644
--- a/compiler/build_cf_graph.jou
+++ b/compiler/build_cf_graph.jou
@@ -114,7 +114,7 @@ def add_unary_op(
target: LocalVariable*,
) -> None:
ins = CfInstruction{location = location, kind = op, destvar = target}
- operands = [arg, NULL as LocalVariable*]
+ operands = [arg, NULL]
ins.set_operands(operands)
add_instruction(st, ins)
@@ -129,7 +129,7 @@ def add_binary_op(
target: LocalVariable*,
) -> None:
ins = CfInstruction{location = location, kind = op, destvar = target}
- operands = [lhs, rhs, NULL as LocalVariable*]
+ operands = [lhs, rhs, NULL]
ins.set_operands(operands)
add_instruction(st, ins)
@@ -331,7 +331,7 @@ def build_class_field_pointer(
assert sizeof(ins.fieldname) == sizeof(f->name)
strcpy(ins.fieldname, f->name)
- operands = [instance, NULL as LocalVariable*]
+ operands = [instance, NULL]
ins.set_operands(operands)
add_instruction(st, ins)
@@ -917,7 +917,7 @@ def build_assert(st: State*, assert_location: Location, assertion: AstAssertion*
add_local_var(st, argtypes[0]),
add_local_var(st, argtypes[1]),
add_local_var(st, argtypes[2]),
- NULL as LocalVariable*,
+ NULL,
]
add_constant(st, assert_location, Constant{kind = ConstantKind::String, str = assertion->condition_str}, args[0])
diff --git a/compiler/typecheck.jou b/compiler/typecheck.jou
index 8856749a..41f94e02 100644
--- a/compiler/typecheck.jou
+++ b/compiler/typecheck.jou
@@ -880,7 +880,7 @@ global nth_result_buffer: byte[100]
def nth(n: int) -> byte*:
assert n >= 1
- first_few = [NULL as byte*, "first", "second", "third", "fourth", "fifth", "sixth"]
+ first_few = [NULL, "first", "second", "third", "fourth", "fifth", "sixth"]
if n < sizeof(first_few) / sizeof(first_few[0]):
return first_few[n]
@@ -1067,6 +1067,13 @@ def cast_array_members_to_a_common_type(fom: FunctionOrMethodTypes*, error_locat
assert compatible_with_all != NULL
compatible_with_all[n_compatible_with_all++] = *t
+ if n_compatible_with_all > 1:
+ # Remove void* if exists, so that type of ["hello", NULL] becomes byte*[2]
+ for i = 0; i < n_compatible_with_all; i++:
+ if compatible_with_all[i] == voidPtrType:
+ compatible_with_all[i] = compatible_with_all[--n_compatible_with_all]
+ break
+
if n_compatible_with_all != 1:
size = 500L
for t = distinct; t < &distinct[ndistinct]; t++:
diff --git a/examples/aoc2024/day21/part2.jou b/examples/aoc2024/day21/part2.jou
index 21b05e1a..10cda56f 100644
--- a/examples/aoc2024/day21/part2.jou
+++ b/examples/aoc2024/day21/part2.jou
@@ -32,35 +32,35 @@ def init_tables() -> None:
# ^ A
# < v >
- arrow_keypad_table['^']['^'] = ["A", NULL as byte*]
- arrow_keypad_table['^']['A'] = [">A", NULL as byte*]
- arrow_keypad_table['^']['<'] = ["vA", NULL]
+ arrow_keypad_table['^']['<'] = ["v'] = ["v>A", ">vA"]
- arrow_keypad_table['A']['^'] = ["'] = ["vA", NULL as byte*]
+ arrow_keypad_table['A']['>'] = ["vA", NULL]
- arrow_keypad_table['<']['^'] = [">^A", NULL as byte*]
- arrow_keypad_table['<']['A'] = [">>^A", NULL as byte*]
- arrow_keypad_table['<']['<'] = ["A", NULL as byte*]
- arrow_keypad_table['<']['v'] = [">A", NULL as byte*]
- arrow_keypad_table['<']['>'] = [">>A", NULL as byte*]
+ arrow_keypad_table['<']['^'] = [">^A", NULL]
+ arrow_keypad_table['<']['A'] = [">>^A", NULL]
+ arrow_keypad_table['<']['<'] = ["A", NULL]
+ arrow_keypad_table['<']['v'] = [">A", NULL]
+ arrow_keypad_table['<']['>'] = [">>A", NULL]
- arrow_keypad_table['v']['^'] = ["^A", NULL as byte*]
+ arrow_keypad_table['v']['^'] = ["^A", NULL]
arrow_keypad_table['v']['A'] = [">^A", "^>A"]
- arrow_keypad_table['v']['<'] = ["'] = [">A", NULL as byte*]
+ arrow_keypad_table['v']['<'] = ["'] = [">A", NULL]
arrow_keypad_table['>']['^'] = ["<^A", "^']['A'] = ["^A", NULL as byte*]
- arrow_keypad_table['>']['<'] = ["<']['v'] = ["']['>'] = ["A", NULL as byte*]
+ arrow_keypad_table['>']['A'] = ["^A", NULL]
+ arrow_keypad_table['>']['<'] = ["<']['v'] = ["']['>'] = ["A", NULL]
# 7 8 9
# 4 5 6
diff --git a/tests/should_succeed/array.jou b/tests/should_succeed/array.jou
index 56b47ffb..edda5bc6 100644
--- a/tests/should_succeed/array.jou
+++ b/tests/should_succeed/array.jou
@@ -42,4 +42,13 @@ def main() -> int:
increment(foo as int*) # same cast explicitly
printf("%d %d %d\n", foo[0], foo[1], foo[2]) # Output: 7 5 6
+ # corner case: byte* <--> void* can be converted both ways, use byte*
+ strings = ["hello", NULL, "world", NULL]
+ printf("%s %s\n", strings[0], strings[2]) # Output: hello world
+ # Output: strings[1] is NULL
+ # Output: strings[3] is NULL
+ for i = 0; i < 4; i++:
+ if strings[i] == NULL:
+ printf("strings[%d] is NULL\n", i)
+
return 0
diff --git a/tests/wrong_type/array_mixed_types_ptr.jou b/tests/wrong_type/array_mixed_types_ptr.jou
index 4791a156..1fb10b76 100644
--- a/tests/wrong_type/array_mixed_types_ptr.jou
+++ b/tests/wrong_type/array_mixed_types_ptr.jou
@@ -1,9 +1,3 @@
def foo() -> None:
- # When we make an array of int* and void*:
- # - we could cast int* to void*, and get an array of void*
- # - we could cast void* to int*, and get an array of int*
- #
- # Because the compiler cannot be sure what you want, it refuses to
- # guess and instead errors.
a = 1
- x = [&a, &a as void*] # Error: array items have different types (int*, void*)
+ x = [&a, "hello"] # Error: array items have different types (int*, byte*)