Jelajahi Sumber

add SafeCom

Simon Krajewski 5 bulan lalu
induk
melakukan
85e7c67d44

+ 127 - 0
src/context/safeCom.ml

@@ -0,0 +1,127 @@
+open Globals
+open Type
+open PlatformConfig
+
+type saved_warning = {
+	w_module : module_def;
+	w_warning : WarningList.warning;
+	w_options : Warning.warning_option list list;
+	w_msg : string;
+	w_pos : pos;
+}
+
+type t = {
+	basic : basic_types;
+	platform : platform;
+	defines : Define.define;
+	platform_config : platform_config;
+	debug : bool;
+	is_macro_context : bool;
+	exceptions : exn list ref;
+	exceptions_mutex : Mutex.t;
+	warnings : saved_warning list ref;
+	warnings_mutex : Mutex.t;
+	timer_ctx : Timer.timer_context;
+	curclass : tclass;
+	curfield : tclass_field;
+}
+
+let of_com (com : Common.context) = {
+	basic = com.basic;
+	platform = com.platform;
+	defines = com.defines;
+	platform_config = com.config;
+	debug = com.debug;
+	is_macro_context = com.is_macro_context;
+	exceptions = ref [];
+	exceptions_mutex = Mutex.create ();
+	warnings = ref [];
+	warnings_mutex = Mutex.create ();
+	timer_ctx = com.timer_ctx;
+	curclass = null_class;
+	curfield = null_field;
+}
+
+let of_typer (ctx : Typecore.typer) = {
+	(of_com ctx.com) with
+	curclass = ctx.c.curclass;
+	curfield = ctx.f.curfield;
+}
+
+let finalize scom com =
+	List.iter (fun warning ->
+		Common.module_warning com warning.w_module warning.w_warning warning.w_options warning.w_msg warning.w_pos
+	) !(scom.warnings);
+	scom.warnings := [];
+	let exns = !(scom.exceptions) in
+	scom.exceptions := [];
+	match exns with
+	| x :: _ ->
+		raise x
+	| [] ->
+		()
+
+let run_with_scom com scom pool f =
+	Std.finally (fun() -> finalize scom com) f ()
+
+let add_exn scom exn =
+	Mutex.protect scom.exceptions_mutex (fun () -> scom.exceptions := exn :: !(scom.exceptions))
+
+let add_warning scom w msg p =
+	let options = (Warning.from_meta scom.curfield.cf_meta) @ (Warning.from_meta scom.curclass.cl_meta) in
+	match Warning.get_mode w options with
+	| WMEnable ->
+		Mutex.protect scom.warnings_mutex (fun () ->
+			let warning = {
+				w_module = scom.curclass.cl_module;
+				w_warning = w;
+				w_options = options;
+				w_msg = msg;
+				w_pos = p;
+			} in
+			scom.warnings := warning :: !(scom.warnings)
+		)
+	| WMDisable ->
+		()
+
+let run_expression_filters_safe scom detail_times filters t =
+	let run scom identifier e =
+		try
+			List.fold_left (fun e (filter_name,f) ->
+				try
+					FilterContext.with_timer scom.timer_ctx detail_times filter_name identifier (fun () -> f scom e)
+				with Failure msg ->
+					Error.raise_typing_error msg e.epos
+			) e filters
+		with exc ->
+			add_exn scom exc;
+			e
+	in
+	match t with
+	| TClassDecl c when FilterContext.is_removable_class c -> ()
+	| TClassDecl c ->
+		let scom = {scom with curclass = c} in
+		let rec process_field cf =
+			if not (has_class_field_flag cf CfPostProcessed) then begin
+				let scom = {scom with curfield = cf} in
+				(match cf.cf_expr with
+				| Some e when not (FilterContext.is_removable_field scom.is_macro_context cf) ->
+					let identifier = Printf.sprintf "%s.%s" (s_type_path c.cl_path) cf.cf_name in
+					cf.cf_expr <- Some (run scom (Some identifier) e);
+				| _ -> ());
+			end;
+			List.iter process_field cf.cf_overloads
+		in
+		List.iter process_field c.cl_ordered_fields;
+		List.iter process_field c.cl_ordered_statics;
+		(match c.cl_constructor with
+		| None -> ()
+		| Some f -> process_field f);
+		(match TClass.get_cl_init c with
+		| None -> ()
+		| Some e ->
+			let identifier = Printf.sprintf "%s.__init__" (s_type_path c.cl_path) in
+			TClass.set_cl_init c (run scom (Some identifier) e))
+	| TEnumDecl _ -> ()
+	| TTypeDecl _ -> ()
+	| TAbstractDecl _ -> ()

+ 41 - 19
src/filters/filters.ml

@@ -180,7 +180,7 @@ let iter_expressions fl mt =
 
 open FilterContext
 
-let destruction tctx ectx detail_times main locals =
+let destruction tctx scom ectx detail_times main locals =
 	let com = tctx.com in
 	with_timer tctx.com.timer_ctx detail_times "type 2" None (fun () ->
 		(* PASS 2: type filters pre-DCE *)
@@ -220,7 +220,7 @@ let destruction tctx ectx detail_times main locals =
 		(fun _ -> check_private_path com);
 		(fun _ -> Native.apply_native_paths);
 		(fun _ -> add_rtti com);
-		(match com.platform with | Jvm -> (fun _ _ -> ()) | _ -> (fun tctx mt -> AddFieldInits.add_field_inits tctx.c.curclass.cl_path locals com mt));
+		(match com.platform with | Jvm -> (fun _ _ -> ()) | _ -> (fun tctx mt -> AddFieldInits.add_field_inits tctx.c.curclass.cl_path locals scom mt));
 		(match com.platform with Hl -> (fun _ _ -> ()) | _ -> (fun _ -> add_meta_field com));
 		(fun _ -> check_void_field);
 		(fun _ -> (match com.platform with | Cpp -> promote_first_interface_to_super | _ -> (fun _ -> ())));
@@ -416,6 +416,8 @@ let run tctx ectx main before_destruction =
 		end;
 		not cached
 	) com.types in
+	let new_types_array = Array.of_list new_types in
+	let scom = SafeCom.of_com com in
 	(* IMPORTANT:
 	    There may be types in new_types which have already been post-processed, but then had their m_processed flag unset
 		because they received an additional dependency. This could happen in cases such as @:generic methods in #10635.
@@ -431,35 +433,55 @@ let run tctx ectx main before_destruction =
 		"handle_abstract_casts",AbstractCast.handle_abstract_casts;
 	] in
 	List.iter (run_expression_filters tctx detail_times filters) new_types;
-	let cv_wrapper_impl = CapturedVars.get_wrapper_implementation com in
+
 	let filters = [
 		"local_statics",LocalStatic.run;
 		"fix_return_dynamic_from_void_function",SafeFilters.fix_return_dynamic_from_void_function;
 		"check_local_vars_init",CheckVarInit.check_local_vars_init;
 		"check_abstract_as_value",SafeFilters.check_abstract_as_value;
 		"Tre",if defined com Define.AnalyzerOptimize then Tre.run else (fun _ e -> e);
+	] in
+	Parallel.run_in_new_pool com.timer_ctx (fun pool ->
+		SafeCom.run_with_scom com scom pool (fun () ->
+			Parallel.ParallelArray.iter pool (SafeCom.run_expression_filters_safe scom detail_times filters) new_types_array
+		);
+	);
+
+	let filters = [
 		"reduce_expression",Optimizer.reduce_expression;
 		"inline_constructors",InlineConstructors.inline_constructors;
 		"Exceptions_filter",(fun _ -> Exceptions.filter ectx);
-		"captured_vars",(fun _ -> CapturedVars.captured_vars com cv_wrapper_impl);
 	] in
 	List.iter (run_expression_filters tctx detail_times filters) new_types;
-	enter_stage com CAnalyzerStart;
-	if com.platform <> Cross then Analyzer.Run.run_on_types com new_types;
-	enter_stage com CAnalyzerDone;
-	let locals = RenameVars.init com in
+
+	let cv_wrapper_impl = CapturedVars.get_wrapper_implementation com in
 	let filters = [
-		"sanitize",(fun _ e -> Sanitize.sanitize com.config e);
-		"add_final_return",(fun _ -> if com.config.pf_add_final_return then AddFinalReturn.add_final_return else (fun e -> e));
-		"RenameVars",(match com.platform with
-		| Eval -> (fun _ e -> e)
-		| Jvm -> (fun _ e -> e)
-		| _ -> (fun tctx e -> RenameVars.run tctx.c.curclass.cl_path locals e));
-		"mark_switch_break_loops",SafeFilters.mark_switch_break_loops;
+		"captured_vars",(fun scom -> CapturedVars.captured_vars scom cv_wrapper_impl);
 	] in
-	Parallel.run_in_new_pool com.timer_ctx (fun pool ->
-		Parallel.ParallelArray.iter pool (run_expression_filters tctx detail_times filters) (Array.of_list new_types)
-	);
+
+	let locals = Parallel.run_in_new_pool com.timer_ctx (fun pool ->
+		SafeCom.run_with_scom com scom pool (fun () ->
+			Parallel.ParallelArray.iter pool (SafeCom.run_expression_filters_safe scom detail_times filters) new_types_array
+		);
+		enter_stage com CAnalyzerStart;
+		if com.platform <> Cross then Analyzer.Run.run_on_types com pool new_types_array;
+		enter_stage com CAnalyzerDone;
+		let locals = RenameVars.init scom.platform_config com.types in
+		let filters = [
+			"sanitize",(fun scom e -> Sanitize.sanitize scom.SafeCom.platform_config e);
+			"add_final_return",(fun _ -> if com.config.pf_add_final_return then AddFinalReturn.add_final_return else (fun e -> e));
+			"RenameVars",(match com.platform with
+				| Eval -> (fun _ e -> e)
+				| Jvm -> (fun _ e -> e)
+				| _ -> (fun scom e -> RenameVars.run scom.curclass.cl_path locals e)
+			);
+			"mark_switch_break_loops",SafeFilters.mark_switch_break_loops;
+		] in
+		SafeCom.run_with_scom com scom pool (fun () ->
+			Parallel.ParallelArray.iter pool (SafeCom.run_expression_filters_safe scom detail_times filters) new_types_array
+		);
+		locals
+	) in
 	with_timer tctx.com.timer_ctx detail_times "callbacks" None (fun () ->
 		com.callbacks#run com.error_ext com.callbacks#get_before_save;
 	);
@@ -475,4 +497,4 @@ let run tctx ectx main before_destruction =
 		com.callbacks#run com.error_ext com.callbacks#get_after_save;
 	);
 	before_destruction();
-	destruction tctx ectx detail_times main locals
+	destruction tctx scom ectx detail_times main locals

+ 8 - 8
src/filters/renameVars.ml

@@ -1,6 +1,6 @@
 open Globals
 open Type
-open Common
+open SafeCom
 open Ast
 open PlatformConfig
 
@@ -26,7 +26,7 @@ let reserve_init ri name =
 	Make all module-level names reserved.
 	No local variable will have a name matching a module-level declaration.
 *)
-let reserve_all_types ri com path_to_name =
+let reserve_all_types ri types path_to_name =
 	List.iter (fun mt ->
 		let tinfos = t_infos mt in
 		let native_name = try fst (Native.get_native_name tinfos.mt_meta) with Not_found -> path_to_name tinfos.mt_path in
@@ -44,14 +44,14 @@ let reserve_all_types ri com path_to_name =
 			) fl
 		| _ ->
 			reserve_init ri native_name
-	) com.types
+	) types
 
 (**
 	Initialize the context for local variables renaming
 *)
-let init com =
+let init config types =
 	let ri = {
-		ri_scope = com.config.pf_scoping.vs_scope;
+		ri_scope = config.pf_scoping.vs_scope;
 		ri_reserved = StringMap.empty;
 		ri_hoisting = false;
 		ri_no_shadowing = false;
@@ -73,11 +73,11 @@ let init com =
 		| ReserveNames names ->
 			List.iter (reserve_init ri) names
 		| ReserveAllTopLevelSymbols ->
-			reserve_all_types ri com (fun (pack,name) -> if pack = [] then name else List.hd pack)
+			reserve_all_types ri types (fun (pack,name) -> if pack = [] then name else List.hd pack)
 		| ReserveAllTypesFlat ->
-			reserve_all_types ri com Path.flat_path
+			reserve_all_types ri types Path.flat_path
 		| ReserveCurrentTopLevelSymbol -> ri.ri_reserve_current_top_level_symbol <- true
-	) com.config.pf_scoping.vs_flags;
+	) config.pf_scoping.vs_flags;
 	ri
 
 module Overlaps = struct

+ 10 - 10
src/filters/safe/addFieldInits.ml

@@ -1,8 +1,8 @@
 open Globals
-open Common
+open SafeCom
 open Type
 
-let add_field_inits cl_path locals com t =
+let add_field_inits cl_path locals scom t =
 	let apply c =
 		let ethis = mk (TConst TThis) (TInst (c,extract_param_types c.cl_params)) c.cl_pos in
 		(* TODO: we have to find a variable name which is not used in any of the functions *)
@@ -28,11 +28,11 @@ let add_field_inits cl_path locals com t =
 			let el = if !need_this then (mk (TVar((v, Some ethis))) ethis.etype ethis.epos) :: el else el in
 			let cf = match c.cl_constructor with
 			| None ->
-				let ct = TFun([],com.basic.tvoid) in
+				let ct = TFun([],scom.basic.tvoid) in
 				let ce = mk (TFunction {
 					tf_args = [];
-					tf_type = com.basic.tvoid;
-					tf_expr = mk (TBlock el) com.basic.tvoid c.cl_pos;
+					tf_type = scom.basic.tvoid;
+					tf_expr = mk (TBlock el) scom.basic.tvoid c.cl_pos;
 				}) ct c.cl_pos in
 				let ctor = mk_field "new" ct c.cl_pos null_pos in
 				ctor.cf_kind <- Method MethNormal;
@@ -41,21 +41,21 @@ let add_field_inits cl_path locals com t =
 				match cf.cf_expr with
 				| Some { eexpr = TFunction f } ->
 					let bl = match f.tf_expr with {eexpr = TBlock b } -> b | x -> [x] in
-					let ce = mk (TFunction {f with tf_expr = mk (TBlock (el @ bl)) com.basic.tvoid c.cl_pos }) cf.cf_type cf.cf_pos in
+					let ce = mk (TFunction {f with tf_expr = mk (TBlock (el @ bl)) scom.basic.tvoid c.cl_pos }) cf.cf_type cf.cf_pos in
 					{cf with cf_expr = Some ce };
 				| _ ->
 					die "" __LOC__
 			in
-			let config = AnalyzerConfig.get_field_config com c cf in
+			let config = AnalyzerConfig.get_field_config scom c cf in
 			remove_class_field_flag cf CfPostProcessed;
-			Analyzer.Run.run_on_field com config c cf;
+			Analyzer.Run.run_on_field scom config c cf;
 			add_class_field_flag cf CfPostProcessed;
 			(match cf.cf_expr with
 			| Some e ->
 				(* This seems a bit expensive, but hopefully constructor expressions aren't that massive. *)
 				let e = RenameVars.run cl_path locals e in
-				let e = Sanitize.sanitize com.config e in
-				let e = if com.config.pf_add_final_return then AddFinalReturn.add_final_return e else e in
+				let e = Sanitize.sanitize scom.platform_config e in
+				let e = if scom.platform_config.pf_add_final_return then AddFinalReturn.add_final_return e else e in
 				cf.cf_expr <- Some e
 			| _ ->
 				());

+ 4 - 4
src/filters/safe/capturedVars.ml

@@ -17,7 +17,7 @@
 	Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
  *)
 open Globals
-open Common
+open SafeCom
 open Type
 open LocalUsage
 
@@ -84,7 +84,7 @@ let get_wrapper_implementation com =
 		funs.push(function(x) { function() return x[0]++; }(x));
 	}
 *)
-let captured_vars com impl e =
+let captured_vars scom impl e =
 
 	let mk_var v used =
 		let v2 = alloc_var v.v_kind v.v_name (PMap.find v.v_id used) v.v_pos in
@@ -146,7 +146,7 @@ let captured_vars com impl e =
 				Create a new function scope to make sure that the captured loop variable
 				will not be overwritten in next loop iteration
 			*)
-			if com.config.pf_capture_policy = CPLoopVars then
+			if scom.platform_config.pf_capture_policy = CPLoopVars then
 				(* We don't want to duplicate any variable declarations, so let's make copies (issue #3902). *)
 				let new_vars = List.map (fun v -> v.v_id,alloc_var v.v_kind v.v_name v.v_type v.v_pos) vars in
 				let rec loop e = match e.eexpr with
@@ -273,7 +273,7 @@ let captured_vars com impl e =
 		!assigned
 	in
 	let captured = all_vars e in
-	match com.config.pf_capture_policy with
+	match scom.platform_config.pf_capture_policy with
 	| CPNone -> e
 	| CPWrapRef -> do_wrap captured e
 	| CPLoopVars -> out_loop e

+ 3 - 3
src/filters/safe/checkVarInit.ml

@@ -4,7 +4,7 @@ open Typecore
 open Error
 open Type
 
-let check_local_vars_init ctx e =
+let check_local_vars_init scom e =
 	let intersect vl1 vl2 =
 		PMap.mapi (fun v t -> t && PMap.find v vl2) vl1
 	in
@@ -29,8 +29,8 @@ let check_local_vars_init ctx e =
 			let init = (try PMap.find v.v_id !vars with Not_found -> true) in
 			if not init then begin
 				if IntMap.mem v.v_id !outside_vars then
-					if v.v_name = "this" then warning ctx WVarInit "this might be used before assigning a value to it" e.epos
-					else warning ctx WVarInit ("Local variable " ^ v.v_name ^ " might be used before being initialized") e.epos
+					if v.v_name = "this" then SafeCom.add_warning scom WVarInit "this might be used before assigning a value to it" e.epos
+					else SafeCom.add_warning scom WVarInit ("Local variable " ^ v.v_name ^ " might be used before being initialized") e.epos
 				else
 					if v.v_name = "this" then raise_typing_error "Missing this = value" e.epos
 					else raise_typing_error ("Local variable " ^ v.v_name ^ " used without being initialized") e.epos

+ 6 - 6
src/filters/safe/localStatic.ml

@@ -4,14 +4,14 @@ open Typecore
 open Error
 
 type lscontext = {
-	ctx : typer;
+	scom : SafeCom.t;
 	lut : tclass_field IntHashtbl.t;
 	mutable added_fields : tclass_field list;
 }
 
 let promote_local_static lsctx run v eo =
-	let name = Printf.sprintf "%s_%s" lsctx.ctx.f.curfield.cf_name v.v_name in
-	let c = lsctx.ctx.c.curclass in
+	let name = Printf.sprintf "%s_%s" lsctx.scom.curfield.cf_name v.v_name in
+	let c = lsctx.scom.curclass in
 	begin try
 		let cf = PMap.find name c.cl_statics in
 		raise_typing_error_ext (make_error (Custom (Printf.sprintf "The expanded name of this local (%s) conflicts with another static field" name)) ~sub:[
@@ -82,13 +82,13 @@ let promote_local_static lsctx run v eo =
 let find_local_static lut v =
 	IntHashtbl.find lut v.v_id
 
-let run ctx e =
+let run scom e =
 	let lsctx = {
-		ctx = ctx;
+		scom = scom;
 		lut = IntHashtbl.create 0;
 		added_fields = [];
 	} in
-	let c = ctx.c.curclass in
+	let c = scom.curclass in
 	let rec run e = match e.eexpr with
 		| TBlock el ->
 			let el = ExtList.List.filter_map (fun e -> match e.eexpr with

+ 15 - 15
src/filters/tre.ml

@@ -1,13 +1,13 @@
 open Type
-open Typecore
+open SafeCom
 open Globals
 
 let rec collect_new_args_values ctx args declarations values n =
 	match args with
 	| [] -> declarations, values
 	| arg :: rest ->
-		let v = gen_local ctx arg.etype arg.epos in
-		let decl = { eexpr = TVar (v, Some arg); etype = ctx.t.tvoid; epos = v.v_pos }
+		let v = alloc_var VGenerated "tmp" arg.etype arg.epos in
+		let decl = { eexpr = TVar (v, Some arg); etype = ctx.basic.tvoid; epos = v.v_pos }
 		and value = { arg with eexpr = TLocal v } in
 		collect_new_args_values ctx rest (decl :: declarations) (value :: values) (n + 1)
 
@@ -22,13 +22,13 @@ let rec assign_args vars exprs =
 
 let replacement_for_TReturn ctx fn args p =
 	let temps_rev, args_rev = collect_new_args_values ctx args [] [] 0
-	and continue = mk TContinue ctx.t.tvoid Globals.null_pos in
+	and continue = mk TContinue ctx.basic.tvoid Globals.null_pos in
 	{
-		etype = ctx.t.tvoid;
+		etype = ctx.basic.tvoid;
 		epos = p;
 		eexpr = TMeta ((Meta.TailRecursion, [], null_pos), {
 			eexpr = TBlock ((List.rev temps_rev) @ (assign_args fn.tf_args (List.rev args_rev)) @ [continue]);
-			etype = ctx.t.tvoid;
+			etype = ctx.basic.tvoid;
 			epos = p;
 		});
 	}
@@ -51,11 +51,11 @@ let rec redeclare_vars ctx vars declarations replace_list =
 	match vars with
 	| [] -> declarations, replace_list
 	| v :: rest ->
-		let new_v = alloc_var VGenerated (gen_local_prefix ^ v.v_name) v.v_type v.v_pos in
+		let new_v = alloc_var VGenerated (Typecore.gen_local_prefix ^ v.v_name) v.v_type v.v_pos in
 		let decl =
 			{
 				eexpr = TVar (new_v, Some { eexpr = TLocal v; etype = v.v_type; epos = v.v_pos; });
-				etype = ctx.t.tvoid;
+				etype = ctx.basic.tvoid;
 				epos = v.v_pos;
 			}
 		in
@@ -78,7 +78,7 @@ let rec replace_vars replace_list in_tail_recursion e =
 
 let wrap_loop ctx args body =
 	let wrap e =
-		let cond = mk (TConst (TBool true)) ctx.t.tbool Globals.null_pos in
+		let cond = mk (TConst (TBool true)) ctx.basic.tbool Globals.null_pos in
 		{ e with eexpr = TWhile (cond, e, Ast.NormalWhile) }
 	in
 	match collect_captured_args args body with
@@ -154,7 +154,7 @@ let rec transform_function ctx is_recursive_call fn =
 		if !add_loop then
 			let body =
 				if ExtType.is_void (follow fn.tf_type) then
-					mk (TBlock [body; mk (TReturn None) ctx.t.tvoid null_pos]) ctx.t.tvoid null_pos
+					mk (TBlock [body; mk (TReturn None) ctx.basic.tvoid null_pos]) ctx.basic.tvoid null_pos
 				else
 					body
 			in
@@ -199,23 +199,23 @@ let rec has_tail_recursion is_recursive_call cancel_tre function_end e =
 		check_expr (has_tail_recursion is_recursive_call cancel_tre function_end) e
 
 let run ctx =
-	if Common.defined ctx.com Define.NoTre then
+	if Define.defined ctx.defines Define.NoTre then
 		(fun e -> e)
 	else
 		(fun e ->
 			match e.eexpr with
 			| TFunction fn ->
 				let is_tre_eligible =
-					match ctx.f.curfield.cf_kind with
+					match ctx.curfield.cf_kind with
 					| Method MethDynamic -> false
 					| Method MethInline -> true
 					| Method MethNormal ->
-						PMap.mem ctx.f.curfield.cf_name ctx.c.curclass.cl_statics
+						PMap.mem ctx.curfield.cf_name ctx.curclass.cl_statics
 					| _ ->
-						has_class_field_flag ctx.f.curfield CfFinal
+						has_class_field_flag ctx.curfield CfFinal
 					in
 				let is_recursive_call callee args =
-					is_tre_eligible && is_recursive_method_call ctx.c.curclass ctx.f.curfield callee args
+					is_tre_eligible && is_recursive_method_call ctx.curclass ctx.curfield callee args
 				in
 				if has_tail_recursion is_recursive_call false true fn.tf_expr then
 					(* print_endline ("TRE: " ^ ctx.f.curfield.cf_pos.pfile ^ ": " ^ ctx.f.curfield.cf_name); *)

+ 12 - 17
src/optimization/analyzer.ml

@@ -20,6 +20,7 @@
 open StringHelper
 open Ast
 open Type
+open SafeCom
 open AnalyzerTexpr
 open AnalyzerTypes
 open OptimizerTexpr
@@ -974,16 +975,10 @@ module Run = struct
 		let id = Timer.determine_id level ["analyzer"] s identifier in
 		Timer.time timer_ctx id f ()
 
-	let create_analyzer_context (com : Common.context) config identifier e =
+	let create_analyzer_context (com : SafeCom.t) config identifier e =
 		let g = Graph.create e.etype e.epos in
 		let ctx = {
-			com = {
-				basic = com.basic;
-				platform = com.platform;
-				platform_config = com.config;
-				defines = com.defines;
-				debug = com.debug;
-			};
+			com = com;
 			config = config;
 			graph = g;
 			(* For CPP we want to use variable names which are "probably" not used by users in order to
@@ -1113,7 +1108,7 @@ module Run = struct
 		Optimizer.reduce_control_flow com e
 
 	let run_on_field' com exc_out config c cf = match cf.cf_expr with
-		| Some e when not (is_ignored cf.cf_meta) && not (FilterContext.is_removable_field com.Common.is_macro_context cf) && not (has_class_field_flag cf CfPostProcessed) ->
+		| Some e when not (is_ignored cf.cf_meta) && not (FilterContext.is_removable_field com.is_macro_context cf) && not (has_class_field_flag cf CfPostProcessed) ->
 			let config = update_config_from_meta com config cf.cf_meta in
 			let actx = create_analyzer_context com config (Printf.sprintf "%s.%s" (s_type_path c.cl_path) cf.cf_name) e in
 			let debug() =
@@ -1133,7 +1128,7 @@ module Run = struct
 			in
 			begin try
 				let e = run_on_expr actx e in
-				let e = reduce_control_flow com e in
+				let e = reduce_control_flow com.platform e in
 				maybe_debug();
 				cf.cf_expr <- Some e;
 			with
@@ -1195,24 +1190,24 @@ module Run = struct
 		| TTypeDecl _ -> ()
 		| TAbstractDecl _ -> ()
 
-	let run_on_types com types =
-		let config = get_base_config com in
+	let run_on_types com pool types =
+		let scom = SafeCom.of_com com in
+		let config = get_base_config scom in
 		with_timer com.timer_ctx config.detail_times None ["other"] (fun () ->
 			if config.optimize && config.purity_inference then
 				with_timer com.timer_ctx config.detail_times None ["optimize";"purity-inference"] (fun () -> Purity.infer com);
 			let exc_out = Atomic.make None in
-			Parallel.run_in_new_pool com.timer_ctx (fun pool ->
-				Parallel.ParallelArray.iter pool (run_on_type com exc_out pool config) (Array.of_list types);
-			);
+			Parallel.ParallelArray.iter pool (run_on_type scom exc_out pool config) types;
 			check_exc_out exc_out
 		)
 end
 ;;
 Typecore.analyzer_run_on_expr_ref := (fun com identifier e ->
-	let config = AnalyzerConfig.get_base_config com in
+	let scom = SafeCom.of_com com in
+	let config = AnalyzerConfig.get_base_config scom in
 	(* We always want to optimize because const propagation might be required to obtain
 	   a constant expression for inline field initializations (see issue #4977). *)
 	let config = {config with AnalyzerConfig.optimize = true} in
-	let actx = Run.create_analyzer_context com config identifier e in
+	let actx = Run.create_analyzer_context scom config identifier e in
 	Run.run_on_expr actx e
 )

+ 10 - 12
src/optimization/analyzerConfig.ml

@@ -19,7 +19,7 @@
 
 open Ast
 open Type
-open Common
+open SafeCom
 open Globals
 
 type debug_kind =
@@ -64,15 +64,15 @@ let is_ignored meta =
 
 let get_base_config com =
 	{
-		optimize = Common.defined com Define.AnalyzerOptimize;
-		const_propagation = not (Common.raw_defined com "analyzer_no_const_propagation");
-		copy_propagation = not (Common.raw_defined com "analyzer_no_copy_propagation");
-		local_dce = not (Common.raw_defined com "analyzer_no_local_dce");
-		fusion = not (Common.raw_defined com "analyzer_no_fusion");
-		purity_inference = not (Common.raw_defined com "analyzer_no_purity_inference");
+		optimize = Define.defined com.defines Define.AnalyzerOptimize;
+		const_propagation = not (Define.raw_defined com.defines "analyzer_no_const_propagation");
+		copy_propagation = not (Define.raw_defined com.defines "analyzer_no_copy_propagation");
+		local_dce = not (Define.raw_defined com.defines "analyzer_no_local_dce");
+		fusion = not (Define.raw_defined com.defines "analyzer_no_fusion");
+		purity_inference = not (Define.raw_defined com.defines "analyzer_no_purity_inference");
 		debug_kind = DebugNone;
 		detail_times = Timer.level_from_define com.defines Define.AnalyzerTimes;
-		user_var_fusion = (match com.platform with Flash | Jvm -> false | _ -> true) && (Common.raw_defined com "analyzer_user_var_fusion" || (not com.debug && not (Common.raw_defined com "analyzer_no_user_var_fusion")));
+		user_var_fusion = (match com.platform with Flash | Jvm -> false | _ -> true) && (Define.raw_defined com.defines "analyzer_user_var_fusion" || (not com.debug && not (Define.raw_defined com.defines "analyzer_no_user_var_fusion")));
 		fusion_debug = false;
 	}
 
@@ -99,14 +99,12 @@ let update_config_from_meta com config ml =
 						| "fusion_debug" -> { config with fusion_debug = true }
 						| "as_var" -> config
 						| _ ->
-							let options = Warning.from_meta ml in
-							com.warning WOptimizer options (StringError.string_error s all_flags ("Unrecognized analyzer option: " ^ s)) (pos e);
+							SafeCom.add_warning com WOptimizer (StringError.string_error s all_flags ("Unrecognized analyzer option: " ^ s)) (pos e);
 							config
 					end
 				| _ ->
 					let s = Ast.Printer.s_expr e in
-					let options = Warning.from_meta ml in
-					com.warning WOptimizer options (StringError.string_error s all_flags ("Unrecognized analyzer option: " ^ s)) (pos e);
+					SafeCom.add_warning com WOptimizer (StringError.string_error s all_flags ("Unrecognized analyzer option: " ^ s)) (pos e);
 					config
 			) config el
 		| (Meta.HasUntyped,_,_) ->

+ 2 - 2
src/optimization/analyzerTexpr.ml

@@ -19,7 +19,7 @@
 
 open Ast
 open Type
-open Common
+open SafeCom
 open AnalyzerTypes
 open OptimizerTexpr
 open Globals
@@ -1252,7 +1252,7 @@ module Purity = struct
 					] impure.pn_field.cf_pos)
 				end
 			| _ -> ()
-		) com.types;
+		) com.Common.types;
 		Hashtbl.iter (fun _ node ->
 			match node.pn_purity with
 			| Pure | MaybePure when not (List.exists (fun (m,_,_) -> m = Meta.Pure) node.pn_field.cf_meta) ->

+ 1 - 9
src/optimization/analyzerTypes.ml

@@ -597,16 +597,8 @@ module Graph = struct
 		Hashtbl.iter (fun _ (bb,_,_,_) -> loop [0] bb) g.g_functions
 end
 
-type light_com = {
-	basic : basic_types;
-	platform : platform;
-	defines : Define.define;
-	platform_config : PlatformConfig.platform_config;
-	debug : bool;
-}
-
 type analyzer_context = {
-	com : light_com;
+	com : SafeCom.t;
 	config : AnalyzerConfig.t;
 	graph : Graph.t;
 	temp_var_name : string;

+ 3 - 3
src/optimization/optimizer.ml

@@ -96,7 +96,7 @@ in
 			else
 				None
 
-let reduce_control_flow com e = match e.eexpr with
+let reduce_control_flow platform e = match e.eexpr with
 	| TIf ({ eexpr = TConst (TBool t) },e1,e2) ->
 		(if t then e1 else match e2 with None -> { e with eexpr = TBlock [] } | Some e -> e)
 	| TWhile ({ eexpr = TConst (TBool false) },sub,flag) ->
@@ -121,7 +121,7 @@ let reduce_control_flow com e = match e.eexpr with
 		(try List.nth el i with Failure _ -> e)
 	| TCast(e1,None) ->
 		(* TODO: figure out what's wrong with these targets *)
-		let require_cast = match com.platform with
+		let require_cast = match platform with
 			| Cpp | Flash -> true
 			| Jvm -> true
 			| _ -> false
@@ -169,7 +169,7 @@ let rec reduce_loop ctx stack e =
 				reduce_expr ctx e
 		end
 	| _ ->
-		reduce_expr ctx (reduce_control_flow ctx.com e))
+		reduce_expr ctx (reduce_control_flow ctx.com.platform e))
 
 let reduce_expression ctx e =
 	if ctx.com.foptimize then begin

+ 15 - 9
src/typing/macroContext.ml

@@ -605,14 +605,6 @@ and flush_macro_context mint mctx =
 		mctx.com.types <- types;
 		mctx.com.Common.modules <- modules;
 		let ectx = Exceptions.create_exception_context mctx in
-		let cv_wrapper_impl = CapturedVars.get_wrapper_implementation mctx.com in
-		(* we should maybe ensure that all filters in Main are applied. Not urgent atm *)
-		let expr_filters = [
-			"handle_abstract_casts",AbstractCast.handle_abstract_casts;
-			"local_statics",LocalStatic.run;
-			"Exceptions",(fun _ -> Exceptions.filter ectx);
-			"captured_vars",(fun _ -> CapturedVars.captured_vars mctx.com cv_wrapper_impl);
-		] in
 		(*
 			some filters here might cause side effects that would break compilation server.
 			let's save the minimal amount of information we need
@@ -653,10 +645,24 @@ and flush_macro_context mint mctx =
 			in
 			if apply_native then Native.apply_native_paths t
 		in
+		let scom = SafeCom.of_com mctx.com in
+		let cv_wrapper_impl = CapturedVars.get_wrapper_implementation mctx.com in
+		let expr_filters = [
+			"handle_abstract_casts",AbstractCast.handle_abstract_casts;
+			"local_statics",(fun tctx ->
+				let scom = SafeCom.of_typer tctx in
+				LocalStatic.run scom
+			);
+			"Exceptions",(fun _ -> Exceptions.filter ectx);
+			"captured_vars",(fun tctx ->
+				let scom = SafeCom.of_typer tctx in
+				CapturedVars.captured_vars scom cv_wrapper_impl
+			);
+		] in
 		let type_filters = [
 			FiltersCommon.remove_generic_base;
 			Exceptions.patch_constructors mctx ectx;
-			(fun mt -> AddFieldInits.add_field_inits mctx.c.curclass.cl_path (RenameVars.init mctx.com) mctx.com mt);
+			(fun mt -> AddFieldInits.add_field_inits mctx.c.curclass.cl_path (RenameVars.init mctx.com.config mctx.com.types) scom mt);
 			Filters.update_cache_dependencies ~close_monomorphs:false mctx.com;
 			minimal_restore;
 			maybe_apply_native_paths

+ 2 - 3
tests/misc/projects/Issue7447/Main.hx → tests/misc/projects/Issue7447/Main1.hx

@@ -1,7 +1,6 @@
-class Main {
+class Main1 {
 	static function main() {
-		var v;
-		trace(() -> v);
+
 	}
 }
 

+ 6 - 0
tests/misc/projects/Issue7447/Main2.hx

@@ -0,0 +1,6 @@
+class Main2 {
+	static function main() {
+		var v;
+		trace(() -> v);
+	}
+}

+ 1 - 0
tests/misc/projects/Issue7447/compile-1.hxml

@@ -0,0 +1 @@
+-main Main1

+ 1 - 0
tests/misc/projects/Issue7447/compile-1.hxml.stderr

@@ -0,0 +1 @@
+Main1.hx:9: characters 15-19 : Warning : (WVarInit) this might be used before assigning a value to it

+ 1 - 0
tests/misc/projects/Issue7447/compile-2.hxml

@@ -0,0 +1 @@
+-main Main2

+ 1 - 0
tests/misc/projects/Issue7447/compile-2.hxml.stderr

@@ -0,0 +1 @@
+Main2.hx:4: characters 15-16 : Warning : (WVarInit) Local variable v might be used before being initialized

+ 0 - 1
tests/misc/projects/Issue7447/compile.hxml

@@ -1 +0,0 @@
--main Main

+ 0 - 2
tests/misc/projects/Issue7447/compile.hxml.stderr

@@ -1,2 +0,0 @@
-Main.hx:4: characters 15-16 : Warning : (WVarInit) Local variable v might be used before being initialized
-Main.hx:10: characters 15-19 : Warning : (WVarInit) this might be used before assigning a value to it

+ 4 - 4
tests/optimization/src/TestTreGeneration.hx

@@ -5,9 +5,9 @@ class TestTreGeneration {
 		}
 		while(true) {
 			if(Std.random(2) == 0) {
-				var _g = a;
+				var tmp = a;
 				a = b + a;
-				b = _g;
+				b = tmp;
 				s += "?";
 				continue;
 			}
@@ -33,9 +33,9 @@ class TestTreGeneration {
 			}
 			while(true) {
 				if(Std.random(2) == 0) {
-					var _g = a;
+					var tmp = a;
 					a = b + a;
-					b = _g;
+					b = tmp;
 					s += "?";
 					continue;
 				}