Browse Source

Reduce excessive casts (#8725)

* reduce sequential unsafe casts

* fix & test

* "fix" cs & cpp

* keep at least one cast for cpp, flash, jvm and cs+erase_generics

* move to optimizer
Aleksandr Kuzmenko 6 năm trước cách đây
mục cha
commit
2d68fc0cce
3 tập tin đã thay đổi với 45 bổ sung1 xóa
  1. 21 1
      src/core/texpr.ml
  2. 9 0
      src/optimization/optimizer.ml
  3. 15 0
      tests/optimization/src/TestJs.hx

+ 21 - 1
src/core/texpr.ml

@@ -532,4 +532,24 @@ let collect_captured_vars e =
 			Type.iter loop e
 	in
 	loop e;
-	List.rev !unknown,!accesses_this
+	List.rev !unknown,!accesses_this
+
+(**
+	If `e` contains a sequence of unsafe casts, then look if that sequence
+	already has casts to `t` and return the bottom-most of such casts.
+	If `require_cast` is `false` and the first non-cast expression has type `t`, then return that expression without any casts.
+	In other cases return `e` as-is.
+*)
+let reduce_unsafe_casts ?(require_cast=false) e t =
+	let t = follow t in
+	let same_type etype = fast_eq t (follow etype) in
+	let rec loop e result =
+		match e.eexpr with
+		| TCast(subject,None) ->
+			if same_type e.etype then loop subject e
+			else loop subject result
+		| _ ->
+			if not require_cast && same_type e.etype then e
+			else result
+	in
+	loop e e

+ 9 - 0
src/optimization/optimizer.ml

@@ -264,6 +264,15 @@ let reduce_control_flow ctx e = match e.eexpr with
 	| TEnumParameter({eexpr = TParenthesis {eexpr = TCall({eexpr = TField(_,FEnum(_,ef1))},el)}},ef2,i)
 		when ef1 == ef2 && check_enum_construction_args el i ->
 		(try List.nth el i with Failure _ -> e)
+	| TCast(e1,None) ->
+		(* TODO: figure out what's wrong with these targets *)
+		let require_cast = match ctx.com.platform with
+			| Cpp | Flash -> true
+			| Java -> defined ctx.com Define.Jvm
+			| Cs -> defined ctx.com Define.EraseGenerics
+			| _ -> false
+		in
+		Texpr.reduce_unsafe_casts ~require_cast e e.etype
 	| _ ->
 		e
 

+ 15 - 0
tests/optimization/src/TestJs.hx

@@ -547,8 +547,23 @@ class TestJs {
 	static function testIssue7874() {
 		if (v && v) {}
 	}
+
+	@:js('')
+	static function testIssue8751() {
+		(2:Issue8751Int) * 3;
+	}
 }
 
 extern class Extern {
 	static public function test(e:haxe.extern.AsVar<String>):Void;
+}
+
+abstract Issue8751Int(Int) from Int {
+	@:op(A * B) static public inline function add(a:Issue8751Int, b:Issue8751Int):Issue8751Int {
+		return a.toInt() * b.toInt();
+	}
+
+	inline public function toInt():Int {
+		return this;
+	}
 }