diff --git a/code/demo.odin b/code/demo.odin index 11ffec8ce..4b88bfea1 100644 --- a/code/demo.odin +++ b/code/demo.odin @@ -1,5 +1,5 @@ import "fmt.odin"; main :: proc() { - fmt.println("Hellope, World!"); + fmt.println("Hellope!"); } diff --git a/core/_preload.odin b/core/_preload.odin index ae331d830..89785b7d3 100644 --- a/core/_preload.odin +++ b/core/_preload.odin @@ -82,7 +82,8 @@ TypeInfo :: struct #ordered { Struct :: Record; RawUnion :: Record; Union :: struct #ordered { - variants: []^TypeInfo; + variants: []^TypeInfo; + tag_offset: int; }; Enum :: struct #ordered { base: ^TypeInfo; diff --git a/core/c.odin b/core/c.odin new file mode 100644 index 000000000..614908edf --- /dev/null +++ b/core/c.odin @@ -0,0 +1,41 @@ +CHAR_BIT :: 8; + +c_bool :: bool; + +c_char :: u8; + +c_schar :: i8; +c_uchar :: i8; + +c_short :: i16; +c_ushort :: i16; + +c_int :: i32; +c_uint :: u32; + +c_long :: ODIN_OS == "windows" ? + i32 : + (size_of(int) == 4) ? + i32 : + i64; + +c_ulong :: ODIN_OS == "windows" ? + u32 : + (size_of(int) == 4) ? + u32 : + u64; + +c_longlong :: i64; +c_ulonglong :: u64; + +c_float :: f32; +c_double :: f64; + +c_complex_float :: complex64; +c_complex_double :: complex128; + +c_size_t :: uint; +c_ssize_t :: int; +c_ptrdiff_t :: int; +c_uintptr_t :: uint; +c_intptr_t :: int; diff --git a/core/fmt.odin b/core/fmt.odin index 1a0090909..25262ef2a 100644 --- a/core/fmt.odin +++ b/core/fmt.odin @@ -866,7 +866,15 @@ fmt_value :: proc(fi: ^FmtInfo, v: any, verb: rune) { } case Union: - write_string(fi.buf, "(union)"); + data := cast(^u8)v.data; + tipp := cast(^^TypeInfo)(data + info.tag_offset); + if data == nil || tipp == nil { + write_string(fi.buf, "(union)"); + } else { + ti := tipp^; + fmt_arg(fi, any{data, ti}, verb); + } + case RawUnion: write_string(fi.buf, "(raw_union)"); diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 7a730629a..2a4d60872 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -1326,10 +1326,6 @@ void check_union_type(Checker *c, Type *named_type, Type *union_type, AstNode *n array_add(&variants, t_invalid); union_type->Union.scope = c->context.scope; - { - Entity *__tag = make_entity_field(c->allocator, nullptr, make_token_ident(str_lit("__tag")), t_int, false, -1); - union_type->Union.union__tag = __tag; - } for_array(i, ut->variants) { AstNode *node = ut->variants[i]; @@ -1353,7 +1349,10 @@ void check_union_type(Checker *c, Type *named_type, Type *union_type, AstNode *n } } } - if (ok) array_add(&variants, t); + if (ok) { + add_type_info_type(c, t); + array_add(&variants, t); + } } } @@ -2044,8 +2043,10 @@ Type *check_get_params(Checker *c, Scope *scope, AstNode *_params, bool *is_vari success = false; type = t_invalid; } - if (is_type_polymorphic_struct(type)) { - error(o.expr, "Cannot pass polymorphic struct as a parameter"); + if (is_type_polymorphic(type)) { + gbString str = type_to_string(type); + error(o.expr, "Cannot pass polymorphic type as a parameter, got `%s`", str); + gb_string_free(str); success = false; type = t_invalid; } @@ -3079,6 +3080,15 @@ bool check_type_internal(Checker *c, AstNode *e, Type **type, Type *named_type) return true; } case_end; + + case_ast_node(te, TernaryExpr, e); + Operand o = {}; + check_expr_or_type(c, &o, e); + if (o.mode == Addressing_Type) { + *type = o.type; + return true; + } + case_end; } *type = t_invalid; @@ -4290,6 +4300,90 @@ void convert_to_typed(Checker *c, Operand *operand, Type *target_type, i32 level } } break; + case Type_Union: + { + gbTempArenaMemory tmp = gb_temp_arena_memory_begin(&c->tmp_arena); + defer (gb_temp_arena_memory_end(tmp)); + i32 count = t->Union.variant_count; + i64 *scores = gb_alloc_array(c->tmp_allocator, i64, count); + i32 success_count = 0; + i32 first_success_index = -1; + for (i32 i = 1; i < count; i++) { + Type *vt = t->Union.variants[i]; + i64 score = 0; + if (check_is_assignable_to_with_score(c, operand, vt, &score)) { + scores[i] = score; + success_count += 1; + if (first_success_index < 0) { + first_success_index = i; + } + } + } + + gbString type_str = type_to_string(target_type); + defer (gb_string_free(type_str)); + + if (success_count == 1) { + operand->mode = Addressing_Value; + operand->type = t->Union.variants[first_success_index]; + target_type = t->Union.variants[first_success_index]; + break; + } else if (success_count > 1) { + GB_ASSERT(first_success_index >= 0); + operand->mode = Addressing_Invalid; + convert_untyped_error(c, operand, target_type); + + gb_printf_err("Ambiguous type conversion to `%s`, which variant did you mean:\n\t", type_str); + i32 j = 0; + for (i32 i = first_success_index; i < count; i++) { + if (scores[i] == 0) continue; + if (j > 0 && success_count > 2) gb_printf_err(", "); + if (j == success_count-1) { + if (success_count == 2) { + gb_printf_err(" or "); + } else { + gb_printf_err(" or "); + } + } + gbString str = type_to_string(t->Union.variants[i]); + gb_printf_err("`%s`", str); + gb_string_free(str); + j++; + } + gb_printf_err("\n\n"); + + return; + } else if (is_type_untyped_undef(operand->type) && type_has_undef(target_type)) { + target_type = t_untyped_undef; + } else if (!is_type_untyped_nil(operand->type) || !type_has_nil(target_type)) { + operand->mode = Addressing_Invalid; + convert_untyped_error(c, operand, target_type); + if (count > 1) { + gb_printf_err("`%s` is a union which only excepts the following types:\n", type_str); + gb_printf_err("\t"); + for (i32 i = 1; i < count; i++) { + Type *v = t->Union.variants[i]; + if (i > 1 && count > 3) gb_printf_err(", "); + if (i == count-1) { + if (count == 3) { + gb_printf_err(" or "); + } else { + gb_printf_err("or "); + } + } + gbString str = type_to_string(v); + gb_printf_err("`%s`", str); + gb_string_free(str); + } + gb_printf_err("\n\n"); + + } + return; + } + + } + /* fallthrough */ + default: if (is_type_untyped_undef(operand->type) && type_has_undef(target_type)) { @@ -6894,16 +6988,6 @@ ExprKind check_call_expr(Checker *c, Operand *operand, AstNode *call) { } -ExprKind Ov(Checker *c, Operand *operand, AstNode *call) { - GB_ASSERT(call->kind == AstNode_MacroCallExpr); - ast_node(mce, MacroCallExpr, call); - - error(call, "Macro call expressions are not yet supported"); - operand->mode = Addressing_Invalid; - operand->expr = call; - return Expr_Stmt; -} - void check_expr_with_type_hint(Checker *c, Operand *o, AstNode *e, Type *t) { check_expr_base(c, o, e, t); check_not_tuple(c, o); @@ -7139,10 +7223,10 @@ ExprKind check_expr_base_internal(Checker *c, Operand *o, AstNode *node, Type *t Operand x = {Addressing_Invalid}; Operand y = {Addressing_Invalid}; - check_expr_with_type_hint(c, &x, te->x, type_hint); + check_expr_or_type(c, &x, te->x, type_hint); if (te->y != nullptr) { - check_expr_with_type_hint(c, &y, te->y, type_hint); + check_expr_or_type(c, &y, te->y, type_hint); } else { error(node, "A ternary expression must have an else clause"); return kind; @@ -7153,6 +7237,19 @@ ExprKind check_expr_base_internal(Checker *c, Operand *o, AstNode *node, Type *t return kind; } + if (x.mode == Addressing_Type && y.mode == Addressing_Type && + cond.mode == Addressing_Constant && is_type_boolean(cond.type)) { + o->mode = Addressing_Type; + if (cond.value.value_bool) { + o->type = x.type; + o->expr = x.expr; + } else { + o->type = y.type; + o->expr = y.expr; + } + return Expr_Expr; + } + convert_to_typed(c, &x, y.type, 0); if (x.mode == Addressing_Invalid) { return kind; @@ -7218,7 +7315,18 @@ ExprKind check_expr_base_internal(Checker *c, Operand *o, AstNode *node, Type *t return kind; } + Type *t = base_type(type); + if (is_type_polymorphic(t)) { + gbString str = type_to_string(type); + error(node, "Cannot use a polymorphic type for a compound literal, got `%s`", str); + o->expr = node; + o->type = type; + gb_string_free(str); + return kind; + } + + switch (t->kind) { case Type_Record: { if (is_type_union(t)) { @@ -7909,7 +8017,8 @@ ExprKind check_expr_base_internal(Checker *c, Operand *o, AstNode *node, Type *t case_end; case_ast_node(ce, MacroCallExpr, node); - return Ov(c, o, node); + error(node, "Macro calls are not yet supported"); + return kind; case_end; case_ast_node(de, DerefExpr, node); diff --git a/src/ir.cpp b/src/ir.cpp index 85eef66c4..833edb0e2 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -954,7 +954,7 @@ irValue *ir_instr_union_tag_ptr(irProcedure *p, irValue *address) { irValue *v = ir_alloc_instr(p, irInstr_UnionTagPtr); irInstr *i = &v->Instr; i->UnionTagPtr.address = address; - i->UnionTagPtr.type = t_int_ptr; + i->UnionTagPtr.type = make_type_pointer(p->module->allocator, t_type_info_ptr); return v; } @@ -962,7 +962,7 @@ irValue *ir_instr_union_tag_value(irProcedure *p, irValue *address) { irValue *v = ir_alloc_instr(p, irInstr_UnionTagValue); irInstr *i = &v->Instr; i->UnionTagValue.address = address; - i->UnionTagValue.type = t_int; + i->UnionTagValue.type = t_type_info_ptr; return v; } @@ -2218,7 +2218,7 @@ irValue *ir_emit_union_tag_ptr(irProcedure *proc, irValue *u) { Type *tpt = ir_type(tag_ptr); GB_ASSERT(is_type_pointer(tpt)); tpt = base_type(type_deref(tpt)); - GB_ASSERT(tpt == t_int); + GB_ASSERT(tpt == t_type_info_ptr); return tag_ptr; } @@ -2379,15 +2379,8 @@ irValue *ir_emit_struct_ep(irProcedure *proc, irValue *s, i32 index) { GB_ASSERT_MSG(gb_is_between(index, 0, t->Record.field_count-1), "0..%d..%d", index, t->Record.field_count); result_type = make_type_pointer(a, t->Record.fields[index]->type); } else if (is_type_union(t)) { - type_set_offsets(a, t); - GB_ASSERT(t->Record.field_count > 0); - if (index == -1) { - index = t->Record.field_count+1; - result_type = t_int_ptr; - } else { - GB_ASSERT(gb_is_between(index, 0, t->Record.field_count-1)); - result_type = make_type_pointer(a, t->Record.fields[index]->type); - } + GB_ASSERT(index == -1); + return ir_emit_union_tag_ptr(proc, s); } else if (is_type_tuple(t)) { GB_ASSERT(t->Tuple.variable_count > 0); GB_ASSERT(gb_is_between(index, 0, t->Tuple.variable_count-1)); @@ -2449,14 +2442,8 @@ irValue *ir_emit_struct_ev(irProcedure *proc, irValue *s, i32 index) { GB_ASSERT(gb_is_between(index, 0, t->Record.field_count-1)); result_type = t->Record.fields[index]->type; } else if (is_type_union(t)) { - type_set_offsets(a, t); - if (index == -1) { - index = t->Record.field_count+1; - result_type = t_int_ptr; - } else { - GB_ASSERT(gb_is_between(index, 0, t->Record.field_count-1)); - } - result_type = t->Record.fields[index]->type; + GB_ASSERT(index == -1); + return ir_emit_union_tag_value(proc, s); } else if (is_type_tuple(t)) { GB_ASSERT(t->Tuple.variable_count > 0); GB_ASSERT(gb_is_between(index, 0, t->Tuple.variable_count-1)); @@ -2523,12 +2510,12 @@ irValue *ir_emit_deep_field_gep(irProcedure *proc, irValue *e, Selection sel) { if (is_type_raw_union(type)) { type = type->Record.fields[index]->type; e = ir_emit_conv(proc, e, make_type_pointer(proc->module->allocator, type)); + } else if (type->kind == Type_Union) { + GB_ASSERT(index == -1); + type = t_type_info_ptr; + e = ir_emit_struct_ep(proc, e, index); } else if (type->kind == Type_Record) { - if (index == -1) { - type = t_int; - } else { - type = type->Record.fields[index]->type; - } + type = type->Record.fields[index]->type; e = ir_emit_struct_ep(proc, e, index); } else if (type->kind == Type_Tuple) { type = type->Tuple.variables[index]->type; @@ -2983,7 +2970,7 @@ irValue *ir_emit_conv(irProcedure *proc, irValue *value, Type *t) { ir_emit_store(proc, underlying, value); irValue *tag_ptr = ir_emit_union_tag_ptr(proc, parent); - ir_emit_store(proc, tag_ptr, ir_const_int(a, i)); + ir_emit_store(proc, tag_ptr, ir_type_info(proc, vt)); return ir_emit_load(proc, parent); } @@ -3308,20 +3295,11 @@ irValue *ir_emit_union_cast(irProcedure *proc, irValue *value, Type *type, Token Type *src = base_type(type_deref(src_type)); GB_ASSERT(is_type_union(src)); Type *dst = tuple->Tuple.variables[0]->type; - Type *dst_ptr = make_type_pointer(a, dst); irValue *value_ = ir_address_from_load_or_generate_local(proc, value); irValue *tag = ir_emit_load(proc, ir_emit_union_tag_ptr(proc, value_)); - irValue *dst_tag = nullptr; - for (isize i = 1; i < src->Union.variant_count; i++) { - Type *vt = src->Union.variants[i]; - if (are_types_identical(vt, dst)) { - dst_tag = ir_const_int(a, i); - break; - } - } - GB_ASSERT(dst_tag != nullptr); + irValue *dst_tag = ir_type_info(proc, dst); irBlock *ok_block = ir_new_block(proc, nullptr, "union_cast.ok"); irBlock *end_block = ir_new_block(proc, nullptr, "union_cast.end"); @@ -6943,18 +6921,18 @@ void ir_build_stmt_internal(irProcedure *proc, AstNode *node) { irValue *cond = nullptr; if (match_type_kind == MatchType_Union) { Type *bt = type_deref(case_type); - irValue *index = nullptr; + irValue *variant_tag = nullptr; Type *ut = base_type(type_deref(parent_type)); GB_ASSERT(ut->kind == Type_Union); for (isize variant_index = 1; variant_index < ut->Union.variant_count; variant_index++) { Type *vt = ut->Union.variants[variant_index]; if (are_types_identical(vt, bt)) { - index = ir_const_int(allocator, variant_index); + variant_tag = ir_type_info(proc, vt); break; } } - GB_ASSERT(index != nullptr); - cond = ir_emit_comp(proc, Token_CmpEq, tag_index, index); + GB_ASSERT(variant_tag != nullptr); + cond = ir_emit_comp(proc, Token_CmpEq, tag_index, variant_tag); } else if (match_type_kind == MatchType_Any) { irValue *any_ti = ir_emit_load(proc, ir_emit_struct_ep(proc, parent_ptr, 1)); irValue *case_ti = ir_type_info(proc, case_type); @@ -8166,7 +8144,8 @@ void ir_gen_tree(irGen *s) { tag = ir_emit_conv(proc, variant_ptr, t_type_info_union_ptr); { - irValue *variant_types = ir_emit_struct_ep(proc, tag, 0); + irValue *variant_types = ir_emit_struct_ep(proc, tag, 0); + irValue *tag_offset_ptr = ir_emit_struct_ep(proc, tag, 1); isize variant_count = gb_max(0, t->Union.variant_count-1); irValue *memory_types = ir_type_info_member_types_offset(proc, variant_count); @@ -8183,6 +8162,9 @@ void ir_gen_tree(irGen *s) { irValue *count = ir_const_int(a, variant_count); ir_fill_slice(proc, variant_types, memory_types, count, count); + + i64 tag_offset = align_formula(t->Union.variant_block_size, build_context.word_size); + ir_emit_store(proc, tag_offset_ptr, ir_const_int(a, tag_offset)); } } break; @@ -8323,21 +8305,9 @@ void ir_gen_tree(irGen *s) { if (tag != nullptr) { Type *tag_type = type_deref(ir_type(tag)); GB_ASSERT(is_type_named(tag_type)); - Type *ti = base_type(t_type_info); - Type *tiv = base_type(ti->Record.fields_in_src_order[2]->type); - GB_ASSERT(is_type_union(tiv)); - bool found = false; - for (isize i = 1; i < tiv->Union.variant_count; i++) { - Type *vt = tiv->Union.variants[i]; - if (are_types_identical(vt, tag_type)) { - found = true; - irValue *tag_val = ir_const_int(a, i); - irValue *ptr = ir_emit_union_tag_ptr(proc, variant_ptr); - ir_emit_store(proc, ptr, tag_val); - break; - } - } - GB_ASSERT_MSG(found, "Tag type not found: %s", type_to_string(tag_type)); + irValue *ti = ir_type_info(proc, tag_type); + irValue *ptr = ir_emit_union_tag_ptr(proc, variant_ptr); + ir_emit_store(proc, ptr, ti); } else { GB_PANIC("Unhandled TypeInfo type: %s", type_to_string(t)); } diff --git a/src/ir_print.cpp b/src/ir_print.cpp index e2d33054b..deb5b9e34 100644 --- a/src/ir_print.cpp +++ b/src/ir_print.cpp @@ -292,7 +292,8 @@ void ir_print_type(irFileBuffer *f, irModule *m, Type *t) { ir_fprintf(f, "{[0 x <%lld x i8>], ", align); ir_fprintf(f, "[%lld x i8], ", block_size); - ir_fprintf(f, "i%lld}", word_bits); + ir_print_type(f, m, t_type_info_ptr); + ir_fprintf(f, "}"); #else i64 block_size = total_size - build_context.word_size; ir_fprintf(f, "{[0 x <%lld x i8>], [%lld x i8], i%lld}", align, block_size, word_bits); diff --git a/src/parser.cpp b/src/parser.cpp index 651bed859..a7da2ee9e 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -4942,7 +4942,7 @@ ParseFileError parse_files(Parser *p, String init_filename) { GB_ASSERT(init_filename.text[init_filename.len] == 0); char *fullpath_str = gb_path_get_full_name(heap_allocator(), cast(char *)&init_filename[0]); - String init_fullpath = make_string_c(fullpath_str); + String init_fullpath = string_trim_whitespace(make_string_c(fullpath_str)); TokenPos init_pos = {}; ImportedFile init_imported_file = {init_fullpath, init_fullpath, init_pos}; diff --git a/src/types.cpp b/src/types.cpp index 3fe9029d8..29a06528d 100644 --- a/src/types.cpp +++ b/src/types.cpp @@ -123,7 +123,7 @@ struct TypeRecord { i32 variant_count; \ AstNode *node; \ Scope * scope; \ - Entity * union__tag; \ + Entity * union__type_info; \ i64 variant_block_size; \ i64 custom_align; \ }) \ @@ -1596,11 +1596,18 @@ Selection lookup_field_with_selection(gbAllocator a, Type *type_, String field_n } } else if (type->kind == Type_Union) { - if (field_name == "__tag") { - Entity *e = type->Union.union__tag; + if (field_name == "__type_info") { + Entity *e = type->Union.union__type_info; + if (e == nullptr) { + Entity *__type_info = make_entity_field(a, nullptr, make_token_ident(str_lit("__type_info")), t_type_info_ptr, false, -1); + type->Union.union__type_info = __type_info; + e = __type_info; + } + GB_ASSERT(e != nullptr); selection_add_index(&sel, -1); // HACK(bill): Leaky memory sel.entity = e; + return sel; } } else if (type->kind == Type_Record) { @@ -2067,9 +2074,9 @@ i64 type_size_of_internal(gbAllocator allocator, Type *t, TypePath *path) { } i64 max = 0; + i64 field_size = 0; isize variant_count = t->Union.variant_count; - i64 field_size = max; for (isize i = 1; i < variant_count; i++) { Type *variant_type = t->Union.variants[i];