aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorgingerBill <bill@gingerbill.org>2022-02-16 11:54:15 +0000
committergingerBill <bill@gingerbill.org>2022-02-16 11:54:15 +0000
commit65dedbb1caaa785a444d32a7a15adaf6c396b07f (patch)
tree37e749a36d79ad05c5e4097b319ae218ba87caac /src
parent0e69993d39e367a67911f361fde0ad2b58f6d4ea (diff)
Add `#subtype` struct field prefix, required to have a COM interface hierarchy
Diffstat (limited to 'src')
-rw-r--r--src/check_expr.cpp3
-rw-r--r--src/check_type.cpp18
-rw-r--r--src/entity.cpp5
-rw-r--r--src/parser.cpp4
-rw-r--r--src/parser.hpp3
-rw-r--r--src/types.cpp12
6 files changed, 37 insertions, 8 deletions
diff --git a/src/check_expr.cpp b/src/check_expr.cpp
index 7fb0e44f2..884f1bb9f 100644
--- a/src/check_expr.cpp
+++ b/src/check_expr.cpp
@@ -9774,6 +9774,9 @@ gbString write_expr_to_string(gbString str, Ast *node, bool shorthand) {
if (f->flags&FieldFlag_const) {
str = gb_string_appendc(str, "#const ");
}
+ if (f->flags&FieldFlag_subtype) {
+ str = gb_string_appendc(str, "#subtype ");
+ }
for_array(i, f->names) {
Ast *name = f->names[i];
diff --git a/src/check_type.cpp b/src/check_type.cpp
index 32340070e..7e0ad2bd9 100644
--- a/src/check_type.cpp
+++ b/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_subtype = (p->flags&FieldFlag_subtype) != 0;
for_array(j, p->names) {
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);
add_entity(ctx, ctx->scope, name, field);
field->Variable.field_group_index = field_group_index;
+ if (is_subtype) {
+ field->flags |= EntityFlag_Subtype;
+ }
if (j == 0) {
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);
}
+
+ 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);
diff --git a/src/entity.cpp b/src/entity.cpp
index df8ee3faa..f5720293f 100644
--- a/src/entity.cpp
+++ b/src/entity.cpp
@@ -74,6 +74,7 @@ enum EntityFlag : u64 {
EntityFlag_Test = 1ull<<30,
EntityFlag_Init = 1ull<<31,
+ EntityFlag_Subtype = 1ull<<32,
EntityFlag_CustomLinkName = 1ull<<40,
EntityFlag_CustomLinkage_Internal = 1ull<<41,
@@ -86,6 +87,10 @@ enum EntityFlag : u64 {
EntityFlag_Overridden = 1ull<<63,
};
+enum : u64 {
+ EntityFlags_IsSubtype = EntityFlag_Using|EntityFlag_Subtype,
+};
+
enum EntityState : u32 {
EntityState_Unresolved = 0,
EntityState_InProgress = 1,
diff --git a/src/parser.cpp b/src/parser.cpp
index 0914c77ca..b55d745f1 100644
--- a/src/parser.cpp
+++ b/src/parser.cpp
@@ -3504,12 +3504,13 @@ enum FieldPrefixKind : i32 {
FieldPrefix_Unknown = -1,
FieldPrefix_Invalid = 0,
- FieldPrefix_using,
+ FieldPrefix_using, // implies #subtype
FieldPrefix_const,
FieldPrefix_no_alias,
FieldPrefix_c_vararg,
FieldPrefix_auto_cast,
FieldPrefix_any_int,
+ FieldPrefix_subtype, // does not imply `using` semantics
};
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("const"), Token_Hash, FieldPrefix_const, FieldFlag_const},
{str_lit("any_int"), Token_Hash, FieldPrefix_any_int, FieldFlag_any_int},
+ {str_lit("subtype"), Token_Hash, FieldPrefix_subtype, FieldFlag_subtype},
};
diff --git a/src/parser.hpp b/src/parser.hpp
index ff0df0382..fb84210b3 100644
--- a/src/parser.hpp
+++ b/src/parser.hpp
@@ -282,6 +282,7 @@ enum FieldFlag : u32 {
FieldFlag_auto_cast = 1<<4,
FieldFlag_const = 1<<5,
FieldFlag_any_int = 1<<6,
+ FieldFlag_subtype = 1<<7,
// Internal use by the parser only
FieldFlag_Tags = 1<<10,
@@ -289,7 +290,7 @@ enum FieldFlag : u32 {
// Parameter List Restrictions
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 {
diff --git a/src/types.cpp b/src/types.cpp
index 78958146b..2c1e6162f 100644
--- a/src/types.cpp
+++ b/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));
for_array(i, src->Struct.fields) {
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)) {
return f->token.string;
}
@@ -2343,7 +2343,7 @@ String lookup_subtype_polymorphic_field(Type *dst, Type *src) {
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);
if (name.len > 0) {
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) {
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;
}
}
@@ -3813,7 +3813,7 @@ isize check_is_assignable_to_using_subtype(Type *src, Type *dst, isize level = 0
for_array(i, src->Struct.fields) {
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;
}