浏览代码

fix valid redefinition for dynamic methods and function variables, and allow read/write variance for interface variables (closes #3361)

Simon Krajewski 11 年之前
父节点
当前提交
244c426621

+ 17 - 0
tests/misc/projects/Issue3361/Main.hx

@@ -0,0 +1,17 @@
+interface I {
+	public var v:Dynamic->Void;
+}
+
+class C implements I {
+	public var v:String->Void;
+	public function new() { }
+}
+
+class Main {
+	static function main() {
+		var c = new C();
+		var i:I = c;
+		i.v = function(i:Main) { trace(i); }
+		c.v("foo");
+	}
+}

+ 17 - 0
tests/misc/projects/Issue3361/Main2.hx

@@ -0,0 +1,17 @@
+interface I {
+	public dynamic function f(d:Dynamic):Void;
+}
+
+class C implements I {
+	public dynamic function f(s:String):Void { }
+	public function new() { }
+}
+
+class Main2 {
+	static function main() {
+		var c = new C();
+		var i:I = c;
+		i.f = function(i:Main2) { trace(i); }
+		c.f("foo");
+	}
+}

+ 31 - 0
tests/misc/projects/Issue3361/Main3.hx

@@ -0,0 +1,31 @@
+interface I {
+    public var v(default, never):Dynamic;
+}
+
+class C implements I {
+    public var v:String;
+    public function new() { }
+}
+
+interface I2 {
+	public var v(never, default):String;
+}
+
+class C2 implements I2 {
+	public var v:Dynamic;
+	public function new() { }
+}
+
+class Main3 {
+    static function main() {
+        var c = new C();
+        var i:I = c;
+		c.v = "foo";
+		i.v;
+
+		var c2 = new C2();
+		var i2:I2 = c2;
+		i2.v = "foo";
+		c.v;
+    }
+}

+ 1 - 0
tests/misc/projects/Issue3361/compile.hxml

@@ -0,0 +1 @@
+--run Main3

+ 1 - 0
tests/misc/projects/Issue3361/compile1-fail.hxml

@@ -0,0 +1 @@
+--run Main

+ 3 - 0
tests/misc/projects/Issue3361/compile1-fail.hxml.stderr

@@ -0,0 +1,3 @@
+Main.hx:5: lines 5-8 : Field v has different type than in I
+Main.hx:5: lines 5-8 : String -> Void should be Dynamic -> Void
+Main.hx:5: lines 5-8 : String should be Dynamic

+ 1 - 0
tests/misc/projects/Issue3361/compile2-fail.hxml

@@ -0,0 +1 @@
+--run Main2

+ 3 - 0
tests/misc/projects/Issue3361/compile2-fail.hxml.stderr

@@ -0,0 +1,3 @@
+Main2.hx:6: characters 16-45 : Field f has different type than in I
+Main2.hx:6: characters 16-45 : s : String -> Void should be d : Dynamic -> Void
+Main2.hx:6: characters 16-45 : String should be Dynamic

+ 20 - 9
typeload.ml

@@ -707,15 +707,26 @@ let valid_redefinition ctx f1 t1 f2 t2 =
 			(* ignore type params, will create other errors later *)
 			t1, t2
 	) in
-	match follow t1, follow t2 with
-	| TFun (args1,r1) , TFun (args2,r2) when List.length args1 = List.length args2 -> (try
-			List.iter2 (fun (n,o1,a1) (_,o2,a2) ->
-				if o1 <> o2 then raise (Unify_error [Not_matching_optional n]);
-				(try valid a2 a1 with Unify_error _ -> raise (Unify_error [Cannot_unify(a1,a2)]))
-			) args1 args2;
-			valid r1 r2
-		with Unify_error l ->
-			raise (Unify_error (Cannot_unify (t1,t2) :: l)))
+	match f1.cf_kind,f2.cf_kind with
+	| Method m1, Method m2 when not (m1 = MethDynamic) && not (m2 = MethDynamic) ->
+		begin match follow t1, follow t2 with
+		| TFun (args1,r1) , TFun (args2,r2) when List.length args1 = List.length args2 -> (try
+				List.iter2 (fun (n,o1,a1) (_,o2,a2) ->
+					if o1 <> o2 then raise (Unify_error [Not_matching_optional n]);
+					(try valid a2 a1 with Unify_error _ -> raise (Unify_error [Cannot_unify(a1,a2)]))
+				) args1 args2;
+				valid r1 r2
+			with Unify_error l ->
+				raise (Unify_error (Cannot_unify (t1,t2) :: l)))
+		| _ ->
+			assert false
+		end
+	| _,(Var { v_write = AccNo | AccNever }) ->
+		(* write variance *)
+		valid t2 t1
+	| _,(Var { v_read = AccNo | AccNever }) ->
+		(* read variance *)
+		valid t1 t2
 	| _ , _ ->
 		(* in case args differs, or if an interface var *)
 		type_eq EqStrict t1 t2;