Browse Source

handle unsafe upcasts while inlining (fixed issue #1219)

Simon Krajewski 12 years ago
parent
commit
31cc9ae008
3 changed files with 45 additions and 5 deletions
  1. 17 4
      optimizer.ml
  2. 23 1
      tests/unit/MyClass.hx
  3. 5 0
      tests/unit/TestType.hx

+ 17 - 4
optimizer.ml

@@ -214,7 +214,11 @@ let rec type_inline ctx cf f ethis params tret config p force =
 			if not term then error "Cannot inline a not final return" po;
 			(match eo with
 			| None -> mk (TConst TNull) f.tf_type p
-			| Some e -> has_return_value := true; map term e)
+			| Some e -> has_return_value := true;
+				(* we can omit unsafe casts to retain the real type, the cast will be added back later anyway *)
+				(match e.eexpr with
+				| TCast(e1,None) -> map term e1
+				| _ -> map term e))
 		| TFor (v,e1,e2) ->
 			let i = local v in
 			let e1 = map false e1 in
@@ -366,15 +370,24 @@ let rec type_inline ctx cf f ethis params tret config p force =
 		let wrap e =
 			(* we can't mute the type of the expression because it is not correct to do so *)
 			(try
+				let etype = if has_params then map_type e.etype else e.etype in
 				(* if the expression is "untyped" and we don't want to unify it accidentally ! *)
 				(match follow e.etype with
 				| TMono _ ->
 					(match follow tret with
 					| TEnum ({ e_path = [],"Void" },_) | TAbstract ({ a_path = [],"Void" },_) -> e
 					| _ -> raise (Unify_error []))
-				| _ ->
-					type_eq EqStrict (if has_params then map_type e.etype else e.etype) tret;
-					e)
+				| _ -> try
+					type_eq EqStrict etype tret;
+					e
+				with Unify_error _ ->
+					(* try to detect upcasts: in that case we may use a safe cast *)
+					Type.unify tret etype;
+					let ct = match follow tret with
+						| TInst(c,_) -> Some (TClassDecl c)
+						| _ -> None
+					in
+					mk (TCast (e,ct)) tret e.epos)
 			with Unify_error _ ->
 				mk (TCast (e,None)) tret e.epos)
 		in

+ 23 - 1
tests/unit/MyClass.hx

@@ -278,5 +278,27 @@ class ChildSuperProp extends BaseSuperProp {
 	
 	public function test() {
 		return super.fProp(2);
-	}	
+	}
+}
+
+class InlineCastA {
+	function self() : InlineCastA {
+		return this;
+	}
 }
+
+class InlineCastB extends InlineCastA {
+	public function new() { }
+
+	public inline function test() : InlineCastB {
+		#if as3
+		return cast (self(), InlineCastB);
+		#else
+		return cast self();
+		#end
+	}
+
+	public function quote() {
+		return "I am the greatest.";
+	}
+}

+ 5 - 0
tests/unit/TestType.hx

@@ -363,6 +363,11 @@ class TestType extends Test {
 		typedAs(c.contravariant, b);
 		typedAs(cast (c, Ctrv1).contravariant, c1);
 	}
+	
+	function testInlineCast() {
+		var s = new InlineCastB().test().quote();
+		eq(s, "I am the greatest.");
+	}
 
 	function testInitFields()
 	{