Bläddra i källkod

[objc] Add casts to field accesses and calls when the resulting type is objc

Since all objective-c types are boxed into Dynamic as the same type,
this cast is needed in order to make sure the type is restored.
This will only kick in if `is_objc_type` is true, which only happens on
`@:objc` types.
Cauê Waneck 10 år sedan
förälder
incheckning
09258320d1
2 ändrade filer med 33 tillägg och 3 borttagningar
  1. 18 1
      gencpp.ml
  2. 15 2
      tests/misc/cppObjc/TestObjc.hx

+ 18 - 1
gencpp.ml

@@ -1836,6 +1836,19 @@ and gen_expression ctx retval expression =
      else
         expression
    in
+   let add_objc_cast_if_needed expression =
+      (* objc-specific: since all NSObject derived types are boxed to the same type,
+         we need to take one extra care when unboxing, and cast them to their
+         actual type *)
+      let is_cast =
+         retval && is_objc_type expression.etype && is_dynamic_in_cpp ctx expression
+      in
+      if is_cast then begin
+         output ("( (" ^ (type_string expression.etype) ^ ") (NSObject *) (");
+         ") )";
+      end else
+         ""
+   in
 
    let rec gen_bin_op_string expr1 op expr2 =
       let cast = (match op with
@@ -2109,6 +2122,7 @@ and gen_expression ctx retval expression =
       error "addressOf must take a local or member variable" expression.epos;
 
    | TCall (func, arg_list) ->
+      let after_cast = add_objc_cast_if_needed expression in
       let rec is_variable e = match e.eexpr with
       | TField _ | TEnumParameter _ -> false
       | TLocal { v_name = "__global__" } -> false
@@ -2184,6 +2198,7 @@ and gen_expression ctx retval expression =
             | _ -> ()
       in
       cast_array_output func;
+      output after_cast
 
    | TBlock expr_list ->
       if (retval) then
@@ -2299,7 +2314,9 @@ and gen_expression ctx retval expression =
       gen_expression ctx true expr;
       output ( "))->__Param(" ^ (string_of_int i) ^ ")")
    | TField (field_object,field) ->
-      gen_tfield field_object field
+      let after_cast = add_objc_cast_if_needed expression in
+      gen_tfield field_object field;
+      output after_cast
 
    | TParenthesis expr when not retval ->
          gen_expression ctx retval expr;

+ 15 - 2
tests/misc/cppObjc/TestObjc.hx

@@ -3,9 +3,7 @@ class TestObjc extends haxe.unit.TestCase
 	static function main()
 	{
 		var x:TestObjc = null;
-		trace(x);
 		var c:TestClass = null;
-		trace(c);
 		var runner = new haxe.unit.TestRunner();
 		runner.add(new TestObjc());
 		var code = runner.run() ? 0 : 1;
@@ -55,6 +53,15 @@ class TestObjc extends haxe.unit.TestCase
 		var dyn:Dynamic = cls;
 		this.assertTrue(dyn != null);
 		this.assertTrue(cls != null);
+
+		var someObjDecl = { a:10, b: cls };
+		dyn = someObjDecl; // don't let Haxe inline that TObjectDecl
+		assertEquals(someObjDecl.b.getOtherThing(), 255);
+		assertEquals(getFieldB(someObjDecl).getOtherThing(), 255);
+		cls = someObjDecl.b;
+		assertTrue(someObjDecl.b == cls);
+		dyn = cls;
+
 		cls.release();
 		cls = null;
 		this.assertTrue(cls == null);
@@ -65,9 +72,14 @@ class TestObjc extends haxe.unit.TestCase
 		dyn = null;
 		dyn = cls;
 		assertTrue(dyn == null);
+		assertEquals(dyn,null);
 		assertTrue(dyn == cls);
+		assertEquals(dyn,cls);
 	}
 
+	static function getFieldB<T>(d:{ a:Int, b: T }):T
+		return d.b;
+
 	public function testNull()
 	{
 		this.assertTrue(TestClass.isNull(null));
@@ -102,6 +114,7 @@ class TestObjc extends haxe.unit.TestCase
 	function isBiggerThan10Int(integer:Int):Bool;
 
 	function release():Void;
+	function retainCount():Int;
 
 	@:plain static function some_c_call(t:TestClass):Int;
 	@:plain static function is_bigger_than_10(t:TestClass, val:Int):Bool;