aboutsummaryrefslogtreecommitdiff
path: root/src/check_type.cpp
diff options
context:
space:
mode:
authorgingerBill <bill@gingerbill.org>2018-08-24 22:28:00 +0100
committergingerBill <bill@gingerbill.org>2018-08-24 22:28:00 +0100
commit0a85d1af6b290d30bc4c171df5fddfef3d09bed6 (patch)
tree246c43366127269cf66168a5060bb58d76096003 /src/check_type.cpp
parent68adadb01a2cb07fba2640afb1d52afc7dc820ee (diff)
Improve error messages for using on fields
Diffstat (limited to 'src/check_type.cpp')
-rw-r--r--src/check_type.cpp71
1 files changed, 67 insertions, 4 deletions
diff --git a/src/check_type.cpp b/src/check_type.cpp
index b6d99772e..28f3d539d 100644
--- a/src/check_type.cpp
+++ b/src/check_type.cpp
@@ -1,5 +1,32 @@
-void populate_using_entity_scope(CheckerContext *ctx, Ast *node, Type *t) {
+void populate_using_array_index(CheckerContext *ctx, Ast *node, AstField *field, Type *t, String name, i32 idx) {
+ t = base_type(t);
+ GB_ASSERT(t->kind == Type_Array);
+ Entity *e = scope_lookup_current(ctx->scope, name);
+ if (e != nullptr) {
+ gbString str = nullptr;
+ defer (gb_string_free(str));
+ if (node != nullptr) {
+ str = expr_to_string(node);
+ }
+ if (str != nullptr) {
+ error(e->token, "'%.*s' is already declared in '%s'", LIT(name), str);
+ } else {
+ error(e->token, "'%.*s' is already declared", LIT(name));
+ }
+ } else {
+ Token tok = make_token_ident(name);
+ if (field->names.count > 0) {
+ tok.pos = ast_token(field->names[0]).pos;
+ } else {
+ tok.pos = ast_token(field->type).pos;
+ }
+ Entity *f = alloc_entity_array_elem(nullptr, tok, t->Array.elem, idx);
+ add_entity(ctx->checker, ctx->scope, nullptr, f);
+ }
+}
+
+void populate_using_entity_scope(CheckerContext *ctx, Ast *node, AstField *field, Type *t) {
t = base_type(type_deref(t));
gbString str = nullptr;
defer (gb_string_free(str));
@@ -11,7 +38,7 @@ void populate_using_entity_scope(CheckerContext *ctx, Ast *node, Type *t) {
for_array(i, t->Struct.fields) {
Entity *f = t->Struct.fields[i];
GB_ASSERT(f->kind == Entity_Variable);
- String name = f->token.string;;
+ String name = f->token.string;
Entity *e = scope_lookup_current(ctx->scope, name);
if (e != nullptr && name != "_") {
// TODO(bill): Better type error
@@ -23,10 +50,46 @@ void populate_using_entity_scope(CheckerContext *ctx, Ast *node, Type *t) {
} else {
add_entity(ctx->checker, ctx->scope, nullptr, f);
if (f->flags & EntityFlag_Using) {
- populate_using_entity_scope(ctx, node, f->type);
+ populate_using_entity_scope(ctx, node, field, f->type);
+ }
+ }
+ }
+ } else if (t->kind == Type_BitField) {
+ for_array(i, t->BitField.fields) {
+ Entity *f = t->BitField.fields[i];
+ String name = f->token.string;
+ Entity *e = scope_lookup_current(ctx->scope, name);
+ if (e != nullptr && name != "_") {
+ // TODO(bill): Better type error
+ if (str != nullptr) {
+ error(e->token, "'%.*s' is already declared in '%s'", LIT(name), str);
+ } else {
+ error(e->token, "'%.*s' is already declared", LIT(name));
}
+ } else {
+ add_entity(ctx->checker, ctx->scope, nullptr, f);
}
}
+ } else if (t->kind == Type_Array && t->Array.count <= 4) {
+ Entity *e = nullptr;
+ String name = {};
+ i32 idx = 0;
+ switch (t->Array.count) {
+ case 4:
+ populate_using_array_index(ctx, node, field, t, str_lit("w"), 3);
+ /*fallthrough*/
+ case 3:
+ populate_using_array_index(ctx, node, field, t, str_lit("z"), 2);
+ /*fallthrough*/
+ case 2:
+ populate_using_array_index(ctx, node, field, t, str_lit("y"), 1);
+ /*fallthrough*/
+ case 1:
+ populate_using_array_index(ctx, node, field, t, str_lit("x"), 0);
+ /*fallthrough*/
+ default:
+ break;
+ }
}
}
@@ -122,7 +185,7 @@ void check_struct_fields(CheckerContext *ctx, Ast *node, Array<Entity *> *fields
continue;
}
- populate_using_entity_scope(ctx, node, type);
+ populate_using_entity_scope(ctx, node, p, type);
}
}
}