Browse Source

fix inline constructor scoping (closes #5855)

Simon Krajewski 8 năm trước cách đây
mục cha
commit
b0e691aaf1

+ 35 - 11
src/optimization/optimizer.ml

@@ -1318,14 +1318,21 @@ let inline_constructors ctx e =
 		with Not_found ->
 			None
 	in
-	let assign_or_declare v name e2 t p =
+	let extra_vars = ref [] in
+	let assign_or_declare v block_depth name e2 t p =
 		 try
 			let v = get_field_var v name in
 			let e1 = mk (TLocal v) t p in
 			mk (TBinop(OpAssign,e1,e2)) e1.etype p
 		with Not_found ->
 			let v = add_field_var v name t in
-			mk (TVar(v,Some e2)) ctx.t.tvoid e.epos
+			if block_depth = 1 then
+				mk (TVar(v,Some e2)) ctx.t.tvoid e.epos
+			else begin
+				let e1 = mk (TLocal v) t p in
+				extra_vars := (mk (TVar(v,None)) ctx.t.tvoid e.epos) :: !extra_vars;
+				mk (TBinop(OpAssign,e1,e2)) e1.etype p
+			end
 	in
 	let use_local_or_null v name t p =
 		try
@@ -1353,31 +1360,41 @@ let inline_constructors ctx e =
 		let e = mk (TBlock (List.rev !el)) e.etype e.epos in
 		mk (TMeta((Meta.MergeBlock,[],e.epos),e)) e.etype e.epos
 	in
-	let rec loop e = match e.eexpr with
+	let rec loop block_depth e = match e.eexpr with
 		| TVar(v,_) when v.v_id < 0 ->
 			begin match inline v e.epos with
 			| Some e ->
 				let e = flatten e in
-				loop e
+				loop (block_depth - 1) e
 			| None ->
 				cancel v e.epos;
 				e
 			end
 		| TBinop(OpAssign,({eexpr = TField({eexpr = TLocal v},fa)} as e1),e2) when v.v_id < 0 ->
-			let e2 = loop e2 in
-			assign_or_declare v (field_name fa) e2 e1.etype e.epos
+			let e2 = loop block_depth e2 in
+			assign_or_declare v block_depth (field_name fa) e2 e1.etype e.epos
 		| TField({eexpr = TLocal v},fa) when v.v_id < 0 ->
 			use_local_or_null v (field_name fa) e.etype e.epos
 		| TBinop(OpAssign,({eexpr = TArray({eexpr = TLocal v},{eexpr = TConst (TInt i)})} as e1),e2) when v.v_id < 0 ->
-			let e2 = loop e2 in
+			let e2 = loop block_depth e2 in
 			let name = int_field_name (Int32.to_int i) in
-			assign_or_declare v name e2 e1.etype e.epos
+			assign_or_declare v block_depth name e2 e1.etype e.epos
 		| TArray({eexpr = TLocal v},{eexpr = TConst (TInt i)}) when v.v_id < 0	->
 			use_local_or_null v (int_field_name (Int32.to_int i)) e.etype e.epos
+		(* TODO: this really shouldn't be here, but we have to deal with scoping even if TBlocks are missing *)
+		| TIf(e1,e2,eo) ->
+			let e1 = loop block_depth e1 in
+			let e2 = loop block_depth (mk_block e2) in
+			let eo = Option.map (fun e -> loop block_depth (mk_block e)) eo in
+			{e with eexpr = TIf(e1,e2,eo)}
+		| TWhile(e1,e2,flag) ->
+			let e1 = loop block_depth e1 in
+			let e2 = loop block_depth (mk_block e2) in
+			{e with eexpr = TWhile(e1,e2,flag)}
 		| TBlock el ->
 			let rec block acc el = match el with
 				| e1 :: el ->
-					begin match loop e1 with
+					begin match loop (block_depth + 1) e1 with
 					| {eexpr = TMeta((Meta.MergeBlock,_,_),{eexpr = TBlock el2})} ->
 						let acc = block acc el2 in
 						block acc el
@@ -1389,9 +1406,16 @@ let inline_constructors ctx e =
 			let el = block [] el in
 			mk (TBlock (List.rev el)) e.etype e.epos
 		| _ ->
-			Type.map_expr loop e
+			Type.map_expr (loop block_depth) e
 	in
-	loop e
+	let e = loop 0 e in
+	match !extra_vars with
+	| [] -> e
+	| _ ->
+		let e_init = mk (TBlock !extra_vars) ctx.t.tvoid e.epos in
+		match e.eexpr with
+		| TFunction tf -> {e with eexpr = TFunction {tf with tf_expr = concat e_init tf.tf_expr}}
+		| _ -> concat e_init e
 
 (* ---------------------------------------------------------------------- *)
 (* COMPLETION *)

+ 25 - 23
tests/optimization/src/issues/Issue2236.hx

@@ -1,40 +1,42 @@
 package issues;
 
 private class ArrayIterator<T> {
-    var a : Array<T>;
-    var pos : Int;
-    public inline function new(a) {
-        this.a = a;
-        this.pos = 0;
-    }
-    public inline function hasNext() {
-        return pos < a.length;
-    }
-    public inline function next() {
-        return a[pos++];
-    }
+	var a : Array<T>;
+	var pos : Int;
+	public inline function new(a) {
+		this.a = a;
+		this.pos = 0;
+	}
+	public inline function hasNext() {
+		return pos < a.length;
+	}
+	public inline function next() {
+		return a[pos++];
+	}
 }
 
 private abstract ArrayRead<T>(Array<T>) {
 
-    public inline function new(a) {
-        this = a;
-    }
+	public inline function new(a) {
+		this = a;
+	}
 
-    function toArray() : Array<T> {
-        return this;
-    }
+	function toArray() : Array<T> {
+		return this;
+	}
 
-    public inline function iterator() : ArrayIterator<T> {
-        return new ArrayIterator(this);
-    }
+	public inline function iterator() : ArrayIterator<T> {
+		return new ArrayIterator(this);
+	}
 
 }
 
 class Issue2236 {
 	@:js('
-		var _g_a = [0];
-		var _g_pos = 0;
+		var _g_pos;
+		var _g_a;
+		_g_a = [0];
+		_g_pos = 0;
 		while(_g_pos < _g_a.length) ++_g_pos;
 	')
 	static function test() {

+ 25 - 0
tests/optimization/src/issues/Issue5855.hx

@@ -0,0 +1,25 @@
+package issues;
+
+class C {
+	public var field:String;
+	public inline function new() {
+		if (Math.random() > 0.5) {
+			field = "foo";
+		}
+	}
+}
+
+class Issue5855 {
+	@:js('
+		var c_field;
+		if(Math.random() > 0.5) {
+			c_field = "foo";
+		}
+		console.log(c_field);
+	')
+	@:analyzer(ignore)
+	static function main() {
+		var c = new C();
+		trace(c.field);
+	}
+}