Jelajahi Sumber

Fix inline constructor field initialization for super constructors. #6093 (#6097)

* Handle inline constructor field initialization for super constructors too. Fixes #6093

* Reuse cl_params map.

* Add Issue6093 unit test.

* Add Issue6093 optimization test.
basro 8 tahun lalu
induk
melakukan
2cb65cb2da

+ 26 - 12
src/optimization/optimizer.ml

@@ -492,8 +492,8 @@ let rec type_inline ctx cf f ethis params tret config p ?(self_calling_closure=f
 			{ e with eexpr = TFunction { tf_args = args; tf_expr = expr; tf_type = f.tf_type } }
 		| TCall({eexpr = TConst TSuper; etype = t},el) ->
 			begin match follow t with
-			| TInst({ cl_constructor = Some ({cf_kind = Method MethInline; cf_expr = Some ({eexpr = TFunction tf})} as cf)},_) ->
-				begin match type_inline ctx cf tf ethis el ctx.t.tvoid None po true with
+			| TInst({ cl_constructor = Some ({cf_kind = Method MethInline; cf_expr = Some ({eexpr = TFunction tf})} as cf)} as c,_) ->
+				begin match type_inline_ctor ctx c cf tf ethis el po with
 				| Some e -> map term e
 				| None -> error "Could not inline super constructor call" po
 				end
@@ -651,6 +651,29 @@ let rec type_inline ctx cf f ethis params tret config p ?(self_calling_closure=f
 			let rec map_expr_type e = Type.map_expr_type map_expr_type map_type map_var e in
 			Some (map_expr_type e)
 
+(* Same as type_inline, but modifies the function body to add field inits *)
+and type_inline_ctor ctx c cf tf ethis el po =
+	let field_inits = 
+		let cparams = List.map snd c.cl_params in
+		let ethis = mk (TConst TThis) (TInst (c,cparams)) c.cl_pos in
+		let el = List.fold_left (fun acc cf -> 
+			match cf.cf_kind,cf.cf_expr with
+			| Var _,Some e ->
+				let lhs = mk (TField(ethis,FInstance (c,cparams,cf))) cf.cf_type e.epos in
+				let eassign = mk (TBinop(OpAssign,lhs,e)) cf.cf_type e.epos in
+				eassign :: acc
+			| _ -> acc
+		) [] c.cl_ordered_fields in
+		List.rev el
+	in
+	let tf =
+		if field_inits = [] then tf
+		else
+			let bl = match tf.tf_expr with {eexpr = TBlock b } -> b | x -> [x] in
+			{tf with tf_expr = mk (TBlock (field_inits @ bl)) ctx.t.tvoid c.cl_pos}
+	in
+	type_inline ctx cf tf ethis el ctx.t.tvoid None po true
+
 
 (* ---------------------------------------------------------------------- *)
 (* LOOPS *)
@@ -1235,17 +1258,8 @@ let inline_constructors ctx e =
 						()
 					end
 				| TNew({ cl_constructor = Some ({cf_kind = Method MethInline; cf_expr = Some ({eexpr = TFunction tf})} as cf)} as c,tl,pl) when type_iseq v.v_type e1.etype ->
-					begin match type_inline ctx cf tf (mk (TLocal v) (TInst (c,tl)) e1.epos) pl ctx.t.tvoid None e1.epos true with
+					begin match type_inline_ctor ctx c cf tf (mk (TLocal v) (TInst (c,tl)) e1.epos) pl e1.epos with
 					| Some e ->
-						(* add field inits here because the filter has not run yet (issue #2336) *)
-						let ev = mk (TLocal v) v.v_type e.epos in
-						let el_init = List.fold_left (fun acc cf -> match cf.cf_kind,cf.cf_expr with
-							| Var _,Some e ->
-								let ef = mk (TField(ev,FInstance(c,tl,cf))) cf.cf_type e.epos in
-								let e = mk (TBinop(OpAssign,ef,e)) cf.cf_type e.epos in
-								e :: acc
-							| _ -> acc
-						) el_init c.cl_ordered_fields in
 						let e' = match el_init with
 							| [] -> e
 							| _ -> mk (TBlock (List.rev (e :: el_init))) e.etype e.epos

+ 24 - 0
tests/optimization/src/issues/Issue6093.hx

@@ -0,0 +1,24 @@
+package issues;
+
+private class A {
+	public var x : Int = 1;
+	public inline function new () {};
+}
+
+private class B extends A {
+	public var y : Int = 2;
+	public inline function new () { super(); };
+}
+
+class Issue6093 {
+	@:js('
+		var a_y;
+		var a_x;
+		a_y = 2;
+		a_x = 1;
+	')
+	@:analyzer(ignore)
+	static public function main() {
+		var a = new B();
+	}
+}

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

@@ -0,0 +1,19 @@
+package unit.issues;
+
+private class A {
+	public var x : Int = 1;
+	public inline function new () {};
+}
+
+private class B extends A {
+	public var y : Int = 2;
+	public inline function new () { super(); };
+}
+
+class Issue6093 extends unit.Test {
+	function test() {
+		var b = new B();
+		eq(b.x, 1);
+		eq(b.y, 2);
+	}
+}