aboutsummaryrefslogtreecommitdiff
path: root/src/check_expr.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/check_expr.cpp')
-rw-r--r--src/check_expr.cpp75
1 files changed, 70 insertions, 5 deletions
diff --git a/src/check_expr.cpp b/src/check_expr.cpp
index 7fb0e44f2..614da2368 100644
--- a/src/check_expr.cpp
+++ b/src/check_expr.cpp
@@ -132,6 +132,62 @@ void check_did_you_mean_print(DidYouMeanAnswers *d, char const *prefix = "") {
}
}
+void populate_check_did_you_mean_objc_entity(StringSet *set, Entity *e, bool is_type) {
+ if (e->kind != Entity_TypeName) {
+ return;
+ }
+ if (e->TypeName.objc_metadata == nullptr) {
+ return;
+ }
+ TypeNameObjCMetadata *objc_metadata = e->TypeName.objc_metadata;
+ Type *t = base_type(e->type);
+ GB_ASSERT(t->kind == Type_Struct);
+
+ if (is_type) {
+ for_array(i, objc_metadata->type_entries) {
+ String name = objc_metadata->type_entries[i].name;
+ string_set_add(set, name);
+ }
+ } else {
+ for_array(i, objc_metadata->value_entries) {
+ String name = objc_metadata->value_entries[i].name;
+ string_set_add(set, name);
+ }
+ }
+
+ for_array(i, t->Struct.fields) {
+ Entity *f = t->Struct.fields[i];
+ if (f->flags & EntityFlag_Using && f->type != nullptr) {
+ if (f->type->kind == Type_Named && f->type->Named.type_name) {
+ populate_check_did_you_mean_objc_entity(set, f->type->Named.type_name, is_type);
+ }
+ }
+ }
+}
+
+
+void check_did_you_mean_objc_entity(String const &name, Entity *e, bool is_type, char const *prefix = "") {
+ ERROR_BLOCK();
+ GB_ASSERT(e->kind == Entity_TypeName);
+ GB_ASSERT(e->TypeName.objc_metadata != nullptr);
+ auto *objc_metadata = e->TypeName.objc_metadata;
+ mutex_lock(objc_metadata->mutex);
+ defer (mutex_unlock(objc_metadata->mutex));
+
+ StringSet set = {};
+ string_set_init(&set, heap_allocator());
+ defer (string_set_destroy(&set));
+ populate_check_did_you_mean_objc_entity(&set, e, is_type);
+
+
+ DidYouMeanAnswers d = did_you_mean_make(heap_allocator(), set.entries.count, name);
+ defer (did_you_mean_destroy(&d));
+ for_array(i, set.entries) {
+ did_you_mean_append(&d, set.entries[i].value);
+ }
+ check_did_you_mean_print(&d, prefix);
+}
+
void check_did_you_mean_type(String const &name, Array<Entity *> const &fields, char const *prefix = "") {
ERROR_BLOCK();
@@ -144,6 +200,7 @@ void check_did_you_mean_type(String const &name, Array<Entity *> const &fields,
check_did_you_mean_print(&d, prefix);
}
+
void check_did_you_mean_type(String const &name, Slice<Entity *> const &fields, char const *prefix = "") {
ERROR_BLOCK();
@@ -4413,14 +4470,19 @@ Entity *check_selector(CheckerContext *c, Operand *operand, Ast *node, Type *typ
if (entity == nullptr) {
gbString op_str = expr_to_string(op_expr);
- gbString type_str = type_to_string(operand->type);
+ gbString type_str = type_to_string_shorthand(operand->type);
gbString sel_str = expr_to_string(selector);
error(op_expr, "'%s' of type '%s' has no field '%s'", op_str, type_str, sel_str);
if (operand->type != nullptr && selector->kind == Ast_Ident) {
String const &name = selector->Ident.token.string;
Type *bt = base_type(operand->type);
- if (bt->kind == Type_Struct) {
+ if (operand->type->kind == Type_Named &&
+ operand->type->Named.type_name &&
+ operand->type->Named.type_name->kind == Entity_TypeName &&
+ operand->type->Named.type_name->TypeName.objc_metadata) {
+ check_did_you_mean_objc_entity(name, operand->type->Named.type_name, operand->mode == Addressing_Type);
+ } else if (bt->kind == Type_Struct) {
check_did_you_mean_type(name, bt->Struct.fields);
} else if (bt->kind == Type_Enum) {
check_did_you_mean_type(name, bt->Enum.fields);
@@ -4449,7 +4511,7 @@ Entity *check_selector(CheckerContext *c, Operand *operand, Ast *node, Type *typ
}
gbString op_str = expr_to_string(op_expr);
- gbString type_str = type_to_string(operand->type);
+ gbString type_str = type_to_string_shorthand(operand->type);
gbString sel_str = expr_to_string(selector);
error(op_expr, "Cannot access non-constant field '%s' from '%s'", sel_str, op_str);
gb_string_free(sel_str);
@@ -4474,7 +4536,7 @@ Entity *check_selector(CheckerContext *c, Operand *operand, Ast *node, Type *typ
}
gbString op_str = expr_to_string(op_expr);
- gbString type_str = type_to_string(operand->type);
+ gbString type_str = type_to_string_shorthand(operand->type);
gbString sel_str = expr_to_string(selector);
error(op_expr, "Cannot access non-constant field '%s' from '%s'", sel_str, op_str);
gb_string_free(sel_str);
@@ -4487,7 +4549,7 @@ Entity *check_selector(CheckerContext *c, Operand *operand, Ast *node, Type *typ
if (expr_entity != nullptr && is_type_polymorphic(expr_entity->type)) {
gbString op_str = expr_to_string(op_expr);
- gbString type_str = type_to_string(operand->type);
+ gbString type_str = type_to_string_shorthand(operand->type);
gbString sel_str = expr_to_string(selector);
error(op_expr, "Cannot access field '%s' from non-specialized polymorphic type '%s'", sel_str, op_str);
gb_string_free(sel_str);
@@ -9774,6 +9836,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];