Prechádzať zdrojové kódy

Add more helpers to `package reflect`

gingerBill 5 rokov pred
rodič
commit
4be385d648
3 zmenil súbory, kde vykonal 333 pridanie a 168 odobranie
  1. 169 36
      core/reflect/reflect.odin
  2. 156 127
      core/reflect/types.odin
  3. 8 5
      src/check_expr.cpp

+ 169 - 36
core/reflect/reflect.odin

@@ -3,6 +3,34 @@ package reflect
 import "core:runtime"
 import "core:runtime"
 import "core:mem"
 import "core:mem"
 
 
+Type_Info :: runtime.Type_Info;
+
+Type_Info_Named            :: runtime.Type_Info_Named;
+Type_Info_Integer          :: runtime.Type_Info_Integer;
+Type_Info_Rune             :: runtime.Type_Info_Rune;
+Type_Info_Float            :: runtime.Type_Info_Float;
+Type_Info_Complex          :: runtime.Type_Info_Complex;
+Type_Info_Quaternion       :: runtime.Type_Info_Quaternion;
+Type_Info_String           :: runtime.Type_Info_String;
+Type_Info_Boolean          :: runtime.Type_Info_Boolean;
+Type_Info_Any              :: runtime.Type_Info_Any;
+Type_Info_Type_Id          :: runtime.Type_Info_Type_Id;
+Type_Info_Pointer          :: runtime.Type_Info_Pointer;
+Type_Info_Procedure        :: runtime.Type_Info_Procedure;
+Type_Info_Array            :: runtime.Type_Info_Array;
+Type_Info_Enumerated_Array :: runtime.Type_Info_Enumerated_Array;
+Type_Info_Dynamic_Array    :: runtime.Type_Info_Dynamic_Array;
+Type_Info_Slice            :: runtime.Type_Info_Slice;
+Type_Info_Tuple            :: runtime.Type_Info_Tuple;
+Type_Info_Struct           :: runtime.Type_Info_Struct;
+Type_Info_Union            :: runtime.Type_Info_Union;
+Type_Info_Enum             :: runtime.Type_Info_Enum;
+Type_Info_Map              :: runtime.Type_Info_Map;
+Type_Info_Bit_Field        :: runtime.Type_Info_Bit_Field;
+Type_Info_Bit_Set          :: runtime.Type_Info_Bit_Set;
+Type_Info_Opaque           :: runtime.Type_Info_Opaque;
+Type_Info_Simd_Vector      :: runtime.Type_Info_Simd_Vector;
+
 
 
 Type_Kind :: enum {
 Type_Kind :: enum {
 	Invalid,
 	Invalid,
@@ -39,31 +67,31 @@ type_kind :: proc(T: typeid) -> Type_Kind {
 	ti := type_info_of(T);
 	ti := type_info_of(T);
 	if ti != nil {
 	if ti != nil {
 		switch _ in ti.variant {
 		switch _ in ti.variant {
-		case runtime.Type_Info_Named:         return .Named;
-		case runtime.Type_Info_Integer:       return .Integer;
-		case runtime.Type_Info_Rune:          return .Rune;
-		case runtime.Type_Info_Float:         return .Float;
-		case runtime.Type_Info_Complex:       return .Complex;
-		case runtime.Type_Info_Quaternion:    return .Quaternion;
-		case runtime.Type_Info_String:        return .String;
-		case runtime.Type_Info_Boolean:       return .Boolean;
-		case runtime.Type_Info_Any:           return .Any;
-		case runtime.Type_Info_Type_Id:       return .Type_Id;
-		case runtime.Type_Info_Pointer:       return .Pointer;
-		case runtime.Type_Info_Procedure:     return .Procedure;
-		case runtime.Type_Info_Array:         return .Array;
-		case runtime.Type_Info_Enumerated_Array: return .Enumerated_Array;
-		case runtime.Type_Info_Dynamic_Array: return .Dynamic_Array;
-		case runtime.Type_Info_Slice:         return .Slice;
-		case runtime.Type_Info_Tuple:         return .Tuple;
-		case runtime.Type_Info_Struct:        return .Struct;
-		case runtime.Type_Info_Union:         return .Union;
-		case runtime.Type_Info_Enum:          return .Enum;
-		case runtime.Type_Info_Map:           return .Map;
-		case runtime.Type_Info_Bit_Field:     return .Bit_Field;
-		case runtime.Type_Info_Bit_Set:       return .Bit_Set;
-		case runtime.Type_Info_Opaque:        return .Opaque;
-		case runtime.Type_Info_Simd_Vector:   return .Simd_Vector;
+		case Type_Info_Named:            return .Named;
+		case Type_Info_Integer:          return .Integer;
+		case Type_Info_Rune:             return .Rune;
+		case Type_Info_Float:            return .Float;
+		case Type_Info_Complex:          return .Complex;
+		case Type_Info_Quaternion:       return .Quaternion;
+		case Type_Info_String:           return .String;
+		case Type_Info_Boolean:          return .Boolean;
+		case Type_Info_Any:              return .Any;
+		case Type_Info_Type_Id:          return .Type_Id;
+		case Type_Info_Pointer:          return .Pointer;
+		case Type_Info_Procedure:        return .Procedure;
+		case Type_Info_Array:            return .Array;
+		case Type_Info_Enumerated_Array: return .Enumerated_Array;
+		case Type_Info_Dynamic_Array:    return .Dynamic_Array;
+		case Type_Info_Slice:            return .Slice;
+		case Type_Info_Tuple:            return .Tuple;
+		case Type_Info_Struct:           return .Struct;
+		case Type_Info_Union:            return .Union;
+		case Type_Info_Enum:             return .Enum;
+		case Type_Info_Map:              return .Map;
+		case Type_Info_Bit_Field:        return .Bit_Field;
+		case Type_Info_Bit_Set:          return .Bit_Set;
+		case Type_Info_Opaque:           return .Opaque;
+		case Type_Info_Simd_Vector:      return .Simd_Vector;
 		}
 		}
 
 
 	}
 	}
@@ -81,6 +109,75 @@ backing_type_kind :: proc(T: typeid) -> Type_Kind {
 }
 }
 
 
 
 
+type_info_base :: proc(info: ^runtime.Type_Info) -> ^runtime.Type_Info {
+	if info == nil do return nil;
+
+	base := info;
+	loop: for {
+		#partial switch i in base.variant {
+		case Type_Info_Named: base = i.base;
+		case: break loop;
+		}
+	}
+	return base;
+}
+
+
+type_info_core :: proc(info: ^runtime.Type_Info) -> ^runtime.Type_Info {
+	if info == nil do return nil;
+
+	base := info;
+	loop: for {
+		#partial switch i in base.variant {
+		case Type_Info_Named:  base = i.base;
+		case Type_Info_Enum:   base = i.base;
+		case Type_Info_Opaque: base = i.elem;
+		case: break loop;
+		}
+	}
+	return base;
+}
+type_info_base_without_enum :: type_info_core;
+
+
+typeid_base :: proc(id: typeid) -> typeid {
+	ti := type_info_of(id);
+	ti = type_info_base(ti);
+	return ti.id;
+}
+typeid_core :: proc(id: typeid) -> typeid {
+	ti := type_info_base_without_enum(type_info_of(id));
+	return ti.id;
+}
+typeid_base_without_enum :: typeid_core;
+
+typeid_elem :: proc(id: typeid) -> typeid {
+	ti := type_info_of(id);
+	if ti == nil do return nil;
+
+	bits := 8*ti.size;
+
+	#partial switch v in ti.variant {
+	case Type_Info_Complex:
+		switch bits {
+		case 64:  return f32;
+		case 128: return f64;
+		}
+	case Type_Info_Quaternion:
+		switch bits {
+		case 128: return f32;
+		case 256: return f64;
+		}
+	case Type_Info_Pointer:          return v.elem.id;
+	case Type_Info_Opaque:           return v.elem.id;
+	case Type_Info_Array:            return v.elem.id;
+	case Type_Info_Enumerated_Array: return v.elem.id;
+	case Type_Info_Slice:            return v.elem.id;
+	case Type_Info_Dynamic_Array:    return v.elem.id;
+	}
+	return id;
+}
+
 
 
 size_of_typeid :: proc(T: typeid) -> int {
 size_of_typeid :: proc(T: typeid) -> int {
 	if ti := type_info_of(T); ti != nil {
 	if ti := type_info_of(T); ti != nil {
@@ -109,6 +206,9 @@ any_data :: inline proc(v: any) -> (data: rawptr, id: typeid) {
 }
 }
 
 
 is_nil :: proc(v: any) -> bool {
 is_nil :: proc(v: any) -> bool {
+	if v == nil {
+		return true;
+	}
 	data := to_bytes(v);
 	data := to_bytes(v);
 	if data != nil {
 	if data != nil {
 		return true;
 		return true;
@@ -125,16 +225,22 @@ length :: proc(val: any) -> int {
 	v := val;
 	v := val;
 	v.id = runtime.typeid_base(v.id);
 	v.id = runtime.typeid_base(v.id);
 	switch a in v {
 	switch a in v {
-	case runtime.Type_Info_Array:
+	case Type_Info_Array:
+		return a.count;
+
+	case Type_Info_Enumerated_Array:
 		return a.count;
 		return a.count;
 
 
-	case runtime.Type_Info_Slice:
+	case Type_Info_Slice:
 		return (^mem.Raw_Slice)(v.data).len;
 		return (^mem.Raw_Slice)(v.data).len;
 
 
-	case runtime.Type_Info_Dynamic_Array:
+	case Type_Info_Dynamic_Array:
 		return (^mem.Raw_Dynamic_Array)(v.data).len;
 		return (^mem.Raw_Dynamic_Array)(v.data).len;
 
 
-	case runtime.Type_Info_String:
+	case Type_Info_Map:
+		return (^mem.Raw_Map)(v.data).entries.len;
+
+	case Type_Info_String:
 		if a.is_cstring {
 		if a.is_cstring {
 			return len((^cstring)(v.data)^);
 			return len((^cstring)(v.data)^);
 		} else {
 		} else {
@@ -144,6 +250,27 @@ length :: proc(val: any) -> int {
 	return 0;
 	return 0;
 }
 }
 
 
+capacity :: proc(val: any) -> int {
+	if val == nil do return 0;
+
+	v := val;
+	v.id = runtime.typeid_base(v.id);
+	switch a in v {
+	case Type_Info_Array:
+		return a.count;
+
+	case Type_Info_Enumerated_Array:
+		return a.count;
+
+	case Type_Info_Dynamic_Array:
+		return (^mem.Raw_Dynamic_Array)(v.data).cap;
+
+	case Type_Info_Map:
+		return (^mem.Raw_Map)(v.data).entries.cap;
+	}
+	return 0;
+}
+
 
 
 index :: proc(val: any, i: int, loc := #caller_location) -> any {
 index :: proc(val: any, i: int, loc := #caller_location) -> any {
 	if val == nil do return nil;
 	if val == nil do return nil;
@@ -151,27 +278,33 @@ index :: proc(val: any, i: int, loc := #caller_location) -> any {
 	v := val;
 	v := val;
 	v.id = runtime.typeid_base(v.id);
 	v.id = runtime.typeid_base(v.id);
 	switch a in v {
 	switch a in v {
-	case runtime.Type_Info_Array:
+	case Type_Info_Array:
+		runtime.bounds_check_error_loc(loc, i, a.count);
+		offset := uintptr(a.elem.size * i);
+		data := rawptr(uintptr(v.data) + offset);
+		return any{data, a.elem.id};
+
+	case Type_Info_Enumerated_Array:
 		runtime.bounds_check_error_loc(loc, i, a.count);
 		runtime.bounds_check_error_loc(loc, i, a.count);
 		offset := uintptr(a.elem.size * i);
 		offset := uintptr(a.elem.size * i);
 		data := rawptr(uintptr(v.data) + offset);
 		data := rawptr(uintptr(v.data) + offset);
 		return any{data, a.elem.id};
 		return any{data, a.elem.id};
 
 
-	case runtime.Type_Info_Slice:
+	case Type_Info_Slice:
 		raw := (^mem.Raw_Slice)(v.data);
 		raw := (^mem.Raw_Slice)(v.data);
 		runtime.bounds_check_error_loc(loc, i, raw.len);
 		runtime.bounds_check_error_loc(loc, i, raw.len);
 		offset := uintptr(a.elem.size * i);
 		offset := uintptr(a.elem.size * i);
 		data := rawptr(uintptr(raw.data) + offset);
 		data := rawptr(uintptr(raw.data) + offset);
 		return any{data, a.elem.id};
 		return any{data, a.elem.id};
 
 
-	case runtime.Type_Info_Dynamic_Array:
+	case Type_Info_Dynamic_Array:
 		raw := (^mem.Raw_Dynamic_Array)(v.data);
 		raw := (^mem.Raw_Dynamic_Array)(v.data);
 		runtime.bounds_check_error_loc(loc, i, raw.len);
 		runtime.bounds_check_error_loc(loc, i, raw.len);
 		offset := uintptr(a.elem.size * i);
 		offset := uintptr(a.elem.size * i);
 		data := rawptr(uintptr(raw.data) + offset);
 		data := rawptr(uintptr(raw.data) + offset);
 		return any{data, a.elem.id};
 		return any{data, a.elem.id};
 
 
-	case runtime.Type_Info_String:
+	case Type_Info_String:
 		if a.is_cstring do return nil;
 		if a.is_cstring do return nil;
 
 
 		raw := (^mem.Raw_String)(v.data);
 		raw := (^mem.Raw_String)(v.data);
@@ -290,12 +423,12 @@ struct_field_offsets :: proc(T: typeid) -> []uintptr {
 
 
 
 
 
 
-struct_tag_get :: proc(tag: Struct_Tag, key: string) -> (value: string) {
+struct_tag_get :: proc(tag: Struct_Tag, key: string) -> (value: Struct_Tag) {
 	value, _ = struct_tag_lookup(tag, key);
 	value, _ = struct_tag_lookup(tag, key);
 	return;
 	return;
 }
 }
 
 
-struct_tag_lookup :: proc(tag: Struct_Tag, key: string) -> (value: string, ok: bool) {
+struct_tag_lookup :: proc(tag: Struct_Tag, key: string) -> (value: Struct_Tag, ok: bool) {
 	for t := tag; t != ""; /**/ {
 	for t := tag; t != ""; /**/ {
 		i := 0;
 		i := 0;
 		for i < len(t) && t[i] == ' ' { // Skip whitespace
 		for i < len(t) && t[i] == ' ' { // Skip whitespace
@@ -336,7 +469,7 @@ struct_tag_lookup :: proc(tag: Struct_Tag, key: string) -> (value: string, ok: b
 		t = t[i+1:];
 		t = t[i+1:];
 
 
 		if key == name {
 		if key == name {
-			return val[1:i], true;
+			return Struct_Tag(val[1:i]), true;
 		}
 		}
 	}
 	}
 	return;
 	return;

+ 156 - 127
core/reflect/types.odin

@@ -1,9 +1,8 @@
 package reflect
 package reflect
 
 
-import rt "core:runtime"
 import "core:strings"
 import "core:strings"
 
 
-are_types_identical :: proc(a, b: ^rt.Type_Info) -> bool {
+are_types_identical :: proc(a, b: ^Type_Info) -> bool {
 	if a == b do return true;
 	if a == b do return true;
 
 
 	if (a == nil && b != nil) ||
 	if (a == nil && b != nil) ||
@@ -18,55 +17,55 @@ are_types_identical :: proc(a, b: ^rt.Type_Info) -> bool {
 	}
 	}
 
 
 	switch x in a.variant {
 	switch x in a.variant {
-	case rt.Type_Info_Named:
-		y, ok := b.variant.(rt.Type_Info_Named);
+	case Type_Info_Named:
+		y, ok := b.variant.(Type_Info_Named);
 		if !ok do return false;
 		if !ok do return false;
 		return x.base == y.base;
 		return x.base == y.base;
 
 
-	case rt.Type_Info_Integer:
-		y, ok := b.variant.(rt.Type_Info_Integer);
+	case Type_Info_Integer:
+		y, ok := b.variant.(Type_Info_Integer);
 		if !ok do return false;
 		if !ok do return false;
-		return x.signed == y.signed;
+		return x.signed == y.signed && x.endianness == y.endianness;
 
 
-	case rt.Type_Info_Rune:
-		_, ok := b.variant.(rt.Type_Info_Rune);
+	case Type_Info_Rune:
+		_, ok := b.variant.(Type_Info_Rune);
 		return ok;
 		return ok;
 
 
-	case rt.Type_Info_Float:
-		_, ok := b.variant.(rt.Type_Info_Float);
+	case Type_Info_Float:
+		_, ok := b.variant.(Type_Info_Float);
 		return ok;
 		return ok;
 
 
-	case rt.Type_Info_Complex:
-		_, ok := b.variant.(rt.Type_Info_Complex);
+	case Type_Info_Complex:
+		_, ok := b.variant.(Type_Info_Complex);
 		return ok;
 		return ok;
 
 
-	case rt.Type_Info_Quaternion:
-		_, ok := b.variant.(rt.Type_Info_Quaternion);
+	case Type_Info_Quaternion:
+		_, ok := b.variant.(Type_Info_Quaternion);
 		return ok;
 		return ok;
 
 
-	case rt.Type_Info_Type_Id:
-		_, ok := b.variant.(rt.Type_Info_Type_Id);
+	case Type_Info_Type_Id:
+		_, ok := b.variant.(Type_Info_Type_Id);
 		return ok;
 		return ok;
 
 
-	case rt.Type_Info_String:
-		_, ok := b.variant.(rt.Type_Info_String);
+	case Type_Info_String:
+		_, ok := b.variant.(Type_Info_String);
 		return ok;
 		return ok;
 
 
-	case rt.Type_Info_Boolean:
-		_, ok := b.variant.(rt.Type_Info_Boolean);
+	case Type_Info_Boolean:
+		_, ok := b.variant.(Type_Info_Boolean);
 		return ok;
 		return ok;
 
 
-	case rt.Type_Info_Any:
-		_, ok := b.variant.(rt.Type_Info_Any);
+	case Type_Info_Any:
+		_, ok := b.variant.(Type_Info_Any);
 		return ok;
 		return ok;
 
 
-	case rt.Type_Info_Pointer:
-		y, ok := b.variant.(rt.Type_Info_Pointer);
+	case Type_Info_Pointer:
+		y, ok := b.variant.(Type_Info_Pointer);
 		if !ok do return false;
 		if !ok do return false;
 		return are_types_identical(x.elem, y.elem);
 		return are_types_identical(x.elem, y.elem);
 
 
-	case rt.Type_Info_Procedure:
-		y, ok := b.variant.(rt.Type_Info_Procedure);
+	case Type_Info_Procedure:
+		y, ok := b.variant.(Type_Info_Procedure);
 		if !ok do return false;
 		if !ok do return false;
 		switch {
 		switch {
 		case x.variadic   != y.variadic,
 		case x.variadic   != y.variadic,
@@ -76,31 +75,31 @@ are_types_identical :: proc(a, b: ^rt.Type_Info) -> bool {
 
 
 		return are_types_identical(x.params, y.params) && are_types_identical(x.results, y.results);
 		return are_types_identical(x.params, y.params) && are_types_identical(x.results, y.results);
 
 
-	case rt.Type_Info_Array:
-		y, ok := b.variant.(rt.Type_Info_Array);
+	case Type_Info_Array:
+		y, ok := b.variant.(Type_Info_Array);
 		if !ok do return false;
 		if !ok do return false;
 		if x.count != y.count do return false;
 		if x.count != y.count do return false;
 		return are_types_identical(x.elem, y.elem);
 		return are_types_identical(x.elem, y.elem);
 
 
-	case rt.Type_Info_Enumerated_Array:
-		y, ok := b.variant.(rt.Type_Info_Enumerated_Array);
+	case Type_Info_Enumerated_Array:
+		y, ok := b.variant.(Type_Info_Enumerated_Array);
 		if !ok do return false;
 		if !ok do return false;
 		if x.count != y.count do return false;
 		if x.count != y.count do return false;
 		return are_types_identical(x.index, y.index) &&
 		return are_types_identical(x.index, y.index) &&
 		       are_types_identical(x.elem, y.elem);
 		       are_types_identical(x.elem, y.elem);
 
 
-	case rt.Type_Info_Dynamic_Array:
-		y, ok := b.variant.(rt.Type_Info_Dynamic_Array);
+	case Type_Info_Dynamic_Array:
+		y, ok := b.variant.(Type_Info_Dynamic_Array);
 		if !ok do return false;
 		if !ok do return false;
 		return are_types_identical(x.elem, y.elem);
 		return are_types_identical(x.elem, y.elem);
 
 
-	case rt.Type_Info_Slice:
-		y, ok := b.variant.(rt.Type_Info_Slice);
+	case Type_Info_Slice:
+		y, ok := b.variant.(Type_Info_Slice);
 		if !ok do return false;
 		if !ok do return false;
 		return are_types_identical(x.elem, y.elem);
 		return are_types_identical(x.elem, y.elem);
 
 
-	case rt.Type_Info_Tuple:
-		y, ok := b.variant.(rt.Type_Info_Tuple);
+	case Type_Info_Tuple:
+		y, ok := b.variant.(Type_Info_Tuple);
 		if !ok do return false;
 		if !ok do return false;
 		if len(x.types) != len(y.types) do return false;
 		if len(x.types) != len(y.types) do return false;
 		for _, i in x.types {
 		for _, i in x.types {
@@ -111,14 +110,17 @@ are_types_identical :: proc(a, b: ^rt.Type_Info) -> bool {
 		}
 		}
 		return true;
 		return true;
 
 
-	case rt.Type_Info_Struct:
-		y, ok := b.variant.(rt.Type_Info_Struct);
+	case Type_Info_Struct:
+		y, ok := b.variant.(Type_Info_Struct);
 		if !ok do return false;
 		if !ok do return false;
 	   	switch {
 	   	switch {
-		case len(x.types)   != len(y.types),
-		     x.is_packed    != y.is_packed,
-		     x.is_raw_union != y.is_raw_union,
-		     x.custom_align != y.custom_align:
+		case len(x.types)    != len(y.types),
+		     x.is_packed     != y.is_packed,
+		     x.is_raw_union  != y.is_raw_union,
+		     x.custom_align  != y.custom_align,
+		     x.soa_kind      != y.soa_kind,
+		     x.soa_base_type != y.soa_base_type,
+		     x.soa_len       != y.soa_len:
 		     return false;
 		     return false;
 		}
 		}
 		for _, i in x.types {
 		for _, i in x.types {
@@ -132,8 +134,8 @@ are_types_identical :: proc(a, b: ^rt.Type_Info) -> bool {
 		}
 		}
 		return true;
 		return true;
 
 
-	case rt.Type_Info_Union:
-		y, ok := b.variant.(rt.Type_Info_Union);
+	case Type_Info_Union:
+		y, ok := b.variant.(Type_Info_Union);
 		if !ok do return false;
 		if !ok do return false;
 		if len(x.variants) != len(y.variants) do return false;
 		if len(x.variants) != len(y.variants) do return false;
 
 
@@ -143,17 +145,17 @@ are_types_identical :: proc(a, b: ^rt.Type_Info) -> bool {
 		}
 		}
 		return true;
 		return true;
 
 
-	case rt.Type_Info_Enum:
+	case Type_Info_Enum:
 		// NOTE(bill): Should be handled above
 		// NOTE(bill): Should be handled above
 		return false;
 		return false;
 
 
-	case rt.Type_Info_Map:
-		y, ok := b.variant.(rt.Type_Info_Map);
+	case Type_Info_Map:
+		y, ok := b.variant.(Type_Info_Map);
 		if !ok do return false;
 		if !ok do return false;
 		return are_types_identical(x.key, y.key) && are_types_identical(x.value, y.value);
 		return are_types_identical(x.key, y.key) && are_types_identical(x.value, y.value);
 
 
-	case rt.Type_Info_Bit_Field:
-		y, ok := b.variant.(rt.Type_Info_Bit_Field);
+	case Type_Info_Bit_Field:
+		y, ok := b.variant.(Type_Info_Bit_Field);
 		if !ok do return false;
 		if !ok do return false;
 		if len(x.names) != len(y.names) do return false;
 		if len(x.names) != len(y.names) do return false;
 
 
@@ -168,18 +170,18 @@ are_types_identical :: proc(a, b: ^rt.Type_Info) -> bool {
 		}
 		}
 		return true;
 		return true;
 
 
-	case rt.Type_Info_Bit_Set:
-		y, ok := b.variant.(rt.Type_Info_Bit_Set);
+	case Type_Info_Bit_Set:
+		y, ok := b.variant.(Type_Info_Bit_Set);
 		if !ok do return false;
 		if !ok do return false;
 		return x.elem == y.elem && x.lower == y.lower && x.upper == y.upper;
 		return x.elem == y.elem && x.lower == y.lower && x.upper == y.upper;
 
 
-	case rt.Type_Info_Opaque:
-		y, ok := b.variant.(rt.Type_Info_Opaque);
+	case Type_Info_Opaque:
+		y, ok := b.variant.(Type_Info_Opaque);
 		if !ok do return false;
 		if !ok do return false;
 		return x.elem == y.elem;
 		return x.elem == y.elem;
 
 
-	case rt.Type_Info_Simd_Vector:
-		y, ok := b.variant.(rt.Type_Info_Simd_Vector);
+	case Type_Info_Simd_Vector:
+		y, ok := b.variant.(Type_Info_Simd_Vector);
 		if !ok do return false;
 		if !ok do return false;
 		return x.count == y.count && x.elem == y.elem;
 		return x.count == y.count && x.elem == y.elem;
 	}
 	}
@@ -187,112 +189,137 @@ are_types_identical :: proc(a, b: ^rt.Type_Info) -> bool {
 	return false;
 	return false;
 }
 }
 
 
-is_signed :: proc(info: ^rt.Type_Info) -> bool {
+is_signed :: proc(info: ^Type_Info) -> bool {
 	if info == nil do return false;
 	if info == nil do return false;
-	#partial switch i in rt.type_info_base(info).variant {
-	case rt.Type_Info_Integer: return i.signed;
-	case rt.Type_Info_Float:   return true;
+	#partial switch i in type_info_base(info).variant {
+	case Type_Info_Integer: return i.signed;
+	case Type_Info_Float:   return true;
 	}
 	}
 	return false;
 	return false;
 }
 }
-is_integer :: proc(info: ^rt.Type_Info) -> bool {
+is_unsigned :: proc(info: ^Type_Info) -> bool {
 	if info == nil do return false;
 	if info == nil do return false;
-	_, ok := rt.type_info_base(info).variant.(rt.Type_Info_Integer);
+	#partial switch i in type_info_base(info).variant {
+	case Type_Info_Integer: return !i.signed;
+	case Type_Info_Float:   return false;
+	}
+	return false;
+}
+
+
+is_integer :: proc(info: ^Type_Info) -> bool {
+	if info == nil do return false;
+	_, ok := type_info_base(info).variant.(Type_Info_Integer);
+	return ok;
+}
+is_rune :: proc(info: ^Type_Info) -> bool {
+	if info == nil do return false;
+	_, ok := type_info_base(info).variant.(Type_Info_Rune);
+	return ok;
+}
+is_float :: proc(info: ^Type_Info) -> bool {
+	if info == nil do return false;
+	_, ok := type_info_base(info).variant.(Type_Info_Float);
 	return ok;
 	return ok;
 }
 }
-is_rune :: proc(info: ^rt.Type_Info) -> bool {
+is_complex :: proc(info: ^Type_Info) -> bool {
 	if info == nil do return false;
 	if info == nil do return false;
-	_, ok := rt.type_info_base(info).variant.(rt.Type_Info_Rune);
+	_, ok := type_info_base(info).variant.(Type_Info_Complex);
 	return ok;
 	return ok;
 }
 }
-is_float :: proc(info: ^rt.Type_Info) -> bool {
+is_quaternion :: proc(info: ^Type_Info) -> bool {
 	if info == nil do return false;
 	if info == nil do return false;
-	_, ok := rt.type_info_base(info).variant.(rt.Type_Info_Float);
+	_, ok := type_info_base(info).variant.(Type_Info_Quaternion);
 	return ok;
 	return ok;
 }
 }
-is_complex :: proc(info: ^rt.Type_Info) -> bool {
+is_any :: proc(info: ^Type_Info) -> bool {
 	if info == nil do return false;
 	if info == nil do return false;
-	_, ok := rt.type_info_base(info).variant.(rt.Type_Info_Complex);
+	_, ok := type_info_base(info).variant.(Type_Info_Any);
 	return ok;
 	return ok;
 }
 }
-is_any :: proc(info: ^rt.Type_Info) -> bool {
+is_string :: proc(info: ^Type_Info) -> bool {
 	if info == nil do return false;
 	if info == nil do return false;
-	_, ok := rt.type_info_base(info).variant.(rt.Type_Info_Any);
+	_, ok := type_info_base(info).variant.(Type_Info_String);
 	return ok;
 	return ok;
 }
 }
-is_string :: proc(info: ^rt.Type_Info) -> bool {
+is_cstring :: proc(info: ^Type_Info) -> bool {
 	if info == nil do return false;
 	if info == nil do return false;
-	_, ok := rt.type_info_base(info).variant.(rt.Type_Info_String);
+	v, ok := type_info_base(info).variant.(Type_Info_String);
+	return ok && v.is_cstring;
+}
+is_boolean :: proc(info: ^Type_Info) -> bool {
+	if info == nil do return false;
+	_, ok := type_info_base(info).variant.(Type_Info_Boolean);
 	return ok;
 	return ok;
 }
 }
-is_boolean :: proc(info: ^rt.Type_Info) -> bool {
+is_pointer :: proc(info: ^Type_Info) -> bool {
 	if info == nil do return false;
 	if info == nil do return false;
-	_, ok := rt.type_info_base(info).variant.(rt.Type_Info_Boolean);
+	_, ok := type_info_base(info).variant.(Type_Info_Pointer);
 	return ok;
 	return ok;
 }
 }
-is_pointer :: proc(info: ^rt.Type_Info) -> bool {
+is_procedure :: proc(info: ^Type_Info) -> bool {
 	if info == nil do return false;
 	if info == nil do return false;
-	_, ok := rt.type_info_base(info).variant.(rt.Type_Info_Pointer);
+	_, ok := type_info_base(info).variant.(Type_Info_Procedure);
 	return ok;
 	return ok;
 }
 }
-is_procedure :: proc(info: ^rt.Type_Info) -> bool {
+is_array :: proc(info: ^Type_Info) -> bool {
 	if info == nil do return false;
 	if info == nil do return false;
-	_, ok := rt.type_info_base(info).variant.(rt.Type_Info_Procedure);
+	_, ok := type_info_base(info).variant.(Type_Info_Array);
 	return ok;
 	return ok;
 }
 }
-is_array :: proc(info: ^rt.Type_Info) -> bool {
+is_enumerated_array :: proc(info: ^Type_Info) -> bool {
 	if info == nil do return false;
 	if info == nil do return false;
-	_, ok := rt.type_info_base(info).variant.(rt.Type_Info_Array);
+	_, ok := type_info_base(info).variant.(Type_Info_Enumerated_Array);
 	return ok;
 	return ok;
 }
 }
-is_dynamic_array :: proc(info: ^rt.Type_Info) -> bool {
+is_dynamic_array :: proc(info: ^Type_Info) -> bool {
 	if info == nil do return false;
 	if info == nil do return false;
-	_, ok := rt.type_info_base(info).variant.(rt.Type_Info_Dynamic_Array);
+	_, ok := type_info_base(info).variant.(Type_Info_Dynamic_Array);
 	return ok;
 	return ok;
 }
 }
-is_dynamic_map :: proc(info: ^rt.Type_Info) -> bool {
+is_dynamic_map :: proc(info: ^Type_Info) -> bool {
 	if info == nil do return false;
 	if info == nil do return false;
-	_, ok := rt.type_info_base(info).variant.(rt.Type_Info_Map);
+	_, ok := type_info_base(info).variant.(Type_Info_Map);
 	return ok;
 	return ok;
 }
 }
-is_slice :: proc(info: ^rt.Type_Info) -> bool {
+is_slice :: proc(info: ^Type_Info) -> bool {
 	if info == nil do return false;
 	if info == nil do return false;
-	_, ok := rt.type_info_base(info).variant.(rt.Type_Info_Slice);
+	_, ok := type_info_base(info).variant.(Type_Info_Slice);
 	return ok;
 	return ok;
 }
 }
-is_tuple :: proc(info: ^rt.Type_Info) -> bool {
+is_tuple :: proc(info: ^Type_Info) -> bool {
 	if info == nil do return false;
 	if info == nil do return false;
-	_, ok := rt.type_info_base(info).variant.(rt.Type_Info_Tuple);
+	_, ok := type_info_base(info).variant.(Type_Info_Tuple);
 	return ok;
 	return ok;
 }
 }
-is_struct :: proc(info: ^rt.Type_Info) -> bool {
+is_struct :: proc(info: ^Type_Info) -> bool {
 	if info == nil do return false;
 	if info == nil do return false;
-	s, ok := rt.type_info_base(info).variant.(rt.Type_Info_Struct);
+	s, ok := type_info_base(info).variant.(Type_Info_Struct);
 	return ok && !s.is_raw_union;
 	return ok && !s.is_raw_union;
 }
 }
-is_raw_union :: proc(info: ^rt.Type_Info) -> bool {
+is_raw_union :: proc(info: ^Type_Info) -> bool {
 	if info == nil do return false;
 	if info == nil do return false;
-	s, ok := rt.type_info_base(info).variant.(rt.Type_Info_Struct);
+	s, ok := type_info_base(info).variant.(Type_Info_Struct);
 	return ok && s.is_raw_union;
 	return ok && s.is_raw_union;
 }
 }
-is_union :: proc(info: ^rt.Type_Info) -> bool {
+is_union :: proc(info: ^Type_Info) -> bool {
 	if info == nil do return false;
 	if info == nil do return false;
-	_, ok := rt.type_info_base(info).variant.(rt.Type_Info_Union);
+	_, ok := type_info_base(info).variant.(Type_Info_Union);
 	return ok;
 	return ok;
 }
 }
-is_enum :: proc(info: ^rt.Type_Info) -> bool {
+is_enum :: proc(info: ^Type_Info) -> bool {
 	if info == nil do return false;
 	if info == nil do return false;
-	_, ok := rt.type_info_base(info).variant.(rt.Type_Info_Enum);
+	_, ok := type_info_base(info).variant.(Type_Info_Enum);
 	return ok;
 	return ok;
 }
 }
-is_opaque :: proc(info: ^rt.Type_Info) -> bool {
+is_opaque :: proc(info: ^Type_Info) -> bool {
 	if info == nil do return false;
 	if info == nil do return false;
-	_, ok := rt.type_info_base(info).variant.(rt.Type_Info_Opaque);
+	_, ok := type_info_base(info).variant.(Type_Info_Opaque);
 	return ok;
 	return ok;
 }
 }
-is_simd_vector :: proc(info: ^rt.Type_Info) -> bool {
+is_simd_vector :: proc(info: ^Type_Info) -> bool {
 	if info == nil do return false;
 	if info == nil do return false;
-	_, ok := rt.type_info_base(info).variant.(rt.Type_Info_Simd_Vector);
+	_, ok := type_info_base(info).variant.(Type_Info_Simd_Vector);
 	return ok;
 	return ok;
 }
 }
 
 
@@ -301,11 +328,13 @@ is_simd_vector :: proc(info: ^rt.Type_Info) -> bool {
 
 
 
 
 
 
+
+
 write_typeid :: proc(buf: ^strings.Builder, id: typeid) {
 write_typeid :: proc(buf: ^strings.Builder, id: typeid) {
 	write_type(buf, type_info_of(id));
 	write_type(buf, type_info_of(id));
 }
 }
 
 
-write_type :: proc(buf: ^strings.Builder, ti: ^rt.Type_Info) {
+write_type :: proc(buf: ^strings.Builder, ti: ^Type_Info) {
 	using strings;
 	using strings;
 	if ti == nil {
 	if ti == nil {
 		write_string(buf, "nil");
 		write_string(buf, "nil");
@@ -313,9 +342,9 @@ write_type :: proc(buf: ^strings.Builder, ti: ^rt.Type_Info) {
 	}
 	}
 
 
 	switch info in ti.variant {
 	switch info in ti.variant {
-	case rt.Type_Info_Named:
+	case Type_Info_Named:
 		write_string(buf, info.name);
 		write_string(buf, info.name);
-	case rt.Type_Info_Integer:
+	case Type_Info_Integer:
 		switch ti.id {
 		switch ti.id {
 		case int:     write_string(buf, "int");
 		case int:     write_string(buf, "int");
 		case uint:    write_string(buf, "uint");
 		case uint:    write_string(buf, "uint");
@@ -329,49 +358,49 @@ write_type :: proc(buf: ^strings.Builder, ti: ^rt.Type_Info) {
 			case .Big:    write_string(buf, "be");
 			case .Big:    write_string(buf, "be");
 			}
 			}
 		}
 		}
-	case rt.Type_Info_Rune:
+	case Type_Info_Rune:
 		write_string(buf, "rune");
 		write_string(buf, "rune");
-	case rt.Type_Info_Float:
+	case Type_Info_Float:
 		write_byte(buf, 'f');
 		write_byte(buf, 'f');
 		write_i64(buf, i64(8*ti.size), 10);
 		write_i64(buf, i64(8*ti.size), 10);
-	case rt.Type_Info_Complex:
+	case Type_Info_Complex:
 		write_string(buf, "complex");
 		write_string(buf, "complex");
 		write_i64(buf, i64(8*ti.size), 10);
 		write_i64(buf, i64(8*ti.size), 10);
-	case rt.Type_Info_Quaternion:
+	case Type_Info_Quaternion:
 		write_string(buf, "quaternion");
 		write_string(buf, "quaternion");
 		write_i64(buf, i64(8*ti.size), 10);
 		write_i64(buf, i64(8*ti.size), 10);
-	case rt.Type_Info_String:
+	case Type_Info_String:
 		if info.is_cstring {
 		if info.is_cstring {
 			write_string(buf, "cstring");
 			write_string(buf, "cstring");
 		} else {
 		} else {
 			write_string(buf, "string");
 			write_string(buf, "string");
 		}
 		}
-	case rt.Type_Info_Boolean:
+	case Type_Info_Boolean:
 		switch ti.id {
 		switch ti.id {
 		case bool: write_string(buf, "bool");
 		case bool: write_string(buf, "bool");
 		case:
 		case:
 			write_byte(buf, 'b');
 			write_byte(buf, 'b');
 			write_i64(buf, i64(8*ti.size), 10);
 			write_i64(buf, i64(8*ti.size), 10);
 		}
 		}
-	case rt.Type_Info_Any:
+	case Type_Info_Any:
 		write_string(buf, "any");
 		write_string(buf, "any");
 
 
-	case rt.Type_Info_Type_Id:
+	case Type_Info_Type_Id:
 		write_string(buf, "typeid");
 		write_string(buf, "typeid");
 
 
-	case rt.Type_Info_Pointer:
+	case Type_Info_Pointer:
 		if info.elem == nil {
 		if info.elem == nil {
 			write_string(buf, "rawptr");
 			write_string(buf, "rawptr");
 		} else {
 		} else {
 			write_string(buf, "^");
 			write_string(buf, "^");
 			write_type(buf, info.elem);
 			write_type(buf, info.elem);
 		}
 		}
-	case rt.Type_Info_Procedure:
+	case Type_Info_Procedure:
 		write_string(buf, "proc");
 		write_string(buf, "proc");
 		if info.params == nil {
 		if info.params == nil {
 			write_string(buf, "()");
 			write_string(buf, "()");
 		} else {
 		} else {
-			t := info.params.variant.(rt.Type_Info_Tuple);
+			t := info.params.variant.(Type_Info_Tuple);
 			write_string(buf, "(");
 			write_string(buf, "(");
 			for t, i in t.types {
 			for t, i in t.types {
 				if i > 0 do write_string(buf, ", ");
 				if i > 0 do write_string(buf, ", ");
@@ -383,7 +412,7 @@ write_type :: proc(buf: ^strings.Builder, ti: ^rt.Type_Info) {
 			write_string(buf, " -> ");
 			write_string(buf, " -> ");
 			write_type(buf, info.results);
 			write_type(buf, info.results);
 		}
 		}
-	case rt.Type_Info_Tuple:
+	case Type_Info_Tuple:
 		count := len(info.names);
 		count := len(info.names);
 		if count != 1 do write_string(buf, "(");
 		if count != 1 do write_string(buf, "(");
 		for name, i in info.names {
 		for name, i in info.names {
@@ -399,32 +428,32 @@ write_type :: proc(buf: ^strings.Builder, ti: ^rt.Type_Info) {
 		}
 		}
 		if count != 1 do write_string(buf, ")");
 		if count != 1 do write_string(buf, ")");
 
 
-	case rt.Type_Info_Array:
+	case Type_Info_Array:
 		write_string(buf, "[");
 		write_string(buf, "[");
 		write_i64(buf, i64(info.count), 10);
 		write_i64(buf, i64(info.count), 10);
 		write_string(buf, "]");
 		write_string(buf, "]");
 		write_type(buf, info.elem);
 		write_type(buf, info.elem);
 
 
-	case rt.Type_Info_Enumerated_Array:
+	case Type_Info_Enumerated_Array:
 		write_string(buf, "[");
 		write_string(buf, "[");
 		write_type(buf, info.index);
 		write_type(buf, info.index);
 		write_string(buf, "]");
 		write_string(buf, "]");
 		write_type(buf, info.elem);
 		write_type(buf, info.elem);
 
 
-	case rt.Type_Info_Dynamic_Array:
+	case Type_Info_Dynamic_Array:
 		write_string(buf, "[dynamic]");
 		write_string(buf, "[dynamic]");
 		write_type(buf, info.elem);
 		write_type(buf, info.elem);
-	case rt.Type_Info_Slice:
+	case Type_Info_Slice:
 		write_string(buf, "[]");
 		write_string(buf, "[]");
 		write_type(buf, info.elem);
 		write_type(buf, info.elem);
 
 
-	case rt.Type_Info_Map:
+	case Type_Info_Map:
 		write_string(buf, "map[");
 		write_string(buf, "map[");
 		write_type(buf, info.key);
 		write_type(buf, info.key);
 		write_byte(buf, ']');
 		write_byte(buf, ']');
 		write_type(buf, info.value);
 		write_type(buf, info.value);
 
 
-	case rt.Type_Info_Struct:
+	case Type_Info_Struct:
 		switch info.soa_kind {
 		switch info.soa_kind {
 		case .None: // Ignore
 		case .None: // Ignore
 		case .Fixed:
 		case .Fixed:
@@ -460,7 +489,7 @@ write_type :: proc(buf: ^strings.Builder, ti: ^rt.Type_Info) {
 		}
 		}
 		write_byte(buf, '}');
 		write_byte(buf, '}');
 
 
-	case rt.Type_Info_Union:
+	case Type_Info_Union:
 		write_string(buf, "union ");
 		write_string(buf, "union ");
 		if info.custom_align {
 		if info.custom_align {
 			write_string(buf, "#align ");
 			write_string(buf, "#align ");
@@ -474,7 +503,7 @@ write_type :: proc(buf: ^strings.Builder, ti: ^rt.Type_Info) {
 		}
 		}
 		write_byte(buf, '}');
 		write_byte(buf, '}');
 
 
-	case rt.Type_Info_Enum:
+	case Type_Info_Enum:
 		write_string(buf, "enum ");
 		write_string(buf, "enum ");
 		write_type(buf, info.base);
 		write_type(buf, info.base);
 		write_string(buf, " {");
 		write_string(buf, " {");
@@ -484,7 +513,7 @@ write_type :: proc(buf: ^strings.Builder, ti: ^rt.Type_Info) {
 		}
 		}
 		write_byte(buf, '}');
 		write_byte(buf, '}');
 
 
-	case rt.Type_Info_Bit_Field:
+	case Type_Info_Bit_Field:
 		write_string(buf, "bit_field ");
 		write_string(buf, "bit_field ");
 		if ti.align != 1 {
 		if ti.align != 1 {
 			write_string(buf, "#align ");
 			write_string(buf, "#align ");
@@ -500,7 +529,7 @@ write_type :: proc(buf: ^strings.Builder, ti: ^rt.Type_Info) {
 		}
 		}
 		write_byte(buf, '}');
 		write_byte(buf, '}');
 
 
-	case rt.Type_Info_Bit_Set:
+	case Type_Info_Bit_Set:
 		write_string(buf, "bit_set[");
 		write_string(buf, "bit_set[");
 		switch {
 		switch {
 		case is_enum(info.elem):
 		case is_enum(info.elem):
@@ -520,11 +549,11 @@ write_type :: proc(buf: ^strings.Builder, ti: ^rt.Type_Info) {
 		}
 		}
 		write_byte(buf, ']');
 		write_byte(buf, ']');
 
 
-	case rt.Type_Info_Opaque:
+	case Type_Info_Opaque:
 		write_string(buf, "opaque ");
 		write_string(buf, "opaque ");
 		write_type(buf, info.elem);
 		write_type(buf, info.elem);
 
 
-	case rt.Type_Info_Simd_Vector:
+	case Type_Info_Simd_Vector:
 		if info.is_x86_mmx {
 		if info.is_x86_mmx {
 			write_string(buf, "intrinsics.x86_mmx");
 			write_string(buf, "intrinsics.x86_mmx");
 		} else {
 		} else {

+ 8 - 5
src/check_expr.cpp

@@ -5446,13 +5446,16 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32
 				switch (bt->Basic.kind) {
 				switch (bt->Basic.kind) {
 				case Basic_complex64:  operand->type = t_f32; break;
 				case Basic_complex64:  operand->type = t_f32; break;
 				case Basic_complex128: operand->type = t_f64; break;
 				case Basic_complex128: operand->type = t_f64; break;
+				case Basic_quaternion128: operand->type = t_f32; break;
+				case Basic_quaternion256: operand->type = t_f64; break;
 				}
 				}
 				break;
 				break;
-			case Type_Pointer:      operand->type = bt->Pointer.elem;      break;
-			case Type_Opaque:       operand->type = bt->Opaque.elem;       break;
-			case Type_Array:        operand->type = bt->Array.elem;        break;
-			case Type_Slice:        operand->type = bt->Slice.elem;        break;
-			case Type_DynamicArray: operand->type = bt->DynamicArray.elem; break;
+			case Type_Pointer:         operand->type = bt->Pointer.elem;         break;
+			case Type_Opaque:          operand->type = bt->Opaque.elem;          break;
+			case Type_Array:           operand->type = bt->Array.elem;           break;
+			case Type_EnumeratedArray: operand->type = bt->EnumeratedArray.elem; break;
+			case Type_Slice:           operand->type = bt->Slice.elem;           break;
+			case Type_DynamicArray:    operand->type = bt->DynamicArray.elem;    break;
 			}
 			}
 		}
 		}
 		operand->mode = Addressing_Type;
 		operand->mode = Addressing_Type;