|
@@ -528,13 +528,21 @@ gb_internal void check_type_decl(CheckerContext *ctx, Entity *e, Ast *init_expr,
|
|
|
e->TypeName.objc_class_name = ac.objc_class;
|
|
|
e->TypeName.objc_superclass = ac.objc_superclass;
|
|
|
e->TypeName.objc_ivar = ac.objc_ivar;
|
|
|
+ e->TypeName.objc_context_provider = ac.objc_context_provider;
|
|
|
|
|
|
if (ac.objc_is_implementation) {
|
|
|
e->TypeName.objc_is_implementation = true;
|
|
|
- mpsc_enqueue(&ctx->info->objc_class_implementations, e); // TODO(harold): Don't need this for anything. Remove.
|
|
|
+ mpsc_enqueue(&ctx->info->objc_class_implementations, e); // TODO(harold): Don't need this for anything? See if needed when using explicit @export
|
|
|
|
|
|
GB_ASSERT(e->TypeName.objc_ivar == nullptr || e->TypeName.objc_ivar->kind == Type_Named);
|
|
|
|
|
|
+ // Enqueue the proc to be checked when resolved
|
|
|
+ if (e->TypeName.objc_context_provider != nullptr) {
|
|
|
+ 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.
|
|
|
+ // See about moving this to the right location.
|
|
|
// Ensure superclass hierarchy are all Objective-C classes and does not cycle
|
|
|
Type *super = ac.objc_superclass;
|
|
|
if (super != nullptr) {
|
|
@@ -571,8 +579,14 @@ gb_internal void check_type_decl(CheckerContext *ctx, Entity *e, Ast *init_expr,
|
|
|
check_single_global_entity(ctx->checker, super->Named.type_name, super->Named.type_name->decl_info);
|
|
|
}
|
|
|
}
|
|
|
- } else if (e->TypeName.objc_superclass != nullptr) {
|
|
|
- error(e->token, "@(objc_superclass) can only be applied when the obj_implement attribute is also applied");
|
|
|
+ } else {
|
|
|
+ if (e->TypeName.objc_superclass != nullptr) {
|
|
|
+ error(e->token, "@(objc_superclass) can only be applied when the @(obj_implement) attribute is also applied");
|
|
|
+ } else if (e->TypeName.objc_ivar != nullptr) {
|
|
|
+ error(e->token, "@(objc_ivar) can only be applied when the @(obj_implement) attribute is also applied");
|
|
|
+ } else if (e->TypeName.objc_context_provider != nullptr) {
|
|
|
+ error(e->token, "@(objc_context_provider) can only be applied when the @(obj_implement) attribute is also applied");
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
if (type_size_of(e->type) > 0) {
|
|
@@ -994,25 +1008,33 @@ gb_internal void check_objc_methods(CheckerContext *ctx, Entity *e, AttributeCon
|
|
|
if (ac.objc_is_implementation) {
|
|
|
GB_ASSERT(e->kind == Entity_Procedure);
|
|
|
|
|
|
- CheckerInfo *info = ctx->info;
|
|
|
- mutex_lock(&info->objc_method_mutex);
|
|
|
- defer (mutex_unlock(&info->objc_method_mutex));
|
|
|
-
|
|
|
- auto method = ObjcMethodData{ ac, e };
|
|
|
-
|
|
|
- if (ac.objc_selector == "") {
|
|
|
- method.ac.objc_selector = ac.objc_name;
|
|
|
- }
|
|
|
-
|
|
|
- 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);
|
|
|
- }
|
|
|
+ Type *proc_type = e->type;
|
|
|
+
|
|
|
+ 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");
|
|
|
+ } else if (proc_type->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");
|
|
|
+ } else if (ac.objc_is_class_method && proc_type->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");
|
|
|
+ } else {
|
|
|
+
|
|
|
+ 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);
|
|
|
+ }
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
mutex_lock(&global_type_name_objc_metadata_mutex);
|