changed cast logic; a test case is not correct at the moment
authorBrendan Hansen <brendan.f.hansen@gmail.com>
Wed, 6 Jan 2021 05:24:49 +0000 (23:24 -0600)
committerBrendan Hansen <brendan.f.hansen@gmail.com>
Wed, 6 Jan 2021 05:24:49 +0000 (23:24 -0600)
20 files changed:
bin/onyx
core/map.onyx
include/onyxastnodes.h
onyx.exe
src/onyxchecker.c
src/onyxutils.c
src/onyxwasm.c
tests/aoc-2020/day14.onyx
tests/aoc-2020/day15.onyx
tests/aoc-2020/day17.onyx
tests/aoc-2020/day20.onyx
tests/aoc-2020/day21.onyx
tests/aoc-2020/day22.onyx
tests/aoc-2020/day24.onyx
tests/aoc-2020/day25.onyx
tests/aoc-2020/day7.onyx
tests/aoc-2020/day8.onyx
tests/general1.onyx
tests/i32map.onyx
tests/overload_with_autocast.onyx

index ab00105d1cfee8b69460970059c457e999420d9f..c30ab5a1437ed471a470bcf639172d30365b0e20 100755 (executable)
Binary files a/bin/onyx and b/bin/onyx differ
index a6e6b76e3e6a23feb8bde1983dc3da58add2e434..ceae9041ed2075950f006761dcba991e43308679 100644 (file)
@@ -7,6 +7,9 @@ use package core.string as string
 Map :: struct ($K, $V) {
     hashes  : [..] i32;
     entries : [..] MapEntry(K, V);
+
+    // The value provided by `map.get`, if nothing was found.
+    default_value : V;
 }
 
 MapEntry :: struct ($K, $T) {
@@ -15,10 +18,12 @@ MapEntry :: struct ($K, $T) {
     value : T;
 }
 
-init :: proc (use map: ^Map($K, $V), hash_count: i32 = 16) {
+init :: proc (use map: ^Map($K, $V), dv: V, hash_count: i32 = 16) {
     array.init(^hashes, hash_count);
     array.init(^entries, 4);
 
+    default_value = dv;
+
     for i: 0 .. hash_count do array.push(^hashes, -1);
 }
 
@@ -50,11 +55,11 @@ has :: proc (use map: ^Map($K, $V), key: K) -> bool {
     return lr.entry_index >= 0;
 }
 
-get :: proc (use map: ^Map($K, $V), key: K, default := cast(V) 0) -> V {
+get :: proc (use map: ^Map($K, $V), key: K) -> V {
     lr := lookup(map, key);
     if lr.entry_index >= 0 do return entries[lr.entry_index].value;
 
-    return default;
+    return default_value;
 }
 
 delete :: proc (use map: ^Map($K, $V), key: K) {
index a8cdc66492a3b33c4f305022aafacca5332a339f..90daef4eee6414b376d2e6153d3bce0ea5ac043c 100644 (file)
@@ -930,6 +930,7 @@ void promote_numlit_to_larger(AstNumLit* num);
 b32 convert_numlit_to_type(AstNumLit* num, Type* type);
 b32 type_check_or_auto_cast(AstTyped** pnode, Type* type);
 Type* resolve_expression_type(AstTyped* node);
+b32 cast_is_legal(Type* from_, Type* to_, char** err_msg);
 char* get_function_name(AstFunction* func);
 
 typedef enum PolyProcLookupMethod {
index 0ea5726e2a689e5a13fb240d4d25ca461a5153d9..e47275a89f782ea3125511cd3a7958af34eeeb54 100644 (file)
Binary files a/onyx.exe and b/onyx.exe differ
index ab6b8aba2b8404dffc2549726759b0a38058c4b9..707e754619fcc2fe51f3b8b7b7e12d033e2e127f 100644 (file)
@@ -893,7 +893,14 @@ CheckStatus check_unaryop(AstUnaryOp** punop) {
     CHECK(expression, &unaryop->expr);
     resolve_expression_type(unaryop->expr);
 
-    if (unaryop->operation != Unary_Op_Cast) {
+    if (unaryop->operation == Unary_Op_Cast) {
+        char* err;
+        if (!cast_is_legal(unaryop->expr->type, unaryop->type, &err)) {
+            onyx_report_error(unaryop->token->pos, "Cast Error: %s", err);
+            return Check_Error;
+        }
+        
+    } else {
         unaryop->type = unaryop->expr->type;
     }
 
index 3edd10e1ceb95e295c410a4a25939cec1c8d427b..00ccec2ae21344a70183c43470e7855e93221141 100644 (file)
@@ -953,9 +953,14 @@ b32 type_check_or_auto_cast(AstTyped** pnode, Type* type) {
 
     if (types_are_compatible(node->type, type)) return 1;
     if (node_is_auto_cast((AstNode *) node)) {
-        // HACK: Check that this cast is legal!
-        ((AstUnaryOp *) node)->type = type;
-        return 1;
+        char* dummy;
+        if (!cast_is_legal(((AstUnaryOp *) node)->expr->type, type, &dummy)) {
+            return 0;
+
+        } else {
+            ((AstUnaryOp *) node)->type = type;
+            return 1;
+        }
     }
     else if (node->kind == Ast_Kind_NumLit) {
         if (convert_numlit_to_type((AstNumLit *) node, type)) return 1;
@@ -983,6 +988,95 @@ Type* resolve_expression_type(AstTyped* node) {
     return node->type;
 }
 
+static const b32 cast_legality[][11] = {
+    /* I8  */ { 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0 },
+    /* U8  */ { 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0 },
+    /* I16 */ { 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0 },
+    /* U16 */ { 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0 },
+    /* I32 */ { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
+    /* U32 */ { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
+    /* I64 */ { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
+    /* U64 */ { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
+    /* F32 */ { 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0 },
+    /* F64 */ { 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0 },
+    /* PTR */ { 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 1 },
+};
+
+b32 cast_is_legal(Type* from_, Type* to_, char** err_msg) {
+    Type* from = from_;
+    Type* to   = to_;
+
+    if (from->kind == Type_Kind_Enum) from = from->Enum.backing;
+    if (to->kind == Type_Kind_Enum) to = to->Enum.backing;
+
+    if (from->kind == Type_Kind_Struct || to->kind == Type_Kind_Struct) {
+        *err_msg = "Cannot cast to or from a struct.";
+        return 0;
+    }
+
+    if (from->kind == Type_Kind_Slice || to->kind == Type_Kind_Slice) {
+        *err_msg = "Cannot cast to or from a slice.";
+        return 0;
+    }
+
+    if (from->kind == Type_Kind_DynArray || to->kind == Type_Kind_DynArray) {
+        *err_msg = "Cannot cast to or from a dynamic array.";
+        return 0;
+    }
+
+    if (to->kind == Type_Kind_Function) {
+        *err_msg = "Cannot cast to a function.";
+        return 0;
+    }
+
+    if (   (type_is_simd(to) && !type_is_simd(from))
+        || (!type_is_simd(to) && type_is_simd(from))) {
+        *err_msg = "Can only perform a SIMD cast between SIMD types.";
+        return 0;
+    }
+
+    if (from->kind == Type_Kind_Basic && from->Basic.kind == Basic_Kind_Void) {
+        *err_msg = "Cannot cast from void.";
+        return 0;
+    }
+    i32 fromidx = -1, toidx = -1;
+    if (from->Basic.flags & Basic_Flag_Pointer || from->kind == Type_Kind_Array) {
+        fromidx = 10;
+    }
+    else if (from->Basic.flags & Basic_Flag_Integer) {
+        b32 unsign = (from->Basic.flags & Basic_Flag_Unsigned) != 0;
+
+        fromidx = log2_dumb(from->Basic.size) * 2 + unsign;
+    }
+    else if (from->Basic.flags & Basic_Flag_Float) {
+        if      (from->Basic.size == 4) fromidx = 8;
+        else if (from->Basic.size == 8) fromidx = 9;
+    }
+
+    if (to->Basic.flags & Basic_Flag_Pointer || to->kind == Type_Kind_Array) {
+        toidx = 10;
+    }
+    else if (to->Basic.flags & Basic_Flag_Integer) {
+        b32 unsign = (to->Basic.flags & Basic_Flag_Unsigned) != 0;
+
+        toidx = log2_dumb(to->Basic.size) * 2 + unsign;
+    }
+    else if (to->Basic.flags & Basic_Flag_Float) {
+        if      (to->Basic.size == 4) toidx = 8;
+        else if (to->Basic.size == 8) toidx = 9;
+    }
+
+    if (fromidx != -1 && toidx != -1) {
+        if (!cast_legality[fromidx][toidx]) {
+            *err_msg = bh_aprintf(global_heap_allocator, "Cast from '%s' to '%s' is not allowed.", type_get_name(from_), type_get_name(to_));
+            return 0;
+        }
+    }
+
+    *err_msg = NULL;
+    return 1;
+}
+
 char* get_function_name(AstFunction* func) {
     if (func->name != NULL) {
         return bh_aprintf(global_scratch_allocator, "%b", func->name->text, func->name->length);
index 1a9ede093a8fbcae5a6a98847c8e49c53ad069f5..fdd4b8427b3768ed9071d3a8368816728fc15ffa 100644 (file)
@@ -2346,56 +2346,10 @@ EMIT_FUNC(cast, AstUnaryOp* cast) {
 
     Type* from = cast->expr->type;
     Type* to = cast->type;
-
-    if (from->kind == Type_Kind_Struct || to->kind == Type_Kind_Struct) {
-        onyx_report_error(cast->token->pos, "Cannot cast to or from a struct.");
-        WI(WI_DROP);
-        *pcode = code;
-        return;
-    }
-
-    if (from->kind == Type_Kind_Slice || to->kind == Type_Kind_Slice) {
-        onyx_report_error(cast->token->pos, "Cannot cast to or from a slice.");
-        WI(WI_DROP);
-        *pcode = code;
-        return;
-    }
-
-    if (from->kind == Type_Kind_DynArray || to->kind == Type_Kind_DynArray) {
-        onyx_report_error(cast->token->pos, "Cannot cast to or from a dynamic array.");
-        WI(WI_DROP);
-        *pcode = code;
-        return;
-    }
-
-    if (to->kind == Type_Kind_Function) {
-        onyx_report_error(cast->token->pos, "Cannot cast to a function.");
-        WI(WI_DROP);
-        *pcode = code;
-        return;
-    }
-
-    if (type_is_simd(to) && !type_is_simd(from)) {
-        onyx_report_error(cast->token->pos, "Can only perform a SIMD cast between SIMD types.");
-        return;
-    }
-
-    if (type_is_simd(from) && !type_is_simd(to)) {
-        onyx_report_error(cast->token->pos, "Can only perform a SIMD cast between SIMD types.");
-        return;
-    }
-
-    if (type_is_simd(from) && type_is_simd(to)) {
-        *pcode = code;
-        return;
-    }
-
     if (from->kind == Type_Kind_Enum) from = from->Enum.backing;
     if (to->kind == Type_Kind_Enum) to = to->Enum.backing;
 
-    if (from->kind == Type_Kind_Basic && from->Basic.kind == Basic_Kind_Void) {
-        onyx_report_error(cast->token->pos, "Cannot cast from void.");
-        WI(WI_DROP);
+    if (type_is_simd(from) && type_is_simd(to)) {
         *pcode = code;
         return;
     }
@@ -2435,11 +2389,9 @@ EMIT_FUNC(cast, AstUnaryOp* cast) {
 
     if (fromidx != -1 && toidx != -1) {
         WasmInstructionType cast_op = cast_map[fromidx][toidx];
-        if (cast_op == WI_UNREACHABLE) {
-            bh_printf("%d %d\n", fromidx, toidx);
-            onyx_report_error(cast->token->pos, "Bad cast.");
-        }
-        else if (cast_op != WI_NOP) {
+        assert(cast_op != WI_UNREACHABLE);
+        
+        if (cast_op != WI_NOP) {
             WI(cast_op);
         }
     }
index 4e1651c1fce6776183c1ebcdeb09e40d8564ef60..9d23a1030dca8a6fe6c3f5471deb8dfdae702640 100644 (file)
@@ -71,6 +71,7 @@ bitmask_iter_next :: proc (use bmi: ^BitmaskIter) -> u64 {
                done = true;
        }
 
+       printf("val is %l\n", val);
        return val;
 }
 
@@ -80,7 +81,7 @@ main :: proc (args: [] cstr) {
        file := reader.make(contents);
 
        mem : map.Map(u64, u64);
-       map.init(^mem, 257);
+       map.init(^mem, 0, 257);
        defer map.free(^mem);
 
        mask : Bitmask;
index 2cc74023f14c52cd0dc1861b57d09b5c2dff82e2..804e1e9f3e69cfdc94d134108a473b514188ac8d 100644 (file)
@@ -15,7 +15,7 @@ main :: proc (args: [] cstr) {
     // Any changes to the implementation of Map should be tested on this
     // file to validate if they 1) work and 2) are faster.
     nums : map.Map(u32, spoken_times);
-    map.init(^nums, 32767);
+    map.init(^nums, spoken_times.{}, 32767);
     defer map.free(^nums);
 
     turn := 1;
@@ -28,12 +28,12 @@ main :: proc (args: [] cstr) {
     }
 
     while turn != 2021 {
-        st := map.get(^nums, last_num, spoken_times.{});
+        st := map.get(^nums, last_num);
 
         if st.previous == 0 do last_num = 0;
         else                do last_num = st.recent - st.previous;
 
-        st = map.get(^nums, last_num, spoken_times.{});
+        st = map.get(^nums, last_num);
         st.previous = st.recent;
         st.recent = turn;
         map.put(^nums, last_num, st);
index 61cee9b441581d95287b58cbfca67dbeb53c7100..4cc8f30452d8292125fdd7d376af3ba91ba3e8fb 100644 (file)
@@ -32,7 +32,7 @@ get_neighbor_count :: proc (cubes: ^map.Map(CubePos, CubeState), pos: CubePos) -
     for x: -1 .. 2 do for y: -1 .. 2 do for z: -1 .. 2 do for w: -1 .. 2 {
         if x == 0 && y == 0 && z == 0 && w == 0 do continue;
         key := CubePos.{ pos.x + x, pos.y + y, pos.z + z, pos.w + w };
-        state := map.get(cubes, key, CubeState.{});
+        state := map.get(cubes, key);
         if state.alive do count += 1;
     }
 
@@ -45,7 +45,7 @@ main :: proc (args: [] cstr) {
     file := reader.make(contents);
 
     cubes : map.Map(CubePos, CubeState);
-    map.init(^cubes, 1021);
+    map.init(^cubes, CubeState.{}, 1021);
     defer map.free(^cubes);
 
     z := 0;
@@ -81,7 +81,7 @@ main :: proc (args: [] cstr) {
         }
 
         for ^cube: cubes_to_consider {
-            state  := map.get(^cubes, *cube, CubeState.{});
+            state  := map.get(^cubes, *cube);
             ncount := get_neighbor_count(^cubes, *cube);
             
             if state.alive {
@@ -94,7 +94,7 @@ main :: proc (args: [] cstr) {
         }
 
         for ^cube: cubes_to_consider {
-            state := map.get(^cubes, *cube, CubeState.{});
+            state := map.get(^cubes, *cube);
             state.alive = state.next;
             map.put(^cubes, *cube, state);
         }
index 988e5a81f6199db7819d4c040142b632007204dc..b4fca178bd9c3ad7c407e0b05150f8b897b3f5c4 100644 (file)
@@ -257,7 +257,7 @@ main :: proc (args: [] cstr) {
        defer array.free(^tiles);
 
     tile_map : map.Map(u32, ^Tile);
-    map.init(^tile_map, 67);
+    map.init(^tile_map, null, 67);
     defer map.free(^tile_map);
 
        tile_data := calloc(200 * sizeof TileData);
index d092ab98c4362d9256ee4b369ad606dadf0fda63..dfe862c86f692d38888a795eb2f8005a4f9d09e5 100644 (file)
@@ -36,8 +36,8 @@ main :: proc (args: [] cstr) {
 
        file := reader.make(contents);
 
-    map.init(^ingredient_map, 127);
-    map.init(^allergen_map);
+    map.init(^ingredient_map, Ingredient.{}, 127);
+    map.init(^allergen_map, Allergen.{});
     defer {
         map.free(^ingredient_map);
         map.free(^allergen_map);
@@ -59,7 +59,7 @@ main :: proc (args: [] cstr) {
 
             array.push(^food.ingredients, ingredient_name);
 
-            ingredient := map.get(^ingredient_map, ingredient_name, Ingredient.{});
+            ingredient := map.get(^ingredient_map, ingredient_name);
             if ingredient.name.data == null {
                 ingredient.name = ingredient_name;
                 array.init(^ingredient.appears_on, 4);
@@ -78,7 +78,7 @@ main :: proc (args: [] cstr) {
 
             array.push(^food.allergens, allergen_name);
 
-            allergen := map.get(^allergen_map, allergen_name, Allergen.{});
+            allergen := map.get(^allergen_map, allergen_name);
             if allergen.name.data == null {
                 allergen.name = allergen_name;
                 array.init(^allergen.appears_on, 4);
@@ -113,7 +113,7 @@ main :: proc (args: [] cstr) {
         potential_allergen_count := 0;
         for ^allergen_name: potential_allergens {
             c := array_count_contains(^potential_allergens, *allergen_name, string.equal);
-            allergen := map.get(^allergen_map, *allergen_name, Allergen.{}); 
+            allergen := map.get(^allergen_map, *allergen_name); 
             if c == allergen.appears_on.count {
                 potential_allergen_count += 1;
             }
@@ -126,7 +126,7 @@ main :: proc (args: [] cstr) {
 
     total_safe := 0;
     for safe: definitely_safe {
-        ingredient := map.get(^ingredient_map, safe, Ingredient.{});
+        ingredient := map.get(^ingredient_map, safe);
         total_safe += ingredient.appears_on.count;
 
         map.delete(^ingredient_map, safe);
@@ -157,7 +157,7 @@ main :: proc (args: [] cstr) {
             }
 
             if match_count == 1 {
-                ingredient := map.get(^ingredient_map, matching_ingredient_name, Ingredient.{});
+                ingredient := map.get(^ingredient_map, matching_ingredient_name);
                 map.delete(^ingredient_map, matching_ingredient_name);
 
                 ingredient.allergen = allergen_entry.key;
index c4c1622beefe652b6a6d2e314430582421b6d61f..7786c40c67766ffeb94ba646ea330511953a179b 100644 (file)
@@ -61,7 +61,7 @@ encode_hands :: proc (alloc: Allocator, p1: ^[..] u32, p2: ^[..] u32) -> str {
 
 recursive_combat :: proc (player1: ^[..] u32, player2: ^[..] u32) -> u32 {
     hand_seen : map.Map(str, bool);
-    map.init(^hand_seen, 31);
+    map.init(^hand_seen, false, 31);
     defer map.free(^hand_seen);
 
     while player1.count > 0 && player2.count > 0 {
index 61b6320f1ae2e51eda98bcbbff5fca8295f18c51..7d9cb5cd903c49382b380677f7c93a993b8f0f21 100644 (file)
@@ -33,7 +33,7 @@ main :: proc (args: [] cstr) {
        file := reader.make(contents);
 
        grid : map.Map(Vec2, Cell); // `true` is black
-       map.init(^grid, 1021);
+       map.init(^grid, Cell.{}, 1021);
        defer map.free(^grid);
 
        while !reader.empty(^file) {
@@ -67,7 +67,7 @@ main :: proc (args: [] cstr) {
                }
 
 
-               curr := map.get(^grid, loc, Cell.{});
+               curr := map.get(^grid, loc);
                map.put(^grid, loc, Cell.{ alive = !curr.alive });
        }
 
@@ -98,7 +98,7 @@ main :: proc (args: [] cstr) {
                }
 
                for ^cell: cells_to_consider {
-                       state  := map.get(^grid, *cell, Cell.{});
+                       state  := map.get(^grid, *cell);
                        ncount := get_neighbor_count(^grid, *cell);
 
                        if state.alive {
@@ -128,7 +128,7 @@ get_neighbor_count :: proc (grid: ^map.Map(Vec2, Cell), pos: Vec2) -> u32 {
        count := 0;
 
        for ^dir: Hex_Directions {
-               cell := map.get(grid, Vec2.{ x = pos.x + dir.x, y = pos.y + dir.y }, Cell.{});
+               cell := map.get(grid, Vec2.{ x = pos.x + dir.x, y = pos.y + dir.y });
                if cell.alive do count += 1;
        }
 
index 09d8994144919fcd945e403e216a2afbe71eca3a..2f20fc22c75fc4bcb43beadf09ea3b8348b54829 100644 (file)
@@ -25,7 +25,7 @@ dlp_bsgs :: proc (n: u32, a: u32, b: u32) -> u32 {
     m := cast(u32) ceil_f64(sqrt_f64(~~n));
 
     t : map.Map(u32, u32);
-    map.init(^t, m / 2);
+    map.init(^t, 0, m / 2);
     defer map.free(^t);
 
     tmp: u64 = 1;
@@ -39,7 +39,7 @@ dlp_bsgs :: proc (n: u32, a: u32, b: u32) -> u32 {
     tmp = ~~b;
     for i: 0 .. m {
         if map.has(^t, cast(u32) tmp) {
-            v := map.get(^t, cast(u32) tmp, 0);
+            v := map.get(^t, cast(u32) tmp);
             return i * m + v; 
         }
 
index 08dceae3b0d2a4811205f1d3f82d3c05964f599c..3282b97688d965c1937f10255be9e6bbc4d2f3d9 100644 (file)
@@ -24,7 +24,7 @@ BagContainment :: struct {
 
 bg_init :: proc (use graph: ^BagGraph) {
     array.init(^nodes, 16);
-    map.init(^node_map);
+    map.init(^node_map, null);
 }
 
 bg_free :: proc (use graph: ^BagGraph) {
index e197fa7c8818bc5da77eb91b4db4527b5a5c11e8..6a0a3f935f5da5ad9a422204ba18e0671741dc01 100644 (file)
@@ -15,7 +15,7 @@ Instruction :: struct {
 // Returns if the program successfully exited.
 get_acc_value :: proc (instrs: [..] Instruction, ret_acc: ^i32) -> bool {
     already_been: map.Map(i32, bool);
-    map.init(^already_been);
+    map.init(^already_been, false);
     defer map.free(^already_been);
 
     ip   := 0;
index d5d870e1ce096e0b1a96d604ee926b1f593b9b5b..8e25d1f81b9c0bb97581b7682e7c1633ba51822b 100644 (file)
@@ -234,7 +234,7 @@ main :: proc (args: [] cstr) {
     print("\n");
 
     pmap : map.Map(rawptr, rawptr);
-    map.init(^pmap, 50);
+    map.init(^pmap, null, 50);
     defer map.free(^pmap);
 
     for i: 0 .. 100 do map.put(^pmap, ^s.a[i], ^s.b[i]);
index d8cf721fe69d5aba7464f1a270c764eebc6a44d8..d43a198fea0bd798a9aa6d39ca50bb92f52d589b 100644 (file)
@@ -6,7 +6,7 @@ use package core
 
 main :: proc (args: [] cstr) {
     imap : map.Map(i32, str);
-    map.init(^imap);
+    map.init(^imap, "");
     defer {
         print("Freeing map\n");
         map.free(^imap);
@@ -17,7 +17,7 @@ main :: proc (args: [] cstr) {
     println(map.has(^imap, 50));
     println(map.has(^imap, 51));
 
-    printf("%s%s\n", map.get(^imap, 50, ""), map.get(^imap, 1234, ""));
+    printf("%s%s\n", map.get(^imap, 50), map.get(^imap, 1234));
 
     map.delete(^imap, 50);
     println(map.has(^imap, 50));
index 9c427e59cefea2893297368c9b4e323ff626b3ea..9048be22a4fe46ffe41fbffa7b0916126d3fa988 100644 (file)
@@ -3,6 +3,7 @@
 use package core
 
 overloaded :: proc {
+    proc (x: str, y: i32) do println("Called str, i32"); ,
     proc (x: f32, y: str) do println("Called f32, str"); ,
     proc (x: i32, y: i32) do println("Called i32, i32"); ,
 }