2
0
Эх сурвалжийг харах

support unop + array access (closes #3702)

Simon Krajewski 9 жил өмнө
parent
commit
453b88bed8

+ 32 - 0
tests/unit/src/unit/issues/Issue3702.hx

@@ -0,0 +1,32 @@
+package unit.issues;
+
+class Issue3702 extends Test {
+
+	static var state = 0;
+
+	function test() {
+        var m = ["hello" => 0];
+		eq(state, 0);
+        var x = m[getKey()]++;
+		eq(0, x);
+		eq(1, state);
+		eq(1, m["hello"]);
+        var x = ++m[getKey()];
+		eq(2, x);
+		eq(2, state);
+		eq(2, m["hello"]);
+        var x = m[getKey()]--;
+		eq(2, x);
+		eq(3, state);
+		eq(1, m["hello"]);
+        var x = --m[getKey()];
+		eq(0, x);
+		eq(4, state);
+		eq(0, m["hello"]);
+	}
+
+	static function getKey() {
+		++state;
+		return "hello";
+	}
+}

+ 21 - 2
typer.ml

@@ -2476,8 +2476,27 @@ and type_unop ctx op flag e p =
 		| AKNo s ->
 			error ("The field or identifier " ^ s ^ " is not accessible for " ^ (if set then "writing" else "reading")) p
 		| AKAccess(a,tl,c,ebase,ekey) ->
-			let e = mk_array_get_call ctx (Codegen.AbstractCast.find_array_access ctx a tl ekey None p) c ebase p in
-			loop (AKExpr e)
+			begin try
+				(match op with Increment | Decrement -> () | _ -> raise Not_found);
+				let v_key = alloc_var "tmp" ekey.etype in
+				let evar_key = mk (TVar(v_key,Some ekey)) ctx.com.basic.tvoid ekey.epos in
+				let ekey = mk (TLocal v_key) ekey.etype ekey.epos in
+				(* get *)
+				let e_get = mk_array_get_call ctx (Codegen.AbstractCast.find_array_access_raise ctx a tl ekey None p) c ebase p in
+				let v_get = alloc_var "tmp" e_get.etype in
+				let ev_get = mk (TLocal v_get) v_get.v_type p in
+				let evar_get = mk (TVar(v_get,Some e_get)) ctx.com.basic.tvoid p in
+				(* op *)
+				let e_one = mk (TConst (TInt (Int32.of_int 1))) ctx.com.basic.tint p in
+				let e_op = mk (TBinop((if op = Increment then OpAdd else OpSub),ev_get,e_one)) ev_get.etype p in
+				(* set *)
+				let e_set = mk_array_set_call ctx (Codegen.AbstractCast.find_array_access_raise ctx a tl ekey (Some e_op) p) c ebase p in
+				let el = evar_key :: evar_get :: e_set :: (if flag = Postfix then [ev_get] else []) in
+				mk (TBlock el) e_set.etype p
+			with Not_found ->
+				let e = mk_array_get_call ctx (Codegen.AbstractCast.find_array_access ctx a tl ekey None p) c ebase p in
+				loop (AKExpr e)
+			end
 		| AKInline _ | AKUsing _ | AKMacro _ ->
 			error "This kind of operation is not supported" p
 		| AKSet (e,t,cf) ->