Browse Source

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

Simon Krajewski 12 years ago
parent
commit
79e7877479
5 changed files with 37 additions and 5 deletions
  1. 7 4
      optimizer.ml
  2. 14 0
      tests/unit/MyAbstract.hx
  3. 13 0
      tests/unit/TestBasetypes.hx
  4. 1 0
      typecore.ml
  5. 2 1
      typer.ml

+ 7 - 4
optimizer.ml

@@ -149,7 +149,7 @@ let rec type_inline ctx cf f ethis params tret config p force =
 			}
 			}
 	in
 	in
 	(* use default values for null/unset arguments *)
 	(* use default values for null/unset arguments *)
-	let rec loop pl al =
+	let rec loop pl al first =
 		match pl, al with
 		match pl, al with
 		| _, [] -> []
 		| _, [] -> []
 		| e :: pl, (v, opt) :: al ->
 		| 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;
 			if v.v_type != t_dynamic && follow e.etype == t_dynamic then (local v).i_write <- true;
 			(match e.eexpr, opt with
 			(match e.eexpr, opt with
 			| TConst TNull , Some c -> mk (TConst c) v.v_type e.epos
 			| 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 ->
 		| [], (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
 	in
 	(*
 	(*
 		Build the expr/var subst list
 		Build the expr/var subst list
 	*)
 	*)
 	let ethis = (match ethis.eexpr with TConst TSuper -> { ethis with eexpr = TConst TThis } | _ -> ethis) in
 	let ethis = (match ethis.eexpr with TConst TSuper -> { ethis with eexpr = TConst TThis } | _ -> ethis) in
 	let vthis = alloc_var "_this" ethis.etype 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.
 		here, we try to eliminate final returns from the expression tree.
 		However, this is not entirely correct since we don't yet correctly propagate
 		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;
 		this.value = s;
 		return 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.5km", "Distance: " + km);
 		eq("Distance: 12.5m", "Distance: " + m);
 		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() {
 	function testAbstractOperatorOverload() {
 		var v1:unit.MyAbstract.MyVector = new unit.MyAbstract.MyPoint3(1, 1, 1);
 		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 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_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 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 *)
 (* Source: http://en.wikibooks.org/wiki/Algorithm_implementation/Strings/Levenshtein_distance#OCaml *)
 let levenshtein a b =
 let levenshtein a b =

+ 2 - 1
typer.ml

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