Odin
Odin copied to clipboard
Compile Error when using `objc_send` on an Objective-C subclass created at runtime.
Context
Odin: dev-2022-10:29f2ecd2
OS: macOS Monterey 12.5 (build: 21G115, kernel: 21.6.0)
CPU: Intel(R) Core(TM) i9-9980HK CPU @ 2.40GHz
RAM: 32768 MiB
Minimal example (subclassing/subclassing.odin
):
// Compile and run with: odin run .
package main
@require foreign import "system:Cocoa.framework"
import "core:fmt"
import "core:intrinsics"
import "core:runtime"
foreign import "system:Foundation.framework"
Class :: ^intrinsics.objc_class
id :: ^intrinsics.objc_object
SEL :: ^intrinsics.objc_selector
BOOL :: bool
IMP :: proc "c" (object: id, sel: SEL, #c_vararg args: ..any) -> id
foreign Foundation {
objc_allocateClassPair :: proc "c" (superclass : Class, name : cstring, /* size_t */ extraBytes : uint) -> Class ---
objc_registerClassPair :: proc "c" (cls : Class) ---
object_getClass :: proc "c" (obj : id) -> Class ---
class_addMethod :: proc "c" (cls: Class, name: SEL, imp: IMP, types: cstring) -> BOOL ---
}
on_test :: proc "c" (self : id, cmd: SEL) {
context = runtime.default_context();
fmt.println("Test Called")
}
main :: proc () {
nsViewClass := intrinsics.objc_find_class("NSView")
newClass := objc_allocateClassPair(nsViewClass, "CustomView", 0)
testSel := intrinsics.objc_find_selector("test")
class_addMethod(newClass, testSel, auto_cast on_test, "v@:v");
objc_registerClassPair(newClass)
allocedClass := intrinsics.objc_send(id, newClass, "alloc")
initedClass := intrinsics.objc_send(id, allocedClass, "init")
isFlipped := intrinsics.objc_send(bool, initedClass, "isFlipped")
fmt.printf("Class: %v IsFlipped: %v", initedClass, isFlipped)
intrinsics.objc_send(nil, initedClass, "test")
}
Expected Behavior
I expect the program to compile and run without errors. The output should be:
Class: 7fdb5a907320 IsFlipped: 0
Test Called
Current Behavior
subclassing/subclassing.odin(39:46) 'objc_send' expected a type or value derived from intrinsics.objc_object, got 'newClass' of type ^objc_class
subclassing/subclassing.odin(40:45) 'objc_send' expected a type or value derived from intrinsics.objc_object, got 'allocedClass' of type invalid type
subclassing/subclassing.odin(41:45) 'objc_send' expected a type or value derived from intrinsics.objc_object, got 'initedClass' of type invalid type
subclassing/subclassing.odin(43:31) 'objc_send' expected a type or value derived from intrinsics.objc_object, got 'initedClass' of type invalid type
Failure Information (for bugs)
This C program has the expected behavior:
// Compile and run with: clang subclassing.c -framework Cocoa; ./a.out
#include <objc/runtime.h>
#include <objc/message.h>
#include <stdio.h>
#define cls objc_getClass
#define sel sel_getUid
typedef id (*object_message_send)(id, SEL, ...);
typedef id (*class_message_send)(Class, SEL, ...);
#define msg ((object_message_send)objc_msgSend)
#define cls_msg ((class_message_send)objc_msgSend)
void on_test(id self, SEL cmd) {
printf("Test Called\n");
}
int main(void) {
Class nsViewClass = objc_lookUpClass("NSView");
Class newClass = objc_allocateClassPair(nsViewClass, "CustomView", 0);
// Class metaclass = object_getClass(newClass); // The headers say to use class_addMethod on this, but that doesn't seem to work.
SEL test_sel = sel("test");
class_addMethod(newClass, test_sel, (IMP) on_test, "v@:v");
objc_registerClassPair(newClass);
id allocedClass = cls_msg(newClass, sel("alloc"));
id initedClass = msg(allocedClass, sel("init"));
bool isFlipped = msg(initedClass, sel("isFlipped"));
printf("Class: %lx IsFlipped: %d\n", (uintptr_t)initedClass, isFlipped);
msg(initedClass, test_sel);
return 0;
}
Steps to Reproduce
Compile and run the provided example program with odin run .
.