Browse Source

[cs] Automatically set nativegen to structs, and enforce that they cannot be subclassed, nor contain a constructor with no arguments

Closes #5399
Cauê Waneck 8 năm trước cách đây
mục cha
commit
b80c8d4c1a

+ 5 - 2
src/generators/gencommon/setHXGen.ml

@@ -45,13 +45,16 @@ let run_filter com types =
 					else
 						Option.map_default (is_hxgen_class) false c.cl_super || List.exists is_hxgen_class c.cl_implements
 				end else begin
-					if Meta.has Meta.NativeChildren c.cl_meta || Meta.has Meta.NativeGen c.cl_meta then
+					if Meta.has Meta.NativeChildren c.cl_meta || Meta.has Meta.NativeGen c.cl_meta || Meta.has Meta.Struct c.cl_meta then
 						Option.map_default is_hxgen_class false c.cl_super || List.exists is_hxgen_class c.cl_implements
 					else
 						let rec has_nativec (c,p) =
 							if is_hxgen_class (c,p) then
 								false
-							else
+							else if Meta.has Meta.Struct c.cl_meta then begin
+								com.error ("Struct types cannot be subclassed") c.cl_pos;
+								true
+							end else
 								(Meta.has Meta.NativeChildren c.cl_meta && not (Option.map_default is_hxgen_class false c.cl_super || List.exists is_hxgen_class c.cl_implements))
 								|| Option.map_default has_nativec false c.cl_super
 						in

+ 19 - 0
src/generators/gencs.ml

@@ -2045,6 +2045,25 @@ let generate con =
 						gen_class_field w ~is_overload:true is_static cl (Meta.has Meta.Final cf.cf_meta) cf
 					) cf.cf_overloads
 				| Var _ | Method MethDynamic -> ()
+				| Method _ when is_new && Meta.has Meta.Struct cl.cl_meta && fst (get_fun cf.cf_type) = [] ->
+						(* make sure that the method is empty *)
+						let rec check_empty expr = match expr.eexpr with
+							| TBlock(bl) -> bl = [] || List.for_all check_empty bl
+							| TMeta(_,e) -> check_empty e
+							| TParenthesis(e) -> check_empty e
+							| TConst(TNull) -> true
+							| TFunction(tf) -> check_empty tf.tf_expr
+							| _ -> false
+						in
+						(match cf.cf_expr with
+							| Some e ->
+								if not (check_empty e) then
+									gen.gcon.error "The body of a zero argument constructor of a struct should be empty" e.epos
+							| _ -> ());
+						List.iter (fun cf ->
+							if cl.cl_interface || cf.cf_expr <> None then
+								gen_class_field w ~is_overload:true is_static cl (Meta.has Meta.Final cf.cf_meta) cf
+						) cf.cf_overloads;
 				| Method mkind ->
 					List.iter (fun cf ->
 						if cl.cl_interface || cf.cf_expr <> None then

+ 19 - 0
tests/unit/src/unit/issues/Issue5399.hx

@@ -0,0 +1,19 @@
+package unit.issues;
+
+class Issue5399 extends Test {
+#if cs
+  public function test() {
+    var s:Something = null;
+    s.width = 10;
+    eq(s.width, 10);
+  }
+#end
+}
+
+#if cs
+@:keep @:struct private class Something {
+  public var width:Float;
+  public function new() {
+  }
+}
+#end