From fd8c4d58bb476f858b5238287b6e9911dd5c333c Mon Sep 17 00:00:00 2001 From: Ginger Bill Date: Mon, 10 Jul 2017 22:32:21 +0100 Subject: [PATCH] `union` type allow for any types and removes common fields --- core/_preload.odin | 121 ++++++++++++++---------- core/fmt.odin | 86 ++++++++--------- core/mem.odin | 30 +++--- core/types.odin | 40 ++++---- src/check_expr.cpp | 132 +++++---------------------- src/check_stmt.cpp | 4 +- src/checker.cpp | 89 +++++++++--------- src/ir.cpp | 223 ++++++++++++++++++++++++++------------------- src/parser.cpp | 52 ++--------- src/types.cpp | 46 ++-------- 10 files changed, 356 insertions(+), 467 deletions(-) diff --git a/core/_preload.odin b/core/_preload.odin index c540a233f..4201823f2 100644 --- a/core/_preload.odin +++ b/core/_preload.odin @@ -34,59 +34,54 @@ CallingConvention :: enum { } // IMPORTANT NOTE(bill): Do not change the order of any of this data // The compiler relies upon this _exact_ order +TypeInfo :: struct #ordered { +// Core Types + EnumValue :: raw_union { + f: f64; + i: i128; + } + Record :: struct #ordered { + types: []^TypeInfo; + names: []string; + offsets: []int; // offsets may not be used in tuples + usings: []bool; // usings may not be used in tuples + packed: bool; + ordered: bool; + custom_align: bool; + } - -TypeInfoEnumValue :: raw_union { - f: f64; - i: i128; -} - -TypeInfoRecord :: struct #ordered { - types: []^TypeInfo; - names: []string; - offsets: []int; // offsets may not be used in tuples - usings: []bool; // usings may not be used in tuples - packed: bool; - ordered: bool; - custom_align: bool; -} - - -TypeInfo :: union { - size: int; - align: int; - - Named{name: string; base: ^TypeInfo}; - Integer{signed: bool}; - Rune{}; - Float{}; - Complex{}; - String{}; - Boolean{}; - Any{}; - Pointer{ +// Variant Types + Named :: struct #ordered {name: string; base: ^TypeInfo}; + Integer :: struct #ordered {signed: bool}; + Rune :: struct{}; + Float :: struct{}; + Complex :: struct{}; + String :: struct{}; + Boolean :: struct{}; + Any :: struct{}; + Pointer :: struct #ordered { elem: ^TypeInfo; // nil -> rawptr }; - Atomic{elem: ^TypeInfo}; - Procedure{ + Atomic :: struct #ordered {elem: ^TypeInfo}; + Procedure :: struct #ordered { params: ^TypeInfo; // TypeInfo.Tuple results: ^TypeInfo; // TypeInfo.Tuple variadic: bool; convention: CallingConvention; }; - Array{ + Array :: struct #ordered { elem: ^TypeInfo; elem_size: int; count: int; }; - DynamicArray{elem: ^TypeInfo; elem_size: int}; - Slice {elem: ^TypeInfo; elem_size: int}; - Vector {elem: ^TypeInfo; elem_size, count: int}; - Tuple {using record: TypeInfoRecord}; // Only really used for procedures - Struct {using record: TypeInfoRecord}; - RawUnion {using record: TypeInfoRecord}; - Union{ - common_fields: struct { + DynamicArray :: struct #ordered {elem: ^TypeInfo; elem_size: int}; + Slice :: struct #ordered {elem: ^TypeInfo; elem_size: int}; + Vector :: struct #ordered {elem: ^TypeInfo; elem_size, count: int}; + Tuple :: Record; // Only really used for procedures + Struct :: Record; + RawUnion :: Record; + Union :: struct #ordered { + common_fields: struct #ordered { types: []^TypeInfo; names: []string; offsets: []int; // offsets may not be used in tuples @@ -94,22 +89,52 @@ TypeInfo :: union { variant_names: []string; variant_types: []^TypeInfo; }; - Enum{ + Enum :: struct #ordered { base: ^TypeInfo; names: []string; - values: []TypeInfoEnumValue; + values: []EnumValue; }; - Map{ + Map :: struct #ordered { key: ^TypeInfo; value: ^TypeInfo; generated_struct: ^TypeInfo; count: int; // == 0 if dynamic }; - BitField{ + BitField :: struct #ordered { names: []string; bits: []i32; offsets: []i32; }; + + +// Fields + size: int; + align: int; + + variant: union { + Named, + Integer, + Rune, + Float, + Complex, + String, + Boolean, + Any, + Pointer, + Atomic, + Procedure, + Array, + DynamicArray, + Slice, + Vector, + Tuple, + Struct, + RawUnion, + Union, + Enum, + Map, + BitField, + }; } // NOTE(bill): only the ones that are needed (not all types) @@ -147,7 +172,7 @@ Context :: struct #ordered { DEFAULT_ALIGNMENT :: align_of([vector 4]f32); -SourceCodeLocation :: struct { +SourceCodeLocation :: struct #ordered { fully_pathed_filename: string; line, column: i64; procedure: string; @@ -190,7 +215,7 @@ type_info_base :: proc(info: ^TypeInfo) -> ^TypeInfo { if info == nil do return nil; base := info; - match i in base { + match i in base.variant { case TypeInfo.Named: base = i.base; } return base; @@ -201,7 +226,7 @@ type_info_base_without_enum :: proc(info: ^TypeInfo) -> ^TypeInfo { if info == nil do return nil; base := info; - match i in base { + match i in base.variant { case TypeInfo.Named: base = i.base; case TypeInfo.Enum: base = i.base; } diff --git a/core/fmt.odin b/core/fmt.odin index f21a36949..8b44587fa 100644 --- a/core/fmt.odin +++ b/core/fmt.odin @@ -10,8 +10,8 @@ import ( _BUFFER_SIZE :: 1<<12; StringBuffer :: union { - Static {buf: []u8;}; - Dynamic{buf: [dynamic]u8;}; + []u8, + [dynamic]u8, } FmtInfo :: struct { @@ -34,28 +34,18 @@ FmtInfo :: struct { } -make_string_buffer_from_slice :: proc(b: []u8) -> StringBuffer { - return StringBuffer.Static{b}; -} -make_string_dynamic_buffer :: proc() -> StringBuffer { - return StringBuffer.Dynamic{make([dynamic]u8)}; -} string_buffer_data :: proc(buf: ^StringBuffer) -> []u8 { match b in buf { - case StringBuffer.Static: - return b.buf[..]; - case StringBuffer.Dynamic: - return b.buf[..]; + case []u8: return b[..]; + case [dynamic]u8: return b[..]; } return nil; } string_buffer_data :: proc(buf: StringBuffer) -> []u8 { match b in buf { - case StringBuffer.Static: - return b.buf[..]; - case StringBuffer.Dynamic: - return b.buf[..]; + case []u8: return b[..]; + case [dynamic]u8: return b[..]; } return nil; } @@ -69,18 +59,14 @@ write_string :: proc(buf: ^StringBuffer, s: string) { } write_bytes :: proc(buf: ^StringBuffer, data: []u8) { match b in buf { - case StringBuffer.Static: - append(&b.buf, ...data); - case StringBuffer.Dynamic: - append(&b.buf, ...data); + case []u8: append(b, ...data); + case [dynamic]u8: append(b, ...data); } } write_byte :: proc(buf: ^StringBuffer, data: u8) { match b in buf { - case StringBuffer.Static: - append(&b.buf, data); - case StringBuffer.Dynamic: - append(&b.buf, data); + case []u8: append(b, data); + case [dynamic]u8: append(b, data); } } write_rune :: proc(buf: ^StringBuffer, r: rune) { @@ -108,7 +94,7 @@ write_int :: proc(buf: ^StringBuffer, i: i64, base: int) { fprint :: proc(fd: os.Handle, args: ...any) -> int { data: [_BUFFER_SIZE]u8; - buf := make_string_buffer_from_slice(data[..0]); + buf := StringBuffer(data[..0]); sbprint(&buf, ...args); res := string_buffer_data(buf); os.write(fd, res); @@ -117,7 +103,7 @@ fprint :: proc(fd: os.Handle, args: ...any) -> int { fprintln :: proc(fd: os.Handle, args: ...any) -> int { data: [_BUFFER_SIZE]u8; - buf := make_string_buffer_from_slice(data[..0]); + buf := StringBuffer(data[..0]); sbprintln(&buf, ...args); res := string_buffer_data(buf); os.write(fd, res); @@ -125,7 +111,7 @@ fprintln :: proc(fd: os.Handle, args: ...any) -> int { } fprintf :: proc(fd: os.Handle, fmt: string, args: ...any) -> int { data: [_BUFFER_SIZE]u8; - buf := make_string_buffer_from_slice(data[..0]); + buf := StringBuffer(data[..0]); sbprintf(&buf, fmt, ...args); res := string_buffer_data(buf); os.write(fd, res); @@ -145,17 +131,17 @@ printf_err :: proc(fmt: string, args: ...any) -> int { return fprintf(os.stderr // aprint* procedures return a string that was allocated with the current context // They must be freed accordingly aprint :: proc(args: ...any) -> string { - buf := make_string_dynamic_buffer(); + buf := StringBuffer(make([dynamic]u8)); sbprint(&buf, ...args); return to_string(buf); } aprintln :: proc(args: ...any) -> string { - buf := make_string_dynamic_buffer(); + buf := StringBuffer(make([dynamic]u8)); sbprintln(&buf, ...args); return to_string(buf); } aprintf :: proc(fmt: string, args: ...any) -> string { - buf := make_string_dynamic_buffer(); + buf := StringBuffer(make([dynamic]u8)); sbprintf(&buf, fmt, ...args); return to_string(buf); } @@ -164,15 +150,15 @@ aprintf :: proc(fmt: string, args: ...any) -> string { // bprint* procedures return a string that was allocated with the current context // They must be freed accordingly bprint :: proc(buf: []u8, args: ...any) -> string { - sb := make_string_buffer_from_slice(buf[..0..len(buf)]); + sb := StringBuffer(buf[..0..len(buf)]); return sbprint(&sb, ...args); } bprintln :: proc(buf: []u8, args: ...any) -> string { - sb := make_string_buffer_from_slice(buf[..0..len(buf)]); + sb := StringBuffer(buf[..0..len(buf)]); return sbprintln(&sb, ...args); } bprintf :: proc(buf: []u8, fmt: string, args: ...any) -> string { - sb := make_string_buffer_from_slice(buf[..0..len(buf)]); + sb := StringBuffer(buf[..0..len(buf)]); return sbprintf(&sb, fmt, ...args); } @@ -183,7 +169,7 @@ bprintf :: proc(buf: []u8, fmt: string, args: ...any) -> string { fprint_type :: proc(fd: os.Handle, info: ^TypeInfo) { data: [_BUFFER_SIZE]u8; - buf := make_string_buffer_from_slice(data[..0]); + buf := StringBuffer(data[..0]); write_type(&buf, info); os.write(fd, string_buffer_data(buf)); } @@ -192,7 +178,7 @@ write_type :: proc(buf: ^StringBuffer, ti: ^TypeInfo) { if ti == nil do return; using TypeInfo; - match info in ti { + match info in ti.variant { case Named: write_string(buf, info.name); case Integer: @@ -201,18 +187,18 @@ write_type :: proc(buf: ^StringBuffer, ti: ^TypeInfo) { case ti == type_info(uint): write_string(buf, "uint"); case: write_string(buf, info.signed ? "i" : "u"); - write_int(buf, i64(8*info.size), 10); + write_int(buf, i64(8*ti.size), 10); } case Rune: write_string(buf, "rune"); case Float: - match info.size { + match ti.size { case 2: write_string(buf, "f16"); case 4: write_string(buf, "f32"); case 8: write_string(buf, "f64"); } case Complex: - match info.size { + match ti.size { case 4: write_string(buf, "complex32"); case 8: write_string(buf, "complex64"); case 16: write_string(buf, "complex128"); @@ -237,7 +223,7 @@ write_type :: proc(buf: ^StringBuffer, ti: ^TypeInfo) { if info.params == nil { write_string(buf, "()"); } else { - t := info.params.(^Tuple); + t := info.params.variant.(Tuple); write_string(buf, "("); for t, i in t.types { if i > 0 do write_string(buf, ", "); @@ -295,7 +281,7 @@ write_type :: proc(buf: ^StringBuffer, ti: ^TypeInfo) { if info.ordered do write_string(buf, "#ordered "); if info.custom_align { write_string(buf, "#align "); - write_int(buf, i64(info.align), 10); + write_int(buf, i64(ti.align), 10); write_byte(buf, ' '); } write_byte(buf, '{'); @@ -324,8 +310,8 @@ write_type :: proc(buf: ^StringBuffer, ti: ^TypeInfo) { write_byte(buf, '{'); defer write_byte(buf, '}'); - variant_type := type_info_base(info.variant_types[i]); - variant := variant_type.(^Struct); + variant_type := type_info_base(info.variant_types[i]).variant; + variant := (&variant_type).(Struct); vc := len(variant.names)-len(cf.names); for j in 0..vc { @@ -359,9 +345,9 @@ write_type :: proc(buf: ^StringBuffer, ti: ^TypeInfo) { write_string(buf, "}"); case BitField: write_string(buf, "bit_field "); - if info.align != 1 { + if ti.align != 1 { write_string(buf, "#align "); - write_int(buf, i64(info.align), 10); + write_int(buf, i64(ti.align), 10); write_rune(buf, ' '); } write_string(buf, " {"); @@ -697,7 +683,7 @@ fmt_enum :: proc(fi: ^FmtInfo, v: any, verb: rune) { } using TypeInfo; - match e in v.type_info { + match e in v.type_info.variant { case: fmt_bad_verb(fi, verb); return; @@ -768,9 +754,9 @@ fmt_value :: proc(fi: ^FmtInfo, v: any, verb: rune) { } using TypeInfo; - match info in v.type_info { + match info in v.type_info.variant { case Named: - match b in info.base { + match b in info.base.variant { case Struct: if verb != 'v' { fmt_bad_verb(fi, verb); @@ -866,9 +852,9 @@ fmt_value :: proc(fi: ^FmtInfo, v: any, verb: rune) { defer write_byte(fi.buf, ']'); entries := &(^raw.DynamicMap(v.data).entries); - gs := type_info_base(info.generated_struct).(^Struct); - ed := type_info_base(gs.types[1]).(^DynamicArray); - entry_type := ed.elem.(^Struct); + gs := type_info_base(info.generated_struct).variant.(Struct); + ed := type_info_base(gs.types[1]).variant.(DynamicArray); + entry_type := ed.elem.variant.(Struct); entry_size := ed.elem_size; for i in 0..entries.len { diff --git a/core/mem.odin b/core/mem.odin index 10b92d5fc..94d1f2cc2 100644 --- a/core/mem.odin +++ b/core/mem.odin @@ -208,15 +208,15 @@ align_of_type_info :: proc(type_info: ^TypeInfo) -> int { WORD_SIZE :: size_of(int); MAX_ALIGN :: size_of([vector 64]f64); // TODO(bill): Should these constants be builtin constants? using TypeInfo; - match info in type_info { + match info in type_info.variant { case Named: return align_of_type_info(info.base); case Integer: - return info.size; + return type_info.align; case Rune: - return info.size; + return type_info.align; case Float: - return info.size; + return type_info.align; case String: return WORD_SIZE; case Boolean: @@ -239,13 +239,13 @@ align_of_type_info :: proc(type_info: ^TypeInfo) -> int { total := size * count; return clamp(total, 1, MAX_ALIGN); case Tuple: - return info.align; + return type_info.align; case Struct: - return info.align; + return type_info.align; case Union: - return info.align; + return type_info.align; case RawUnion: - return info.align; + return type_info.align; case Enum: return align_of_type_info(info.base); case Map: @@ -263,15 +263,15 @@ align_formula :: proc(size, align: int) -> int { size_of_type_info :: proc(type_info: ^TypeInfo) -> int { WORD_SIZE :: size_of(int); using TypeInfo; - match info in type_info { + match info in type_info.variant { case Named: return size_of_type_info(info.base); case Integer: - return info.size; + return type_info.size; case Rune: - return info.size; + return type_info.size; case Float: - return info.size; + return type_info.size; case String: return 2*WORD_SIZE; case Boolean: @@ -301,11 +301,11 @@ size_of_type_info :: proc(type_info: ^TypeInfo) -> int { alignment := align_formula(size, align); return alignment*(count-1) + size; case Struct: - return info.size; + return type_info.size; case Union: - return info.size; + return type_info.size; case RawUnion: - return info.size; + return type_info.size; case Enum: return size_of_type_info(info.base); case Map: diff --git a/core/types.odin b/core/types.odin index df1866c32..fde32fe63 100644 --- a/core/types.odin +++ b/core/types.odin @@ -1,6 +1,6 @@ is_signed :: proc(info: ^TypeInfo) -> bool { if info == nil do return false; - match i in type_info_base(info) { + match i in type_info_base(info).variant { case TypeInfo.Integer: return i.signed; case TypeInfo.Float: return true; } @@ -8,96 +8,96 @@ is_signed :: proc(info: ^TypeInfo) -> bool { } is_integer :: proc(info: ^TypeInfo) -> bool { if info == nil do return false; - _, ok := type_info_base(info).(^TypeInfo.Integer); + _, ok := type_info_base(info).variant.(TypeInfo.Integer); return ok; } is_rune :: proc(info: ^TypeInfo) -> bool { if info == nil do return false; - _, ok := type_info_base(info).(^TypeInfo.Rune); + _, ok := type_info_base(info).variant.(TypeInfo.Rune); return ok; } is_float :: proc(info: ^TypeInfo) -> bool { if info == nil do return false; - _, ok := type_info_base(info).(^TypeInfo.Float); + _, ok := type_info_base(info).variant.(TypeInfo.Float); return ok; } is_complex :: proc(info: ^TypeInfo) -> bool { if info == nil do return false; - _, ok := type_info_base(info).(^TypeInfo.Complex); + _, ok := type_info_base(info).variant.(TypeInfo.Complex); return ok; } is_any :: proc(info: ^TypeInfo) -> bool { if info == nil do return false; - _, ok := type_info_base(info).(^TypeInfo.Any); + _, ok := type_info_base(info).variant.(TypeInfo.Any); return ok; } is_string :: proc(info: ^TypeInfo) -> bool { if info == nil do return false; - _, ok := type_info_base(info).(^TypeInfo.String); + _, ok := type_info_base(info).variant.(TypeInfo.String); return ok; } is_boolean :: proc(info: ^TypeInfo) -> bool { if info == nil do return false; - _, ok := type_info_base(info).(^TypeInfo.Boolean); + _, ok := type_info_base(info).variant.(TypeInfo.Boolean); return ok; } is_pointer :: proc(info: ^TypeInfo) -> bool { if info == nil do return false; - _, ok := type_info_base(info).(^TypeInfo.Pointer); + _, ok := type_info_base(info).variant.(TypeInfo.Pointer); return ok; } is_procedure :: proc(info: ^TypeInfo) -> bool { if info == nil do return false; - _, ok := type_info_base(info).(^TypeInfo.Procedure); + _, ok := type_info_base(info).variant.(TypeInfo.Procedure); return ok; } is_array :: proc(info: ^TypeInfo) -> bool { if info == nil do return false; - _, ok := type_info_base(info).(^TypeInfo.Array); + _, ok := type_info_base(info).variant.(TypeInfo.Array); return ok; } is_dynamic_array :: proc(info: ^TypeInfo) -> bool { if info == nil do return false; - _, ok := type_info_base(info).(^TypeInfo.DynamicArray); + _, ok := type_info_base(info).variant.(TypeInfo.DynamicArray); return ok; } is_dynamic_map :: proc(info: ^TypeInfo) -> bool { if info == nil do return false; - _, ok := type_info_base(info).(^TypeInfo.Map); + _, ok := type_info_base(info).variant.(TypeInfo.Map); return ok; } is_slice :: proc(info: ^TypeInfo) -> bool { if info == nil do return false; - _, ok := type_info_base(info).(^TypeInfo.Slice); + _, ok := type_info_base(info).variant.(TypeInfo.Slice); return ok; } is_vector :: proc(info: ^TypeInfo) -> bool { if info == nil do return false; - _, ok := type_info_base(info).(^TypeInfo.Vector); + _, ok := type_info_base(info).variant.(TypeInfo.Vector); return ok; } is_tuple :: proc(info: ^TypeInfo) -> bool { if info == nil do return false; - _, ok := type_info_base(info).(^TypeInfo.Tuple); + _, ok := type_info_base(info).variant.(TypeInfo.Tuple); return ok; } is_struct :: proc(info: ^TypeInfo) -> bool { if info == nil do return false; - _, ok := type_info_base(info).(^TypeInfo.Struct); + _, ok := type_info_base(info).variant.(TypeInfo.Struct); return ok; } is_union :: proc(info: ^TypeInfo) -> bool { if info == nil do return false; - _, ok := type_info_base(info).(^TypeInfo.Union); + _, ok := type_info_base(info).variant.(TypeInfo.Union); return ok; } is_raw_union :: proc(info: ^TypeInfo) -> bool { if info == nil do return false; - _, ok := type_info_base(info).(^TypeInfo.RawUnion); + _, ok := type_info_base(info).variant.(TypeInfo.RawUnion); return ok; } is_enum :: proc(info: ^TypeInfo) -> bool { if info == nil do return false; - _, ok := type_info_base(info).(^TypeInfo.Enum); + _, ok := type_info_base(info).variant.(TypeInfo.Enum); return ok; } diff --git a/src/check_expr.cpp b/src/check_expr.cpp index ebddbb0f3..7a0088f86 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -500,8 +500,8 @@ i64 check_distance_between_types(Checker *c, Operand *operand, Type *type) { if (is_type_union(dst)) { for (isize i = 0; i < dst->Record.variant_count; i++) { - Entity *f = dst->Record.variants[i]; - if (are_types_identical(f->type, s)) { + Type *vt = dst->Record.variants[i]; + if (are_types_identical(vt, s)) { return 1; } } @@ -980,41 +980,17 @@ void check_union_type(Checker *c, Type *named_type, Type *union_type, AstNode *n ast_node(ut, UnionType, node); isize variant_count = ut->variants.count+1; - isize min_field_count = 0; - for_array(i, ut->fields) { - AstNode *field = ut->fields[i]; - switch (field->kind) { - case_ast_node(f, ValueDecl, field); - min_field_count += f->names.count; - case_end; - } - } gbTempArenaMemory tmp = gb_temp_arena_memory_begin(&c->tmp_arena); defer (gb_temp_arena_memory_end(tmp)); - Map entity_map = {}; // Key: String - map_init_with_reserve(&entity_map, c->tmp_allocator, 2*variant_count); - Entity *using_index_expr = nullptr; - Array variants = {}; - array_init(&variants, heap_allocator(), variant_count); - - array_add(&variants, make_entity_type_name(c->allocator, c->context.scope, empty_token, nullptr)); - - auto fields = check_fields(c, nullptr, ut->fields, min_field_count, str_lit("union")); - - for (isize i = 0; i < fields.count; i++) { - Entity *f = fields[i]; - String name = f->token.string; - map_set(&entity_map, hash_string(name), f); - } + Array variants = {}; + array_init(&variants, c->allocator, variant_count); + array_add(&variants, t_invalid); union_type->Record.scope = c->context.scope; - union_type->Record.fields = fields.data; - union_type->Record.fields_in_src_order = fields.data; - union_type->Record.field_count = fields.count; union_type->Record.are_offsets_set = false; union_type->Record.is_ordered = true; { @@ -1023,75 +999,21 @@ void check_union_type(Checker *c, Type *named_type, Type *union_type, AstNode *n } for_array(i, ut->variants) { - AstNode *variant = ut->variants[i]; - if (variant->kind != AstNode_UnionField) { - continue; - } - ast_node(f, UnionField, variant); - Token name_token = f->name->Ident.token; - - Type *base_type = make_type_struct(c->allocator); - { - ast_node(fl, FieldList, f->list); - - // NOTE(bill): Copy the contents for the common fields for now - Array list = {}; - array_init_count(&list, c->allocator, ut->fields.count+fl->list.count); - gb_memmove_array(list.data, ut->fields.data, ut->fields.count); - gb_memmove_array(list.data+ut->fields.count, fl->list.data, fl->list.count); - - isize list_count = 0; - for_array(j, list) { - if (list[j]->kind == AstNode_Field) { - list_count += list[j]->Field.names.count; - } else { - ast_node(f, ValueDecl, list[j]); - list_count += f->names.count; + AstNode *node = ut->variants[i]; + Type *t = check_type(c, node); + if (t != nullptr && t != t_invalid) { + bool ok = true; + for_array(j, variants) { + if (are_types_identical(t, variants[j])) { + ok = false; + gbString str = type_to_string(t); + error(node, "Duplicate variant type `%s`", str); + gb_string_free(str); + break; } } - - - Token token = name_token; - token.kind = Token_struct; - AstNode *dummy_struct = ast_struct_type(c->curr_ast_file, token, list, list_count, false, true, nullptr); - - check_open_scope(c, dummy_struct); - base_type->Record.names = make_names_field_for_record(c, c->context.scope); - auto fields = check_fields(c, dummy_struct, list, list_count, str_lit("variant")); - base_type->Record.is_packed = false; - base_type->Record.is_ordered = true; - base_type->Record.fields = fields.data; - base_type->Record.fields_in_src_order = fields.data; - base_type->Record.field_count = fields.count; - base_type->Record.node = dummy_struct; - base_type->Record.variant_parent = named_type != nullptr ? named_type : union_type; - base_type->Record.variant_index = variants.count; - - - type_set_offsets(c->allocator, base_type); - - check_close_scope(c); + if (ok) array_add(&variants, t); } - - Type *type = make_type_named(c->allocator, name_token.string, base_type, nullptr); - Entity *e = make_entity_type_name(c->allocator, c->context.scope, name_token, type); - type->Named.type_name = e; - add_entity(c, c->context.scope, f->name, e); - - if (name_token.string == "_") { - error(name_token, "`_` cannot be used a union subtype"); - continue; - } - - HashKey key = hash_string(name_token.string); - if (map_get(&entity_map, key) != nullptr) { - // NOTE(bill): Scope checking already checks the declaration - error(name_token, "`%.*s` is already declared in this union", LIT(name_token.string)); - } else { - map_set(&entity_map, key, e); - array_add(&variants, e); - } - add_entity_use(c, f->name, e); } type_set_offsets(c->allocator, union_type); @@ -6889,28 +6811,17 @@ ExprKind check_expr_base_internal(Checker *c, Operand *o, AstNode *node, Type *t bool src_is_ptr = is_type_pointer(o->type); - bool dst_is_ptr = is_type_pointer(t); Type *src = type_deref(o->type); - Type *dst = type_deref(t); + Type *dst = t; Type *bsrc = base_type(src); Type *bdst = base_type(dst); - if (src_is_ptr != dst_is_ptr) { - gbString src_type_str = type_to_string(o->type); - gbString dst_type_str = type_to_string(t); - error(o->expr, "Invalid type assertion types: `%s` and `%s`", src_type_str, dst_type_str); - gb_string_free(dst_type_str); - gb_string_free(src_type_str); - o->mode = Addressing_Invalid; - o->expr = node; - return kind; - } if (is_type_union(src)) { bool ok = false; for (isize i = 1; i < bsrc->Record.variant_count; i++) { - Entity *f = bsrc->Record.variants[i]; - if (are_types_identical(f->type, dst)) { + Type *vt = bsrc->Record.variants[i]; + if (are_types_identical(vt, dst)) { ok = true; break; } @@ -7088,6 +6999,7 @@ ExprKind check_expr_base_internal(Checker *c, Operand *o, AstNode *node, Type *t case Type_Slice: valid = true; + o->type = type_deref(o->type); break; case Type_DynamicArray: @@ -7602,7 +7514,7 @@ gbString write_expr_to_string(gbString str, AstNode *node) { case_ast_node(st, UnionType, node); str = gb_string_appendc(str, "union "); str = gb_string_appendc(str, "{"); - str = write_record_fields_to_string(str, st->fields); + str = write_record_fields_to_string(str, st->variants); str = gb_string_appendc(str, "}"); case_end; diff --git a/src/check_stmt.cpp b/src/check_stmt.cpp index c7aa5424f..3f7b9a456 100644 --- a/src/check_stmt.cpp +++ b/src/check_stmt.cpp @@ -1504,8 +1504,8 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) { GB_ASSERT(is_type_union(bt)); bool tag_type_found = false; for (isize i = 0; i < bt->Record.variant_count; i++) { - Entity *f = bt->Record.variants[i]; - if (are_types_identical(f->type, y.type)) { + Type *vt = bt->Record.variants[i]; + if (are_types_identical(vt, y.type)) { tag_type_found = true; break; } diff --git a/src/checker.cpp b/src/checker.cpp index faeff2212..d239d5953 100644 --- a/src/checker.cpp +++ b/src/checker.cpp @@ -1156,8 +1156,7 @@ void add_type_info_type(Checker *c, Type *t) { case TypeRecord_Union: add_type_info_type(c, t_int); for (isize i = 0; i < bt->Record.variant_count; i++) { - Entity *f = bt->Record.variants[i]; - add_type_info_type(c, f->type); + add_type_info_type(c, bt->Record.variants[i]); } /* fallthrough */ default: @@ -1307,30 +1306,30 @@ Entity *find_core_entity(Checker *c, String name) { return e; } +Entity *find_sub_core_entity(TypeRecord *parent, String name) { + GB_ASSERT(parent->scope->parent->is_global); + Entity *e = current_scope_lookup_entity(parent->scope, name); + if (e == nullptr) { + compiler_error("Could not find type declaration for `%.*s`\n" + "Is `_preload.odin` missing from the `core` directory relative to odin.exe?", LIT(name)); + // NOTE(bill): This will exit the program as it's cannot continue without it! + } + return e; +} + +void check_entity_decl(Checker *c, Entity *e, DeclInfo *d, Type *named_type); + void init_preload(Checker *c) { if (t_type_info == nullptr) { Entity *type_info_entity = find_core_entity(c, str_lit("TypeInfo")); t_type_info = type_info_entity->type; t_type_info_ptr = make_type_pointer(c->allocator, t_type_info); - GB_ASSERT(is_type_union(type_info_entity->type)); + GB_ASSERT(is_type_struct(type_info_entity->type)); TypeRecord *record = &base_type(type_info_entity->type)->Record; - // Entity *type_info_record = current_scope_lookup_entity(record->scope, str_lit("Record")); - // if (type_info_record == nullptr) { - // compiler_error("Could not find type declaration for TypeInfo.Record\n" - // "Is `_preload.odin` missing from the `core` directory relative to the odin executable?"); - // } - // Entity *type_info_enum_value = current_scope_lookup_entity(record->scope, str_lit("EnumValue")); - // if (type_info_record == nullptr) { - // compiler_error("Could not find type declaration for TypeInfo.EnumValue\n" - // "Is `_preload.odin` missing from the `core` directory relative to the odin executable?"); - // } - - // GB_ASSERT(type_info_record->type != nullptr); - // GB_ASSERT(type_info_enum_value->type != nullptr); - Entity *type_info_record = find_core_entity(c, str_lit("TypeInfoRecord")); - Entity *type_info_enum_value = find_core_entity(c, str_lit("TypeInfoEnumValue")); + Entity *type_info_record = find_sub_core_entity(record, str_lit("Record")); + Entity *type_info_enum_value = find_sub_core_entity(record, str_lit("EnumValue")); t_type_info_record = type_info_record->type; @@ -1338,33 +1337,38 @@ void init_preload(Checker *c) { t_type_info_enum_value = type_info_enum_value->type; t_type_info_enum_value_ptr = make_type_pointer(c->allocator, t_type_info_enum_value); + GB_ASSERT(record->field_count == 3); + Entity *type_info_variant = record->fields_in_src_order[2]; + Type *tiv_type = type_info_variant->type; + GB_ASSERT(is_type_union(tiv_type)); + TypeRecord *tiv = &tiv_type->Record; - if (record->variant_count != 23) { + if (tiv->variant_count != 23) { compiler_error("Invalid `TypeInfo` layout"); } - t_type_info_named = record->variants[ 1]->type; - t_type_info_integer = record->variants[ 2]->type; - t_type_info_rune = record->variants[ 3]->type; - t_type_info_float = record->variants[ 4]->type; - t_type_info_complex = record->variants[ 5]->type; - t_type_info_string = record->variants[ 6]->type; - t_type_info_boolean = record->variants[ 7]->type; - t_type_info_any = record->variants[ 8]->type; - t_type_info_pointer = record->variants[ 9]->type; - t_type_info_atomic = record->variants[10]->type; - t_type_info_procedure = record->variants[11]->type; - t_type_info_array = record->variants[12]->type; - t_type_info_dynamic_array = record->variants[13]->type; - t_type_info_slice = record->variants[14]->type; - t_type_info_vector = record->variants[15]->type; - t_type_info_tuple = record->variants[16]->type; - t_type_info_struct = record->variants[17]->type; - t_type_info_raw_union = record->variants[18]->type; - t_type_info_union = record->variants[19]->type; - t_type_info_enum = record->variants[20]->type; - t_type_info_map = record->variants[21]->type; - t_type_info_bit_field = record->variants[22]->type; + t_type_info_named = tiv->variants[ 1]; + t_type_info_integer = tiv->variants[ 2]; + t_type_info_rune = tiv->variants[ 3]; + t_type_info_float = tiv->variants[ 4]; + t_type_info_complex = tiv->variants[ 5]; + t_type_info_string = tiv->variants[ 6]; + t_type_info_boolean = tiv->variants[ 7]; + t_type_info_any = tiv->variants[ 8]; + t_type_info_pointer = tiv->variants[ 9]; + t_type_info_atomic = tiv->variants[10]; + t_type_info_procedure = tiv->variants[11]; + t_type_info_array = tiv->variants[12]; + t_type_info_dynamic_array = tiv->variants[13]; + t_type_info_slice = tiv->variants[14]; + t_type_info_vector = tiv->variants[15]; + t_type_info_tuple = tiv->variants[16]; + t_type_info_struct = tiv->variants[17]; + t_type_info_raw_union = tiv->variants[18]; + t_type_info_union = tiv->variants[19]; + t_type_info_enum = tiv->variants[20]; + t_type_info_map = tiv->variants[21]; + t_type_info_bit_field = tiv->variants[22]; t_type_info_named_ptr = make_type_pointer(c->allocator, t_type_info_named); t_type_info_integer_ptr = make_type_pointer(c->allocator, t_type_info_integer); @@ -1719,9 +1723,6 @@ void check_collect_entities(Checker *c, Array nodes, bool is_file_sco } Token token = name->Ident.token; - if (token.string == "EnumValue") { - gb_printf_err("EnumValue %p\n", name); - } AstNode *fl = c->context.curr_foreign_library; DeclInfo *d = make_declaration_info(c->allocator, c->context.scope, c->context.decl); diff --git a/src/ir.cpp b/src/ir.cpp index 477ae799e..61e693666 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -2355,7 +2355,7 @@ irValue *ir_emit_struct_ep(irProcedure *proc, irValue *s, i32 index) { if (is_type_struct(t)) { GB_ASSERT(t->Record.field_count > 0); - GB_ASSERT(gb_is_between(index, 0, t->Record.field_count-1)); + 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); @@ -2950,12 +2950,12 @@ irValue *ir_emit_conv(irProcedure *proc, irValue *value, Type *t) { if (is_type_union(dst)) { for (isize i = 1; i < dst->Record.variant_count; i++) { - Entity *f = dst->Record.variants[i]; - if (are_types_identical(f->type, src_type)) { + Type *vt = dst->Record.variants[i]; + if (are_types_identical(vt, src_type)) { ir_emit_comment(proc, str_lit("union - child to parent")); gbAllocator a = proc->module->allocator; irValue *parent = ir_add_local_generated(proc, t); - irValue *underlying = ir_emit_conv(proc, parent, make_type_pointer(a, f->type)); + irValue *underlying = ir_emit_conv(proc, parent, make_type_pointer(a, vt)); ir_emit_store(proc, underlying, value); irValue *tag_ptr = ir_emit_union_tag_ptr(proc, parent); @@ -3207,6 +3207,7 @@ irValue *ir_emit_union_cast(irProcedure *proc, irValue *value, Type *type, Token irValue *v = ir_add_local_generated(proc, tuple); + #if 0 if (is_ptr) { Type *src = base_type(type_deref(src_type)); Type *src_ptr = src_type; @@ -3217,8 +3218,8 @@ irValue *ir_emit_union_cast(irProcedure *proc, irValue *value, Type *type, Token irValue *tag = ir_emit_load(proc, ir_emit_union_tag_ptr(proc, value)); irValue *dst_tag = nullptr; for (isize i = 1; i < src->Record.variant_count; i++) { - Entity *f = src->Record.variants[i]; - if (are_types_identical(f->type, dst)) { + Type *vt = src->Record.variants[i]; + if (are_types_identical(vt, dst)) { dst_tag = ir_const_int(a, i); break; } @@ -3252,8 +3253,8 @@ irValue *ir_emit_union_cast(irProcedure *proc, irValue *value, Type *type, Token irValue *tag = ir_emit_load(proc, ir_emit_union_tag_ptr(proc, value_)); irValue *dst_tag = nullptr; for (isize i = 1; i < src->Record.variant_count; i++) { - Entity *f = src->Record.variants[i]; - if (are_types_identical(f->type, dst)) { + Type *vt = src->Record.variants[i]; + if (are_types_identical(vt, dst)) { dst_tag = ir_const_int(a, i); break; } @@ -3276,7 +3277,44 @@ irValue *ir_emit_union_cast(irProcedure *proc, irValue *value, Type *type, Token ir_emit_jump(proc, end_block); ir_start_block(proc, end_block); } + #else + if (is_ptr) { + value = ir_emit_load(proc, value); + } + 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->Record.variant_count; i++) { + Type *vt = src->Record.variants[i]; + if (are_types_identical(vt, dst)) { + dst_tag = ir_const_int(a, i); + break; + } + } + GB_ASSERT(dst_tag != nullptr); + + irBlock *ok_block = ir_new_block(proc, nullptr, "union_cast.ok"); + irBlock *end_block = ir_new_block(proc, nullptr, "union_cast.end"); + irValue *cond = ir_emit_comp(proc, Token_CmpEq, tag, dst_tag); + ir_emit_if(proc, cond, ok_block, end_block); + ir_start_block(proc, ok_block); + + irValue *gep0 = ir_emit_struct_ep(proc, v, 0); + irValue *gep1 = ir_emit_struct_ep(proc, v, 1); + + irValue *data = ir_emit_load(proc, ir_emit_conv(proc, value_, ir_type(gep0))); + ir_emit_store(proc, gep0, data); + ir_emit_store(proc, gep1, v_true); + + ir_emit_jump(proc, end_block); + ir_start_block(proc, end_block); + #endif if (!is_tuple) { // NOTE(bill): Panic on invalid conversion Type *dst_type = tuple->Tuple.variables[0]->type; @@ -6789,8 +6827,8 @@ void ir_build_stmt_internal(irProcedure *proc, AstNode *node) { Type *ut = base_type(type_deref(parent_type)); GB_ASSERT(ut->Record.kind == TypeRecord_Union); for (isize variant_index = 1; variant_index < ut->Record.variant_count; variant_index++) { - Entity *f = ut->Record.variants[variant_index]; - if (are_types_identical(f->type, bt)) { + Type *vt = ut->Record.variants[variant_index]; + if (are_types_identical(vt, bt)) { index = ir_const_int(allocator, variant_index); break; } @@ -7782,6 +7820,7 @@ void ir_gen_tree(irGen *s) { irValue *tag = nullptr; irValue *ti_ptr = ir_emit_array_epi(proc, ir_global_type_info_data, entry_index); + irValue *variant_ptr = ir_emit_struct_ep(proc, ti_ptr, 2); ir_emit_store(proc, ir_emit_struct_ep(proc, ti_ptr, 0), ir_const_int(a, type_size_of(a, t))); ir_emit_store(proc, ir_emit_struct_ep(proc, ti_ptr, 1), ir_const_int(a, type_align_of(a, t))); @@ -7790,21 +7829,21 @@ void ir_gen_tree(irGen *s) { switch (t->kind) { case Type_Named: { ir_emit_comment(proc, str_lit("TypeInfoNamed")); - tag = ir_emit_conv(proc, ti_ptr, t_type_info_named_ptr); + tag = ir_emit_conv(proc, variant_ptr, t_type_info_named_ptr); // TODO(bill): Which is better? The mangled name or actual name? irValue *name = ir_const_string(a, t->Named.type_name->token.string); irValue *gtip = ir_get_type_info_ptr(proc, t->Named.base); - ir_emit_store(proc, ir_emit_struct_ep(proc, tag, 2), name); - ir_emit_store(proc, ir_emit_struct_ep(proc, tag, 3), gtip); + ir_emit_store(proc, ir_emit_struct_ep(proc, tag, 0), name); + ir_emit_store(proc, ir_emit_struct_ep(proc, tag, 1), gtip); } break; case Type_Basic: ir_emit_comment(proc, str_lit("TypeInfoBasic")); switch (t->Basic.kind) { case Basic_bool: - tag = ir_emit_conv(proc, ti_ptr, t_type_info_boolean_ptr); + tag = ir_emit_conv(proc, variant_ptr, t_type_info_boolean_ptr); break; case Basic_i8: @@ -7819,106 +7858,106 @@ void ir_gen_tree(irGen *s) { case Basic_u128: case Basic_int: case Basic_uint: { - tag = ir_emit_conv(proc, ti_ptr, t_type_info_integer_ptr); + tag = ir_emit_conv(proc, variant_ptr, t_type_info_integer_ptr); irValue *is_signed = ir_const_bool(a, (t->Basic.flags & BasicFlag_Unsigned) == 0); - ir_emit_store(proc, ir_emit_struct_ep(proc, tag, 2), is_signed); + ir_emit_store(proc, ir_emit_struct_ep(proc, tag, 0), is_signed); } break; case Basic_rune: - tag = ir_emit_conv(proc, ti_ptr, t_type_info_rune_ptr); + tag = ir_emit_conv(proc, variant_ptr, t_type_info_rune_ptr); break; // case Basic_f16: case Basic_f32: case Basic_f64: - tag = ir_emit_conv(proc, ti_ptr, t_type_info_float_ptr); + tag = ir_emit_conv(proc, variant_ptr, t_type_info_float_ptr); break; // case Basic_complex32: case Basic_complex64: case Basic_complex128: - tag = ir_emit_conv(proc, ti_ptr, t_type_info_complex_ptr); + tag = ir_emit_conv(proc, variant_ptr, t_type_info_complex_ptr); break; case Basic_rawptr: - tag = ir_emit_conv(proc, ti_ptr, t_type_info_pointer_ptr); + tag = ir_emit_conv(proc, variant_ptr, t_type_info_pointer_ptr); break; case Basic_string: - tag = ir_emit_conv(proc, ti_ptr, t_type_info_string_ptr); + tag = ir_emit_conv(proc, variant_ptr, t_type_info_string_ptr); break; case Basic_any: - tag = ir_emit_conv(proc, ti_ptr, t_type_info_any_ptr); + tag = ir_emit_conv(proc, variant_ptr, t_type_info_any_ptr); break; } break; case Type_Pointer: { ir_emit_comment(proc, str_lit("TypeInfoPointer")); - tag = ir_emit_conv(proc, ti_ptr, t_type_info_pointer_ptr); + tag = ir_emit_conv(proc, variant_ptr, t_type_info_pointer_ptr); irValue *gep = ir_get_type_info_ptr(proc, t->Pointer.elem); - ir_emit_store(proc, ir_emit_struct_ep(proc, tag, 2), gep); + ir_emit_store(proc, ir_emit_struct_ep(proc, tag, 0), gep); } break; case Type_Atomic: { ir_emit_comment(proc, str_lit("TypeInfoAtomic")); - tag = ir_emit_conv(proc, ti_ptr, t_type_info_atomic_ptr); + tag = ir_emit_conv(proc, variant_ptr, t_type_info_atomic_ptr); irValue *gep = ir_get_type_info_ptr(proc, t->Atomic.elem); - ir_emit_store(proc, ir_emit_struct_ep(proc, tag, 2), gep); + ir_emit_store(proc, ir_emit_struct_ep(proc, tag, 0), gep); } break; case Type_Array: { ir_emit_comment(proc, str_lit("TypeInfoArray")); - tag = ir_emit_conv(proc, ti_ptr, t_type_info_array_ptr); + tag = ir_emit_conv(proc, variant_ptr, t_type_info_array_ptr); irValue *gep = ir_get_type_info_ptr(proc, t->Array.elem); - ir_emit_store(proc, ir_emit_struct_ep(proc, tag, 2), gep); + ir_emit_store(proc, ir_emit_struct_ep(proc, tag, 0), gep); isize ez = type_size_of(a, t->Array.elem); - irValue *elem_size = ir_emit_struct_ep(proc, tag, 3); + irValue *elem_size = ir_emit_struct_ep(proc, tag, 1); ir_emit_store(proc, elem_size, ir_const_int(a, ez)); - irValue *count = ir_emit_struct_ep(proc, tag, 4); + irValue *count = ir_emit_struct_ep(proc, tag, 2); ir_emit_store(proc, count, ir_const_int(a, t->Array.count)); } break; case Type_DynamicArray: { ir_emit_comment(proc, str_lit("TypeInfoDynamicArray")); - tag = ir_emit_conv(proc, ti_ptr, t_type_info_dynamic_array_ptr); + tag = ir_emit_conv(proc, variant_ptr, t_type_info_dynamic_array_ptr); irValue *gep = ir_get_type_info_ptr(proc, t->DynamicArray.elem); - ir_emit_store(proc, ir_emit_struct_ep(proc, tag, 2), gep); + ir_emit_store(proc, ir_emit_struct_ep(proc, tag, 0), gep); isize ez = type_size_of(a, t->DynamicArray.elem); - irValue *elem_size = ir_emit_struct_ep(proc, tag, 3); + irValue *elem_size = ir_emit_struct_ep(proc, tag, 1); ir_emit_store(proc, elem_size, ir_const_int(a, ez)); } break; case Type_Slice: { ir_emit_comment(proc, str_lit("TypeInfoSlice")); - tag = ir_emit_conv(proc, ti_ptr, t_type_info_slice_ptr); + tag = ir_emit_conv(proc, variant_ptr, t_type_info_slice_ptr); irValue *gep = ir_get_type_info_ptr(proc, t->Slice.elem); - ir_emit_store(proc, ir_emit_struct_ep(proc, tag, 2), gep); + ir_emit_store(proc, ir_emit_struct_ep(proc, tag, 0), gep); isize ez = type_size_of(a, t->Slice.elem); - irValue *elem_size = ir_emit_struct_ep(proc, tag, 3); + irValue *elem_size = ir_emit_struct_ep(proc, tag, 1); ir_emit_store(proc, elem_size, ir_const_int(a, ez)); } break; case Type_Vector: { ir_emit_comment(proc, str_lit("TypeInfoVector")); - tag = ir_emit_conv(proc, ti_ptr, t_type_info_vector_ptr); + tag = ir_emit_conv(proc, variant_ptr, t_type_info_vector_ptr); irValue *gep = ir_get_type_info_ptr(proc, t->Vector.elem); - ir_emit_store(proc, ir_emit_struct_ep(proc, tag, 2), gep); + ir_emit_store(proc, ir_emit_struct_ep(proc, tag, 0), gep); isize ez = type_size_of(a, t->Vector.elem); - ir_emit_store(proc, ir_emit_struct_ep(proc, tag, 3), ir_const_int(a, ez)); - ir_emit_store(proc, ir_emit_struct_ep(proc, tag, 4), ir_const_int(a, t->Vector.count)); + ir_emit_store(proc, ir_emit_struct_ep(proc, tag, 1), ir_const_int(a, ez)); + ir_emit_store(proc, ir_emit_struct_ep(proc, tag, 2), ir_const_int(a, t->Vector.count)); } break; case Type_Proc: { ir_emit_comment(proc, str_lit("TypeInfoProc")); - tag = ir_emit_conv(proc, ti_ptr, t_type_info_procedure_ptr); + tag = ir_emit_conv(proc, variant_ptr, t_type_info_procedure_ptr); - irValue *params = ir_emit_struct_ep(proc, tag, 2); - irValue *results = ir_emit_struct_ep(proc, tag, 3); - irValue *variadic = ir_emit_struct_ep(proc, tag, 4); - irValue *convention = ir_emit_struct_ep(proc, tag, 5); + irValue *params = ir_emit_struct_ep(proc, tag, 0); + irValue *results = ir_emit_struct_ep(proc, tag, 1); + irValue *variadic = ir_emit_struct_ep(proc, tag, 2); + irValue *convention = ir_emit_struct_ep(proc, tag, 3); if (t->Proc.params != nullptr) { ir_emit_store(proc, params, ir_get_type_info_ptr(proc, t->Proc.params)); @@ -7933,8 +7972,7 @@ void ir_gen_tree(irGen *s) { } break; case Type_Tuple: { ir_emit_comment(proc, str_lit("TypeInfoTuple")); - tag = ir_emit_conv(proc, ti_ptr, t_type_info_tuple_ptr); - irValue *record = ir_emit_struct_ep(proc, tag, 2); + tag = ir_emit_conv(proc, variant_ptr, t_type_info_tuple_ptr); irValue *memory_types = ir_type_info_member_types_offset(proc, t->Tuple.variable_count); irValue *memory_names = ir_type_info_member_names_offset(proc, t->Tuple.variable_count); @@ -7954,23 +7992,22 @@ void ir_gen_tree(irGen *s) { } irValue *count = ir_const_int(a, t->Tuple.variable_count); - ir_fill_slice(proc, ir_emit_struct_ep(proc, record, 0), memory_types, count, count); - ir_fill_slice(proc, ir_emit_struct_ep(proc, record, 1), memory_names, count, count); + ir_fill_slice(proc, ir_emit_struct_ep(proc, tag, 0), memory_types, count, count); + ir_fill_slice(proc, ir_emit_struct_ep(proc, tag, 1), memory_names, count, count); } break; case Type_Record: { switch (t->Record.kind) { case TypeRecord_Struct: { ir_emit_comment(proc, str_lit("TypeInfoStruct")); - tag = ir_emit_conv(proc, ti_ptr, t_type_info_struct_ptr); - irValue *record = ir_emit_struct_ep(proc, tag, 2); + tag = ir_emit_conv(proc, variant_ptr, t_type_info_struct_ptr); { irValue *packed = ir_const_bool(a, t->Record.is_packed); irValue *ordered = ir_const_bool(a, t->Record.is_ordered); irValue *custom_align = ir_const_bool(a, t->Record.custom_align != 0); - ir_emit_store(proc, ir_emit_struct_ep(proc, record, 4), packed); - ir_emit_store(proc, ir_emit_struct_ep(proc, record, 5), ordered); - ir_emit_store(proc, ir_emit_struct_ep(proc, record, 6), custom_align); + ir_emit_store(proc, ir_emit_struct_ep(proc, tag, 4), packed); + ir_emit_store(proc, ir_emit_struct_ep(proc, tag, 5), ordered); + ir_emit_store(proc, ir_emit_struct_ep(proc, tag, 6), custom_align); } irValue *memory_types = ir_type_info_member_types_offset(proc, t->Record.field_count); @@ -8001,17 +8038,17 @@ void ir_gen_tree(irGen *s) { } irValue *count = ir_const_int(a, t->Record.field_count); - ir_fill_slice(proc, ir_emit_struct_ep(proc, record, 0), memory_types, count, count); - ir_fill_slice(proc, ir_emit_struct_ep(proc, record, 1), memory_names, count, count); - ir_fill_slice(proc, ir_emit_struct_ep(proc, record, 2), memory_offsets, count, count); - ir_fill_slice(proc, ir_emit_struct_ep(proc, record, 3), memory_usings, count, count); + ir_fill_slice(proc, ir_emit_struct_ep(proc, tag, 0), memory_types, count, count); + ir_fill_slice(proc, ir_emit_struct_ep(proc, tag, 1), memory_names, count, count); + ir_fill_slice(proc, ir_emit_struct_ep(proc, tag, 2), memory_offsets, count, count); + ir_fill_slice(proc, ir_emit_struct_ep(proc, tag, 3), memory_usings, count, count); } break; case TypeRecord_Union: { ir_emit_comment(proc, str_lit("TypeInfoUnion")); - tag = ir_emit_conv(proc, ti_ptr, t_type_info_union_ptr); + tag = ir_emit_conv(proc, variant_ptr, t_type_info_union_ptr); { - irValue *common_fields = ir_emit_struct_ep(proc, tag, 2); + irValue *common_fields = ir_emit_struct_ep(proc, tag, 0); isize field_count = t->Record.field_count; irValue *memory_types = ir_type_info_member_types_offset(proc, field_count); @@ -8046,8 +8083,8 @@ void ir_gen_tree(irGen *s) { } { - irValue *variant_names = ir_emit_struct_ep(proc, tag, 3); - irValue *variant_types = ir_emit_struct_ep(proc, tag, 4); + irValue *variant_names = ir_emit_struct_ep(proc, tag, 1); + irValue *variant_types = ir_emit_struct_ep(proc, tag, 2); isize variant_count = gb_max(0, t->Record.variant_count-1); irValue *memory_names = ir_type_info_member_names_offset(proc, variant_count); @@ -8055,17 +8092,12 @@ void ir_gen_tree(irGen *s) { // NOTE(bill): Zeroth is nil so ignore it for (isize variant_index = 0; variant_index < variant_count; variant_index++) { - Entity *f = t->Record.variants[variant_index+1]; // Skip zeroth - irValue *tip = ir_get_type_info_ptr(proc, f->type); + Type *vt = t->Record.variants[variant_index+1]; // Skip zeroth + irValue *tip = ir_get_type_info_ptr(proc, vt); irValue *index = ir_const_int(a, variant_index); irValue *type_info = ir_emit_ptr_offset(proc, memory_types, index); - ir_emit_store(proc, type_info, ir_type_info(proc, f->type)); - - if (f->token.string.len > 0) { - irValue *name = ir_emit_ptr_offset(proc, memory_names, index); - ir_emit_store(proc, name, ir_const_string(a, f->token.string)); - } + ir_emit_store(proc, type_info, ir_type_info(proc, vt)); } irValue *count = ir_const_int(a, variant_count); @@ -8076,8 +8108,7 @@ void ir_gen_tree(irGen *s) { } break; case TypeRecord_RawUnion: { ir_emit_comment(proc, str_lit("TypeInfoRawUnion")); - tag = ir_emit_conv(proc, ti_ptr, t_type_info_raw_union_ptr); - irValue *record = ir_emit_struct_ep(proc, tag, 2); + tag = ir_emit_conv(proc, variant_ptr, t_type_info_raw_union_ptr); irValue *memory_types = ir_type_info_member_types_offset(proc, t->Record.field_count); irValue *memory_names = ir_type_info_member_names_offset(proc, t->Record.field_count); @@ -8097,17 +8128,17 @@ void ir_gen_tree(irGen *s) { } irValue *count = ir_const_int(a, t->Record.field_count); - ir_fill_slice(proc, ir_emit_struct_ep(proc, record, 0), memory_types, count, count); - ir_fill_slice(proc, ir_emit_struct_ep(proc, record, 1), memory_names, count, count); - ir_fill_slice(proc, ir_emit_struct_ep(proc, record, 2), memory_offsets, count, count); + ir_fill_slice(proc, ir_emit_struct_ep(proc, tag, 0), memory_types, count, count); + ir_fill_slice(proc, ir_emit_struct_ep(proc, tag, 1), memory_names, count, count); + ir_fill_slice(proc, ir_emit_struct_ep(proc, tag, 2), memory_offsets, count, count); } break; case TypeRecord_Enum: ir_emit_comment(proc, str_lit("TypeInfoEnum")); - tag = ir_emit_conv(proc, ti_ptr, t_type_info_enum_ptr); + tag = ir_emit_conv(proc, variant_ptr, t_type_info_enum_ptr); { GB_ASSERT(t->Record.enum_base_type != nullptr); irValue *base = ir_type_info(proc, t->Record.enum_base_type); - ir_emit_store(proc, ir_emit_struct_ep(proc, tag, 2), base); + ir_emit_store(proc, ir_emit_struct_ep(proc, tag, 0), base); if (t->Record.field_count > 0) { Entity **fields = t->Record.fields; @@ -8140,11 +8171,11 @@ void ir_gen_tree(irGen *s) { irValue *v_count = ir_const_int(a, count); - irValue *names = ir_emit_struct_ep(proc, tag, 3); + irValue *names = ir_emit_struct_ep(proc, tag, 1); irValue *name_array_elem = ir_array_elem(proc, name_array); ir_fill_slice(proc, names, name_array_elem, v_count, v_count); - irValue *values = ir_emit_struct_ep(proc, tag, 4); + irValue *values = ir_emit_struct_ep(proc, tag, 2); irValue *value_array_elem = ir_array_elem(proc, value_array); ir_fill_slice(proc, values, value_array_elem, v_count, v_count); } @@ -8154,12 +8185,12 @@ void ir_gen_tree(irGen *s) { } break; case Type_Map: { ir_emit_comment(proc, str_lit("TypeInfoMap")); - tag = ir_emit_conv(proc, ti_ptr, t_type_info_map_ptr); + tag = ir_emit_conv(proc, variant_ptr, t_type_info_map_ptr); - irValue *key = ir_emit_struct_ep(proc, tag, 2); - irValue *value = ir_emit_struct_ep(proc, tag, 3); - irValue *generated_struct = ir_emit_struct_ep(proc, tag, 4); - irValue *count = ir_emit_struct_ep(proc, tag, 5); + irValue *key = ir_emit_struct_ep(proc, tag, 0); + irValue *value = ir_emit_struct_ep(proc, tag, 1); + irValue *generated_struct = ir_emit_struct_ep(proc, tag, 2); + irValue *count = ir_emit_struct_ep(proc, tag, 3); ir_emit_store(proc, key, ir_get_type_info_ptr(proc, t->Map.key)); ir_emit_store(proc, value, ir_get_type_info_ptr(proc, t->Map.value)); @@ -8169,7 +8200,7 @@ void ir_gen_tree(irGen *s) { case Type_BitField: { ir_emit_comment(proc, str_lit("TypeInfoBitField")); - tag = ir_emit_conv(proc, ti_ptr, t_type_info_map_ptr); + tag = ir_emit_conv(proc, variant_ptr, t_type_info_map_ptr); // names: []string, // bits: []u32, // offsets: []u32, @@ -8196,15 +8227,15 @@ void ir_gen_tree(irGen *s) { irValue *v_count = ir_const_int(a, count); - irValue *names = ir_emit_struct_ep(proc, tag, 3); + irValue *names = ir_emit_struct_ep(proc, tag, 1); irValue *name_array_elem = ir_array_elem(proc, name_array); ir_fill_slice(proc, names, name_array_elem, v_count, v_count); - irValue *bits = ir_emit_struct_ep(proc, tag, 4); + irValue *bits = ir_emit_struct_ep(proc, tag, 2); irValue *bit_array_elem = ir_array_elem(proc, bit_array); ir_fill_slice(proc, bits, bit_array_elem, v_count, v_count); - irValue *offsets = ir_emit_struct_ep(proc, tag, 5); + irValue *offsets = ir_emit_struct_ep(proc, tag, 3); irValue *offset_array_elem = ir_array_elem(proc, offset_array); ir_fill_slice(proc, offsets, offset_array_elem, v_count, v_count); } @@ -8216,18 +8247,20 @@ void ir_gen_tree(irGen *s) { 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 < ti->Record.variant_count; i++) { - Entity *f = ti->Record.variants[i]; - if (are_types_identical(f->type, tag_type)) { + for (isize i = 1; i < tiv->Record.variant_count; i++) { + Type *vt = tiv->Record.variants[i]; + if (are_types_identical(vt, tag_type)) { found = true; - irValue *tag = ir_const_int(a, i); - irValue *ptr = ir_emit_union_tag_ptr(proc, ti_ptr); - ir_emit_store(proc, ptr, tag); + 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, "%s", type_to_string(tag_type)); + GB_ASSERT_MSG(found, "Tag type not found: %s", type_to_string(tag_type)); } else { GB_PANIC("Unhandled TypeInfo type: %s", type_to_string(t)); } diff --git a/src/parser.cpp b/src/parser.cpp index cb2026d49..ef4c9809b 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -425,8 +425,6 @@ AST_NODE_KIND(_TypeBegin, "", i32) \ }) \ AST_NODE_KIND(UnionType, "union type", struct { \ Token token; \ - Array fields; \ - isize field_count; \ Array variants; \ }) \ AST_NODE_KIND(RawUnionType, "raw union type", struct { \ @@ -864,7 +862,6 @@ AstNode *clone_ast_node(gbAllocator a, AstNode *node) { n->StructType.align = clone_ast_node(a, n->StructType.align); break; case AstNode_UnionType: - n->UnionType.fields = clone_ast_node_array(a, n->UnionType.fields); n->UnionType.variants = clone_ast_node_array(a, n->UnionType.variants); break; case AstNode_RawUnionType: @@ -1459,11 +1456,9 @@ AstNode *ast_struct_type(AstFile *f, Token token, Array fields, isize } -AstNode *ast_union_type(AstFile *f, Token token, Array fields, isize field_count, Array variants) { +AstNode *ast_union_type(AstFile *f, Token token, Array variants) { AstNode *result = make_ast_node(f, AstNode_UnionType); result->UnionType.token = token; - result->UnionType.fields = fields; - result->UnionType.field_count = field_count; result->UnionType.variants = variants; return result; } @@ -3707,7 +3702,6 @@ AstNode *parse_type_or_ident(AstFile *f) { case Token_union: { Token token = expect_token(f, Token_union); Token open = expect_token_after(f, Token_OpenBrace, "union"); - Array decls = make_ast_node_array(f); Array variants = make_ast_node_array(f); isize total_decl_name_count = 0; @@ -3717,50 +3711,18 @@ AstNode *parse_type_or_ident(AstFile *f) { while (f->curr_token.kind != Token_CloseBrace && f->curr_token.kind != Token_EOF) { - CommentGroup docs = f->lead_comment; - u32 flags = parse_field_prefixes(f); - auto names = parse_ident_list(f); - if (names.count == 0) { - break; + AstNode *type = parse_type(f); + if (type->kind != AstNode_BadExpr) { + array_add(&variants, type); } - u32 set_flags = check_field_prefixes(f, names.count, FieldFlag_using, flags); - if (names.count == 1 && f->curr_token.kind == Token_OpenBrace) { - if (set_flags != 0) { - error(names[0], "Variants cannot have field prefixes"); - set_flags = 0; - } - AstNode *name = names[0]; - Token open = expect_token(f, Token_OpenBrace); - isize decl_count = 0; - AstNode *list = parse_record_field_list(f, &decl_count); - Token close = expect_token(f, Token_CloseBrace); - - array_add(&variants, ast_union_field(f, name, list)); - expect_semicolon(f, nullptr); - } else { - AstNode *decl = parse_value_decl(f, names, docs); - if (decl->kind != AstNode_ValueDecl) { - error(decl, "Expected a field list, got %.*s", LIT(ast_node_strings[decl->kind])); - } else { - ast_node(vd, ValueDecl, decl); - if (vd->is_mutable) { - if (set_flags&FieldFlag_using) { - vd->flags |= VarDeclFlag_using; - } - if (vd->flags&VarDeclFlag_thread_local) { - vd->flags &= ~VarDeclFlag_thread_local; - error(decl, "Field values cannot be #thread_local"); - } - } - array_add(&decls, decl); - total_decl_name_count += vd->names.count; - } + if (!allow_token(f, Token_Comma)) { + break; } } Token close = expect_token(f, Token_CloseBrace); - return ast_union_type(f, token, decls, total_decl_name_count, variants); + return ast_union_type(f, token, variants); } break; case Token_raw_union: { diff --git a/src/types.cpp b/src/types.cpp index d8e87ff71..a43921d1f 100644 --- a/src/types.cpp +++ b/src/types.cpp @@ -93,7 +93,7 @@ struct TypeRecord { Scope * scope; // Entity_TypeName - union - Entity **variants; + Type ** variants; i32 variant_count; Entity * union__tag; i64 variant_block_size; // NOTE(bill): Internal use only @@ -1002,7 +1002,7 @@ bool is_type_polymorphic(Type *t) { } } for (isize i = 1; i < t->Record.variant_count; i++) { - if (is_type_polymorphic(t->Record.variants[i]->type)) { + if (is_type_polymorphic(t->Record.variants[i])) { return true; } } @@ -1163,10 +1163,7 @@ bool are_types_identical(Type *x, Type *y) { } // NOTE(bill): zeroth variant is nullptr for (isize i = 1; i < x->Record.variant_count; i++) { - if (!are_types_identical(x->Record.variants[i]->type, y->Record.variants[i]->type)) { - return false; - } - if (x->Record.variants[i]->token.string != y->Record.variants[i]->token.string) { + if (!are_types_identical(x->Record.variants[i], y->Record.variants[i])) { return false; } } @@ -1555,19 +1552,7 @@ Selection lookup_field_with_selection(gbAllocator a, Type *type_, String field_n } } - if (is_type_union(type)) { - for (isize i = 1; i < type->Record.variant_count; i++) { - Entity *f = type->Record.variants[i]; - GB_ASSERT(f->kind == Entity_TypeName); - String str = f->token.string; - - if (str == field_name) { - sel.entity = f; - // selection_add_index(&sel, i); - return sel; - } - } - } else if (is_type_enum(type)) { + if (is_type_enum(type)) { // NOTE(bill): These may not have been added yet, so check in case if (type->Record.enum_count != nullptr) { if (field_name == "count") { @@ -1880,7 +1865,7 @@ i64 type_align_of_internal(gbAllocator allocator, Type *t, TypePath *path) { } // NOTE(bill): field zero is null for (isize i = 1; i < t->Record.variant_count; i++) { - Type *variant = t->Record.variants[i]->type; + Type *variant = t->Record.variants[i]; type_path_push(path, variant); if (path->failure) { return FAILURE_ALIGNMENT; @@ -2139,7 +2124,7 @@ i64 type_size_of_internal(gbAllocator allocator, Type *t, TypePath *path) { i64 field_size = max; for (isize i = 1; i < variant_count; i++) { - Type *variant_type = t->Record.variants[i]->type; + Type *variant_type = t->Record.variants[i]; i64 size = type_size_of_internal(allocator, variant_type, path); if (max < size) { max = size; @@ -2369,26 +2354,11 @@ gbString write_type_to_string(gbString str, Type *type) { str = write_type_to_string(str, f->type); } for (isize i = 1; i < type->Record.variant_count; i++) { - Entity *f = type->Record.variants[i]; - GB_ASSERT(f->kind == Entity_TypeName); + Type *t = type->Record.variants[i]; if (i > 1 || type->Record.field_count > 1) { str = gb_string_appendc(str, ", "); } - str = gb_string_append_length(str, f->token.string.text, f->token.string.len); - str = gb_string_appendc(str, "{"); - Type *variant = base_type(f->type); - for (isize i = 0; i < variant->Record.field_count; i++) { - Entity *f = variant->Record.fields[i]; - GB_ASSERT(f->kind == Entity_Variable); - if (i > 0) { - str = gb_string_appendc(str, ", "); - } - str = gb_string_append_length(str, f->token.string.text, f->token.string.len); - str = gb_string_appendc(str, ": "); - str = write_type_to_string(str, f->type); - } - str = gb_string_appendc(str, "{"); - + str = write_type_to_string(str, t); } str = gb_string_appendc(str, "}"); break;