mirror of
https://github.com/Ed94/Odin.git
synced 2026-08-06 07:38:48 +00:00
Resolve other TODOs
This commit is contained in:
+92
-93
@@ -551,7 +551,7 @@ gb_internal void check_type_decl(CheckerContext *ctx, Entity *e, Ast *init_expr,
|
|||||||
mpsc_enqueue(&ctx->checker->procs_with_objc_context_provider_to_check, e);
|
mpsc_enqueue(&ctx->checker->procs_with_objc_context_provider_to_check, e);
|
||||||
}
|
}
|
||||||
|
|
||||||
// @TODO(harold): I think there's a Check elsewhere in the checker for checking cycles.
|
// TODO(harold): I think there's a Check elsewhere in the checker for checking cycles.
|
||||||
// See about moving this to the right location.
|
// See about moving this to the right location.
|
||||||
// Ensure superclass hierarchy are all Objective-C classes and does not cycle
|
// Ensure superclass hierarchy are all Objective-C classes and does not cycle
|
||||||
|
|
||||||
@@ -1013,107 +1013,106 @@ gb_internal void check_objc_methods(CheckerContext *ctx, Entity *e, AttributeCon
|
|||||||
} else {
|
} else {
|
||||||
Type *t = ac.objc_type;
|
Type *t = ac.objc_type;
|
||||||
|
|
||||||
if (t->kind == Type_Named) { // TODO(harold): Shouldn't this be an error otherwise? Or is it checked elsehwere?
|
GB_ASSERT(t->kind == Type_Named); // NOTE(harold): This is already checked for at the attribute resolution stage.
|
||||||
Entity *tn = t->Named.type_name;
|
Entity *tn = t->Named.type_name;
|
||||||
|
|
||||||
GB_ASSERT(tn->kind == Entity_TypeName);
|
GB_ASSERT(tn->kind == Entity_TypeName);
|
||||||
|
|
||||||
if (tn->scope != e->scope) {
|
if (tn->scope != e->scope) {
|
||||||
error(e->token, "@(objc_name) attribute may only be applied to procedures and types within the same scope");
|
error(e->token, "@(objc_name) attribute may only be applied to procedures and types within the same scope");
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
// Enable implementation by default if the class is an implementer too and
|
// Enable implementation by default if the class is an implementer too and
|
||||||
// @objc_implement was not set to false explicitly in this proc.
|
// @objc_implement was not set to false explicitly in this proc.
|
||||||
bool implement = tn->TypeName.objc_is_implementation;
|
bool implement = tn->TypeName.objc_is_implementation;
|
||||||
if (ac.objc_is_disabled_implement) {
|
if (ac.objc_is_disabled_implement) {
|
||||||
implement = false;
|
implement = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (implement) {
|
if (implement) {
|
||||||
GB_ASSERT(e->kind == Entity_Procedure);
|
GB_ASSERT(e->kind == Entity_Procedure);
|
||||||
|
|
||||||
auto &proc = e->type->Proc;
|
auto &proc = e->type->Proc;
|
||||||
Type *first_param = proc.param_count > 0 ? proc.params->Tuple.variables[0]->type : t_untyped_nil;
|
Type *first_param = proc.param_count > 0 ? proc.params->Tuple.variables[0]->type : t_untyped_nil;
|
||||||
|
|
||||||
if (!tn->TypeName.objc_is_implementation) {
|
if (!tn->TypeName.objc_is_implementation) {
|
||||||
error(e->token, "@(objc_is_implement) attribute may only be applied to procedures whose class also have @(objc_is_implement) applied");
|
error(e->token, "@(objc_is_implement) attribute may only be applied to procedures whose class also have @(objc_is_implement) applied");
|
||||||
} else if (!ac.objc_is_class_method && !(first_param->kind == Type_Pointer && internal_check_is_assignable_to(t, first_param->Pointer.elem))) {
|
} else if (!ac.objc_is_class_method && !(first_param->kind == Type_Pointer && internal_check_is_assignable_to(t, first_param->Pointer.elem))) {
|
||||||
error(e->token, "Objective-C instance methods implementations require the first parameter to be a pointer to the class type set by @(objc_type)");
|
error(e->token, "Objective-C instance methods implementations require the first parameter to be a pointer to the class type set by @(objc_type)");
|
||||||
} else if (proc.calling_convention == ProcCC_Odin && !tn->TypeName.objc_context_provider) {
|
} else if (proc.calling_convention == ProcCC_Odin && !tn->TypeName.objc_context_provider) {
|
||||||
error(e->token, "Objective-C methods with Odin calling convention can only be used with classes that have @(objc_context_provider) set");
|
error(e->token, "Objective-C methods with Odin calling convention can only be used with classes that have @(objc_context_provider) set");
|
||||||
} else if (ac.objc_is_class_method && proc.calling_convention != ProcCC_CDecl) {
|
} else if (ac.objc_is_class_method && proc.calling_convention != ProcCC_CDecl) {
|
||||||
error(e->token, "Objective-C class methods (objc_is_class_method=true) that have @objc_is_implementation can only use \"c\" calling convention");
|
error(e->token, "Objective-C class methods (objc_is_class_method=true) that have @objc_is_implementation can only use \"c\" calling convention");
|
||||||
} else if (proc.result_count > 1) {
|
} else if (proc.result_count > 1) {
|
||||||
error(e->token, "Objective-C method implementations may return at most 1 value");
|
error(e->token, "Objective-C method implementations may return at most 1 value");
|
||||||
} else {
|
|
||||||
// Always export unconditionally
|
|
||||||
// NOTE(harold): This means check_objc_methods() MUST be called before
|
|
||||||
// e->Procedure.is_export is set in check_proc_decl()!
|
|
||||||
if (ac.is_export) {
|
|
||||||
error(e->token, "Explicit export not allowed when @(objc_implement) is set. It set exported implicitly");
|
|
||||||
}
|
|
||||||
if (ac.link_name != "") {
|
|
||||||
error(e->token, "Explicit linkage not allowed when @(objc_implement) is set. It set to \"strong\" implicitly");
|
|
||||||
}
|
|
||||||
|
|
||||||
ac.is_export = true;
|
|
||||||
ac.linkage = STR_LIT("strong");
|
|
||||||
|
|
||||||
auto method = ObjcMethodData{ ac, e };
|
|
||||||
method.ac.objc_selector = ac.objc_selector != "" ? ac.objc_selector : ac.objc_name;
|
|
||||||
|
|
||||||
CheckerInfo *info = ctx->info;
|
|
||||||
mutex_lock(&info->objc_method_mutex);
|
|
||||||
defer (mutex_unlock(&info->objc_method_mutex));
|
|
||||||
|
|
||||||
Array<ObjcMethodData>* method_list = map_get(&info->objc_method_implementations, t);
|
|
||||||
if (method_list) {
|
|
||||||
array_add(method_list, method);
|
|
||||||
} else {
|
|
||||||
auto list = array_make<ObjcMethodData>(permanent_allocator(), 1, 8);
|
|
||||||
list[0] = method;
|
|
||||||
|
|
||||||
map_set(&info->objc_method_implementations, t, list);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else if (ac.objc_selector != "") {
|
|
||||||
error(e->token, "@(objc_selector) may only be applied to procedures that are Objective-C implementations.");
|
|
||||||
}
|
|
||||||
|
|
||||||
mutex_lock(&global_type_name_objc_metadata_mutex);
|
|
||||||
defer (mutex_unlock(&global_type_name_objc_metadata_mutex));
|
|
||||||
|
|
||||||
if (!tn->TypeName.objc_metadata) {
|
|
||||||
tn->TypeName.objc_metadata = create_type_name_obj_c_metadata();
|
|
||||||
}
|
|
||||||
auto *md = tn->TypeName.objc_metadata;
|
|
||||||
mutex_lock(md->mutex);
|
|
||||||
defer (mutex_unlock(md->mutex));
|
|
||||||
|
|
||||||
if (!ac.objc_is_class_method) {
|
|
||||||
bool ok = true;
|
|
||||||
for (TypeNameObjCMetadataEntry const &entry : md->value_entries) {
|
|
||||||
if (entry.name == ac.objc_name) {
|
|
||||||
error(e->token, "Previous declaration of @(objc_name=\"%.*s\")", LIT(ac.objc_name));
|
|
||||||
ok = false;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (ok) {
|
|
||||||
array_add(&md->value_entries, TypeNameObjCMetadataEntry{ac.objc_name, e});
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
bool ok = true;
|
// Always export unconditionally
|
||||||
for (TypeNameObjCMetadataEntry const &entry : md->type_entries) {
|
// NOTE(harold): This means check_objc_methods() MUST be called before
|
||||||
if (entry.name == ac.objc_name) {
|
// e->Procedure.is_export is set in check_proc_decl()!
|
||||||
error(e->token, "Previous declaration of @(objc_name=\"%.*s\")", LIT(ac.objc_name));
|
if (ac.is_export) {
|
||||||
ok = false;
|
error(e->token, "Explicit export not allowed when @(objc_implement) is set. It set exported implicitly");
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (ok) {
|
if (ac.link_name != "") {
|
||||||
array_add(&md->type_entries, TypeNameObjCMetadataEntry{ac.objc_name, e});
|
error(e->token, "Explicit linkage not allowed when @(objc_implement) is set. It set to \"strong\" implicitly");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ac.is_export = true;
|
||||||
|
ac.linkage = STR_LIT("strong");
|
||||||
|
|
||||||
|
auto method = ObjcMethodData{ ac, e };
|
||||||
|
method.ac.objc_selector = ac.objc_selector != "" ? ac.objc_selector : ac.objc_name;
|
||||||
|
|
||||||
|
CheckerInfo *info = ctx->info;
|
||||||
|
mutex_lock(&info->objc_method_mutex);
|
||||||
|
defer (mutex_unlock(&info->objc_method_mutex));
|
||||||
|
|
||||||
|
Array<ObjcMethodData>* method_list = map_get(&info->objc_method_implementations, t);
|
||||||
|
if (method_list) {
|
||||||
|
array_add(method_list, method);
|
||||||
|
} else {
|
||||||
|
auto list = array_make<ObjcMethodData>(permanent_allocator(), 1, 8);
|
||||||
|
list[0] = method;
|
||||||
|
|
||||||
|
map_set(&info->objc_method_implementations, t, list);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (ac.objc_selector != "") {
|
||||||
|
error(e->token, "@(objc_selector) may only be applied to procedures that are Objective-C implementations.");
|
||||||
|
}
|
||||||
|
|
||||||
|
mutex_lock(&global_type_name_objc_metadata_mutex);
|
||||||
|
defer (mutex_unlock(&global_type_name_objc_metadata_mutex));
|
||||||
|
|
||||||
|
if (!tn->TypeName.objc_metadata) {
|
||||||
|
tn->TypeName.objc_metadata = create_type_name_obj_c_metadata();
|
||||||
|
}
|
||||||
|
auto *md = tn->TypeName.objc_metadata;
|
||||||
|
mutex_lock(md->mutex);
|
||||||
|
defer (mutex_unlock(md->mutex));
|
||||||
|
|
||||||
|
if (!ac.objc_is_class_method) {
|
||||||
|
bool ok = true;
|
||||||
|
for (TypeNameObjCMetadataEntry const &entry : md->value_entries) {
|
||||||
|
if (entry.name == ac.objc_name) {
|
||||||
|
error(e->token, "Previous declaration of @(objc_name=\"%.*s\")", LIT(ac.objc_name));
|
||||||
|
ok = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (ok) {
|
||||||
|
array_add(&md->value_entries, TypeNameObjCMetadataEntry{ac.objc_name, e});
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
bool ok = true;
|
||||||
|
for (TypeNameObjCMetadataEntry const &entry : md->type_entries) {
|
||||||
|
if (entry.name == ac.objc_name) {
|
||||||
|
error(e->token, "Previous declaration of @(objc_name=\"%.*s\")", LIT(ac.objc_name));
|
||||||
|
ok = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (ok) {
|
||||||
|
array_add(&md->type_entries, TypeNameObjCMetadataEntry{ac.objc_name, e});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1173,7 +1173,6 @@ gb_internal lbProcedure *lb_create_objc_names(lbModule *main_module) {
|
|||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO(harold): Perhaps move this out of here and into a more suitable place?
|
|
||||||
String lb_get_objc_type_encoding(Type *t, isize pointer_depth = 0) {
|
String lb_get_objc_type_encoding(Type *t, isize pointer_depth = 0) {
|
||||||
// NOTE(harold): See https://developer.apple.com/library/archive/documentation/Cocoa/Conceptual/ObjCRuntimeGuide/Articles/ocrtTypeEncodings.html#//apple_ref/doc/uid/TP40008048-CH100
|
// NOTE(harold): See https://developer.apple.com/library/archive/documentation/Cocoa/Conceptual/ObjCRuntimeGuide/Articles/ocrtTypeEncodings.html#//apple_ref/doc/uid/TP40008048-CH100
|
||||||
|
|
||||||
@@ -1424,6 +1423,7 @@ String lb_get_objc_type_encoding(Type *t, isize pointer_depth = 0) {
|
|||||||
#undef INT_SIZE_ENCODING
|
#undef INT_SIZE_ENCODING
|
||||||
|
|
||||||
GB_PANIC("Unreachable");
|
GB_PANIC("Unreachable");
|
||||||
|
return str_lit("");
|
||||||
}
|
}
|
||||||
|
|
||||||
struct lbObjCGlobalClass {
|
struct lbObjCGlobalClass {
|
||||||
@@ -1778,7 +1778,10 @@ gb_internal void lb_finalize_objc_names(lbGenerator *gen, lbProcedure *p) {
|
|||||||
const i64 size = type_size_of(ivar_base);
|
const i64 size = type_size_of(ivar_base);
|
||||||
const i64 alignment = (i64)floor_log2((u64)type_align_of(ivar_base));
|
const i64 alignment = (i64)floor_log2((u64)type_align_of(ivar_base));
|
||||||
|
|
||||||
// TODO(harold): Should we pass the actual type encoding? Might not be ideal for obfuscation.
|
// NOTE(harold): I've opted to not emit the type encoding for ivars in order to keep the data private.
|
||||||
|
// If there is desire in the future to emit the type encoding for introspection through the Obj-C runtime,
|
||||||
|
// then perhaps an option can be added for it then.
|
||||||
|
// Should we pass the actual type encoding? Might not be ideal for obfuscation.
|
||||||
String ivar_name = str_lit("__$ivar");
|
String ivar_name = str_lit("__$ivar");
|
||||||
String ivar_types = str_lit("{= }"); //lb_get_objc_type_encoding(ivar_type);
|
String ivar_types = str_lit("{= }"); //lb_get_objc_type_encoding(ivar_type);
|
||||||
args.count = 5;
|
args.count = 5;
|
||||||
|
|||||||
Reference in New Issue
Block a user