kit

kit
git clone https://git.ryansepassi.com/git/kit.git
Log | Files | Refs | README

commit 056fc9ea14811f46112837b87a5a7de5630bce80
parent 87ffbeeee00a842e9209d9665120e25ce814e3d4
Author: Ryan Sepassi <rsepassi@gmail.com>
Date:   Wed,  3 Jun 2026 22:01:27 -0700

toy: pointer-width isize/usize, int widening

Diffstat:
Mlang/toy/builtins.c | 124+++++++++++++++++++++++++++++++++++++++++++++++++++++--------------------------
Mlang/toy/expr.c | 218++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---------------
Mlang/toy/internal.h | 8++++++++
Mlang/toy/parser.c | 74++++++++++++++++++++++++++++++++++++++++++++++++++------------------------
Mlang/toy/parser_core.c | 8++++++--
Mlang/toy/symbols.c | 8++++----
Mlang/toy/types.c | 80++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---------------
Mtest/toy/cases/102_typed_asm_operands.toy | 2+-
Mtest/toy/cases/105_typed_asm_record_outputs.toy | 2+-
Mtest/toy/cases/110_typed_asm_named_outputs.toy | 2+-
Mtest/toy/cases/119_static_labeladdr_data.toy | 2+-
Mtest/toy/cases/121_dynamic_memory_builtin.toy | 4++--
Mtest/toy/cases/123_spec_demo.toy | 8++++----
Mtest/toy/cases/133_varargs_mixed_types.toy | 6+++---
Mtest/toy/cases/139_variadic_stack_arg_call_result.toy | 4++--
Mtest/toy/cases/140_fp_callee_save_bottom_frame.toy | 2+-
Mtest/toy/cases/19_cg_api_variadic_asm.toy | 4++--
Mtest/toy/cases/23_cg_api_typed_varargs.toy | 2+-
Mtest/toy/err/type_mismatch.toy | 2+-
Mtest/toy/err/unsupported_coro_switch.toy | 2+-
20 files changed, 415 insertions(+), 147 deletions(-)

diff --git a/lang/toy/builtins.c b/lang/toy/builtins.c @@ -41,20 +41,20 @@ static void toy_emit_dynamic_memory_loop(ToyParser* p, KitCgLocal dst_local, uint8_t set_value) { KitCgTypeId u8_ty = toy_builtin_type(p, KIT_CG_BUILTIN_I8); KitCgTypeId u8_ptr_ty = kit_cg_type_ptr(p->c, u8_ty, 0); - KitCgLocal index_local = kit_cg_local(p->cg, p->int_type, toy_slot_attrs(0)); + KitCgLocal index_local = kit_cg_local(p->cg, p->size_type, toy_slot_attrs(0)); KitCgLabel loop_label = kit_cg_label_new(p->cg); KitCgLabel end_label = kit_cg_label_new(p->cg); - toy_store_const_to_local(p, index_local, p->int_type, 0); + toy_store_const_to_local(p, index_local, p->size_type, 0); kit_cg_label_place(p->cg, loop_label); - toy_push_loaded_local(p, index_local, p->int_type); - toy_push_loaded_local(p, size_local, p->int_type); + toy_push_loaded_local(p, index_local, p->size_type); + toy_push_loaded_local(p, size_local, p->size_type); kit_cg_int_cmp(p->cg, KIT_CG_INT_LT_U); kit_cg_branch_false(p->cg, end_label); toy_push_loaded_local(p, dst_local, u8_ptr_ty); - toy_push_loaded_local(p, index_local, p->int_type); + toy_push_loaded_local(p, index_local, p->size_type); /* Build the destination element place from [dst_ptr, index]; the element * scale = sizeof(u8) = 1 is derived from the base type. The store then * consumes [dst_place, value]. */ @@ -63,17 +63,17 @@ static void toy_emit_dynamic_memory_loop(ToyParser* p, KitCgLocal dst_local, kit_cg_push_int(p->cg, set_value, u8_ty); } else { toy_push_loaded_local(p, src_local, u8_ptr_ty); - toy_push_loaded_local(p, index_local, p->int_type); + toy_push_loaded_local(p, index_local, p->size_type); kit_cg_elem(p->cg, 0); kit_cg_load(p->cg, toy_mem_access(p, u8_ty)); } kit_cg_store(p->cg, toy_mem_access(p, u8_ty)); kit_cg_push_local(p->cg, index_local); - toy_push_loaded_local(p, index_local, p->int_type); - kit_cg_push_int(p->cg, 1, p->int_type); + toy_push_loaded_local(p, index_local, p->size_type); + kit_cg_push_int(p->cg, 1, p->size_type); kit_cg_int_binop(p->cg, KIT_CG_INT_ADD, 0); - kit_cg_store(p->cg, toy_mem_access(p, p->int_type)); + kit_cg_store(p->cg, toy_mem_access(p, p->size_type)); kit_cg_jump(p->cg, loop_label); kit_cg_label_place(p->cg, end_label); @@ -89,10 +89,11 @@ static int toy_parse_memory_align_operand(ToyParser* p, int64_t* align, { KitCgTypeId ty = toy_parse_expr(p); if (ty == KIT_CG_TYPE_NONE) return 0; - if (ty != p->int_type) { - toy_error(p, p->cur.loc, "memory alignment must be i64"); + if (!toy_type_can_implicitly_cast(p, ty, p->size_type)) { + toy_error(p, p->cur.loc, "memory alignment must be usize"); return 0; } + if (!toy_emit_implicit_cast(p, ty, p->size_type)) return 0; kit_cg_drop(p->cg); *dynamic = 1; } @@ -256,10 +257,18 @@ static int toy_parse_call_braced_args(ToyParser* p, ToyToken call_tok, toy_error(p, call_tok.loc, "function argument type mismatch"); return 0; } - if (expected == TOY_TYPE_NONE && arg_ty != param.type) { + if (expected == TOY_TYPE_NONE && + !toy_type_can_implicitly_cast(p, arg_ty, param.type)) { toy_error(p, call_tok.loc, "function argument type mismatch"); return 0; } + if (arg_ty != param.type) { + if (expected != TOY_TYPE_NONE) { + if (!toy_emit_checked_cast(p, arg_ty, param.type)) return 0; + } else if (!toy_emit_implicit_cast(p, arg_ty, param.type)) { + return 0; + } + } } else if (!variadic) { toy_error(p, call_tok.loc, "too many arguments"); return 0; @@ -768,11 +777,14 @@ KitCgTypeId toy_parse_generic_builtin(ToyParser* p, KitSym name, if (count_ty == KIT_CG_TYPE_NONE || !toy_expect_comma(p) || !toy_parse_number_arg(p, &align) || !toy_parser_expect(p, TOK_RPAREN)) return KIT_CG_TYPE_NONE; - if (count_ty != p->int_type || align <= 0) { + if (!toy_type_can_implicitly_cast(p, count_ty, p->size_type) || + align <= 0) { toy_error(p, p->cur.loc, "invalid alloca arguments"); return KIT_CG_TYPE_NONE; } - kit_cg_push_int(p->cg, kit_cg_type_size(p->c, ty), p->int_type); + if (!toy_emit_implicit_cast(p, count_ty, p->size_type)) + return KIT_CG_TYPE_NONE; + kit_cg_push_int(p->cg, kit_cg_type_size(p->c, ty), p->size_type); kit_cg_int_binop(p->cg, KIT_CG_INT_MUL, 0); ptr_ty = kit_cg_type_ptr(p->c, ty, 0); kit_cg_alloca(p->cg, (uint32_t)align, ptr_ty); @@ -886,7 +898,7 @@ KitCgTypeId toy_parse_generic_builtin(ToyParser* p, KitSym name, toy_error(p, p->cur.loc, "invalid assume_aligned arguments"); return KIT_CG_TYPE_NONE; } - kit_cg_push_int(p->cg, (uint64_t)align, p->int_type); + kit_cg_push_int(p->cg, (uint64_t)align, p->size_type); kit_cg_intrinsic(p->cg, KIT_CG_INTRIN_ASSUME_ALIGNED, 2, ty); return ty; } @@ -904,8 +916,8 @@ KitCgTypeId toy_parse_generic_builtin(ToyParser* p, KitSym name, kit_cg_push_int( p->cg, is_align ? kit_cg_type_align(p->c, ty) : kit_cg_type_size(p->c, ty), - p->int_type); - return p->int_type; + p->size_type); + return p->size_type; } if (toy_sym_is(p, name, "offsetof")) { @@ -958,8 +970,8 @@ KitCgTypeId toy_parse_generic_builtin(ToyParser* p, KitSym name, return KIT_CG_TYPE_NONE; } } - kit_cg_push_int(p->cg, off, p->int_type); - return p->int_type; + kit_cg_push_int(p->cg, off, p->size_type); + return p->size_type; } if (toy_sym_is(p, name, "va_arg")) { @@ -1002,10 +1014,19 @@ KitCgTypeId toy_parse_generic_builtin(ToyParser* p, KitSym name, rhs_ty = toy_parse_expr(p); if (rhs_ty == KIT_CG_TYPE_NONE || !toy_parser_expect(p, TOK_RPAREN)) return KIT_CG_TYPE_NONE; - if (lhs_ty != ty || rhs_ty != ty || !toy_type_is_intlike(p, ty)) { + if (!toy_type_is_intlike(p, ty) || + !toy_type_can_implicitly_cast(p, lhs_ty, ty) || + !toy_type_can_implicitly_cast(p, rhs_ty, ty)) { toy_error(p, p->cur.loc, "overflow operand type mismatch"); return KIT_CG_TYPE_NONE; } + if (lhs_ty != ty) { + kit_cg_swap(p->cg); + if (!toy_emit_implicit_cast(p, lhs_ty, ty)) return KIT_CG_TYPE_NONE; + kit_cg_swap(p->cg); + } + if (rhs_ty != ty && !toy_emit_implicit_cast(p, rhs_ty, ty)) + return KIT_CG_TYPE_NONE; kit_cg_intrinsic(p->cg, intrin, 2, ty); memset(fields, 0, sizeof fields); fields[0].name = kit_sym_intern(p->c, KIT_SLICE_LIT("value")); @@ -1062,13 +1083,15 @@ static KitCgTypeId toy_parse_mem_copy_move(ToyParser* p, int is_move) { } else { KitCgTypeId size_ty = toy_parse_expr(p); if (size_ty == KIT_CG_TYPE_NONE) return KIT_CG_TYPE_NONE; - if (size_ty != p->int_type) { - toy_error(p, p->cur.loc, "memory size must be i64"); + if (!toy_type_can_implicitly_cast(p, size_ty, p->size_type)) { + toy_error(p, p->cur.loc, "memory size must be usize"); return KIT_CG_TYPE_NONE; } + if (!toy_emit_implicit_cast(p, size_ty, p->size_type)) + return KIT_CG_TYPE_NONE; dynamic_size = 1; - size_local = kit_cg_local(p->cg, p->int_type, toy_slot_attrs(0)); - toy_store_top_to_local(p, size_local, p->int_type); + size_local = kit_cg_local(p->cg, p->size_type, toy_slot_attrs(0)); + toy_store_top_to_local(p, size_local, p->size_type); } if (!toy_parse_memory_align_operand(p, &align, &dynamic_align)) return KIT_CG_TYPE_NONE; @@ -1077,8 +1100,8 @@ static KitCgTypeId toy_parse_mem_copy_move(ToyParser* p, int is_move) { if (!toy_parser_expect(p, TOK_RPAREN)) return KIT_CG_TYPE_NONE; if (dynamic_size || dynamic_align) { if (!dynamic_size) { - size_local = kit_cg_local(p->cg, p->int_type, toy_slot_attrs(0)); - toy_store_const_to_local(p, size_local, p->int_type, (uint64_t)size); + size_local = kit_cg_local(p->cg, p->size_type, toy_slot_attrs(0)); + toy_store_const_to_local(p, size_local, p->size_type, (uint64_t)size); } src_local = kit_cg_local(p->cg, u8_ptr_ty, toy_slot_attrs(0)); kit_cg_bitcast(p->cg, u8_ptr_ty); @@ -1119,13 +1142,15 @@ KitCgTypeId toy_parse_memory_builtin_call(ToyParser* p, KitSym name, } else { KitCgTypeId size_ty = toy_parse_expr(p); if (size_ty == KIT_CG_TYPE_NONE) return KIT_CG_TYPE_NONE; - if (size_ty != p->int_type) { - toy_error(p, p->cur.loc, "memory size must be i64"); + if (!toy_type_can_implicitly_cast(p, size_ty, p->size_type)) { + toy_error(p, p->cur.loc, "memory size must be usize"); return KIT_CG_TYPE_NONE; } + if (!toy_emit_implicit_cast(p, size_ty, p->size_type)) + return KIT_CG_TYPE_NONE; dynamic_size = 1; - size_local = kit_cg_local(p->cg, p->int_type, toy_slot_attrs(0)); - toy_store_top_to_local(p, size_local, p->int_type); + size_local = kit_cg_local(p->cg, p->size_type, toy_slot_attrs(0)); + toy_store_top_to_local(p, size_local, p->size_type); } if (!toy_parse_memory_align_operand(p, &align, &dynamic_align)) return KIT_CG_TYPE_NONE; @@ -1138,8 +1163,8 @@ KitCgTypeId toy_parse_memory_builtin_call(ToyParser* p, KitSym name, return KIT_CG_TYPE_NONE; } if (!dynamic_size) { - size_local = kit_cg_local(p->cg, p->int_type, toy_slot_attrs(0)); - toy_store_const_to_local(p, size_local, p->int_type, (uint64_t)size); + size_local = kit_cg_local(p->cg, p->size_type, toy_slot_attrs(0)); + toy_store_const_to_local(p, size_local, p->size_type, (uint64_t)size); } dst_local = kit_cg_local(p->cg, u8_ptr_ty, toy_slot_attrs(0)); kit_cg_bitcast(p->cg, u8_ptr_ty); @@ -1221,10 +1246,13 @@ KitCgTypeId toy_parse_atomic_generic_builtin(ToyParser* p, KitSym name, !toy_parser_expect(p, TOK_RPAREN)) return KIT_CG_TYPE_NONE; if (!toy_type_is_ptr(p, ptr_ty) || - kit_cg_type_ptr_pointee(p->c, ptr_ty) != ty || val_ty != ty) { + kit_cg_type_ptr_pointee(p->c, ptr_ty) != ty || + !toy_type_can_implicitly_cast(p, val_ty, ty)) { toy_error(p, p->cur.loc, "atomic_store type mismatch"); return KIT_CG_TYPE_NONE; } + if (val_ty != ty && !toy_emit_implicit_cast(p, val_ty, ty)) + return KIT_CG_TYPE_NONE; kit_cg_atomic_store(p->cg, access, order); return toy_builtin_type(p, KIT_CG_BUILTIN_VOID); } @@ -1252,10 +1280,13 @@ KitCgTypeId toy_parse_atomic_generic_builtin(ToyParser* p, KitSym name, !toy_parser_expect(p, TOK_RPAREN)) return KIT_CG_TYPE_NONE; if (!toy_type_is_ptr(p, ptr_ty) || - kit_cg_type_ptr_pointee(p->c, ptr_ty) != ty || val_ty != ty) { + kit_cg_type_ptr_pointee(p->c, ptr_ty) != ty || + !toy_type_can_implicitly_cast(p, val_ty, ty)) { toy_error(p, p->cur.loc, "atomic_rmw type mismatch"); return KIT_CG_TYPE_NONE; } + if (val_ty != ty && !toy_emit_implicit_cast(p, val_ty, ty)) + return KIT_CG_TYPE_NONE; kit_cg_atomic_rmw(p->cg, access, op, order); return ty; } @@ -1276,8 +1307,16 @@ KitCgTypeId toy_parse_atomic_generic_builtin(ToyParser* p, KitSym name, if (ptr_ty == KIT_CG_TYPE_NONE || !toy_expect_comma(p)) return KIT_CG_TYPE_NONE; expected_ty = toy_parse_expr(p); - if (expected_ty == KIT_CG_TYPE_NONE || !toy_expect_comma(p)) + if (expected_ty == KIT_CG_TYPE_NONE) return KIT_CG_TYPE_NONE; + if (!toy_type_can_implicitly_cast(p, expected_ty, ty)) { + toy_error(p, p->cur.loc, "atomic_cmpxchg type mismatch"); + return KIT_CG_TYPE_NONE; + } + if (expected_ty != ty && !toy_emit_implicit_cast(p, expected_ty, ty)) + return KIT_CG_TYPE_NONE; + expected_ty = ty; + if (!toy_expect_comma(p)) return KIT_CG_TYPE_NONE; desired_ty = toy_parse_expr(p); if (desired_ty == KIT_CG_TYPE_NONE || !toy_expect_comma(p) || !toy_parse_mem_order(p, &success_order) || !toy_expect_comma(p) || @@ -1290,10 +1329,12 @@ KitCgTypeId toy_parse_atomic_generic_builtin(ToyParser* p, KitSym name, return KIT_CG_TYPE_NONE; if (!toy_type_is_ptr(p, ptr_ty) || kit_cg_type_ptr_pointee(p->c, ptr_ty) != ty || expected_ty != ty || - desired_ty != ty) { + !toy_type_can_implicitly_cast(p, desired_ty, ty)) { toy_error(p, p->cur.loc, "atomic_cmpxchg type mismatch"); return KIT_CG_TYPE_NONE; } + if (desired_ty != ty && !toy_emit_implicit_cast(p, desired_ty, ty)) + return KIT_CG_TYPE_NONE; kit_cg_atomic_cmpxchg(p->cg, access, success_order, failure_order, weak); memset(fields, 0, sizeof fields); fields[0].name = kit_sym_intern(p->c, KIT_SLICE_LIT("prior")); @@ -1443,9 +1484,8 @@ KitCgTypeId toy_parse_low_level_builtin_call(ToyParser* p, KitSym name, return KIT_CG_TYPE_NONE; if (!kit_cg_target_supports_intrinsic(p->c, KIT_CG_INTRIN_IRQ_SAVE)) return toy_unsupported_intrinsic(p); - /* Returns the saved interrupt-mask state as a usize (toy int type). */ - kit_cg_intrinsic(p->cg, KIT_CG_INTRIN_IRQ_SAVE, 0, p->int_type); - return p->int_type; + kit_cg_intrinsic(p->cg, KIT_CG_INTRIN_IRQ_SAVE, 0, p->size_type); + return p->size_type; } if (toy_sym_is(p, name, "irq_restore")) { @@ -1454,10 +1494,12 @@ KitCgTypeId toy_parse_low_level_builtin_call(ToyParser* p, KitSym name, prev_ty = toy_parse_expr(p); if (prev_ty == KIT_CG_TYPE_NONE || !toy_parser_expect(p, TOK_RPAREN)) return KIT_CG_TYPE_NONE; - if (!toy_type_is_intlike(p, prev_ty)) { - toy_error(p, p->cur.loc, "irq_restore expects integer state"); + if (!toy_type_can_implicitly_cast(p, prev_ty, p->size_type)) { + toy_error(p, p->cur.loc, "irq_restore expects usize state"); return KIT_CG_TYPE_NONE; } + if (!toy_emit_implicit_cast(p, prev_ty, p->size_type)) + return KIT_CG_TYPE_NONE; if (!kit_cg_target_supports_intrinsic(p->c, KIT_CG_INTRIN_IRQ_RESTORE)) return toy_unsupported_intrinsic(p); kit_cg_intrinsic(p->cg, KIT_CG_INTRIN_IRQ_RESTORE, 1, diff --git a/lang/toy/expr.c b/lang/toy/expr.c @@ -142,10 +142,18 @@ int toy_parse_call_args(ToyParser* p, ToyToken call_tok, KitCgTypeId fn_ty, toy_error(p, call_tok.loc, "function argument type mismatch"); return 0; } - if (expected == TOY_TYPE_NONE && arg_ty != param.type) { + if (expected == TOY_TYPE_NONE && + !toy_type_can_implicitly_cast(p, arg_ty, param.type)) { toy_error(p, call_tok.loc, "function argument type mismatch"); return 0; } + if (arg_ty != param.type) { + if (expected != TOY_TYPE_NONE) { + if (!toy_emit_checked_cast(p, arg_ty, param.type)) return 0; + } else if (!toy_emit_implicit_cast(p, arg_ty, param.type)) { + return 0; + } + } } else if (!variadic) { toy_error(p, call_tok.loc, "too many arguments"); return 0; @@ -174,7 +182,32 @@ KitCgMemAccess toy_mem_access(ToyParser* p, KitCgTypeId type) { return access; } -static int toy_emit_cast(ToyParser* p, KitCgTypeId src, KitCgTypeId dst) { +static int toy_type_is_promotable_int(ToyParser* p, KitCgTypeId ty) { + return kit_cg_type_kind(p->c, ty) == KIT_CG_TYPE_INT; +} + +static KitCgTypeId toy_int_literal_type(ToyParser* p, int64_t value) { + if (value <= INT8_MAX) return toy_builtin_type(p, KIT_CG_BUILTIN_I8); + if (value <= INT16_MAX) return toy_builtin_type(p, KIT_CG_BUILTIN_I16); + if (value <= INT32_MAX) return toy_builtin_type(p, KIT_CG_BUILTIN_I32); + return toy_builtin_type(p, KIT_CG_BUILTIN_I64); +} + +int toy_type_can_implicitly_cast(ToyParser* p, KitCgTypeId src, + KitCgTypeId dst) { + KitCgTypeKind sk, dk; + if (src == dst) return 1; + sk = kit_cg_type_kind(p->c, src); + dk = kit_cg_type_kind(p->c, dst); + if (sk == KIT_CG_TYPE_INT && dk == KIT_CG_TYPE_INT) + return toy_type_int_width(p, src) <= toy_type_int_width(p, dst); + if (sk == KIT_CG_TYPE_FLOAT && dk == KIT_CG_TYPE_FLOAT) + return kit_cg_type_float_width(p->c, src) <= + kit_cg_type_float_width(p->c, dst); + return 0; +} + +int toy_emit_cast(ToyParser* p, KitCgTypeId src, KitCgTypeId dst) { KitCgTypeKind sk, dk; if (src == dst) return 1; sk = kit_cg_type_kind(p->c, src); @@ -229,6 +262,64 @@ static int toy_emit_cast(ToyParser* p, KitCgTypeId src, KitCgTypeId dst) { return 0; } +int toy_emit_implicit_cast(ToyParser* p, KitCgTypeId src, KitCgTypeId dst) { + if (src == dst) return 1; + if (!toy_type_can_implicitly_cast(p, src, dst)) { + toy_error(p, p->cur.loc, "implicit conversion would lose information"); + return 0; + } + return toy_emit_cast(p, src, dst); +} + +int toy_emit_checked_cast(ToyParser* p, KitCgTypeId src, KitCgTypeId dst) { + KitCgTypeKind sk, dk; + if (src == dst) return 1; + if (toy_type_can_implicitly_cast(p, src, dst)) + return toy_emit_cast(p, src, dst); + sk = kit_cg_type_kind(p->c, src); + dk = kit_cg_type_kind(p->c, dst); + if (sk == KIT_CG_TYPE_PTR && dk == KIT_CG_TYPE_PTR) { + kit_cg_bitcast(p->cg, dst); + return 1; + } + toy_error(p, p->cur.loc, "unsupported checked conversion"); + return 0; +} + +static int toy_promote_right_operand(ToyParser* p, KitCgTypeId src, + KitCgTypeId dst) { + return toy_emit_implicit_cast(p, src, dst); +} + +static int toy_promote_left_operand(ToyParser* p, KitCgTypeId src, + KitCgTypeId dst) { + kit_cg_swap(p->cg); + if (!toy_emit_implicit_cast(p, src, dst)) return 0; + kit_cg_swap(p->cg); + return 1; +} + +static int toy_promote_binary_int_operands(ToyParser* p, KitCgTypeId* left, + KitCgTypeId* right) { + uint32_t lw, rw; + if (*left == *right) return 1; + if (!toy_type_is_promotable_int(p, *left) || + !toy_type_is_promotable_int(p, *right)) + return 0; + lw = toy_type_int_width(p, *left); + rw = toy_type_int_width(p, *right); + if (lw < rw) { + if (!toy_promote_left_operand(p, *left, *right)) return 0; + *left = *right; + } else if (rw < lw) { + if (!toy_promote_right_operand(p, *right, *left)) return 0; + *right = *left; + } else { + return 0; + } + return 1; +} + KitCgLocalAttrs toy_slot_attrs(KitSym name) { KitCgLocalAttrs attrs; memset(&attrs, 0, sizeof attrs); @@ -522,12 +613,12 @@ KitCgTypeId toy_emit_slice_index_lvalue(ToyParser* p, KitCgTypeId slice_ty, } /* Stash the index, then load the slice's ptr field, then re-push idx * and compute element pointer. */ - idx_slot = kit_cg_local(p->cg, p->int_type, toy_slot_attrs(0)); - toy_store_tos_to_local(p, idx_slot, p->int_type); + idx_slot = kit_cg_local(p->cg, p->size_type, toy_slot_attrs(0)); + toy_store_tos_to_local(p, idx_slot, p->size_type); kit_cg_deref(p->cg, (int64_t)ptr_field_off); kit_cg_load(p->cg, toy_mem_access(p, ptr_field.type)); kit_cg_push_local(p->cg, idx_slot); - kit_cg_load(p->cg, toy_mem_access(p, p->int_type)); + kit_cg_load(p->cg, toy_mem_access(p, p->size_type)); toy_addr_index(p, kit_cg_type_size(p->c, elem_ty), kit_cg_type_ptr(p->c, elem_ty, 0)); if (elem_toy_out) *elem_toy_out = elem_toy; @@ -546,7 +637,7 @@ KitCgTypeId toy_emit_slice_value(ToyParser* p, KitCgTypeId base_ty, KitCgLocal end_slot; KitCgLocal result_slot; - if (start_ty != p->int_type || end_ty != p->int_type) { + if (start_ty != p->size_type || end_ty != p->size_type) { toy_error(p, p->cur.loc, "slice bounds must be isize"); return KIT_CG_TYPE_NONE; } @@ -581,10 +672,10 @@ KitCgTypeId toy_emit_slice_value(ToyParser* p, KitCgTypeId base_ty, return KIT_CG_TYPE_NONE; } - end_slot = kit_cg_local(p->cg, p->int_type, toy_slot_attrs(0)); - toy_store_tos_to_local(p, end_slot, p->int_type); - start_slot = kit_cg_local(p->cg, p->int_type, toy_slot_attrs(0)); - toy_store_tos_to_local(p, start_slot, p->int_type); + end_slot = kit_cg_local(p->cg, p->size_type, toy_slot_attrs(0)); + toy_store_tos_to_local(p, end_slot, p->size_type); + start_slot = kit_cg_local(p->cg, p->size_type, toy_slot_attrs(0)); + toy_store_tos_to_local(p, start_slot, p->size_type); result_slot = kit_cg_local(p->cg, slice_ty, toy_slot_attrs(0)); /* TOS = [base] (slice lvalue/pointer or array lvalue/pointer). */ @@ -600,7 +691,7 @@ KitCgTypeId toy_emit_slice_value(ToyParser* p, KitCgTypeId base_ty, /* Compute (base + start * sizeof(elem)) as a pointer to the slice's * first element. */ kit_cg_push_local(p->cg, start_slot); - kit_cg_load(p->cg, toy_mem_access(p, p->int_type)); + kit_cg_load(p->cg, toy_mem_access(p, p->size_type)); toy_addr_index(p, kit_cg_type_size(p->c, elem_ty), kit_cg_type_ptr(p->c, elem_ty, 0)); /* Store the data pointer into result_slot.ptr. */ @@ -615,11 +706,11 @@ KitCgTypeId toy_emit_slice_value(ToyParser* p, KitCgTypeId base_ty, kit_cg_addr(p->cg); kit_cg_deref(p->cg, (int64_t)len_off); kit_cg_push_local(p->cg, end_slot); - kit_cg_load(p->cg, toy_mem_access(p, p->int_type)); + kit_cg_load(p->cg, toy_mem_access(p, p->size_type)); kit_cg_push_local(p->cg, start_slot); - kit_cg_load(p->cg, toy_mem_access(p, p->int_type)); + kit_cg_load(p->cg, toy_mem_access(p, p->size_type)); kit_cg_int_binop(p->cg, KIT_CG_INT_SUB, 0); - kit_cg_store(p->cg, toy_mem_access(p, p->int_type)); + kit_cg_store(p->cg, toy_mem_access(p, p->size_type)); } /* Hand back the slice record as a pointer VALUE (its address), matching the @@ -694,10 +785,13 @@ static KitCgTypeId toy_parse_expr_primary(ToyParser* p) { toy_type_from_cg(p, toy_builtin_type(p, KIT_CG_BUILTIN_F64)); return toy_builtin_type(p, KIT_CG_BUILTIN_F64); } - kit_cg_push_int(p->cg, p->cur.int_value, p->int_type); - toy_parser_advance(p); - p->last_type = toy_type_from_cg(p, p->int_type); - return p->int_type; + { + KitCgTypeId lit_ty = toy_int_literal_type(p, p->cur.int_value); + kit_cg_push_int(p->cg, (uint64_t)p->cur.int_value, lit_ty); + toy_parser_advance(p); + p->last_type = toy_type_from_cg(p, lit_ty); + return lit_ty; + } } if (p->cur.kind == TOK_IDENT) { @@ -872,10 +966,24 @@ static KitCgTypeId toy_parse_expr_postfix(ToyParser* p) { if (toy_parser_match(p, TOK_LBRACKET)) { KitCgTypeId idx_ty = toy_parse_expr(p); if (idx_ty == KIT_CG_TYPE_NONE) return KIT_CG_TYPE_NONE; + if (!toy_type_can_implicitly_cast(p, idx_ty, p->size_type)) { + toy_error(p, p->cur.loc, "index must be isize"); + return KIT_CG_TYPE_NONE; + } + if (!toy_emit_implicit_cast(p, idx_ty, p->size_type)) + return KIT_CG_TYPE_NONE; + idx_ty = p->size_type; if (toy_parser_match(p, TOK_COLON)) { KitCgTypeId end_ty = toy_parse_expr(p); ToyTypeId slice_toy_type = TOY_TYPE_NONE; if (end_ty == KIT_CG_TYPE_NONE) return KIT_CG_TYPE_NONE; + if (!toy_type_can_implicitly_cast(p, end_ty, p->size_type)) { + toy_error(p, p->cur.loc, "slice bounds must be isize"); + return KIT_CG_TYPE_NONE; + } + if (!toy_emit_implicit_cast(p, end_ty, p->size_type)) + return KIT_CG_TYPE_NONE; + end_ty = p->size_type; if (!toy_parser_expect(p, TOK_RBRACKET)) { toy_error(p, p->cur.loc, "expected ']' after slice"); return KIT_CG_TYPE_NONE; @@ -891,10 +999,6 @@ static KitCgTypeId toy_parse_expr_postfix(ToyParser* p) { toy_error(p, p->cur.loc, "expected ']' after index"); return KIT_CG_TYPE_NONE; } - if (idx_ty != p->int_type) { - toy_error(p, p->cur.loc, "index must be isize"); - return KIT_CG_TYPE_NONE; - } if (kit_cg_type_kind(p->c, ty) == KIT_CG_TYPE_PTR) { KitCgTypeId pointee = kit_cg_type_ptr_pointee(p->c, ty); ToyTypeId source_pointee = toy_type_pointee(p, toy_ty); @@ -981,7 +1085,8 @@ static KitCgTypeId toy_parse_expr_postfix(ToyParser* p) { p->last_type = field_toy_type; toy_ty = field_toy_type; if (resolved != KIT_CG_TYPE_NONE && resolved != ty) { - kit_cg_bitcast(p->cg, resolved); + if (!toy_emit_checked_cast(p, ty, resolved)) + return KIT_CG_TYPE_NONE; ty = resolved; } } else { @@ -1027,7 +1132,8 @@ static KitCgTypeId toy_parse_expr_postfix(ToyParser* p) { p->last_type = field_toy_type; toy_ty = field_toy_type; if (resolved != KIT_CG_TYPE_NONE && resolved != ty) { - kit_cg_bitcast(p->cg, resolved); + if (!toy_emit_checked_cast(p, ty, resolved)) + return KIT_CG_TYPE_NONE; ty = resolved; } } else { @@ -1132,12 +1238,15 @@ static KitCgTypeId toy_parse_expr_unary(ToyParser* p) { if (toy_parser_match(p, TOK_LBRACKET)) { KitCgTypeId idx_ty = toy_parse_expr(p); if (idx_ty == KIT_CG_TYPE_NONE) return KIT_CG_TYPE_NONE; - if (!toy_parser_expect(p, TOK_RBRACKET)) { - toy_error(p, p->cur.loc, "expected ']' after index"); + if (!toy_type_can_implicitly_cast(p, idx_ty, p->size_type)) { + toy_error(p, p->cur.loc, "index must be isize"); return KIT_CG_TYPE_NONE; } - if (idx_ty != p->int_type) { - toy_error(p, p->cur.loc, "index must be isize"); + if (!toy_emit_implicit_cast(p, idx_ty, p->size_type)) + return KIT_CG_TYPE_NONE; + idx_ty = p->size_type; + if (!toy_parser_expect(p, TOK_RBRACKET)) { + toy_error(p, p->cur.loc, "expected ']' after index"); return KIT_CG_TYPE_NONE; } if (kit_cg_type_kind(p->c, ty) == KIT_CG_TYPE_PTR) { @@ -1145,16 +1254,16 @@ static KitCgTypeId toy_parse_expr_unary(ToyParser* p) { /* TOS holds **T_chain; load the inner pointer first. */ { KitCgLocal idx_slot = - kit_cg_local(p->cg, p->int_type, toy_slot_attrs(0)); + kit_cg_local(p->cg, p->size_type, toy_slot_attrs(0)); kit_cg_push_local(p->cg, idx_slot); kit_cg_swap(p->cg); - kit_cg_store(p->cg, toy_mem_access(p, p->int_type)); + kit_cg_store(p->cg, toy_mem_access(p, p->size_type)); /* TOS is the chain pointer VALUE (**T); deref to a PLACE and * load the inner pointer it addresses. */ kit_cg_deref(p->cg, 0); kit_cg_load(p->cg, toy_mem_access(p, ty)); kit_cg_push_local(p->cg, idx_slot); - kit_cg_load(p->cg, toy_mem_access(p, p->int_type)); + kit_cg_load(p->cg, toy_mem_access(p, p->size_type)); } if (kit_cg_type_kind(p->c, pointee) == KIT_CG_TYPE_ARRAY) { KitCgTypeId elem_ty = kit_cg_type_array_elem(p->c, pointee); @@ -1322,8 +1431,13 @@ static KitCgTypeId toy_parse_expr_mul(ToyParser* p) { KitCgTypeId ty2 = toy_parse_expr_cast(p); if (ty2 == KIT_CG_TYPE_NONE) return KIT_CG_TYPE_NONE; if (toy_reject_tail_call_operand(p)) return KIT_CG_TYPE_NONE; - if (ty != ty2 || - (!toy_type_is_intlike(p, ty) && !toy_type_is_float(p, ty))) { + if (toy_type_is_intlike(p, ty) && toy_type_is_intlike(p, ty2)) { + if (!toy_promote_binary_int_operands(p, &ty, &ty2)) { + toy_error(p, p->cur.loc, + "arithmetic operands must have same numeric type"); + return KIT_CG_TYPE_NONE; + } + } else if (ty != ty2 || !toy_type_is_float(p, ty)) { toy_error(p, p->cur.loc, "arithmetic operands must have same numeric type"); return KIT_CG_TYPE_NONE; @@ -1361,6 +1475,7 @@ static KitCgTypeId toy_parse_expr_mul(ToyParser* p) { } kit_cg_int_binop(p->cg, binop, 0); } + toy_note_cg_result_type(p, ty); } return ty; } @@ -1378,8 +1493,13 @@ static KitCgTypeId toy_parse_expr_add(ToyParser* p) { KitCgTypeId ty2 = toy_parse_expr_mul(p); if (ty2 == KIT_CG_TYPE_NONE) return KIT_CG_TYPE_NONE; if (toy_reject_tail_call_operand(p)) return KIT_CG_TYPE_NONE; - if (ty != ty2 || - (!toy_type_is_intlike(p, ty) && !toy_type_is_float(p, ty))) { + if (toy_type_is_intlike(p, ty) && toy_type_is_intlike(p, ty2)) { + if (!toy_promote_binary_int_operands(p, &ty, &ty2)) { + toy_error(p, p->cur.loc, + "arithmetic operands must have same numeric type"); + return KIT_CG_TYPE_NONE; + } + } else if (ty != ty2 || !toy_type_is_float(p, ty)) { toy_error(p, p->cur.loc, "arithmetic operands must have same numeric type"); return KIT_CG_TYPE_NONE; @@ -1389,6 +1509,7 @@ static KitCgTypeId toy_parse_expr_add(ToyParser* p) { } else { kit_cg_int_binop(p->cg, binop, 0); } + toy_note_cg_result_type(p, ty); } return ty; } @@ -1406,7 +1527,12 @@ static KitCgTypeId toy_parse_expr_cmp(ToyParser* p) { KitCgTypeId ty2 = toy_parse_expr_add(p); if (ty2 == KIT_CG_TYPE_NONE) return KIT_CG_TYPE_NONE; if (toy_reject_tail_call_operand(p)) return KIT_CG_TYPE_NONE; - if (ty != ty2) { + if (toy_type_is_intlike(p, ty) && toy_type_is_intlike(p, ty2)) { + if (!toy_promote_binary_int_operands(p, &ty, &ty2)) { + toy_error(p, p->cur.loc, "comparison operands must have same type"); + return KIT_CG_TYPE_NONE; + } + } else if (ty != ty2) { toy_error(p, p->cur.loc, "comparison operands must have same type"); return KIT_CG_TYPE_NONE; } @@ -1484,11 +1610,14 @@ static KitCgTypeId toy_parse_expr_shift(ToyParser* p) { KitCgTypeId ty2 = toy_parse_expr_cmp(p); if (ty2 == KIT_CG_TYPE_NONE) return KIT_CG_TYPE_NONE; if (toy_reject_tail_call_operand(p)) return KIT_CG_TYPE_NONE; - if (ty != p->int_type || ty2 != p->int_type) { + if (!toy_type_is_promotable_int(p, ty) || + !toy_type_is_promotable_int(p, ty2) || + !toy_promote_binary_int_operands(p, &ty, &ty2)) { toy_error(p, p->cur.loc, "shift operands must be int"); return KIT_CG_TYPE_NONE; } kit_cg_int_binop(p->cg, binop, 0); + toy_note_cg_result_type(p, ty); } return ty; } @@ -1504,11 +1633,14 @@ static KitCgTypeId toy_parse_expr_band(ToyParser* p) { KitCgTypeId ty2 = toy_parse_expr_shift(p); if (ty2 == KIT_CG_TYPE_NONE) return KIT_CG_TYPE_NONE; if (toy_reject_tail_call_operand(p)) return KIT_CG_TYPE_NONE; - if (ty != p->int_type || ty2 != p->int_type) { + if (!toy_type_is_promotable_int(p, ty) || + !toy_type_is_promotable_int(p, ty2) || + !toy_promote_binary_int_operands(p, &ty, &ty2)) { toy_error(p, p->cur.loc, "bitwise operands must be int"); return KIT_CG_TYPE_NONE; } kit_cg_int_binop(p->cg, KIT_CG_INT_AND, 0); + toy_note_cg_result_type(p, ty); } return ty; } @@ -1524,11 +1656,14 @@ static KitCgTypeId toy_parse_expr_bxor(ToyParser* p) { KitCgTypeId ty2 = toy_parse_expr_band(p); if (ty2 == KIT_CG_TYPE_NONE) return KIT_CG_TYPE_NONE; if (toy_reject_tail_call_operand(p)) return KIT_CG_TYPE_NONE; - if (ty != p->int_type || ty2 != p->int_type) { + if (!toy_type_is_promotable_int(p, ty) || + !toy_type_is_promotable_int(p, ty2) || + !toy_promote_binary_int_operands(p, &ty, &ty2)) { toy_error(p, p->cur.loc, "bitwise operands must be int"); return KIT_CG_TYPE_NONE; } kit_cg_int_binop(p->cg, KIT_CG_INT_XOR, 0); + toy_note_cg_result_type(p, ty); } return ty; } @@ -1544,11 +1679,14 @@ static KitCgTypeId toy_parse_expr_bor(ToyParser* p) { KitCgTypeId ty2 = toy_parse_expr_bxor(p); if (ty2 == KIT_CG_TYPE_NONE) return KIT_CG_TYPE_NONE; if (toy_reject_tail_call_operand(p)) return KIT_CG_TYPE_NONE; - if (ty != p->int_type || ty2 != p->int_type) { + if (!toy_type_is_promotable_int(p, ty) || + !toy_type_is_promotable_int(p, ty2) || + !toy_promote_binary_int_operands(p, &ty, &ty2)) { toy_error(p, p->cur.loc, "bitwise operands must be int"); return KIT_CG_TYPE_NONE; } kit_cg_int_binop(p->cg, KIT_CG_INT_OR, 0); + toy_note_cg_result_type(p, ty); } return ty; } diff --git a/lang/toy/internal.h b/lang/toy/internal.h @@ -235,6 +235,7 @@ typedef struct ToyParser { KitCg* cg; KitCgBuiltinTypes types; KitCgTypeId int_type; + KitCgTypeId size_type; KitCgTypeId int_ptr_type; KitCgTypeId va_list_type; KitTargetSpec target; @@ -376,6 +377,11 @@ int toy_parse_record_attr_list(ToyParser* p, int* packed_out, uint32_t* align_out); KitCgTypeId toy_parse_type(ToyParser* p); KitCgTypeId toy_parse_expr(ToyParser* p); +int toy_emit_cast(ToyParser* p, KitCgTypeId src, KitCgTypeId dst); +int toy_type_can_implicitly_cast(ToyParser* p, KitCgTypeId src, + KitCgTypeId dst); +int toy_emit_implicit_cast(ToyParser* p, KitCgTypeId src, KitCgTypeId dst); +int toy_emit_checked_cast(ToyParser* p, KitCgTypeId src, KitCgTypeId dst); KitCgTypeId toy_push_named_rvalue(ToyParser* p, KitSym name); int toy_parse_call_args(ToyParser* p, ToyToken call_tok, KitCgTypeId fn_ty, const ToyTypeId* toy_params, size_t toy_nparams, @@ -447,6 +453,8 @@ ToyTypeId toy_type_register_slice(ToyParser* p, KitCgTypeId elem_cg, ToyTypeId toy_type_register_func(ToyParser* p, KitCgTypeId cg, ToyTypeId ret, const ToyTypeId* params, size_t nparams, int variadic); +int toy_type_accepts_storage(ToyParser* p, ToyTypeId expected, + ToyTypeId actual); int toy_type_accepts_type(ToyParser* p, ToyTypeId expected, ToyTypeId actual); KitCgTypeId toy_type_resolved_cg(ToyParser* p, ToyTypeId id); ToyTypeId toy_type_pointee(ToyParser* p, ToyTypeId id); diff --git a/lang/toy/parser.c b/lang/toy/parser.c @@ -41,7 +41,7 @@ static void toy_push_local_indexed(ToyParser* p, KitCgLocal slot, kit_cg_push_local(p->cg, slot); kit_cg_addr(p->cg); kit_cg_bitcast(p->cg, kit_cg_type_ptr(p->c, elem_ty, 0)); - kit_cg_push_int(p->cg, index, p->int_type); + kit_cg_push_int(p->cg, index, p->size_type); } static int toy_check_source_value(ToyParser* p, KitCgTypeId expected_cg, @@ -54,7 +54,7 @@ static int toy_check_source_value(ToyParser* p, KitCgTypeId expected_cg, } return 1; } - if (actual_cg != expected_cg) { + if (!toy_type_can_implicitly_cast(p, actual_cg, expected_cg)) { toy_error(p, p->cur.loc, message); return 0; } @@ -170,7 +170,8 @@ static int toy_parse_array_initializer(ToyParser* p, KitCgLocal slot, p->last_type, "array element type mismatch")) { return 0; } - if (expr_ty != elem_ty) kit_cg_bitcast(p->cg, elem_ty); + if (expr_ty != elem_ty && !toy_emit_checked_cast(p, expr_ty, elem_ty)) + return 0; kit_cg_store(p->cg, toy_mem_access(p, elem_ty)); index++; if (!toy_parser_match(p, TOK_COMMA)) break; @@ -242,7 +243,9 @@ static int toy_parse_record_initializer(ToyParser* p, KitCgLocal slot, return 0; } } - if (expr_ty != field.type) kit_cg_bitcast(p->cg, field.type); + if (expr_ty != field.type && + !toy_emit_checked_cast(p, expr_ty, field.type)) + return 0; kit_cg_store(p->cg, toy_mem_access(p, field.type)); field_index++; if (!toy_parser_match(p, TOK_COMMA)) break; @@ -292,7 +295,9 @@ static int toy_parse_record_initializer(ToyParser* p, KitCgLocal slot, return 0; } } - if (expr_ty != field.type) kit_cg_bitcast(p->cg, field.type); + if (expr_ty != field.type && + !toy_emit_checked_cast(p, expr_ty, field.type)) + return 0; kit_cg_store(p->cg, toy_mem_access(p, field.type)); if (!toy_parser_match(p, TOK_COMMA)) break; } @@ -371,7 +376,10 @@ static int toy_parse_value_block_body_to_local(ToyParser* p, KitCgLocal slot, p->nvars = saved_nvars; return 0; } - if (arm_ty != result_ty) kit_cg_bitcast(p->cg, result_ty); + if (arm_ty != result_ty && !toy_emit_checked_cast(p, arm_ty, result_ty)) { + p->nvars = saved_nvars; + return 0; + } kit_cg_push_local(p->cg, slot); kit_cg_swap(p->cg); kit_cg_store(p->cg, toy_mem_access(p, result_ty)); @@ -641,7 +649,11 @@ static int toy_parse_while_initializer_named(ToyParser* p, KitCgLocal slot, p->nscopes--; return 0; } - if (else_ty != result_ty) kit_cg_bitcast(p->cg, result_ty); + if (else_ty != result_ty && + !toy_emit_checked_cast(p, else_ty, result_ty)) { + p->nscopes--; + return 0; + } } if (!toy_parser_expect(p, TOK_RBRACE)) { toy_error(p, p->cur.loc, "expected '}' after while else"); @@ -939,10 +951,11 @@ static int toy_parse_let_stmt(ToyParser* p) { return 0; } if (init_ty != ty) { - if (toy_records_have_matching_storage(p, ty, init_ty)) + if (toy_records_have_matching_storage(p, ty, init_ty)) { copy_record_init = 1; - else - kit_cg_bitcast(p->cg, ty); + } else { + if (!toy_emit_checked_cast(p, init_ty, ty)) return 0; + } } } } @@ -1266,7 +1279,9 @@ static int toy_parse_break_stmt(ToyParser* p) { expr_ty, p->last_type, "break value type mismatch")) return 0; - if (expr_ty != result_ty) kit_cg_bitcast(p->cg, result_ty); + if (expr_ty != result_ty && + !toy_emit_checked_cast(p, expr_ty, result_ty)) + return 0; kit_cg_break(p->cg, target_scope->cg_scope); if (!toy_parser_expect(p, TOK_SEMI)) { toy_error(p, p->cur.loc, "expected ';' after break"); @@ -1361,7 +1376,7 @@ static int toy_parse_return_stmt(ToyParser* p) { if (!toy_parse_call_args(p, call_tok, fn_ty, fn ? fn->toy_params : NULL, fn ? fn->nparams : 0, &nargs)) return 0; - if (fn && !toy_type_accepts_type(p, p->cur_fn_ret_toy, fn->toy_ret)) { + if (fn && !toy_type_accepts_storage(p, p->cur_fn_ret_toy, fn->toy_ret)) { toy_error(p, p->cur.loc, "tail call signature mismatch"); return 0; } @@ -1464,7 +1479,8 @@ static int toy_parse_return_stmt(ToyParser* p) { if (!toy_check_source_value(p, p->cur_fn_ret, p->cur_fn_ret_toy, ty, p->last_type, "return type mismatch")) return 0; - if (ty != p->cur_fn_ret) kit_cg_bitcast(p->cg, p->cur_fn_ret); + if (ty != p->cur_fn_ret && !toy_emit_checked_cast(p, ty, p->cur_fn_ret)) + return 0; kit_cg_ret(p->cg); if (!toy_parser_expect(p, TOK_SEMI)) { toy_error(p, p->cur.loc, "expected ';' after return"); @@ -1564,12 +1580,14 @@ static int toy_parse_stmt(ToyParser* p) { KitCgTypeId idx_ty = toy_parse_expr(p); lhs_slice_metadata = 0; if (idx_ty == KIT_CG_TYPE_NONE) return 0; - if (!toy_parser_expect(p, TOK_RBRACKET)) { - toy_error(p, p->cur.loc, "expected ']' after index"); + if (!toy_type_can_implicitly_cast(p, idx_ty, p->size_type)) { + toy_error(p, p->cur.loc, "index must be isize"); return 0; } - if (idx_ty != p->int_type) { - toy_error(p, p->cur.loc, "index must be isize"); + if (!toy_emit_implicit_cast(p, idx_ty, p->size_type)) return 0; + idx_ty = p->size_type; + if (!toy_parser_expect(p, TOK_RBRACKET)) { + toy_error(p, p->cur.loc, "expected ']' after index"); return 0; } if (kit_cg_type_kind(p->c, lhs_ty) == KIT_CG_TYPE_PTR) { @@ -1580,16 +1598,16 @@ static int toy_parse_stmt(ToyParser* p) { /* index is currently on top; stash so we can load the pointer. */ { KitCgLocal idx_slot = - kit_cg_local(p->cg, p->int_type, toy_slot_attrs(0)); + kit_cg_local(p->cg, p->size_type, toy_slot_attrs(0)); kit_cg_push_local(p->cg, idx_slot); kit_cg_swap(p->cg); - kit_cg_store(p->cg, toy_mem_access(p, p->int_type)); + kit_cg_store(p->cg, toy_mem_access(p, p->size_type)); /* TOS is the chain pointer VALUE (**T); deref to a PLACE and * load the inner pointer it addresses. */ kit_cg_deref(p->cg, 0); kit_cg_load(p->cg, toy_mem_access(p, lhs_ty)); kit_cg_push_local(p->cg, idx_slot); - kit_cg_load(p->cg, toy_mem_access(p, p->int_type)); + kit_cg_load(p->cg, toy_mem_access(p, p->size_type)); } if (kit_cg_type_kind(p->c, pointee) == KIT_CG_TYPE_ARRAY) { KitCgTypeId elem_ty = kit_cg_type_array_elem(p->c, pointee); @@ -1717,10 +1735,14 @@ static int toy_parse_stmt(ToyParser* p) { toy_error(p, p->cur.loc, "type mismatch in assignment"); return 0; } - if (expr_ty != lhs_ty) kit_cg_bitcast(p->cg, lhs_ty); - } else if (expr_ty != lhs_ty) { + if (expr_ty != lhs_ty && + !toy_emit_checked_cast(p, expr_ty, lhs_ty)) + return 0; + } else if (!toy_type_can_implicitly_cast(p, expr_ty, lhs_ty)) { toy_error(p, p->cur.loc, "type mismatch in assignment"); return 0; + } else if (expr_ty != lhs_ty) { + if (!toy_emit_implicit_cast(p, expr_ty, lhs_ty)) return 0; } kit_cg_store(p->cg, toy_mem_access(p, lhs_ty)); } @@ -1761,7 +1783,9 @@ static int toy_parse_stmt(ToyParser* p) { toy_push_var_lvalue(p, v); kit_cg_deref(p->cg, 0); /* pointer VALUE -> PLACE for store */ kit_cg_swap(p->cg); - if (expr_ty != v->type) kit_cg_bitcast(p->cg, v->type); + if (expr_ty != v->type && + !toy_emit_checked_cast(p, expr_ty, v->type)) + return 0; kit_cg_store(p->cg, toy_mem_access(p, v->type)); } else { ToyGlobal* g = toy_find_global(p, name); @@ -1789,7 +1813,9 @@ static int toy_parse_stmt(ToyParser* p) { kit_cg_push_symbol_addr(p->cg, toy_global_cur_sym(p, g), 0); kit_cg_deref(p->cg, 0); /* pointer VALUE -> PLACE for store */ kit_cg_swap(p->cg); - if (expr_ty != g->type) kit_cg_bitcast(p->cg, g->type); + if (expr_ty != g->type && + !toy_emit_checked_cast(p, expr_ty, g->type)) + return 0; kit_cg_store(p->cg, toy_mem_access(p, g->type)); } } diff --git a/lang/toy/parser_core.c b/lang/toy/parser_core.c @@ -59,10 +59,12 @@ void toy_parser_init(ToyParser* p, KitCompiler* c, KitCg* cg, ToyModule* module, p->c = c; p->cg = cg; p->types = kit_cg_builtin_types(c); + p->target = kit_compiler_target_spec(c); p->int_type = toy_builtin_type(p, KIT_CG_BUILTIN_I64); + p->size_type = toy_builtin_type( + p, p->target.ptr_size <= 4u ? KIT_CG_BUILTIN_I32 : KIT_CG_BUILTIN_I64); p->int_ptr_type = kit_cg_type_ptr(c, p->int_type, 0); p->va_list_type = toy_builtin_type(p, KIT_CG_BUILTIN_VARARG_STATE); - p->target = kit_compiler_target_spec(c); p->nvars = 0; p->cap_vars = 0; p->vars = NULL; @@ -100,10 +102,12 @@ void toy_parser_reinit(ToyParser* p, KitCompiler* c, KitCg* cg, p->c = c; p->cg = cg; p->types = kit_cg_builtin_types(c); + p->target = kit_compiler_target_spec(c); p->int_type = toy_builtin_type(p, KIT_CG_BUILTIN_I64); + p->size_type = toy_builtin_type( + p, p->target.ptr_size <= 4u ? KIT_CG_BUILTIN_I32 : KIT_CG_BUILTIN_I64); p->int_ptr_type = kit_cg_type_ptr(c, p->int_type, 0); p->va_list_type = toy_builtin_type(p, KIT_CG_BUILTIN_VARARG_STATE); - p->target = kit_compiler_target_spec(c); p->nvars = 0; p->nscopes = 0; p->nlabels = 0; diff --git a/lang/toy/symbols.c b/lang/toy/symbols.c @@ -202,8 +202,8 @@ void toy_push_var_addr(ToyParser* p, const ToyVar* v) { /* TOS: [base_ptr]. After: [base_ptr + offset] as `result_ptr_ty`. */ void toy_addr_offset(ToyParser* p, int64_t offset, KitCgTypeId result_ptr_ty) { if (offset != 0) { - kit_cg_ptr_to_int(p->cg, p->int_type); - kit_cg_push_int(p->cg, (uint64_t)offset, p->int_type); + kit_cg_ptr_to_int(p->cg, p->size_type); + kit_cg_push_int(p->cg, (uint64_t)offset, p->size_type); kit_cg_int_binop(p->cg, KIT_CG_INT_ADD, 0); kit_cg_int_to_ptr(p->cg, result_ptr_ty); } else { @@ -215,10 +215,10 @@ void toy_addr_offset(ToyParser* p, int64_t offset, KitCgTypeId result_ptr_ty) { * After: [base_ptr + index * elem_size] as `result_ptr_ty`. */ void toy_addr_index(ToyParser* p, uint64_t elem_size, KitCgTypeId result_ptr_ty) { - kit_cg_push_int(p->cg, elem_size, p->int_type); + kit_cg_push_int(p->cg, elem_size, p->size_type); kit_cg_int_binop(p->cg, KIT_CG_INT_MUL, 0); kit_cg_swap(p->cg); - kit_cg_ptr_to_int(p->cg, p->int_type); + kit_cg_ptr_to_int(p->cg, p->size_type); kit_cg_int_binop(p->cg, KIT_CG_INT_ADD, 0); kit_cg_int_to_ptr(p->cg, result_ptr_ty); } diff --git a/lang/toy/types.c b/lang/toy/types.c @@ -324,9 +324,9 @@ KitCgTypeId toy_parse_type(ToyParser* p) { p->cur.text[3] == '8') ty = toy_builtin_type(p, KIT_CG_BUILTIN_I128); else if (p->cur.text_len == 5 && memcmp(p->cur.text, "isize", 5) == 0) - ty = p->int_type; + ty = p->size_type; else if (p->cur.text_len == 5 && memcmp(p->cur.text, "usize", 5) == 0) - ty = p->int_type; + ty = p->size_type; else if (p->cur.text_len == 3 && memcmp(p->cur.text, "f32", 3) == 0) ty = toy_builtin_type(p, KIT_CG_BUILTIN_F32); else if (p->cur.text_len == 3 && memcmp(p->cur.text, "f64", 3) == 0) @@ -586,7 +586,7 @@ ToyTypeId toy_type_register_slice(ToyParser* p, KitCgTypeId elem_cg, fields[0].name = kit_sym_intern(p->c, KIT_SLICE_LIT("ptr")); fields[0].type = ptr_ty; fields[1].name = kit_sym_intern(p->c, KIT_SLICE_LIT("len")); - fields[1].type = p->int_type; + fields[1].type = p->size_type; memset(&type, 0, sizeof type); type.kind = TOY_TYPE_SLICE; type.cg = kit_cg_type_record(p->c, 0, fields, 2); @@ -682,51 +682,101 @@ static int toy_anon_record_types_match(ToyParser* p, KitCgTypeId expected, return 0; } if (exp_field.name != act_field.name) return 0; - if (!toy_type_accepts_type(p, toy_type_from_cg(p, exp_field.type), - toy_type_from_cg(p, act_field.type))) { - return 0; - } + if (exp_field.type != act_field.type) return 0; } return 1; } -int toy_type_accepts_type(ToyParser* p, ToyTypeId expected, ToyTypeId actual) { +static int toy_type_accepts_storage_type(ToyParser* p, ToyTypeId expected, + ToyTypeId actual) { const ToyType* exp = toy_type_get(p, expected); const ToyType* act = toy_type_get(p, actual); KitCgTypeId exp_cg, act_cg; if (!exp || !act) return 0; if (expected == actual) return 1; if (exp->kind == TOY_TYPE_ALIAS || exp->kind == TOY_TYPE_QUALIFIED) - return toy_type_accepts_type(p, exp->base, actual); + return toy_type_accepts_storage_type(p, exp->base, actual); if (act->kind == TOY_TYPE_ALIAS || act->kind == TOY_TYPE_QUALIFIED) - return toy_type_accepts_type(p, expected, act->base); + return toy_type_accepts_storage_type(p, expected, act->base); if (exp->kind == TOY_TYPE_PTR && act->kind == TOY_TYPE_PTR) { if (exp->address_space != act->address_space) return 0; if (exp->pointee == TOY_TYPE_NONE || act->pointee == TOY_TYPE_NONE) return exp->cg == act->cg; - return toy_type_accepts_type(p, exp->pointee, act->pointee); + return toy_type_accepts_storage_type(p, exp->pointee, act->pointee); } if (exp->kind == TOY_TYPE_ARRAY && act->kind == TOY_TYPE_ARRAY) { return exp->count == act->count && - toy_type_accepts_type(p, exp->elem, act->elem); + toy_type_accepts_storage_type(p, exp->elem, act->elem); } if (exp->kind == TOY_TYPE_SLICE && act->kind == TOY_TYPE_SLICE) - return toy_type_accepts_type(p, exp->elem, act->elem); + return toy_type_accepts_storage_type(p, exp->elem, act->elem); if (exp->kind == TOY_TYPE_FUNC && act->kind == TOY_TYPE_FUNC) { size_t i; if (exp->nparams != act->nparams || exp->variadic != act->variadic) return 0; - if (!toy_type_accepts_type(p, exp->ret, act->ret)) return 0; + if (!toy_type_accepts_storage_type(p, exp->ret, act->ret)) return 0; if (!exp->params || !act->params) return exp->cg == act->cg; for (i = 0; i < exp->nparams; ++i) { - if (!toy_type_accepts_type(p, exp->params[i], act->params[i])) return 0; + if (!toy_type_accepts_storage_type(p, exp->params[i], act->params[i])) + return 0; } return 1; } if (exp->kind == TOY_TYPE_ANON_RECORD && act->kind == TOY_TYPE_ANON_RECORD) return toy_anon_record_types_match(p, exp->cg, act->cg); + if (exp->kind == TOY_TYPE_NOMINAL_RECORD || + exp->kind == TOY_TYPE_TUPLE_RECORD || exp->kind == TOY_TYPE_ENUM || + act->kind == TOY_TYPE_NOMINAL_RECORD || + act->kind == TOY_TYPE_TUPLE_RECORD || act->kind == TOY_TYPE_ENUM) + return 0; + exp_cg = toy_type_resolved_cg(p, expected); + act_cg = toy_type_resolved_cg(p, actual); + return exp_cg != KIT_CG_TYPE_NONE && exp_cg == act_cg; +} + +int toy_type_accepts_storage(ToyParser* p, ToyTypeId expected, + ToyTypeId actual) { + return toy_type_accepts_storage_type(p, expected, actual); +} + +int toy_type_accepts_type(ToyParser* p, ToyTypeId expected, ToyTypeId actual) { + const ToyType* exp = toy_type_get(p, expected); + const ToyType* act = toy_type_get(p, actual); + KitCgTypeId exp_cg, act_cg; + if (!exp || !act) return 0; + if (expected == actual) return 1; + if (exp->kind == TOY_TYPE_ALIAS || exp->kind == TOY_TYPE_QUALIFIED) + return toy_type_accepts_type(p, exp->base, actual); + if (act->kind == TOY_TYPE_ALIAS || act->kind == TOY_TYPE_QUALIFIED) + return toy_type_accepts_type(p, expected, act->base); + if (exp->kind == TOY_TYPE_PTR && act->kind == TOY_TYPE_PTR) { + return toy_type_accepts_storage_type(p, expected, actual); + } + if (exp->kind == TOY_TYPE_ARRAY && act->kind == TOY_TYPE_ARRAY) { + return toy_type_accepts_storage_type(p, expected, actual); + } + if (exp->kind == TOY_TYPE_SLICE && act->kind == TOY_TYPE_SLICE) + return toy_type_accepts_storage_type(p, expected, actual); + if (exp->kind == TOY_TYPE_FUNC && act->kind == TOY_TYPE_FUNC) { + return toy_type_accepts_storage_type(p, expected, actual); + } + if (exp->kind == TOY_TYPE_ANON_RECORD && act->kind == TOY_TYPE_ANON_RECORD) + return toy_anon_record_types_match(p, exp->cg, act->cg); exp_cg = toy_type_resolved_cg(p, expected); act_cg = toy_type_resolved_cg(p, actual); + if (exp_cg != KIT_CG_TYPE_NONE && act_cg != KIT_CG_TYPE_NONE) { + KitCgTypeKind exp_kind = kit_cg_type_kind(p->c, exp_cg); + KitCgTypeKind act_kind = kit_cg_type_kind(p->c, act_cg); + if (exp_kind == KIT_CG_TYPE_INT && act_kind == KIT_CG_TYPE_INT && + toy_type_int_width(p, act_cg) <= toy_type_int_width(p, exp_cg)) { + return 1; + } + if (exp_kind == KIT_CG_TYPE_FLOAT && act_kind == KIT_CG_TYPE_FLOAT && + kit_cg_type_float_width(p->c, act_cg) <= + kit_cg_type_float_width(p->c, exp_cg)) { + return 1; + } + } return exp_cg != KIT_CG_TYPE_NONE && exp_cg == act_cg && exp->kind != TOY_TYPE_NOMINAL_RECORD && exp->kind != TOY_TYPE_TUPLE_RECORD && exp->kind != TOY_TYPE_ENUM; diff --git a/test/toy/cases/102_typed_asm_operands.toy b/test/toy/cases/102_typed_asm_operands.toy @@ -1,7 +1,7 @@ fn __user_main(): i64 { let value: i64 = @asm<i64>( "", - outputs(inout("+r", 42)), + outputs(inout("+r", 42 as i64)), inputs(), clobbers(), flags(.volatile) diff --git a/test/toy/cases/105_typed_asm_record_outputs.toy b/test/toy/cases/105_typed_asm_record_outputs.toy @@ -1,7 +1,7 @@ fn __user_main(): i64 { return @asm<record { lo: i64, hi: i64 }>( "", - outputs(inout("+r", 20), inout("+r", 22)), + outputs(inout("+r", 20 as i64), inout("+r", 22 as i64)), inputs(), clobbers(), flags(.volatile) diff --git a/test/toy/cases/110_typed_asm_named_outputs.toy b/test/toy/cases/110_typed_asm_named_outputs.toy @@ -1,7 +1,7 @@ fn __user_main(): i64 { let pair = @asm<record { lo: i64, hi: i64 }>( "", - outputs(hi = inout("+r", 20), lo = inout("+r", 22)) + outputs(hi = inout("+r", 20 as i64), lo = inout("+r", 22 as i64)) ); @asm<void>("", outputs(), inputs(in("r", pair.lo), in("r", pair.hi))); return 0; diff --git a/test/toy/cases/119_static_labeladdr_data.toy b/test/toy/cases/119_static_labeladdr_data.toy @@ -7,7 +7,7 @@ fn __user_main(): i64 { @labeladdr(one), ]; - let idx: i64 = 1; + let idx: isize = 1; goto *dispatch[idx] within (zero, one); zero: diff --git a/test/toy/cases/121_dynamic_memory_builtin.toy b/test/toy/cases/121_dynamic_memory_builtin.toy @@ -1,8 +1,8 @@ fn __user_main(): i64 { let src: *i64 = @alloca<i64>(2, 8); let dst: *i64 = @alloca<i64>(2, 8); - let n: i64 = 16; - let a: i64 = 8; + let n: usize = 16; + let a: usize = 8; src[0] = 40; src[1] = 2; diff --git a/test/toy/cases/123_spec_demo.toy b/test/toy/cases/123_spec_demo.toy @@ -181,7 +181,7 @@ outer: while i < limit { return branch + found; } -fn memory_demo(n: Word): Word { +fn memory_demo(n: usize): Word { let src: *Word = @alloca<Word>(2, 8); let dst: *Word = @alloca<Word>(2, 8); let tmp: *Word = @alloca<Word>(2, 8); @@ -245,7 +245,7 @@ fn intrinsic_demo(): Word { if @expect(1, 1) != 1 { return 0; } - if @bswap(1) == 0 { + if @bswap(1 as Word) == 0 { return 0; } if (@fma(2.0, 3.0, 4.0) as Word) != 10 { @@ -280,7 +280,7 @@ fn target_demo(): Word { return 0; } -fn label_demo(idx: Word): Word { +fn label_demo(idx: isize): Word { label zero; label one; label done; @@ -363,7 +363,7 @@ fn __user_main(): Word { if label_demo(1) != 42 { return 15; } - if sum_var(3, 5, 6, 7) != 23 { + if sum_var(3, 5 as Word, 6 as Word, 7 as Word) != 23 { return 16; } if (answer_ptr.* as Word) != 42 { diff --git a/test/toy/cases/133_varargs_mixed_types.toy b/test/toy/cases/133_varargs_mixed_types.toy @@ -45,11 +45,11 @@ fn adjacent_i32(n: i64, ...): i64 { } fn __user_main(): i64 { - let s: i64 = sum3(10, 1, 2, 3 as i32); + let s: i64 = sum3(10, 1 as i64, 2 as i64, 3 as i32); if s != (16 as i64) { return 1; } - let t: i64 = pick_third(0, 100, 200, 300); + let t: i64 = pick_third(0, 100 as i64, 200 as i64, 300 as i64); if t != (300 as i64) { return 2; } - let c: i64 = copy_then_read(0, 7, 11, 13); + let c: i64 = copy_then_read(0, 7 as i64, 11 as i64, 13 as i64); if c != (7 + 11 + 11) { return 3; } let z: i64 = no_varargs(21); if z != (42 as i64) { return 4; } diff --git a/test/toy/cases/139_variadic_stack_arg_call_result.toy b/test/toy/cases/139_variadic_stack_arg_call_result.toy @@ -25,9 +25,9 @@ fn vfn(n: i64, ...): i64 { fn __user_main(): i64 { // Call result is the last (second) variadic stack arg. - if vfn(7, 3, make(64)) != (858 as i64) { return 1; } + if vfn(7, 3 as i64, make(64)) != (858 as i64) { return 1; } // Call result is the first variadic stack arg. - if vfn(7, make(64), 3) != (1983 as i64) { return 2; } + if vfn(7, make(64), 3 as i64) != (1983 as i64) { return 2; } // Both variadic stack args are call results. if vfn(1, make(10), make(20)) != (340 as i64) { return 3; } return 42; diff --git a/test/toy/cases/140_fp_callee_save_bottom_frame.toy b/test/toy/cases/140_fp_callee_save_bottom_frame.toy @@ -14,7 +14,7 @@ fn bump(x: i64): i64 { return x + 100; } fn big_fp(seed: i64): i64 { var buf: [40]i64; - var i: i64 = 0; + var i: isize = 0; while i < 40 { buf[i] = seed + i; i = i + 1; diff --git a/test/toy/cases/19_cg_api_variadic_asm.toy b/test/toy/cases/19_cg_api_variadic_asm.toy @@ -20,7 +20,7 @@ fn sum_first(n: i64, ...): i64 { fn __user_main(): i64 { var v: i64 = @asm<i64>( "", - outputs(inout("+r", 42)), + outputs(inout("+r", 42 as i64)), inputs(), clobbers(), flags(.volatile) @@ -28,7 +28,7 @@ fn __user_main(): i64 { var s: i64 = 23; @asm<void>("", outputs(), inputs(in("r", 19), in("r", 23))); @asm<void>("", outputs(), inputs()); - s = sum_first(3, 5, 6, 7); + s = sum_first(3, 5 as i64, 6 as i64, 7 as i64); return s + v; } diff --git a/test/toy/cases/23_cg_api_typed_varargs.toy b/test/toy/cases/23_cg_api_typed_varargs.toy @@ -7,7 +7,7 @@ fn pick(n: i64, ...): i64 { } fn __user_main(): i64 { - return pick(4, 38); + return pick(4, 38 as i64); } fn main(): i32 { return __user_main() as i32; } diff --git a/test/toy/err/type_mismatch.toy b/test/toy/err/type_mismatch.toy @@ -1,3 +1,3 @@ fn main(): i32 { - return 1; + return NULL; } diff --git a/test/toy/err/unsupported_coro_switch.toy b/test/toy/err/unsupported_coro_switch.toy @@ -1,5 +1,5 @@ fn main(): i64 { var from: *void = NULL as *void; var to: *void = NULL as *void; - return @coro_switch<i64>(from, to, 0); + return @coro_switch<i64>(from, to, 0 as i64); }