Browse Source

[cs] Various enum-related fixes:

- Generate all non-@:nativeGen enums as classes (See #3338, Closes
- [java/cs] Cleanup how enums and enums with parameters are generated; use Vector
instead of array
- Do not make any assumptions about how the enums will be laid out at
runtime (Closes #2931)
- Added test for #3389
Cauê Waneck 10 years ago
parent
commit
90ddbdfa14

+ 31 - 37
gencommon.ml

@@ -631,6 +631,9 @@ and gen_classes =
 	cl_dyn : tclass;
 	cl_dyn : tclass;
 
 
 	t_iterator : tdef;
 	t_iterator : tdef;
+
+	a_vector : tabstract;
+	tvector : Type.t -> Type.t;
 }
 }
 
 
 (* add here all reflection transformation additions *)
 (* add here all reflection transformation additions *)
@@ -687,6 +690,9 @@ let new_ctx con =
 			cl_dyn = cl_dyn;
 			cl_dyn = cl_dyn;
 
 
 			t_iterator = get_tdef (get_type con.types ([], "Iterator"));
 			t_iterator = get_tdef (get_type con.types ([], "Iterator"));
+
+			a_vector = get_abstract (get_type con.types (["haxe";"ds"],"Vector"));
+			tvector = (fun t -> TAbstract(gen.gclasses.a_vector,[t]));
 		};
 		};
 		gtools = {
 		gtools = {
 			r_create_empty = (fun eclass t ->
 			r_create_empty = (fun eclass t ->
@@ -8939,6 +8945,7 @@ struct
 		dependencies:
 		dependencies:
 			Should run before ReflectionCFs, in order to enable proper reflection access.
 			Should run before ReflectionCFs, in order to enable proper reflection access.
 			Should run before TypeParams.RealTypeParams.RealTypeParamsModf, since generic enums must be first converted to generic classes
 			Should run before TypeParams.RealTypeParams.RealTypeParamsModf, since generic enums must be first converted to generic classes
+			It needs that the target platform implements __array__() as a shortcut to declare haxe.ds.Vector
 	*)
 	*)
 
 
 	module EnumToClassModf =
 	module EnumToClassModf =
@@ -8954,7 +8961,7 @@ struct
 			let has_meta meta = List.exists (fun (m,_,_) -> match m with Meta.Custom _ -> true | _ -> false) meta in
 			let has_meta meta = List.exists (fun (m,_,_) -> match m with Meta.Custom _ -> true | _ -> false) meta in
 			has_meta en.e_meta || pmap_exists (fun _ ef -> has_meta ef.ef_meta) en.e_constrs
 			has_meta en.e_meta || pmap_exists (fun _ ef -> has_meta ef.ef_meta) en.e_constrs
 
 
-		let convert gen t base_class en should_be_hxgen handle_type_params =
+		let convert gen t base_class base_param_class en should_be_hxgen handle_type_params =
 			let basic = gen.gcon.basic in
 			let basic = gen.gcon.basic in
 			let pos = en.e_pos in
 			let pos = en.e_pos in
 
 
@@ -8971,7 +8978,9 @@ struct
 				| _ -> ()
 				| _ -> ()
 			);
 			);
 
 
-			cl.cl_super <- Some(base_class,[]);
+			let super, has_params = if Meta.has Meta.FlatEnum en.e_meta then base_class, false else base_param_class, true in
+
+			cl.cl_super <- Some(super,[]);
 			cl.cl_extern <- en.e_extern;
 			cl.cl_extern <- en.e_extern;
 			en.e_extern <- true;
 			en.e_extern <- true;
 			en.e_meta <- (Meta.Class, [], pos) :: en.e_meta;
 			en.e_meta <- (Meta.Class, [], pos) :: en.e_meta;
@@ -9019,7 +9028,12 @@ struct
 						cf.cf_meta <- [];
 						cf.cf_meta <- [];
 
 
 						let tf_args = List.map (fun (name,opt,t) ->  (alloc_var name t, if opt then Some TNull else None) ) params in
 						let tf_args = List.map (fun (name,opt,t) ->  (alloc_var name t, if opt then Some TNull else None) ) params in
-						let arr_decl = { eexpr = TArrayDecl(List.map (fun (v,_) -> mk_local v pos) tf_args); etype = basic.tarray t_empty; epos = pos } in
+						let special = alloc_var "__array__" t_dynamic in
+						let arr_decl = {
+							eexpr = TCall(mk_local special pos, List.map (fun (v,_) -> mk_local v pos) tf_args);
+							etype = gen.gclasses.tvector t_dynamic;
+							epos = pos
+						} in
 						let expr = {
 						let expr = {
 							eexpr = TFunction({
 							eexpr = TFunction({
 								tf_args = tf_args;
 								tf_args = tf_args;
@@ -9036,10 +9050,15 @@ struct
 							| TEnum(e, p) -> TEnum(e, List.map (fun _ -> t_dynamic) p)
 							| TEnum(e, p) -> TEnum(e, List.map (fun _ -> t_dynamic) p)
 							| _ -> assert false
 							| _ -> assert false
 						in
 						in
-						let cf = mk_class_field name actual_t true pos (Var { v_read = AccNormal; v_write = AccNormal }) [] in
-						cf.cf_meta <- [];
+						let cf = mk_class_field name actual_t true pos (Var { v_read = AccNormal; v_write = AccNever }) [] in
+						let args = if has_params then
+							[mk_int gen old_i pos; null (gen.gclasses.tvector t_dynamic) pos]
+						else
+							[mk_int gen old_i pos]
+						in
+						cf.cf_meta <- [Meta.ReadOnly,[],pos];
 						cf.cf_expr <- Some {
 						cf.cf_expr <- Some {
-							eexpr = TNew(cl, List.map (fun _ -> t_empty) cl.cl_params, [mk_int gen old_i pos; { eexpr = TArrayDecl []; etype = basic.tarray t_empty; epos = pos }]);
+							eexpr = TNew(cl, List.map (fun _ -> t_empty) cl.cl_params, args);
 							etype = TInst(cl, List.map (fun _ -> t_empty) cl.cl_params);
 							etype = TInst(cl, List.map (fun _ -> t_empty) cl.cl_params);
 							epos = pos;
 							epos = pos;
 						};
 						};
@@ -9090,32 +9109,7 @@ struct
 			cl.cl_fields <- PMap.add "getTag" getTag_cf cl.cl_fields;
 			cl.cl_fields <- PMap.add "getTag" getTag_cf cl.cl_fields;
 			cl.cl_overrides <- getTag_cf :: cl.cl_overrides;
 			cl.cl_overrides <- getTag_cf :: cl.cl_overrides;
 
 
-			(if should_be_hxgen then
-				cl.cl_meta <- (Meta.HxGen,[],cl.cl_pos) :: cl.cl_meta
-			else begin
-				(* create the constructor *)
-				let tf_args = [ alloc_var "index" basic.tint, None; alloc_var "params" (basic.tarray t_empty), None ] in
-				let ftype = TFun(fun_args tf_args, basic.tvoid) in
-				let ctor = mk_class_field "new" ftype true pos (Method MethNormal) [] in
-				let me = TInst(cl, List.map snd cl.cl_params) in
-				ctor.cf_expr <-
-				Some {
-					eexpr = TFunction(
-					{
-						tf_args = tf_args;
-						tf_type = basic.tvoid;
-						tf_expr = mk_block {
-							eexpr = TCall({ eexpr = TConst TSuper; etype = me; epos = pos }, List.map (fun (v,_) -> mk_local v pos) tf_args);
-							etype = basic.tvoid;
-							epos = pos;
-						}
-					});
-					etype = ftype;
-					epos = pos
-				};
-
-				cl.cl_constructor <- Some ctor
-			end);
+			if should_be_hxgen then cl.cl_meta <- (Meta.HxGen,[],cl.cl_pos) :: cl.cl_meta;
 			gen.gadd_to_module (TClassDecl cl) (max_dep);
 			gen.gadd_to_module (TClassDecl cl) (max_dep);
 
 
 			TEnumDecl en
 			TEnumDecl en
@@ -9128,8 +9122,8 @@ struct
 				enum_base_class : tclass - the enum base class.
 				enum_base_class : tclass - the enum base class.
 				should_be_hxgen : bool - should the created enum be hxgen?
 				should_be_hxgen : bool - should the created enum be hxgen?
 		*)
 		*)
-		let traverse gen t convert_all convert_if_has_meta enum_base_class should_be_hxgen handle_tparams =
-			let convert e = convert gen t enum_base_class e should_be_hxgen handle_tparams in
+		let traverse gen t convert_all convert_if_has_meta enum_base_class param_enum_class should_be_hxgen handle_tparams =
+			let convert e = convert gen t enum_base_class param_enum_class e should_be_hxgen handle_tparams in
 			let run md = match md with
 			let run md = match md with
 				| TEnumDecl e when is_hxgen md ->
 				| TEnumDecl e when is_hxgen md ->
 					if convert_all then
 					if convert_all then
@@ -9202,7 +9196,7 @@ struct
 						with Not_found ->
 						with Not_found ->
 							f
 							f
 						in
 						in
-						let cond_array = { (mk_field_access gen f "params" f.epos) with etype = gen.gcon.basic.tarray t_empty } in
+						let cond_array = { (mk_field_access gen f "params" f.epos) with etype = gen.gclasses.tvector t_dynamic } in
 						{ e with eexpr = TArray(cond_array, mk_int gen i cond_array.epos); }
 						{ e with eexpr = TArray(cond_array, mk_int gen i cond_array.epos); }
 					| _ -> Type.map_expr run e
 					| _ -> Type.map_expr run e
 			in
 			in
@@ -9215,9 +9209,9 @@ struct
 
 
 	end;;
 	end;;
 
 
-	let configure gen opt_get_native_enum_tag convert_all convert_if_has_meta enum_base_class should_be_hxgen handle_tparams =
+	let configure gen opt_get_native_enum_tag convert_all convert_if_has_meta enum_base_class param_enum_class should_be_hxgen handle_tparams =
 		let t = new_t () in
 		let t = new_t () in
-		EnumToClassModf.configure gen (EnumToClassModf.traverse gen t convert_all convert_if_has_meta enum_base_class should_be_hxgen handle_tparams);
+		EnumToClassModf.configure gen (EnumToClassModf.traverse gen t convert_all convert_if_has_meta enum_base_class param_enum_class should_be_hxgen handle_tparams);
 		EnumToClassExprf.configure gen (EnumToClassExprf.traverse gen t opt_get_native_enum_tag)
 		EnumToClassExprf.configure gen (EnumToClassExprf.traverse gen t opt_get_native_enum_tag)
 
 
 end;;
 end;;

+ 9 - 2
gencs.ml

@@ -2653,7 +2653,9 @@ let configure gen =
 
 
 	ClosuresToClass.configure gen (ClosuresToClass.default_implementation closure_t (get_cl (get_type gen (["haxe";"lang"],"Function")) ));
 	ClosuresToClass.configure gen (ClosuresToClass.default_implementation closure_t (get_cl (get_type gen (["haxe";"lang"],"Function")) ));
 
 
-	EnumToClass.configure gen (Some (fun e -> mk_cast gen.gcon.basic.tint e)) false true (get_cl (get_type gen (["haxe";"lang"],"Enum")) ) true false;
+	let enum_base = (get_cl (get_type gen (["haxe";"lang"],"Enum")) ) in
+	let param_enum_base = (get_cl (get_type gen (["haxe";"lang"],"ParamEnum")) ) in
+	EnumToClass.configure gen (Some (fun e -> mk_cast gen.gcon.basic.tint e)) true true enum_base param_enum_base true false;
 
 
 	InterfaceVarsDeleteModf.configure gen;
 	InterfaceVarsDeleteModf.configure gen;
 	InterfaceProps.configure gen;
 	InterfaceProps.configure gen;
@@ -3271,7 +3273,12 @@ let get_cls = function
 	| _,_,c -> c
 	| _,_,c -> c
 
 
 let convert_ilenum ctx p ilcls =
 let convert_ilenum ctx p ilcls =
-	let meta = ref [Meta.Native, [EConst (String (ilpath_s ilcls.cpath) ), p], p ] in
+	let meta = ref [
+		Meta.Native, [EConst (String (ilpath_s ilcls.cpath) ), p], p;
+		Meta.Enum, [], p;
+		Meta.CsNative, [], p;
+		Meta.Extern, [], p; (* abstracts can't be externs *)
+	] in
 	let data = ref [] in
 	let data = ref [] in
 	List.iter (fun f -> match f.fname with
 	List.iter (fun f -> match f.fname with
 		| "value__" -> ()
 		| "value__" -> ()

+ 3 - 1
genjava.ml

@@ -1917,7 +1917,9 @@ let configure gen =
 
 
 	ClosuresToClass.configure gen (ClosuresToClass.default_implementation closure_t (get_cl (get_type gen (["haxe";"lang"],"Function")) ));
 	ClosuresToClass.configure gen (ClosuresToClass.default_implementation closure_t (get_cl (get_type gen (["haxe";"lang"],"Function")) ));
 
 
-	EnumToClass.configure gen (None) false true (get_cl (get_type gen (["haxe";"lang"],"Enum")) ) false false;
+	let enum_base = (get_cl (get_type gen (["haxe";"lang"],"Enum")) ) in
+	let param_enum_base = (get_cl (get_type gen (["haxe";"lang"],"ParamEnum")) ) in
+	EnumToClass.configure gen (None) false true enum_base param_enum_base false false;
 
 
 	InterfaceVarsDeleteModf.configure gen;
 	InterfaceVarsDeleteModf.configure gen;
 
 

+ 14 - 3
optimizer.ml

@@ -53,10 +53,21 @@ let mk_untyped_call name p params =
 
 
 let api_inline ctx c field params p =
 let api_inline ctx c field params p =
 	match c.cl_path, field, params with
 	match c.cl_path, field, params with
-	| ([],"Type"),"enumIndex",[{ eexpr = TField (_,FEnum (en,f)) }] ->
-		Some (mk (TConst (TInt (Int32.of_int f.ef_index))) ctx.t.tint p)
+	| ([],"Type"),"enumIndex",[{ eexpr = TField (_,FEnum (en,f)) }] -> (match ctx.com.platform with
+		| Cs when en.e_extern && not (Meta.has Meta.HxGen en.e_meta) ->
+			(* We don't want to optimize enums from external sources; as they might change unexpectedly *)
+			(* and since native C# enums don't have the concept of index - they have rather a value, *)
+			(* which can't be mapped to a native API - this kind of substitution is dangerous *)
+			None
+		| _ ->
+			Some (mk (TConst (TInt (Int32.of_int f.ef_index))) ctx.t.tint p))
 	| ([],"Type"),"enumIndex",[{ eexpr = TCall({ eexpr = TField (_,FEnum (en,f)) },pl) }] when List.for_all (fun e -> not (has_side_effect e)) pl ->
 	| ([],"Type"),"enumIndex",[{ eexpr = TCall({ eexpr = TField (_,FEnum (en,f)) },pl) }] when List.for_all (fun e -> not (has_side_effect e)) pl ->
-		Some (mk (TConst (TInt (Int32.of_int f.ef_index))) ctx.t.tint p)
+		(match ctx.com.platform with
+			| Cs when en.e_extern && not (Meta.has Meta.HxGen en.e_meta) ->
+				(* see comment above *)
+				None
+			| _ ->
+				Some (mk (TConst (TInt (Int32.of_int f.ef_index))) ctx.t.tint p))
 	| ([],"Std"),"int",[{ eexpr = TConst (TInt _) } as e] ->
 	| ([],"Std"),"int",[{ eexpr = TConst (TInt _) } as e] ->
 		Some { e with epos = p }
 		Some { e with epos = p }
 	| ([],"String"),"fromCharCode",[{ eexpr = TConst (TInt i) }] when i > 0l && i < 128l ->
 	| ([],"String"),"fromCharCode",[{ eexpr = TConst (TInt i) }] when i > 0l && i < 128l ->

+ 4 - 4
std/cs/_std/Type.hx

@@ -177,14 +177,14 @@ using StringTools;
 	@:functionCode('
 	@:functionCode('
 		if (name == "Bool") return typeof(bool);
 		if (name == "Bool") return typeof(bool);
 		System.Type t = resolveClass(name);
 		System.Type t = resolveClass(name);
-		if (t != null && (t.BaseType.Equals(typeof(System.Enum)) || t.BaseType.Equals(typeof(haxe.lang.Enum))))
+		if (t != null && (t.BaseType.Equals(typeof(System.Enum)) || (typeof(haxe.lang.Enum)).IsAssignableFrom(t)))
 			return t;
 			return t;
 		return null;
 		return null;
 	')
 	')
 	public static function resolveEnum( name : String ) : Enum<Dynamic> untyped
 	public static function resolveEnum( name : String ) : Enum<Dynamic> untyped
 	{
 	{
-		if (name == "Bool") return Bool;
-		return cast resolveClass(name);
+		return null;
+		// if (ret != null && (ret.BaseType.Equals(cs.Lib.toNativeType(cs.system.Enum)) || ret.IsAssignableFrom(cs.Lib.toNativeType(haxe.
 	}
 	}
 
 
 	public static function createInstance<T>( cl : Class<T>, args : Array<Dynamic> ) : T
 	public static function createInstance<T>( cl : Class<T>, args : Array<Dynamic> ) : T
@@ -385,7 +385,7 @@ using StringTools;
 	}
 	}
 
 
 	@:functionCode('
 	@:functionCode('
-		return ( e is System.Enum ) ? new Array<object>() : ((haxe.lang.Enum) e).@params;
+		return ( e is System.Enum ) ? new Array<object>() : ((haxe.lang.Enum) e).getParams();
 	')
 	')
 	public static function enumParameters( e : EnumValue ) : Array<Dynamic> untyped
 	public static function enumParameters( e : EnumValue ) : Array<Dynamic> untyped
 	{
 	{

+ 1 - 1
std/cs/internal/FieldLookup.hx

@@ -120,4 +120,4 @@ package cs.internal;
 		return ~min;
 		return ~min;
 	}
 	}
 
 
-}
+}

+ 37 - 10
std/cs/internal/HxObject.hx

@@ -21,6 +21,7 @@
  */
  */
 package cs.internal;
 package cs.internal;
 import cs.system.Type;
 import cs.system.Type;
+import haxe.ds.Vector;
 private typedef StdType = std.Type;
 private typedef StdType = std.Type;
 
 
 @:keep @:native('haxe.lang.HxObject')
 @:keep @:native('haxe.lang.HxObject')
@@ -67,27 +68,52 @@ private class DynamicObject extends HxObject implements Dynamic
 {
 {
 }
 }
 
 
-@:native('haxe.lang.Enum')
-@:keep @:skipCtor
+@:keep @:native('haxe.lang.Enum') @:nativeGen
 #if core_api_serialize
 #if core_api_serialize
 @:meta(System.Serializable)
 @:meta(System.Serializable)
 #end
 #end
 private class Enum
 private class Enum
 {
 {
 	@:readOnly private var index(default,never):Int;
 	@:readOnly private var index(default,never):Int;
-	@:readOnly private var params(default,never):Array<{}>;
 
 
-	public function new(index:Int, params:Array<{}>)
+	public function new(index:Int)
 	{
 	{
 		untyped this.index = index;
 		untyped this.index = index;
-		untyped this.params = params;
 	}
 	}
+
 	public function getTag():String
 	public function getTag():String
 	{
 	{
-		var cl:Dynamic = StdType.getClass(this);
-		return cl.constructs[index];
+		return throw 'Not Implemented';
+	}
+
+	public function getParams():Array<{}>
+	{
+		return [];
 	}
 	}
+
 	public function toString():String
 	public function toString():String
+	{
+		return getTag();
+	}
+}
+
+@:keep @:native('haxe.lang.ParamEnum') @:nativeGen
+private class ParamEnum extends Enum
+{
+	@:readOnly private var params(default,never):Vector<Dynamic>;
+
+	public function new(index:Int, params:Vector<Dynamic>)
+	{
+		super(index);
+		untyped this.params = params;
+	}
+
+	override public function getParams():Array<{}>
+	{
+		return params == null ? [] : cs.Lib.array(params.toData());
+	}
+
+	override public function toString():String
 	{
 	{
 		if (params == null || params.length == 0) return getTag();
 		if (params == null || params.length == 0) return getTag();
 		var ret = new StringBuf();
 		var ret = new StringBuf();
@@ -104,11 +130,12 @@ private class Enum
 		ret.add(")");
 		ret.add(")");
 		return ret.toString();
 		return ret.toString();
 	}
 	}
+
 	public function Equals(obj:Dynamic)
 	public function Equals(obj:Dynamic)
 	{
 	{
 		if (obj == this) //we cannot use == as .Equals !
 		if (obj == this) //we cannot use == as .Equals !
 			return true;
 			return true;
-		var obj:Enum = cast obj;
+		var obj:ParamEnum = Std.instance(obj, ParamEnum);
 		var ret = obj != null && Std.is(obj, StdType.getClass(this)) && obj.index == this.index;
 		var ret = obj != null && Std.is(obj, StdType.getClass(this)) && obj.index == this.index;
 		if (!ret)
 		if (!ret)
 			return false;
 			return false;
@@ -127,12 +154,12 @@ private class Enum
 
 
 	public function GetHashCode():Int
 	public function GetHashCode():Int
 	{
 	{
-		var h = 19;
+		var h:Int = 19;
 		if (params != null) for (p in params)
 		if (params != null) for (p in params)
 		{
 		{
 			h = h * 31;
 			h = h * 31;
 			if (p != null)
 			if (p != null)
-				h += untyped p.GetHashCode();
+				untyped h += p.GetHashCode();
 		}
 		}
 		h += index;
 		h += index;
 		return h;
 		return h;

+ 1 - 1
std/cs/internal/StringExt.hx

@@ -23,7 +23,7 @@ package cs.internal;
 import cs.internal.Function;
 import cs.internal.Function;
 private typedef NativeString = String;
 private typedef NativeString = String;
 
 
-@:keep @:nativeGen @:native("haxe.lang.StringExt") private class StringExt
+@:keep @:nativeGen @:native("haxe.lang.StringExt") class StringExt
 {
 {
 
 
 	@:functionCode('
 	@:functionCode('

+ 2 - 2
std/java/_std/Type.hx

@@ -119,7 +119,7 @@
 	@:functionCode('
 	@:functionCode('
 		if ("Bool".equals(name)) return boolean.class;
 		if ("Bool".equals(name)) return boolean.class;
 		Class r = resolveClass(name);
 		Class r = resolveClass(name);
-		if (r != null && (r.getSuperclass() == java.lang.Enum.class || r.getSuperclass() == haxe.lang.Enum.class))
+		if (r != null && (r.getSuperclass() == java.lang.Enum.class || haxe.lang.Enum.class.isAssignableFrom(r)))
 			return r;
 			return r;
 		return null;
 		return null;
 	')
 	')
@@ -398,7 +398,7 @@
 	}
 	}
 
 
 	@:functionCode('
 	@:functionCode('
-		return ( e instanceof java.lang.Enum ) ? new haxe.root.Array() : ((haxe.lang.Enum) e).params;
+		return ( e instanceof java.lang.Enum ) ? new haxe.root.Array() : ((haxe.lang.Enum) e).getParams();
 	')
 	')
 	public static function enumParameters( e : EnumValue ) : Array<Dynamic> untyped
 	public static function enumParameters( e : EnumValue ) : Array<Dynamic> untyped
 	{
 	{

+ 37 - 11
std/java/internal/HxObject.hx

@@ -21,6 +21,8 @@
  */
  */
 package java.internal;
 package java.internal;
 import java.internal.IEquatable;
 import java.internal.IEquatable;
+import haxe.ds.Vector;
+
 private typedef StdType = Type;
 private typedef StdType = Type;
 
 
 @:native('haxe.lang.HxObject')
 @:native('haxe.lang.HxObject')
@@ -64,26 +66,49 @@ private class DynamicObject extends HxObject implements Dynamic
 	}
 	}
 }
 }
 
 
-@:native('haxe.lang.Enum')
-//@:skipCtor
-@:nativeGen
-@:keep
+@:keep @:native('haxe.lang.Enum') @:nativeGen
 private class Enum
 private class Enum
 {
 {
 	@:readOnly private var index(default,never):Int;
 	@:readOnly private var index(default,never):Int;
-	@:readOnly private var params(default,never):Array<{}>;
 
 
-	public function new(index:Int, params:Array<{}>)
+	public function new(index:Int)
 	{
 	{
 		untyped this.index = index;
 		untyped this.index = index;
-		untyped this.params = params;
 	}
 	}
+
 	public function getTag():String
 	public function getTag():String
 	{
 	{
-		var cl:Dynamic = StdType.getEnum(cast this);
-		return cl.constructs[index];
+		return throw 'Not Implemented';
 	}
 	}
+
+	public function getParams():Array<{}>
+	{
+		return [];
+	}
+
 	public function toString():String
 	public function toString():String
+	{
+		return getTag();
+	}
+}
+
+@:keep @:native('haxe.lang.ParamEnum') @:nativeGen
+private class ParamEnum extends Enum
+{
+	@:readOnly private var params(default,never):Vector<Dynamic>;
+
+	public function new(index:Int, params:Vector<Dynamic>)
+	{
+		super(index);
+		untyped this.params = params;
+	}
+
+	override public function getParams():Array<{}>
+	{
+		return params == null ? [] : cast params.toArray();
+	}
+
+	override public function toString():String
 	{
 	{
 		if (params == null || params.length == 0) return getTag();
 		if (params == null || params.length == 0) return getTag();
 		var ret = new StringBuf();
 		var ret = new StringBuf();
@@ -100,11 +125,12 @@ private class Enum
 		ret.add(")");
 		ret.add(")");
 		return ret.toString();
 		return ret.toString();
 	}
 	}
+
 	public function equals(obj:Dynamic)
 	public function equals(obj:Dynamic)
 	{
 	{
 		if (obj == this) //we cannot use == as .Equals !
 		if (obj == this) //we cannot use == as .Equals !
 			return true;
 			return true;
-		var obj:Enum = cast obj;
+		var obj:ParamEnum = Std.is(obj,ParamEnum) ? cast obj : null;
 		var ret = obj != null && Std.is(obj, StdType.getEnum(cast this)) && obj.index == this.index;
 		var ret = obj != null && Std.is(obj, StdType.getEnum(cast this)) && obj.index == this.index;
 		if (!ret)
 		if (!ret)
 			return false;
 			return false;
@@ -128,7 +154,7 @@ private class Enum
 		{
 		{
 			h = h * 31;
 			h = h * 31;
 			if (p != null)
 			if (p != null)
-				h += untyped p.hashCode();
+				untyped h += p.hashCode();
 		}
 		}
 		h += index;
 		h += index;
 		return h;
 		return h;

+ 9 - 0
tests/unit/native_cs/src/haxe/test/TEnumWithValue.cs

@@ -6,4 +6,13 @@ public enum TEnumWithValue
 	TVA = 0x100,TVB = 0x1,TVD = 0x10, TVC = 0x20
 	TVA = 0x100,TVB = 0x1,TVD = 0x10, TVC = 0x20
 }
 }
 
 
+public enum TEnumWithBigValue : ulong
+{
+	TBA = 0x1000000000L, 
+	TBD = 0x200000000000L, 
+	TBB = 0x100000000L, 
+	TBC = 0x3000000000000L, 
+}
+
 }
 }
+

+ 30 - 22
tests/unit/src/unit/TestCSharp.hx

@@ -4,6 +4,7 @@ import haxe.test.Base;
 import haxe.test.Base.Base_InnerClass;
 import haxe.test.Base.Base_InnerClass;
 import haxe.test.TEnum;
 import haxe.test.TEnum;
 import haxe.test.TEnumWithValue;
 import haxe.test.TEnumWithValue;
+import haxe.test.TEnumWithBigValue;
 import haxe.test.IEditableTextBuffer;
 import haxe.test.IEditableTextBuffer;
 import haxe.test.LowerCaseClass;
 import haxe.test.LowerCaseClass;
 
 
@@ -302,32 +303,34 @@ class TestCSharp extends Test
 		}
 		}
 		eq("TA",Type.enumConstructor(e));
 		eq("TA",Type.enumConstructor(e));
 
 
-		eq(0, Type.enumIndex(TEnum.TA));
-		eq(0, Type.enumIndex(getTA()));
-		eq(3, Type.enumIndex(TEnumWithValue.TVA));
-		eq(3, Type.enumIndex(getTVA()));
+		eq(Type.enumIndex(getTA()), Type.enumIndex(TEnum.TA));
+		eq(Type.enumIndex(getTVA()), Type.enumIndex(TEnumWithValue.TVA));
+		eq(Type.enumIndex(getTBA()), Type.enumIndex(TEnumWithBigValue.TBA));
 
 
-		eq(0, Type.enumIndex(TEnumWithValue.TVB));
-		eq(0, Type.enumIndex(getTVB()));
-		eq(1, Type.enumIndex(TEnum.TB));
-		eq(1, Type.enumIndex(getTB()));
+		eq(Type.enumIndex(getTVB()), Type.enumIndex(TEnumWithValue.TVB));
+		eq(Type.enumIndex(getTBB()), Type.enumIndex(TEnumWithBigValue.TBB));
+		eq(Type.enumIndex(getTB()), Type.enumIndex(TEnum.TB));
 
 
-		eq(2, Type.enumIndex(TEnum.TC));
-		eq(2, Type.enumIndex(getTC()));
-		eq(2, Type.enumIndex(TEnumWithValue.TVC));
-		eq(2, Type.enumIndex(getTVC()));
+		eq(Type.enumIndex(getTC()), Type.enumIndex(TEnum.TC));
+		eq(Type.enumIndex(getTVC()), Type.enumIndex(TEnumWithValue.TVC));
+		eq(Type.enumIndex(getTBC()), Type.enumIndex(TEnumWithBigValue.TBC));
 
 
-		eq(1, Type.enumIndex(TEnumWithValue.TVD));
-		eq(1, Type.enumIndex(getTVD()));
+		eq(Type.enumIndex(getTVD()), Type.enumIndex(TEnumWithValue.TVD));
+		eq(Type.enumIndex(getTBD()), Type.enumIndex(TEnumWithBigValue.TBD));
 
 
-		checkEnum(TEnum,0,TEnum.TA);
-		checkEnum(TEnum,1,TEnum.TB);
-		checkEnum(TEnum,2,TEnum.TC);
+		checkEnum(TEnum,TEnum.TA);
+		checkEnum(TEnum,TEnum.TB);
+		checkEnum(TEnum,TEnum.TC);
 
 
-		checkEnum(TEnumWithValue,3,TEnumWithValue.TVA);
-		checkEnum(TEnumWithValue,0,TEnumWithValue.TVB);
-		checkEnum(TEnumWithValue,2,TEnumWithValue.TVC);
-		checkEnum(TEnumWithValue,1,TEnumWithValue.TVD);
+		checkEnum(TEnumWithValue,TEnumWithValue.TVA);
+		checkEnum(TEnumWithValue,TEnumWithValue.TVB);
+		checkEnum(TEnumWithValue,TEnumWithValue.TVC);
+		checkEnum(TEnumWithValue,TEnumWithValue.TVD);
+
+		checkEnum(TEnumWithBigValue,TEnumWithBigValue.TBA);
+		checkEnum(TEnumWithBigValue,TEnumWithBigValue.TBB);
+		checkEnum(TEnumWithBigValue,TEnumWithBigValue.TBC);
+		checkEnum(TEnumWithBigValue,TEnumWithBigValue.TBD);
 	}
 	}
 
 
 	private static function getArray(arr:cs.system.Array)
 	private static function getArray(arr:cs.system.Array)
@@ -335,18 +338,23 @@ class TestCSharp extends Test
 		return [ for (i in 0...arr.Length) arr.GetValue(i) ];
 		return [ for (i in 0...arr.Length) arr.GetValue(i) ];
 	}
 	}
 
 
-	function checkEnum<T>(e:Enum<T>,idx:Int,v:T,?pos:haxe.PosInfos)
+	function checkEnum<T : EnumValue>(e:Enum<T>,v:T,?pos:haxe.PosInfos)
 	{
 	{
+		var idx = Type.enumIndex(v);
 		eq(v,Type.createEnumIndex(e,idx),pos);
 		eq(v,Type.createEnumIndex(e,idx),pos);
 	}
 	}
 
 
 	function getTA() return TEnum.TA;
 	function getTA() return TEnum.TA;
 	function getTVA() return TEnumWithValue.TVA;
 	function getTVA() return TEnumWithValue.TVA;
+	function getTBA() return TEnumWithBigValue.TBA;
 	function getTB() return TEnum.TB;
 	function getTB() return TEnum.TB;
 	function getTVB() return TEnumWithValue.TVB;
 	function getTVB() return TEnumWithValue.TVB;
+	function getTBB() return TEnumWithBigValue.TBB;
 	function getTC() return TEnum.TC;
 	function getTC() return TEnum.TC;
 	function getTVC() return TEnumWithValue.TVC;
 	function getTVC() return TEnumWithValue.TVC;
+	function getTBC() return TEnumWithBigValue.TBC;
 	function getTVD() return TEnumWithValue.TVD;
 	function getTVD() return TEnumWithValue.TVD;
+	function getTBD() return TEnumWithBigValue.TBD;
 
 
 	@:skipReflection private function refTest(i:cs.Ref<Int>):Void
 	@:skipReflection private function refTest(i:cs.Ref<Int>):Void
 	{
 	{

+ 22 - 0
tests/unit/src/unit/issues/Issue3389.hx

@@ -0,0 +1,22 @@
+package unit.issues;
+
+class Issue3389 extends Test
+{
+	public function test()
+	{
+		eq(Type.allEnums(ETest).join(','),'A,B');
+		eq(Type.allEnums(ETest2).join(','),'A2,B2');
+	}
+}
+
+private enum ETest
+{
+	A;
+	B;
+}
+
+@:nativeGen private enum ETest2
+{
+	A2;
+	B2;
+}

+ 21 - 0
tests/unit/src/unit/issues/Issue3860.hx

@@ -0,0 +1,21 @@
+package unit.issues;
+
+class Issue3860 extends Test
+{
+	public function test()
+	{
+		var a = ETest.A;
+		t(Std.is(a,ETest));
+		f(Std.is(a,Int));
+
+		var dyn:Dynamic = a;
+		t(Std.is(dyn,ETest));
+		f(Std.is(dyn,Int));
+	}
+}
+
+private enum ETest
+{
+	A;
+	B;
+}