Browse Source

`opaque` keyword and type

gingerBill 6 years ago
parent
commit
b55b1ffe14
13 changed files with 177 additions and 5 deletions
  1. 51 0
      core/fmt/fmt.odin
  2. 6 0
      core/runtime/core.odin
  3. 10 1
      core/types/types.odin
  4. 3 0
      src/check_decl.cpp
  5. 12 0
      src/check_expr.cpp
  6. 7 0
      src/check_type.cpp
  7. 6 0
      src/checker.cpp
  8. 10 2
      src/ir.cpp
  9. 4 0
      src/ir_print.cpp
  10. 17 0
      src/parser.cpp
  11. 4 0
      src/parser.hpp
  12. 1 0
      src/tokenizer.cpp
  13. 46 2
      src/types.cpp

+ 51 - 0
core/fmt/fmt.odin

@@ -409,6 +409,11 @@ write_type :: proc(buf: ^String_Buffer, ti: ^runtime.Type_Info) {
 			write_type(buf, info.underlying);
 		}
 		write_byte(buf, ']');
+
+	case runtime.Type_Info_Opaque:
+		write_string(buf, "opaque ");
+		write_type(buf, info.elem);
+
 	}
 }
 
@@ -927,6 +932,47 @@ fmt_bit_field :: proc(fi: ^Fmt_Info, v: any, name: string = "") {
 	}
 }
 
+fmt_opaque :: proc(fi: ^Fmt_Info, v: any) {
+	is_nil :: proc(data: rawptr, n: int) -> bool {
+		if data == nil do return true;
+		if n == 0 do return true;
+
+		a := (^byte)(data);
+		for i in 0..n-1 do if mem.ptr_offset(a, i)^ != 0 {
+			return false;
+		}
+		return true;
+	}
+
+	rt :: runtime;
+
+	type_info := type_info_of(v.id);
+
+	if is_nil(v.data, type_info.size) {
+		write_string(fi.buf, "nil");
+		return;
+	}
+
+	if ot, ok := rt.type_info_base(type_info).variant.(rt.Type_Info_Opaque); ok {
+		elem := rt.type_info_base(ot.elem);
+		if elem == nil do return;
+		write_type(fi.buf, type_info);
+		write_byte(fi.buf, '{');
+		defer write_byte(fi.buf, '}');
+
+		switch in elem.variant {
+		case rt.Type_Info_Integer, rt.Type_Info_Pointer, rt.Type_Info_Float:
+			fmt_value(fi, any{v.data, elem.id}, 'v');
+		case:
+			// Okay
+		}
+	} else {
+		write_type(fi.buf, type_info);
+		write_byte(fi.buf, '{');
+		defer write_byte(fi.buf, '}');
+	}
+}
+
 fmt_value :: proc(fi: ^Fmt_Info, v: any, verb: rune) {
 	if v.data == nil || v.id == nil {
 		write_string(fi.buf, "<nil>");
@@ -986,6 +1032,8 @@ fmt_value :: proc(fi: ^Fmt_Info, v: any, verb: rune) {
 			fmt_bit_set(fi, v);
 		case runtime.Type_Info_Bit_Field:
 			fmt_bit_field(fi, v);
+		case runtime.Type_Info_Opaque:
+			fmt_opaque(fi, v);
 		case:
 			fmt_value(fi, any{v.data, info.base.id}, verb);
 		}
@@ -1158,6 +1206,9 @@ fmt_value :: proc(fi: ^Fmt_Info, v: any, verb: rune) {
 
 	case runtime.Type_Info_Bit_Set:
 		fmt_bit_set(fi, v);
+
+	case runtime.Type_Info_Opaque:
+		fmt_opaque(fi, v);
 	}
 }
 

+ 6 - 0
core/runtime/core.odin

@@ -107,6 +107,10 @@ Type_Info_Bit_Set :: struct {
 	upper:      i64,
 };
 
+Type_Info_Opaque :: struct {
+	elem: ^Type_Info,
+}
+
 Type_Info :: struct {
 	size:  int,
 	align: int,
@@ -134,6 +138,7 @@ Type_Info :: struct {
 		Type_Info_Map,
 		Type_Info_Bit_Field,
 		Type_Info_Bit_Set,
+		Type_Info_Opaque,
 	},
 }
 
@@ -160,6 +165,7 @@ Typeid_Kind :: enum u8 {
 	Map,
 	Bit_Field,
 	Bit_Set,
+	Opaque,
 }
 
 Typeid_Bit_Field :: bit_field #align align_of(uintptr) {

+ 10 - 1
core/types/types.odin

@@ -154,12 +154,16 @@ are_types_identical :: proc(a, b: ^rt.Type_Info) -> bool {
 		y, ok := b.variant.(rt.Type_Info_Bit_Set);
 		if !ok do return false;
 		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);
+		if !ok do return false;
+		return x.elem == y.elem;
 	}
 
 	return false;
 }
 
-
 is_signed :: proc(info: ^rt.Type_Info) -> bool {
 	if info == nil do return false;
 	switch i in rt.type_info_base(info).variant {
@@ -258,3 +262,8 @@ is_enum :: proc(info: ^rt.Type_Info) -> bool {
 	_, ok := rt.type_info_base(info).variant.(rt.Type_Info_Enum);
 	return ok;
 }
+is_opaque :: proc(info: ^rt.Type_Info) -> bool {
+	if info == nil do return false;
+	_, ok := rt.type_info_base(info).variant.(rt.Type_Info_Opaque);
+	return ok;
+}

+ 3 - 0
src/check_decl.cpp

@@ -198,6 +198,9 @@ bool is_type_distinct(Ast *node) {
 	case Ast_DynamicArrayType:
 	case Ast_MapType:
 		return false;
+
+	case Ast_OpaqueType:
+		return true;
 	}
 	return false;
 }

+ 12 - 0
src/check_expr.cpp

@@ -1911,6 +1911,13 @@ bool check_is_castable_to(CheckerContext *c, Operand *operand, Type *y) {
 		return true;
 	}
 
+	if (is_type_opaque(src)) {
+		return are_types_identical(dst, src->Opaque.elem);
+	}
+	if (is_type_opaque(dst)) {
+		return are_types_identical(dst->Opaque.elem, src);
+	}
+
 	return false;
 }
 
@@ -6602,6 +6609,11 @@ gbString write_expr_to_string(gbString str, Ast *node) {
 		str = write_expr_to_string(str, ht->type);
 	case_end;
 
+	case_ast_node(ht, OpaqueType, node);
+		str = gb_string_appendc(str, "opaque ");
+		str = write_expr_to_string(str, ht->type);
+	case_end;
+
 	case_ast_node(pt, PolyType, node);
 		str = gb_string_append_rune(str, '$');
 		str = write_expr_to_string(str, pt->type);

+ 7 - 0
src/check_type.cpp

@@ -2341,6 +2341,13 @@ bool check_type_internal(CheckerContext *ctx, Ast *e, Type **type, Type *named_t
 		return true;
 	case_end;
 
+	case_ast_node(ot, OpaqueType, e);
+		Type *elem = strip_opaque_type(check_type(ctx, ot->type));
+		*type = alloc_type_opaque(elem);
+		set_base_type(named_type, *type);
+		return true;
+	case_end;
+
 	case_ast_node(at, ArrayType, e);
 		if (at->count != nullptr) {
 			Operand o = {};

+ 6 - 0
src/checker.cpp

@@ -1064,6 +1064,10 @@ void add_type_info_type(CheckerContext *c, Type *t) {
 		add_type_info_type(c, bt->BitSet.elem);
 		break;
 
+	case Type_Opaque:
+		add_type_info_type(c, bt->Opaque.elem);
+		break;
+
 	case Type_Union:
 		add_type_info_type(c, t_int);
 		add_type_info_type(c, t_type_info_ptr);
@@ -1626,6 +1630,7 @@ void init_core_type_info(Checker *c) {
 	t_type_info_map           = find_core_type(c, str_lit("Type_Info_Map"));
 	t_type_info_bit_field     = find_core_type(c, str_lit("Type_Info_Bit_Field"));
 	t_type_info_bit_set       = find_core_type(c, str_lit("Type_Info_Bit_Set"));
+	t_type_info_opaque        = find_core_type(c, str_lit("Type_Info_Opaque"));
 
 	t_type_info_named_ptr         = alloc_type_pointer(t_type_info_named);
 	t_type_info_integer_ptr       = alloc_type_pointer(t_type_info_integer);
@@ -1648,6 +1653,7 @@ void init_core_type_info(Checker *c) {
 	t_type_info_map_ptr           = alloc_type_pointer(t_type_info_map);
 	t_type_info_bit_field_ptr     = alloc_type_pointer(t_type_info_bit_field);
 	t_type_info_bit_set_ptr       = alloc_type_pointer(t_type_info_bit_set);
+	t_type_info_opaque_ptr        = alloc_type_pointer(t_type_info_opaque);
 }
 
 void init_mem_allocator(Checker *c) {

+ 10 - 2
src/ir.cpp

@@ -2273,6 +2273,10 @@ irDebugInfo *ir_add_debug_info_type(irModule *module, Type *type, Entity *e, irD
 		return di;
 	}
 
+	if (is_type_opaque(type)) {
+		return ir_add_debug_info_type(module, strip_opaque_type(type), e, scope, file);
+	}
+
 	if (is_type_struct(type) ||
 	    is_type_union(type) || is_type_enum(type) || is_type_tuple(type)) {
 		if (type->kind == Type_Named) {
@@ -9455,10 +9459,14 @@ void ir_setup_type_info_data(irProcedure *proc) { // NOTE(bill): Setup type_info
 			ir_emit_store(proc, ir_emit_struct_ep(proc, tag, 3), ir_const_i64(t->BitSet.upper));
 			break;
 
-
-
+		case Type_Opaque:
+			ir_emit_comment(proc, str_lit("Type_Opaque"));
+			tag = ir_emit_conv(proc, variant_ptr, t_type_info_opaque_ptr);
+			ir_emit_store(proc, ir_emit_struct_ep(proc, tag, 0), ir_get_type_info_ptr(proc, t->Opaque.elem));
+			break;
 		}
 
+
 		if (tag != nullptr) {
 			Type *tag_type = type_deref(ir_type(tag));
 			GB_ASSERT(is_type_named(tag_type));

+ 4 - 0
src/ir_print.cpp

@@ -512,6 +512,10 @@ void ir_print_type(irFileBuffer *f, irModule *m, Type *t, bool in_struct) {
 		ir_print_type(f, m, bit_set_to_int(t));
 		return;
 	}
+
+	case Type_Opaque:
+		ir_print_type(f, m, strip_opaque_type(t));
+		return;
 	}
 }
 

+ 17 - 0
src/parser.cpp

@@ -80,6 +80,7 @@ Token ast_token(Ast *node) {
 	case Ast_TypeidType:       return node->TypeidType.token;
 	case Ast_HelperType:       return node->HelperType.token;
 	case Ast_DistinctType:     return node->DistinctType.token;
+	case Ast_OpaqueType:       return node->OpaqueType.token;
 	case Ast_PolyType:         return node->PolyType.token;
 	case Ast_ProcType:         return node->ProcType.token;
 	case Ast_PointerType:      return node->PointerType.token;
@@ -319,6 +320,9 @@ Ast *clone_ast(Ast *node) {
 	case Ast_DistinctType:
 		n->DistinctType.type = clone_ast(n->DistinctType.type);
 		break;
+	case Ast_OpaqueType:
+		n->OpaqueType.type = clone_ast(n->OpaqueType.type);
+		break;
 	case Ast_ProcType:
 		n->ProcType.params  = clone_ast(n->ProcType.params);
 		n->ProcType.results = clone_ast(n->ProcType.results);
@@ -849,6 +853,13 @@ Ast *ast_distinct_type(AstFile *f, Token token, Ast *type) {
 	return result;
 }
 
+Ast *ast_opaque_type(AstFile *f, Token token, Ast *type) {
+	Ast *result = alloc_ast_node(f, Ast_OpaqueType);
+	result->OpaqueType.token = token;
+	result->OpaqueType.type  = type;
+	return result;
+}
+
 Ast *ast_poly_type(AstFile *f, Token token, Ast *type, Ast *specialization) {
 	Ast *result = alloc_ast_node(f, Ast_PolyType);
 	result->PolyType.token = token;
@@ -1654,6 +1665,12 @@ Ast *parse_operand(AstFile *f, bool lhs) {
 		return ast_distinct_type(f, token, type);
 	}
 
+	case Token_opaque: {
+		Token token = expect_token(f, Token_opaque);
+		Ast *type = parse_type(f);
+		return ast_opaque_type(f, token, type);
+	}
+
 	case Token_Hash: {
 		Token token = expect_token(f, Token_Hash);
 		Token name = expect_token(f, Token_Ident);

+ 4 - 0
src/parser.hpp

@@ -434,6 +434,10 @@ AST_KIND(_TypeBegin, "", bool) \
 		Token token; \
 		Ast *type; \
 	}) \
+	AST_KIND(OpaqueType, "opaque type", struct { \
+		Token token; \
+		Ast *type; \
+	}) \
 	AST_KIND(PolyType, "polymorphic type", struct { \
 		Token token; \
 		Ast * type;  \

+ 1 - 0
src/tokenizer.cpp

@@ -113,6 +113,7 @@ TOKEN_KIND(Token__KeywordBegin, ""), \
 	TOKEN_KIND(Token_cast,        "cast"),        \
 	TOKEN_KIND(Token_transmute,   "transmute"),   \
 	TOKEN_KIND(Token_distinct,    "distinct"),    \
+	TOKEN_KIND(Token_opaque,      "opaque"),      \
 	TOKEN_KIND(Token_using,       "using"),       \
 	TOKEN_KIND(Token_inline,      "inline"),      \
 	TOKEN_KIND(Token_no_inline,   "no_inline"),   \

+ 46 - 2
src/types.cpp

@@ -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;