Преглед на файлове

[cs] Correctly handle generic types when accessing through Class or resolveClass. Closes #3658

Cauê Waneck преди 10 години
родител
ревизия
dd57bdae17
променени са 7 файла, в които са добавени 92 реда и са изтрити 10 реда
  1. 6 0
      gencommon.ml
  2. 5 0
      gencs.ml
  3. 6 7
      std/cs/_std/Type.hx
  4. 13 0
      std/cs/internal/HxObject.hx
  5. 38 3
      std/cs/internal/Runtime.hx
  6. 7 0
      tests/unit/src/unit/TestReflect.hx
  7. 17 0
      tests/unit/src/unit/issues/Issue3658.hx

+ 6 - 0
gencommon.ml

@@ -4830,6 +4830,12 @@ struct
 							iface.cl_array_access <- Option.map (apply_params (cl.cl_params) (List.map (fun _ -> t_dynamic) cl.cl_params)) cl.cl_array_access;
 							iface.cl_module <- cl.cl_module;
 							iface.cl_meta <- (Meta.HxGen, [], cl.cl_pos) :: iface.cl_meta;
+							if gen.gcon.platform = Cs then begin
+								let tparams = List.map (fun _ -> "object") cl.cl_params in
+								iface.cl_meta <- (Meta.Meta, [
+									EConst( String("haxe.lang.GenericInterface(typeof(" ^ path_s cl.cl_path ^ "<" ^ String.concat ", " tparams ^">))") ), cl.cl_pos
+								], cl.cl_pos) :: iface.cl_meta
+							end;
 							Hashtbl.add ifaces cl.cl_path iface;
 
 							iface.cl_implements <- (base_generic, []) :: iface.cl_implements;

+ 5 - 0
gencs.ml

@@ -1789,6 +1789,11 @@ let configure gen =
 
 	let gen_attributes w metadata =
 		List.iter (function
+			| Meta.Meta, [EConst(String s), _], _ ->
+				write w "[";
+				write w s;
+				write w "]";
+				newline w
 			| Meta.Meta, [meta], _ ->
 				write w "[";
 				gen_spart w meta;

+ 6 - 7
std/cs/_std/Type.hx

@@ -127,18 +127,17 @@ using StringTools;
 				case #if no_root "haxe.root.String" #else "String" #end: return cast String;
 				default: return null;
 			}
+#if !erase_generics
 		} else if (t.IsInterface && cast(untyped __typeof__(IGenericObject), cs.system.Type).IsAssignableFrom(t)) {
-			t = null;
-			var i = 0;
-			var ts = "";
-			while (t == null && i < 18)
+			for (attr in t.GetCustomAttributes(true))
 			{
-				i++;
-				ts += (i == 1 ? "" : ",") + "System.Object";
-				t = cs.system.Type._GetType(name + "`" + i + "[" + ts + "]");
+				var g = cs.Lib.as(attr, cs.internal.HxObject.GenericInterface);
+				if (g != null)
+					return Lib.fromNativeType(g.generic);
 			}
 
 			return Lib.fromNativeType(t);
+#end
 		} else {
 			return Lib.fromNativeType(t);
 		}

+ 13 - 0
std/cs/internal/HxObject.hx

@@ -64,10 +64,23 @@ class DynamicObject extends HxObject implements Dynamic
 	}
 }
 
+#if !erase_generics
 @:keep @:native('haxe.lang.IGenericObject') interface IGenericObject
 {
 }
 
+@:nativeGen @:keep @:native('haxe.lang.GenericInterface') class GenericInterface extends cs.system.Attribute
+{
+	@:readOnly public var generic(default,never):cs.system.Type;
+
+	public function new(generic)
+	{
+		super();
+		untyped this.generic = generic;
+	}
+}
+#end
+
 @:keep @:native('haxe.lang.Enum') @:nativeGen
 #if core_api_serialize
 @:meta(System.Serializable)

+ 38 - 3
std/cs/internal/Runtime.hx

@@ -119,6 +119,7 @@ import cs.system.Object;
 		if (v1v != null)
 		{
 			return v1.Equals(v2);
+#if !erase_generics
 		} else {
 			var v1t = Lib.as(v1, Type);
 			if (v1t != null)
@@ -128,6 +129,7 @@ import cs.system.Object;
 					return typeEq(v1t, v2t);
 				return false;
 			}
+#end
 		}
 
 		return false;
@@ -135,8 +137,10 @@ import cs.system.Object;
 
 	public static function refEq(v1: { }, v2: { } ):Bool
 	{
+#if !erase_generics
 		if (Std.is(v1, Type))
 			return typeEq(Lib.as(v1,Type), Lib.as(v2,Type));
+#end
 		return Object.ReferenceEquals(v1,v2);
 	}
 
@@ -752,16 +756,47 @@ import cs.system.Object;
 		return untyped obj.ToString();
 	}
 
+#if erase_generics
+	inline
+#end
 	public static function typeEq(t1:Type, t2:Type):Bool
 	{
 		if (t1 == null || t2 == null)
 			return t1 == t2;
-		var n1 = std.Type.getClassName(cast t1);
-		var n2 = std.Type.getClassName(cast t2);
-		return n1 == n2;
+#if !erase_generics
+		var t1i = t1.IsInterface,
+		    t2i = t2.IsInterface;
+		if (t1i != t2i)
+		{
+			if (t1i)
+			{
+				var g = getGenericAttr(t1);
+				if (g != null)
+					t1 = g.generic;
+			} else {
+				var g = getGenericAttr(t2);
+				if (g != null)
+					t2 = g.generic;
+			}
+		}
+
+#end
+		if (t1.GetGenericArguments().Length > 0) t1 = t1.GetGenericTypeDefinition();
+		if (t2.GetGenericArguments().Length > 0) t2 = t2.GetGenericTypeDefinition();
+		return Object.ReferenceEquals(t1,t2);
 	}
 
 
+#if !erase_generics
+	private static function getGenericAttr(t:cs.system.Type):cs.internal.HxObject.GenericInterface
+	{
+		for (attr in t.GetCustomAttributes(true))
+			if (Std.is(attr,cs.internal.HxObject.GenericInterface))
+				return cast attr;
+		return null;
+	}
+#end
+
 #if !erase_generics
 	@:functionCode('
 		if (obj is To)

+ 7 - 0
tests/unit/src/unit/TestReflect.hx

@@ -153,6 +153,13 @@ class TestReflect extends Test {
 		t( Std.is(v,Dynamic), pos );
 	}
 
+	public function testTypeEq()
+	{
+		eq(cast Array, Type.resolveClass("Array"));
+		eq(cast Array, Type.getClass([]));
+		eq(cast Array, Type.getClass([1]));
+	}
+
 	public function testTypeof() {
 		typeof(null,TNull);
 		typeof(0,TInt);

+ 17 - 0
tests/unit/src/unit/issues/Issue3658.hx

@@ -0,0 +1,17 @@
+package unit.issues;
+
+class Issue3658 extends Test
+{
+	public function test()
+	{
+		eq("testStatic", Type.getClassFields(MyClass)[0]);
+		eq("testStatic", Type.getClassFields(Type.resolveClass(Type.getClassName(MyClass)))[0]);
+	}
+}
+
+@:keep private class MyClass<T>
+{
+	public static function testStatic()
+	{
+	}
+}