2
0
Эх сурвалжийг харах

handle abstract casts for arguments while inlining (fixed issue #1730)

Simon Krajewski 12 жил өмнө
parent
commit
79e7877479

+ 7 - 4
optimizer.ml

@@ -149,7 +149,7 @@ let rec type_inline ctx cf f ethis params tret config p force =
 			}
 	in
 	(* use default values for null/unset arguments *)
-	let rec loop pl al =
+	let rec loop pl al first =
 		match pl, al with
 		| _, [] -> []
 		| e :: pl, (v, opt) :: al ->
@@ -165,16 +165,19 @@ let rec type_inline ctx cf f ethis params tret config p force =
 			if v.v_type != t_dynamic && follow e.etype == t_dynamic then (local v).i_write <- true;
 			(match e.eexpr, opt with
 			| TConst TNull , Some c -> mk (TConst c) v.v_type e.epos
-			| _ -> e) :: loop pl al
+			(* we have to check for abstract casts here because we can't do that later. However, we have to skip the check for the
+			   first argument of abstract implementation functions. *)
+			| _ when not (first && Meta.has Meta.Impl cf.cf_meta) -> (!check_abstract_cast_ref) ctx (map_type v.v_type) e e.epos
+			| _ -> e) :: loop pl al false
 		| [], (v,opt) :: al ->
-			mk (TConst (match opt with None -> TNull | Some c -> c)) v.v_type p :: loop [] al
+			mk (TConst (match opt with None -> TNull | Some c -> c)) v.v_type p :: loop [] al false
 	in
 	(*
 		Build the expr/var subst list
 	*)
 	let ethis = (match ethis.eexpr with TConst TSuper -> { ethis with eexpr = TConst TThis } | _ -> ethis) in
 	let vthis = alloc_var "_this" ethis.etype in
-	let inlined_vars = List.map2 (fun e (v,_) -> local v, e) (ethis :: loop params f.tf_args) ((vthis,None) :: f.tf_args) in
+	let inlined_vars = List.map2 (fun e (v,_) -> local v, e) (ethis :: loop params f.tf_args true) ((vthis,None) :: f.tf_args) in
 	(*
 		here, we try to eliminate final returns from the expression tree.
 		However, this is not entirely correct since we don't yet correctly propagate

+ 14 - 0
tests/unit/MyAbstract.hx

@@ -250,4 +250,18 @@ abstract MyAbstractSetter(Dynamic) {
 		this.value = s;
 		return s;
 	}
+}
+
+abstract MyAbstractCounter(Int) {
+	public static var counter = 0;
+	inline function new(v:Int) {
+		this = v;
+		counter++;
+	}
+
+	@:from inline static public function fromInt(v:Int) {
+		return new MyAbstractCounter(v);
+	}
+	
+	inline public function getValue():Int return this + 1;
 }

+ 13 - 0
tests/unit/TestBasetypes.hx

@@ -433,6 +433,19 @@ class TestBasetypes extends Test {
 		eq("Distance: 12.5km", "Distance: " + km);
 		eq("Distance: 12.5m", "Distance: " + m);
 	}
+	
+	function testAbstractInline() {
+		eq(getAbstractValue(1), 2);
+		eq(unit.MyAbstract.MyAbstractCounter.counter, 1);
+		eq(getAbstractValue(2), 3);
+		eq(unit.MyAbstract.MyAbstractCounter.counter, 2);
+		eq(getAbstractValue(3), 4);
+		eq(unit.MyAbstract.MyAbstractCounter.counter, 3);
+	}
+	
+	inline function getAbstractValue(a:unit.MyAbstract.MyAbstractCounter) {
+		return a.getValue();
+	}
 
 	function testAbstractOperatorOverload() {
 		var v1:unit.MyAbstract.MyVector = new unit.MyAbstract.MyPoint3(1, 1, 1);

+ 1 - 0
typecore.ml

@@ -142,6 +142,7 @@ let unify_min_ref : (typer -> texpr list -> t) ref = ref (fun _ _ -> assert fals
 let match_expr_ref : (typer -> Ast.expr -> (Ast.expr list * Ast.expr option * Ast.expr option) list -> Ast.expr option option -> with_type -> Ast.pos -> texpr) ref = ref (fun _ _ _ _ _ _ -> assert false)
 let get_pattern_locals_ref : (typer -> Ast.expr -> Type.t -> (string, tvar) PMap.t) ref = ref (fun _ _ _ -> assert false)
 let get_constructor_ref : (typer -> tclass -> t list -> Ast.pos -> (t * tclass_field)) ref = ref (fun _ _ _ _ -> assert false)
+let check_abstract_cast_ref : (typer -> t -> texpr -> Ast.pos -> texpr) ref = ref (fun _ _ _ _ -> assert false)
 
 (* Source: http://en.wikibooks.org/wiki/Algorithm_implementation/Strings/Levenshtein_distance#OCaml *)
 let levenshtein a b =

+ 2 - 1
typer.ml

@@ -4076,4 +4076,5 @@ let rec create com =
 ;;
 unify_min_ref := unify_min;
 make_call_ref := make_call;
-get_constructor_ref := get_constructor;
+get_constructor_ref := get_constructor;
+check_abstract_cast_ref := Codegen.Abstract.check_cast;