|
@@ -127,6 +127,7 @@ struct TypeUnion {
|
|
|
Scope *scope; \
|
|
|
}) \
|
|
|
TYPE_KIND(Pointer, struct { Type *elem; }) \
|
|
|
+ TYPE_KIND(Opaque, struct { Type *elem; }) \
|
|
|
TYPE_KIND(Array, struct { \
|
|
|
Type *elem; \
|
|
|
i64 count; \
|
|
@@ -400,6 +401,7 @@ gb_global Type *t_type_info_enum = nullptr;
|
|
|
gb_global Type *t_type_info_map = nullptr;
|
|
|
gb_global Type *t_type_info_bit_field = nullptr;
|
|
|
gb_global Type *t_type_info_bit_set = nullptr;
|
|
|
+gb_global Type *t_type_info_opaque = nullptr;
|
|
|
|
|
|
gb_global Type *t_type_info_named_ptr = nullptr;
|
|
|
gb_global Type *t_type_info_integer_ptr = nullptr;
|
|
@@ -423,6 +425,7 @@ gb_global Type *t_type_info_enum_ptr = nullptr;
|
|
|
gb_global Type *t_type_info_map_ptr = nullptr;
|
|
|
gb_global Type *t_type_info_bit_field_ptr = nullptr;
|
|
|
gb_global Type *t_type_info_bit_set_ptr = nullptr;
|
|
|
+gb_global Type *t_type_info_opaque_ptr = nullptr;
|
|
|
|
|
|
gb_global Type *t_allocator = nullptr;
|
|
|
gb_global Type *t_allocator_ptr = nullptr;
|
|
@@ -461,6 +464,19 @@ Type *base_type(Type *t) {
|
|
|
return t;
|
|
|
}
|
|
|
|
|
|
+Type *strip_opaque_type(Type *t) {
|
|
|
+ for (;;) {
|
|
|
+ if (t == nullptr) {
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ if (t->kind != Type_Opaque) {
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ t = t->Opaque.elem;
|
|
|
+ }
|
|
|
+ return t;
|
|
|
+}
|
|
|
+
|
|
|
Type *base_enum_type(Type *t) {
|
|
|
Type *bt = base_type(t);
|
|
|
if (bt != nullptr &&
|
|
@@ -486,6 +502,9 @@ Type *core_type(Type *t) {
|
|
|
case Type_Enum:
|
|
|
t = t->Enum.base_type;
|
|
|
continue;
|
|
|
+ case Type_Opaque:
|
|
|
+ t = t->Opaque.elem;
|
|
|
+ continue;
|
|
|
}
|
|
|
break;
|
|
|
}
|
|
@@ -519,6 +538,12 @@ Type *alloc_type_generic(Scope *scope, i64 id, String name, Type *specialized) {
|
|
|
return t;
|
|
|
}
|
|
|
|
|
|
+Type *alloc_type_opaque(Type *elem) {
|
|
|
+ Type *t = alloc_type(Type_Opaque);
|
|
|
+ t->Opaque.elem = elem;
|
|
|
+ return t;
|
|
|
+}
|
|
|
+
|
|
|
Type *alloc_type_pointer(Type *elem) {
|
|
|
Type *t = alloc_type(Type_Pointer);
|
|
|
t->Pointer.elem = elem;
|
|
@@ -819,8 +844,10 @@ bool is_type_tuple(Type *t) {
|
|
|
t = base_type(t);
|
|
|
return t->kind == Type_Tuple;
|
|
|
}
|
|
|
-
|
|
|
-
|
|
|
+bool is_type_opaque(Type *t) {
|
|
|
+ t = base_type(t);
|
|
|
+ return t->kind == Type_Opaque;
|
|
|
+}
|
|
|
bool is_type_uintptr(Type *t) {
|
|
|
if (t->kind == Type_Basic) {
|
|
|
return (t->Basic.kind == Basic_uintptr);
|
|
@@ -1212,6 +1239,8 @@ bool type_has_nil(Type *t) {
|
|
|
return true;
|
|
|
case Type_Struct:
|
|
|
return false;
|
|
|
+ case Type_Opaque:
|
|
|
+ return true;
|
|
|
}
|
|
|
return false;
|
|
|
}
|
|
@@ -1257,6 +1286,9 @@ bool is_type_comparable(Type *t) {
|
|
|
|
|
|
case Type_BitSet:
|
|
|
return true;
|
|
|
+
|
|
|
+ case Type_Opaque:
|
|
|
+ return is_type_comparable(t->Opaque.elem);
|
|
|
}
|
|
|
return false;
|
|
|
}
|
|
@@ -1294,6 +1326,12 @@ bool are_types_identical(Type *x, Type *y) {
|
|
|
}
|
|
|
break;
|
|
|
|
|
|
+ case Type_Opaque:
|
|
|
+ if (y->kind == Type_Opaque) {
|
|
|
+ return are_types_identical(x->Opaque.elem, y->Opaque.elem);
|
|
|
+ }
|
|
|
+ break;
|
|
|
+
|
|
|
case Type_Basic:
|
|
|
if (y->kind == Type_Basic) {
|
|
|
return x->Basic.kind == y->Basic.kind;
|
|
@@ -2061,6 +2099,9 @@ i64 type_align_of_internal(Type *t, TypePath *path) {
|
|
|
return align;
|
|
|
}
|
|
|
|
|
|
+ case Type_Opaque:
|
|
|
+ return type_align_of_internal(t->Opaque.elem, path);
|
|
|
+
|
|
|
case Type_DynamicArray:
|
|
|
// data, count, capacity, allocator
|
|
|
return build_context.word_size;
|
|
@@ -2265,6 +2306,9 @@ i64 type_size_of_internal(Type *t, TypePath *path) {
|
|
|
case Type_Pointer:
|
|
|
return build_context.word_size;
|
|
|
|
|
|
+ case Type_Opaque:
|
|
|
+ return type_size_of_internal(t->Opaque.elem, path);
|
|
|
+
|
|
|
case Type_Array: {
|
|
|
i64 count, align, size, alignment;
|
|
|
count = t->Array.count;
|