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*)