Jelajahi Sumber

cancel constructor inlining if an invalid field is assigned to (closes #2425)

Simon Krajewski 11 tahun lalu
induk
melakukan
649cd73c46
1 mengubah file dengan 30 tambahan dan 12 penghapusan
  1. 30 12
      optimizer.ml

+ 30 - 12
optimizer.ml

@@ -1033,6 +1033,23 @@ let inline_constructors ctx e =
 		| _ ->
 			IKNone
 	in
+	let is_valid_field v s =
+		try
+			let (_,_,fields,_,_) = PMap.find (-v.v_id) !vars in
+			List.exists (fun (s2,_,_) -> s = s2) fields
+		with Not_found ->
+			false
+	in
+	let cancel v =
+		v.v_id <- -v.v_id;
+		(* error if the constructor is extern *)
+		(match PMap.find v.v_id !vars with
+		| _,_,_,true,p ->
+			display_error ctx "Extern constructor could not be inlined" p;
+			error "Variable is used here" e.epos
+		| _ -> ());
+		vars := PMap.remove v.v_id !vars;
+	in
 	let rec find_locals e =
 		match e.eexpr with
 		| TVar (v,eo) ->
@@ -1081,21 +1098,22 @@ let inline_constructors ctx e =
 					end
 				| None -> ()
 			end
-		| TField ({ eexpr = TLocal _ },FInstance (_,{ cf_kind = Var _ })) ->
-			()
-		| TArray ({eexpr = TLocal _},{eexpr = TConst (TInt _)}) ->
+		| TField({eexpr = TLocal v}, (FInstance(_, {cf_kind = Var _; cf_name = s}) | FAnon({cf_kind = Var _; cf_name = s}))) ->
 			()
-		| TField({eexpr = TLocal _},FAnon({cf_kind = Var _})) ->
+		| TArray ({eexpr = TLocal v},{eexpr = TConst (TInt i)}) ->
 			()
+		| TBinop((OpAssign | OpAssignOp _),e1,e2) ->
+			begin match e1.eexpr with
+				| TArray ({eexpr = TLocal v},{eexpr = TConst (TInt i)}) when v.v_id < 0 && not (is_valid_field v (Int32.to_string i)) ->
+					cancel v
+				| TField({eexpr = TLocal v}, (FInstance(_, {cf_kind = Var _; cf_name = s}) | FAnon({cf_kind = Var _; cf_name = s}))) when v.v_id < 0 && not (is_valid_field v s) ->
+					cancel v
+				| _ ->
+					find_locals e1
+			end;
+			find_locals e2
 		| TLocal v when v.v_id < 0 ->
-			v.v_id <- -v.v_id;
-			(* error if the constructor is extern *)
-			(match PMap.find v.v_id !vars with
-			| _,_,_,true,p ->
-				display_error ctx "Extern constructor could not be inlined" p;
-				error "Variable is used here" e.epos
-			| _ -> ());
-			vars := PMap.remove v.v_id !vars;
+			cancel v
 		| _ ->
 			Type.iter find_locals e
 	in