浏览代码

Respect `@:pure(false)` on var fields (#8338)

* wip

* respect `@:pure(false)` on var fields
Aleksandr Kuzmenko 6 年之前
父节点
当前提交
1ac9d2a388

+ 1 - 0
src/context/display/diagnostics.ml

@@ -69,6 +69,7 @@ let check_other_things com e =
 			no_effect e.epos;
 		| TConst _ | TLocal _ | TTypeExpr _ | TEnumParameter _ | TEnumIndex _ | TVar _ | TIdent _ ->
 			()
+		| TField (_, fa) when PurityState.is_explicitly_impure fa -> ()
 		| TFunction tf ->
 			loop false tf.tf_expr
 		| TCall({eexpr = TField(e1,fa)},el) when not in_value && PurityState.is_pure_field_access fa -> compound "call" el e.epos

+ 8 - 0
src/context/purityState.ml

@@ -52,6 +52,14 @@ let is_pure_field_access fa = match fa with
 	| FEnum _ -> true
 	| FDynamic _ -> false
 
+let is_explicitly_impure fa = match fa with
+	| FInstance(c,_,cf) | FClosure(Some(c,_),cf) | FStatic(c,cf) ->
+		get_purity_from_meta cf.cf_meta = Impure
+		|| get_purity_from_meta c.cl_meta = Impure
+	| FAnon cf | FClosure(None,cf) ->
+		get_purity_from_meta cf.cf_meta = Impure
+	| _ -> false
+
 let to_string = function
 	| Pure -> "pure"
 	| Impure -> "impure"

+ 1 - 0
src/optimization/analyzer.ml

@@ -622,6 +622,7 @@ module LocalDce = struct
 			| TCall ({eexpr = TField(_,FEnum _)},_) -> Type.iter loop e
 			| TCall ({eexpr = TConst (TString ("phi" | "fun"))},_) -> ()
 			| TCall({eexpr = TField(e1,fa)},el) when PurityState.is_pure_field_access fa -> loop e1; List.iter loop el
+			| TField(_,fa) when PurityState.is_explicitly_impure fa -> raise Exit
 			| TNew _ | TCall _ | TBinop ((OpAssignOp _ | OpAssign),_,_) | TUnop ((Increment|Decrement),_,_) -> raise Exit
 			| TReturn _ | TBreak | TContinue | TThrow _ | TCast (_,Some _) -> raise Exit
 			| TFor _ -> raise Exit

+ 2 - 0
src/optimization/analyzerTexpr.ml

@@ -647,6 +647,8 @@ module Fusion = struct
 			| {eexpr = TLocal v} :: el ->
 				state#dec_reads v;
 				block_element acc el
+			| {eexpr = TField (_,fa)} as e1 :: el when PurityState.is_explicitly_impure fa ->
+				block_element (e1 :: acc) el
 			(* no-side-effect *)
 			| {eexpr = TEnumParameter _ | TEnumIndex _ | TFunction _ | TConst _ | TTypeExpr _} :: el ->
 				block_element acc el

+ 4 - 0
src/optimization/analyzerTexprTransformer.ml

@@ -601,6 +601,10 @@ let rec func ctx bb tf t p =
 		| TLocal _ when not ctx.config.AnalyzerConfig.local_dce ->
 			add_texpr bb e;
 			bb
+		| TField (e1,fa) when has_side_effect e ->
+			let bb,e1 = value bb e1 in
+			add_texpr bb {e with eexpr = TField(e1,fa)};
+			bb
 		(* no-side-effect *)
 		| TEnumParameter _ | TEnumIndex _ | TFunction _ | TConst _ | TTypeExpr _ | TLocal _ | TIdent _ ->
 			bb

+ 1 - 0
src/optimization/optimizerTexpr.ml

@@ -10,6 +10,7 @@ let has_side_effect e =
 		| TConst _ | TLocal _ | TTypeExpr _ | TFunction _ | TIdent _ -> ()
 		| TCall({eexpr = TField(e1,fa)},el) when PurityState.is_pure_field_access fa -> loop e1; List.iter loop el
 		| TNew(c,_,el) when (match c.cl_constructor with Some cf when PurityState.is_pure c cf -> true | _ -> false) -> List.iter loop el
+		| TField(_,fa) when PurityState.is_explicitly_impure fa -> raise Exit
 		| TNew _ | TCall _ | TBinop ((OpAssignOp _ | OpAssign),_,_) | TUnop ((Increment|Decrement),_,_) -> raise Exit
 		| TReturn _ | TBreak | TContinue | TThrow _ | TCast (_,Some _) -> raise Exit
 		| TArray _ | TEnumParameter _ | TEnumIndex _ | TCast (_,None) | TBinop _ | TUnop _ | TParenthesis _ | TMeta _ | TWhile _ | TFor _

+ 24 - 0
tests/optimization/src/issues/Issue8226.hx

@@ -0,0 +1,24 @@
+package issues;
+
+class Issue8226 {
+	@:pure(false) static var testStatic:String;
+	static var pureStatic:String;
+
+	@:pure(false) var testInstance:String;
+	var pureInstance:String;
+
+	@:js('
+		issues_Issue8226.testStatic;
+		new issues_Issue8226().testInstance;
+	')
+	static function test() {
+		testStatic;
+		pureStatic;
+
+		var m = new Issue8226();
+		m.testInstance;
+		m.pureInstance;
+	}
+
+	public function new() {}
+}