Browse Source

Add `#subtype` struct field prefix, required to have a COM interface hierarchy

gingerBill 3 years ago
parent
commit
65dedbb1ca
6 changed files with 37 additions and 8 deletions
  1. 3 0
      src/check_expr.cpp
  2. 18 0
      src/check_type.cpp
  3. 5 0
      src/entity.cpp
  4. 3 1
      src/parser.cpp
  5. 2 1
      src/parser.hpp
  6. 6 6
      src/types.cpp

+ 3 - 0
src/check_expr.cpp

@@ -9774,6 +9774,9 @@ gbString write_expr_to_string(gbString str, Ast *node, bool shorthand) {
 		if (f->flags&FieldFlag_const) {
 		if (f->flags&FieldFlag_const) {
 			str = gb_string_appendc(str, "#const ");
 			str = gb_string_appendc(str, "#const ");
 		}
 		}
+		if (f->flags&FieldFlag_subtype) {
+			str = gb_string_appendc(str, "#subtype ");
+		}
 
 
 		for_array(i, f->names) {
 		for_array(i, f->names) {
 			Ast *name = f->names[i];
 			Ast *name = f->names[i];

+ 18 - 0
src/check_type.cpp

@@ -144,6 +144,7 @@ void check_struct_fields(CheckerContext *ctx, Ast *node, Slice<Entity *> *fields
 		}
 		}
 
 
 		bool is_using = (p->flags&FieldFlag_using) != 0;
 		bool is_using = (p->flags&FieldFlag_using) != 0;
+		bool is_subtype = (p->flags&FieldFlag_subtype) != 0;
 
 
 		for_array(j, p->names) {
 		for_array(j, p->names) {
 			Ast *name = p->names[j];
 			Ast *name = p->names[j];
@@ -158,6 +159,9 @@ void check_struct_fields(CheckerContext *ctx, Ast *node, Slice<Entity *> *fields
 			Entity *field = alloc_entity_field(ctx->scope, name_token, type, is_using, field_src_index);
 			Entity *field = alloc_entity_field(ctx->scope, name_token, type, is_using, field_src_index);
 			add_entity(ctx, ctx->scope, name, field);
 			add_entity(ctx, ctx->scope, name, field);
 			field->Variable.field_group_index = field_group_index;
 			field->Variable.field_group_index = field_group_index;
+			if (is_subtype) {
+				field->flags |= EntityFlag_Subtype;
+			}
 
 
 			if (j == 0) {
 			if (j == 0) {
 				field->Variable.docs = docs;
 				field->Variable.docs = docs;
@@ -194,6 +198,20 @@ void check_struct_fields(CheckerContext *ctx, Ast *node, Slice<Entity *> *fields
 
 
 			populate_using_entity_scope(ctx, node, p, type);
 			populate_using_entity_scope(ctx, node, p, type);
 		}
 		}
+
+		if (is_subtype && p->names.count > 0) {
+			Type *first_type = fields_array[fields_array.count-1]->type;
+			Type *t = base_type(type_deref(first_type));
+
+			if (!does_field_type_allow_using(t) &&
+			    p->names.count >= 1 &&
+			    p->names[0]->kind == Ast_Ident) {
+				Token name_token = p->names[0]->Ident.token;
+				gbString type_str = type_to_string(first_type);
+				error(name_token, "'subtype' cannot be applied to the field '%.*s' of type '%s'", LIT(name_token.string), type_str);
+				gb_string_free(type_str);
+			}
+		}
 	}
 	}
 	
 	
 	*fields = slice_from_array(fields_array);
 	*fields = slice_from_array(fields_array);

+ 5 - 0
src/entity.cpp

@@ -74,6 +74,7 @@ enum EntityFlag : u64 {
 
 
 	EntityFlag_Test          = 1ull<<30,
 	EntityFlag_Test          = 1ull<<30,
 	EntityFlag_Init          = 1ull<<31,
 	EntityFlag_Init          = 1ull<<31,
+	EntityFlag_Subtype       = 1ull<<32,
 	
 	
 	EntityFlag_CustomLinkName = 1ull<<40,
 	EntityFlag_CustomLinkName = 1ull<<40,
 	EntityFlag_CustomLinkage_Internal = 1ull<<41,
 	EntityFlag_CustomLinkage_Internal = 1ull<<41,
@@ -86,6 +87,10 @@ enum EntityFlag : u64 {
 	EntityFlag_Overridden    = 1ull<<63,
 	EntityFlag_Overridden    = 1ull<<63,
 };
 };
 
 
+enum : u64 {
+	EntityFlags_IsSubtype = EntityFlag_Using|EntityFlag_Subtype,
+};
+
 enum EntityState : u32 {
 enum EntityState : u32 {
 	EntityState_Unresolved = 0,
 	EntityState_Unresolved = 0,
 	EntityState_InProgress = 1,
 	EntityState_InProgress = 1,

+ 3 - 1
src/parser.cpp

@@ -3504,12 +3504,13 @@ enum FieldPrefixKind : i32 {
 	FieldPrefix_Unknown = -1,
 	FieldPrefix_Unknown = -1,
 	FieldPrefix_Invalid = 0,
 	FieldPrefix_Invalid = 0,
 
 
-	FieldPrefix_using,
+	FieldPrefix_using, // implies #subtype
 	FieldPrefix_const,
 	FieldPrefix_const,
 	FieldPrefix_no_alias,
 	FieldPrefix_no_alias,
 	FieldPrefix_c_vararg,
 	FieldPrefix_c_vararg,
 	FieldPrefix_auto_cast,
 	FieldPrefix_auto_cast,
 	FieldPrefix_any_int,
 	FieldPrefix_any_int,
+	FieldPrefix_subtype, // does not imply `using` semantics
 };
 };
 
 
 struct ParseFieldPrefixMapping {
 struct ParseFieldPrefixMapping {
@@ -3526,6 +3527,7 @@ gb_global ParseFieldPrefixMapping parse_field_prefix_mappings[] = {
 	{str_lit("c_vararg"),   Token_Hash,      FieldPrefix_c_vararg,  FieldFlag_c_vararg},
 	{str_lit("c_vararg"),   Token_Hash,      FieldPrefix_c_vararg,  FieldFlag_c_vararg},
 	{str_lit("const"),      Token_Hash,      FieldPrefix_const,     FieldFlag_const},
 	{str_lit("const"),      Token_Hash,      FieldPrefix_const,     FieldFlag_const},
 	{str_lit("any_int"),    Token_Hash,      FieldPrefix_any_int,   FieldFlag_any_int},
 	{str_lit("any_int"),    Token_Hash,      FieldPrefix_any_int,   FieldFlag_any_int},
+	{str_lit("subtype"),    Token_Hash,      FieldPrefix_subtype,   FieldFlag_subtype},
 };
 };
 
 
 
 

+ 2 - 1
src/parser.hpp

@@ -282,6 +282,7 @@ enum FieldFlag : u32 {
 	FieldFlag_auto_cast = 1<<4,
 	FieldFlag_auto_cast = 1<<4,
 	FieldFlag_const     = 1<<5,
 	FieldFlag_const     = 1<<5,
 	FieldFlag_any_int   = 1<<6,
 	FieldFlag_any_int   = 1<<6,
+	FieldFlag_subtype   = 1<<7,
 
 
 	// Internal use by the parser only
 	// Internal use by the parser only
 	FieldFlag_Tags      = 1<<10,
 	FieldFlag_Tags      = 1<<10,
@@ -289,7 +290,7 @@ enum FieldFlag : u32 {
 
 
 	// Parameter List Restrictions
 	// Parameter List Restrictions
 	FieldFlag_Signature = FieldFlag_ellipsis|FieldFlag_using|FieldFlag_no_alias|FieldFlag_c_vararg|FieldFlag_auto_cast|FieldFlag_const|FieldFlag_any_int,
 	FieldFlag_Signature = FieldFlag_ellipsis|FieldFlag_using|FieldFlag_no_alias|FieldFlag_c_vararg|FieldFlag_auto_cast|FieldFlag_const|FieldFlag_any_int,
-	FieldFlag_Struct    = FieldFlag_using|FieldFlag_Tags,
+	FieldFlag_Struct    = FieldFlag_using|FieldFlag_subtype|FieldFlag_Tags,
 };
 };
 
 
 enum StmtAllowFlag {
 enum StmtAllowFlag {

+ 6 - 6
src/types.cpp

@@ -2334,7 +2334,7 @@ String lookup_subtype_polymorphic_field(Type *dst, Type *src) {
 	GB_ASSERT(is_type_struct(src) || is_type_union(src));
 	GB_ASSERT(is_type_struct(src) || is_type_union(src));
 	for_array(i, src->Struct.fields) {
 	for_array(i, src->Struct.fields) {
 		Entity *f = src->Struct.fields[i];
 		Entity *f = src->Struct.fields[i];
-		if (f->kind == Entity_Variable && f->flags & EntityFlag_Using) {
+		if (f->kind == Entity_Variable && f->flags & EntityFlags_IsSubtype) {
 			if (are_types_identical(dst, f->type)) {
 			if (are_types_identical(dst, f->type)) {
 				return f->token.string;
 				return f->token.string;
 			}
 			}
@@ -2343,7 +2343,7 @@ String lookup_subtype_polymorphic_field(Type *dst, Type *src) {
 					return f->token.string;
 					return f->token.string;
 				}
 				}
 			}
 			}
-			if (is_type_struct(f->type)) {
+			if ((f->flags & EntityFlag_Using) != 0 && is_type_struct(f->type)) {
 				String name = lookup_subtype_polymorphic_field(dst, f->type);
 				String name = lookup_subtype_polymorphic_field(dst, f->type);
 				if (name.len > 0) {
 				if (name.len > 0) {
 					return name;
 					return name;
@@ -2489,9 +2489,9 @@ bool are_types_identical_internal(Type *x, Type *y, bool check_tuple_names) {
 					if (xf->token.string != yf->token.string) {
 					if (xf->token.string != yf->token.string) {
 						return false;
 						return false;
 					}
 					}
-					bool xf_is_using = (xf->flags&EntityFlag_Using) != 0;
-					bool yf_is_using = (yf->flags&EntityFlag_Using) != 0;
-					if (xf_is_using ^ yf_is_using) {
+					u64 xf_flags = (xf->flags&EntityFlags_IsSubtype);
+					u64 yf_flags = (yf->flags&EntityFlags_IsSubtype);
+					if (xf_flags != yf_flags) {
 						return false;
 						return false;
 					}
 					}
 				}
 				}
@@ -3813,7 +3813,7 @@ isize check_is_assignable_to_using_subtype(Type *src, Type *dst, isize level = 0
 
 
 	for_array(i, src->Struct.fields) {
 	for_array(i, src->Struct.fields) {
 		Entity *f = src->Struct.fields[i];
 		Entity *f = src->Struct.fields[i];
-		if (f->kind != Entity_Variable || (f->flags&EntityFlag_Using) == 0) {
+		if (f->kind != Entity_Variable || (f->flags&EntityFlags_IsSubtype) == 0) {
 			continue;
 			continue;
 		}
 		}