Browse Source

only create runtime fields for properties which have a default or @:isVar set

Nicolas Cannasse 12 years ago
parent
commit
85a19f22a2
11 changed files with 113 additions and 30 deletions
  1. 4 3
      genjs.ml
  2. 2 3
      genneko.ml
  3. 2 2
      genswf8.ml
  4. 12 11
      genswf9.ml
  5. 1 0
      std/flash8/_std/Type.hx
  6. 58 1
      tests/unit/MyClass.hx
  7. 9 9
      tests/unit/TestDCE.hx
  8. 1 1
      tests/unit/TestMisc.hx
  9. 17 0
      tests/unit/TestType.hx
  10. 6 0
      type.ml
  11. 1 0
      typer.ml

+ 4 - 3
genjs.ml

@@ -897,6 +897,8 @@ let gen_class_static_field ctx c f =
 	match f.cf_expr with
 	| None | Some { eexpr = TConst TNull } when not (has_feature ctx "Type.getClassFields") ->
 		()
+	| None when is_extern_field f ->
+		()
 	| None ->
 		print ctx "%s%s = null" (s_path ctx c.cl_path) (static_field f.cf_name);
 		newline ctx
@@ -914,11 +916,10 @@ let gen_class_static_field ctx c f =
 			ctx.statics <- (c,f.cf_name,e) :: ctx.statics
 
 let can_gen_class_field ctx = function
-	| { cf_kind = Var { v_read = AccResolve } } -> false
 	| { cf_expr = (None | Some { eexpr = TConst TNull }) } when not (has_feature ctx "Type.getInstanceFields") ->
 		false
-	| _ ->
-		true
+	| f ->
+		not (is_extern_field f)
 
 let gen_class_field ctx c f =
 	check_field_name c f;

+ 2 - 3
genneko.ml

@@ -448,11 +448,10 @@ and gen_expr ctx e =
 
 let gen_method ctx p c acc =
 	ctx.curmethod <- c.cf_name;
+	if is_extern_field c then acc else
 	match c.cf_expr with
 	| None ->
-		(match c.cf_kind with
-		| Var { v_read = AccResolve } -> acc
-		| _ -> (c.cf_name, null p) :: acc)
+		((c.cf_name, null p) :: acc)
 	| Some e ->
 		match e.eexpr with
 		| TCall ({ eexpr = TField ({ eexpr = TTypeExpr (TClassDecl { cl_path = (["neko"],"Lib") }) }, load)},[{ eexpr = TConst (TString m) };{ eexpr = TConst (TString f) };{ eexpr = TConst (TInt n) }]) when load = "load" || load = "loadLazy" ->

+ 2 - 2
genswf8.ml

@@ -1415,9 +1415,9 @@ let gen_type_def ctx t =
 		let flag = is_protected ctx ~stat:true (TInst (c,[])) "" in
 		if (Common.has_feature ctx.com "Reflect.getProperty") || (Common.has_feature ctx.com "Reflect.setProperty") then
 			Codegen.add_property_field ctx.com c;
-		List.iter (gen_class_static_field ctx c flag) c.cl_ordered_statics;
+		List.iter (fun f -> if not (is_extern_field f) then gen_class_static_field ctx c flag f) c.cl_ordered_statics;
 		let flag = is_protected ctx (TInst (c,[])) "" in
-		PMap.iter (fun _ f -> match f.cf_kind with Var { v_read = AccResolve } -> () | _ -> gen_class_field ctx flag f) c.cl_fields;
+		PMap.iter (fun _ f -> if not (is_extern_field f) then gen_class_field ctx flag f) c.cl_fields;
 	| TEnumDecl e when e.e_extern ->
 		()
 	| TEnumDecl e ->

+ 12 - 11
genswf9.ml

@@ -1921,6 +1921,7 @@ let generate_field_kind ctx f c stat =
 		in
 		loop f.cf_meta
 	in
+	if is_extern_field f then None else
 	match f.cf_expr with
 	| Some { eexpr = TFunction fdata } ->
 		let rec loop c name =
@@ -1966,8 +1967,6 @@ let generate_field_kind ctx f c stat =
 			})
 		| _ ->
 			None)
-	| _ when (match f.cf_kind with Var { v_read = AccResolve } -> true | _ -> false) ->
-		None
 	| _ ->
 		Some (HFVar {
 			hlv_type = if Codegen.is_volatile f.cf_type then Some (type_path ctx ([],"Array")) else type_opt ctx f.cf_type;
@@ -2132,15 +2131,17 @@ let generate_class ctx c =
 	let st_meth_count = ref 0 in
 	let statics = List.rev (List.fold_left (fun acc f ->
 		let acc = generate_prop f acc (fun() -> incr st_meth_count; !st_meth_count) in
-		let k = (match generate_field_kind ctx f c true with None -> assert false | Some k -> k) in
-		let count = (match k with HFMethod _ -> st_meth_count | HFVar _ -> st_field_count | _ -> assert false) in
-		incr count;
-		{
-			hlf_name = make_name f;
-			hlf_slot = !count;
-			hlf_kind = k;
-			hlf_metas = extract_meta f.cf_meta;
-		} :: acc
+		match generate_field_kind ctx f c true with 
+		| None -> acc
+		| Some k ->
+			let count = (match k with HFMethod _ -> st_meth_count | HFVar _ -> st_field_count | _ -> assert false) in
+			incr count;
+			{
+				hlf_name = make_name f;
+				hlf_slot = !count;
+				hlf_kind = k;
+				hlf_metas = extract_meta f.cf_meta;
+			} :: acc
 	) [] c.cl_ordered_statics) in
 	let statics = if not (need_init ctx c) then statics else
 		{

+ 1 - 0
std/flash8/_std/Type.hx

@@ -129,6 +129,7 @@ enum ValueType {
 		a.remove(__unprotect__("__name__"));
 		a.remove(__unprotect__("__interfaces__"));
 		a.remove(__unprotect__("__super__"));
+		a.remove(__unprotect__("__properties__"));
 		return a;
 	}
 

+ 58 - 1
tests/unit/MyClass.hx

@@ -194,4 +194,61 @@ class UsingUnrelated {
 		#end
 		return "foo".pupFunc() + "foo".siblingFunc();
 	}
-}
+}
+
+@:keep class VarProps {
+	
+	static var SX(get, set) : Int;
+	@:isVar static var SY(get, set) : Int;
+	
+	static function get_SX() {
+		return 1;
+	}
+	
+	static function set_SX(v) {
+		return v;
+	}
+	
+	static function get_SY() {
+		return SY;
+	}
+
+	static function set_SY(v) {
+		SY = v;
+		return v;
+	}
+		
+
+	public var x(get, set) : Int;
+	@:isVar public var y(get, set) : Int;
+	public var z(default, set) : Int;
+	
+	public function new() {
+		x = 1;
+		y = 2;
+		z = 3;
+	}
+	
+	function get_x() {
+		return 1;
+	}
+	
+	function set_x(v) {
+		return v;
+	}
+	
+	function get_y() {
+		return y;
+	}
+
+	function set_y(v) {
+		y = v;
+		return v;
+	}
+	
+	function set_z(v) {
+		z = v + 1;
+		return z;
+	}
+
+}

+ 9 - 9
tests/unit/TestDCE.hx

@@ -5,7 +5,7 @@ class DCEClass {
 	static function staticUsed() { }
 	@:keep static function staticKeep() { }
 	static var staticVarUsed = "foo";
-	static var staticPropUsed(get_staticPropUsed, set_staticPropUsed):Int = 1;
+	@:isVar static var staticPropUsed(get, set):Int = 1;
 	static function get_staticPropUsed() return staticPropUsed
 	static function set_staticPropUsed(i:Int) return 0
 	
@@ -13,23 +13,23 @@ class DCEClass {
 	function memberUsed() { }
 	@:keep function memberKeep() { }
 	var memberVarUsed = 0;
-	var memberPropUsed(get_memberPropUsed, set_memberPropUsed):Int = 1;
+	@:isVar var memberPropUsed(get, set):Int = 1;
 	function get_memberPropUsed() return memberPropUsed
 	function set_memberPropUsed(i:Int) return 0
 	
 	// unused statics
 	static function staticUnused() { }
 	static var staticVarUnused = "bar";
-	static var staticPropUnused(get_staticPropUnused, set_staticPropUnused):Int = 1;
+	static var staticPropUnused(get, set):Int = 1;
 	static function get_staticPropUnused() return 0
 	static function set_staticPropUnused(i:Int) return 0
 	
 	// unused members
 	function memberUnused() { }
 	var memberVarUnused = 1;
-	var memberPropUnused(get_memberPropUnused, set_memberPropUnused):Int = 1;
+	var memberPropUnused(get, set):Int = 1;
 	function get_memberPropUnused() return 0
-	function set_memberPropUnused(i:Int) return 0	
+	function set_memberPropUnused(i:Int) return 0
 	
 	static var c :Array<Dynamic> = [null, unit.UsedReferenced2];
 	
@@ -82,7 +82,7 @@ class TestDCE extends Test {
 		nhsf(c, "staticVarUnused");
 		nhsf(c, "staticPropUnused");
 		nhsf(c, "get_staticPropUnused");
-		nhsf(c, "set_staticPropUnused");	
+		nhsf(c, "set_staticPropUnused");
 	}
 	
 	public function testInterface() {
@@ -98,7 +98,7 @@ class TestDCE extends Test {
 		hf(bc, "usedInterfaceFunc");
 		nhf(ic, "unusedInterfaceFunc");
 		nhf(c, "unusedInterfaceFunc");
-		nhf(bc, "unusedInterfaceFunc");	
+		nhf(bc, "unusedInterfaceFunc");
 	}
 	
 	public function testProperty() {
@@ -126,10 +126,10 @@ class TestDCE extends Test {
 		t(Type.resolveClass("unit.UsedAsBaseChild") != null);
 		
 		t(Type.resolveClass("unit.Unused") == null);
-		t(Type.resolveClass("unit.UnusedChild") == null);		
+		t(Type.resolveClass("unit.UnusedChild") == null);
 		t(Type.resolveClass("unit.UnusedImplements") == null);
 		t(Type.resolveClass("unit.UsedConstructedChild") == null);
-		t(Type.resolveClass("unit.UsedReferencedChild") == null);	
+		t(Type.resolveClass("unit.UsedReferencedChild") == null);
 	}
 }
 

+ 1 - 1
tests/unit/TestMisc.hx

@@ -26,7 +26,7 @@ class MyDynamicClass {
 		return Z + x + y;
 	}
 
-	public static var W(get, set) : Int = 55;
+	@:isVar public static var W(get, set) : Int = 55;
 	static function get_W() return W + 2
 	static function set_W(v) { W = v; return v; }
 	

+ 17 - 0
tests/unit/TestType.hx

@@ -50,6 +50,23 @@ class TestType extends Test {
 		var fl = Type.getInstanceFields(unit.MySubClass);
 		fl.sort(Reflect.compare);
 		eq( fl.join("|"), fields.join("|") );
+		
+		// AS3 generator will create native properties
+		#if !as3
+		
+		// x should not be listed since it's not a variable
+		var fl = Type.getInstanceFields(VarProps);
+		var fields = ["get_x","get_y","set_x","set_y","set_z","y","z"];
+		fl.sort(Reflect.compare);
+		eq( fl.join("|"), fields.join("|"));
+		
+		// same for statics
+		var fl = Type.getClassFields(VarProps);
+		var fields = ["SY", "get_SX", "get_SY", "set_SX", "set_SY"];
+		fl.sort(Reflect.compare);
+		eq( fl.join("|"), fields.join("|"));
+		
+		#end
 	}
 
 	public function testEnumEq() {

+ 6 - 0
type.ml

@@ -838,6 +838,12 @@ let type_iseq a b =
 
 let unify_stack = ref []
 
+let is_extern_field f =
+	match f.cf_kind with
+	| Method _ -> false
+	| Var { v_read = AccNormal } | Var { v_write = AccNormal } -> false
+	| _ -> not (has_meta ":isVar" f.cf_meta)
+
 let field_type f =
 	match f.cf_params with
 	| [] -> f.cf_type

+ 1 - 0
typer.ml

@@ -636,6 +636,7 @@ let field_access ctx mode f t e p =
 		| AccCall m ->
 			if m = ctx.curfield.cf_name && (match e.eexpr with TConst TThis -> true | TTypeExpr (TClassDecl c) when c == ctx.curclass -> true | _ -> false) then
 				let prefix = (match ctx.com.platform with Flash when Common.defined ctx.com Define.As3 -> "$" | _ -> "") in
+				if is_extern_field f then display_error ctx "This field cannot be accessed since it is not an actual var, add @:isVar to enable it" p;
 				AKExpr (mk (TField (e,prefix ^ f.cf_name)) t p)
 			else if mode = MSet then
 				AKSet (e,m,t,f.cf_name)