Browse Source

deal with complex array access bases (closes #5957)

Simon Krajewski 8 years ago
parent
commit
70d6095032
2 changed files with 36 additions and 15 deletions
  1. 19 15
      src/typing/typer.ml
  2. 17 0
      tests/unit/src/unit/issues/Issue5957.hx

+ 19 - 15
src/typing/typer.ml

@@ -1942,36 +1942,40 @@ let rec type_binop ctx op e1 e2 is_assign_op with_type p =
 		| AKAccess(a,tl,c,ebase,ekey) ->
 		| AKAccess(a,tl,c,ebase,ekey) ->
 			let cf_get,tf_get,r_get,ekey,_ = AbstractCast.find_array_access ctx a tl ekey None p in
 			let cf_get,tf_get,r_get,ekey,_ = AbstractCast.find_array_access ctx a tl ekey None p in
 			(* bind complex keys to a variable so they do not make it into the output twice *)
 			(* bind complex keys to a variable so they do not make it into the output twice *)
-			let ekey,l = match Optimizer.make_constant_expression ctx ekey with
-				| Some e -> e, fun () -> None
+			let save = save_locals ctx in
+			let maybe_bind_to_temp e = match Optimizer.make_constant_expression ctx e with
+				| Some e -> e,None
 				| None ->
 				| None ->
-					let save = save_locals ctx in
-					let v = gen_local ctx ekey.etype p in
-					let e = mk (TLocal v) ekey.etype p in
-					e, fun () -> (save(); Some (mk (TVar (v,Some ekey)) ctx.t.tvoid p))
+					let v = gen_local ctx e.etype p in
+					let e' = mk (TLocal v) e.etype p in
+					e', Some (mk (TVar (v,Some e)) ctx.t.tvoid p)
 			in
 			in
+			let ekey,ekey' = maybe_bind_to_temp ekey in
+			let ebase,ebase' = maybe_bind_to_temp ebase in
 			let eget = mk_array_get_call ctx (cf_get,tf_get,r_get,ekey,None) c ebase p in
 			let eget = mk_array_get_call ctx (cf_get,tf_get,r_get,ekey,None) c ebase p in
 			let eget = type_binop2 ctx op eget e2 true (WithType eget.etype) p in
 			let eget = type_binop2 ctx op eget e2 true (WithType eget.etype) p in
 			unify ctx eget.etype r_get p;
 			unify ctx eget.etype r_get p;
 			let cf_set,tf_set,r_set,ekey,eget = AbstractCast.find_array_access ctx a tl ekey (Some eget) p in
 			let cf_set,tf_set,r_set,ekey,eget = AbstractCast.find_array_access ctx a tl ekey (Some eget) p in
 			let eget = match eget with None -> assert false | Some e -> e in
 			let eget = match eget with None -> assert false | Some e -> e in
 			let et = type_module_type ctx (TClassDecl c) None p in
 			let et = type_module_type ctx (TClassDecl c) None p in
-			begin match cf_set.cf_expr,cf_get.cf_expr with
+			let e = match cf_set.cf_expr,cf_get.cf_expr with
 				| None,None ->
 				| None,None ->
 					let ea = mk (TArray(ebase,ekey)) r_get p in
 					let ea = mk (TArray(ebase,ekey)) r_get p in
 					mk (TBinop(OpAssignOp op,ea,type_expr ctx e2 (WithType r_get))) r_set p
 					mk (TBinop(OpAssignOp op,ea,type_expr ctx e2 (WithType r_get))) r_set p
 				| Some _,Some _ ->
 				| Some _,Some _ ->
 					let ef_set = mk (TField(et,(FStatic(c,cf_set)))) tf_set p in
 					let ef_set = mk (TField(et,(FStatic(c,cf_set)))) tf_set p in
-					(match l() with
-					| None -> make_call ctx ef_set [ebase;ekey;eget] r_set p
-					| Some e ->
-						mk (TBlock [
-							e;
-							make_call ctx ef_set [ebase;ekey;eget] r_set p
-						]) r_set p)
+					let el = [make_call ctx ef_set [ebase;ekey;eget] r_set p] in
+					let el = match ebase' with None -> el | Some ebase -> ebase :: el in
+					let el = match ekey' with None -> el | Some ekey -> ekey :: el in
+					begin match el with
+						| [e] -> e
+						| el -> mk (TBlock el) r_set p
+					end
 				| _ ->
 				| _ ->
 					error "Invalid array access getter/setter combination" p
 					error "Invalid array access getter/setter combination" p
-			end;
+			in
+			save();
+			e
 		| AKInline _ | AKMacro _ ->
 		| AKInline _ | AKMacro _ ->
 			assert false)
 			assert false)
 	| _ ->
 	| _ ->

+ 17 - 0
tests/unit/src/unit/issues/Issue5957.hx

@@ -0,0 +1,17 @@
+package unit.issues;
+
+import haxe.ds.Vector;
+
+class Issue5957 extends Test {
+	static var foo:Vector<Vector<Int>> = {
+		var vec = new Vector<Vector<Int>>(10);
+		vec[0] = new Vector<Int>(2);
+		vec[0][0] = 0;
+		vec;
+	}
+
+	public function test() {
+		foo[0][0] += 1;
+		eq(1, foo[0][0]);
+	}
+}