Browse Source

fixed autogenerated constructor for extending @:structInit classes (fixes #6822, fixes #6078)

Alexander Kuzmenko 7 years ago
parent
commit
64ba1f1f84
2 changed files with 51 additions and 6 deletions
  1. 32 6
      src/typing/typeload.ml
  2. 19 0
      tests/unit/src/unit/issues/Issue6822.hx

+ 32 - 6
src/typing/typeload.ml

@@ -1272,10 +1272,33 @@ let add_constructor ctx c force_constructor p =
 		(* nothing to do *)
 		(* nothing to do *)
 		()
 		()
 
 
-let check_struct_init_constructor ctx c p = match c.cl_constructor with
+let get_method_args field = 
+	match field.cf_expr with
+		| Some { eexpr = TFunction { tf_args = args } } -> args
+		| _ -> raise Not_found
+
+let get_struct_init_super_info ctx c p =
+	match c.cl_super with
+		| Some ({ cl_constructor = Some ctor } as csup, cparams) -> 
+			let args = (try get_method_args ctor with Not_found -> []) in
+			let tl,el = 
+				List.fold_left (fun (args,exprs) (v,value) ->
+					let opt = match value with Some _ -> true | None -> false in
+					let t = if opt then ctx.t.tnull v.v_type else v.v_type in
+					(v.v_name,opt,t) :: args,(mk (TLocal v) v.v_type p) :: exprs
+				) ([],[]) args
+			in
+			let super_expr = mk (TCall (mk (TConst TSuper) (TInst (csup,cparams)) p, el)) ctx.t.tvoid p in
+			(args,Some super_expr,tl)
+		| _ -> 
+			[],None,[]
+
+let check_struct_init_constructor ctx c p =
+	match c.cl_constructor with
 	| Some _ ->
 	| Some _ ->
 		()
 		()
 	| None ->
 	| None ->
+		let super_args,super_expr,super_tl = get_struct_init_super_info ctx c p in
 		let params = List.map snd c.cl_params in
 		let params = List.map snd c.cl_params in
 		let ethis = mk (TConst TThis) (TInst(c,params)) p in
 		let ethis = mk (TConst TThis) (TInst(c,params)) p in
 		let args,el,tl = List.fold_left (fun (args,el,tl) cf -> match cf.cf_kind with
 		let args,el,tl = List.fold_left (fun (args,el,tl) cf -> match cf.cf_kind with
@@ -1290,12 +1313,13 @@ let check_struct_init_constructor ctx c p = match c.cl_constructor with
 			| Method _ ->
 			| Method _ ->
 				args,el,tl
 				args,el,tl
 		) ([],[],[]) (List.rev c.cl_ordered_fields) in
 		) ([],[],[]) (List.rev c.cl_ordered_fields) in
+		let el = match super_expr with Some e -> e :: el | None -> el in
 		let tf = {
 		let tf = {
-			tf_args = args;
+			tf_args = args @ super_args;
 			tf_type = ctx.t.tvoid;
 			tf_type = ctx.t.tvoid;
 			tf_expr = mk (TBlock el) ctx.t.tvoid p
 			tf_expr = mk (TBlock el) ctx.t.tvoid p
 		} in
 		} in
-		let e = mk (TFunction tf) (TFun(tl,ctx.t.tvoid)) p in
+		let e = mk (TFunction tf) (TFun(tl @ super_tl,ctx.t.tvoid)) p in
 		let cf = mk_field "new" e.etype p null_pos in
 		let cf = mk_field "new" e.etype p null_pos in
 		cf.cf_expr <- Some e;
 		cf.cf_expr <- Some e;
 		cf.cf_type <- e.etype;
 		cf.cf_type <- e.etype;
@@ -2893,9 +2917,11 @@ module ClassInitializer = struct
 			| _ ->
 			| _ ->
 				()
 				()
 		end;
 		end;
-		(* add_constructor does not deal with overloads correctly *)
-		if not ctx.com.config.pf_overload then add_constructor ctx c cctx.force_constructor p;
-		if Meta.has Meta.StructInit c.cl_meta then check_struct_init_constructor ctx c p;
+		if Meta.has Meta.StructInit c.cl_meta then 
+			check_struct_init_constructor ctx c p
+		else
+			(* add_constructor does not deal with overloads correctly *)
+			if not ctx.com.config.pf_overload then add_constructor ctx c cctx.force_constructor p;
 		(* check overloaded constructors *)
 		(* check overloaded constructors *)
 		(if ctx.com.config.pf_overload && not cctx.is_lib then match c.cl_constructor with
 		(if ctx.com.config.pf_overload && not cctx.is_lib then match c.cl_constructor with
 		| Some ctor ->
 		| Some ctor ->

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

@@ -0,0 +1,19 @@
+package unit.issues;
+
+class Issue6822 extends Test {
+	function test() {
+		var o:BiggerThing = { something:1, somethingElse:2 };
+		eq(o.something, 1);
+		eq(o.somethingElse, 2);
+	}
+}
+
+@:structInit
+private class Thing {
+	public var something:Int;
+}
+
+@:structInit
+private class BiggerThing extends Thing {
+	public var somethingElse:Float;
+}