瀏覽代碼

[java] Properly rewrite basic type parameters as their boxed counterparts

Closes #784
Related #3728
Cauê Waneck 8 年之前
父節點
當前提交
b760ddc22c

+ 1 - 1
src/generators/gencommon.ml

@@ -605,7 +605,7 @@ let new_ctx con =
 		ghandle_cast = (fun to_t from_t e -> mk_cast to_t e);
 		gon_unsafe_cast = (fun t t2 pos -> (gen.gcon.warning ("Type " ^ (debug_type t2) ^ " is being cast to the unrelated type " ^ (s_type (print_context()) t)) pos));
 		gneeds_box = (fun t -> false);
-		gspecial_needs_cast = (fun to_t from_t -> true);
+		gspecial_needs_cast = (fun to_t from_t -> false);
 		gsupported_conversions = Hashtbl.create 0;
 
 		gadd_type = (fun md should_filter ->

+ 40 - 18
src/generators/genjava.ml

@@ -136,6 +136,11 @@ let rec replace_type_param t = match follow t with
 	| TInst(cl, params) -> TInst(cl, List.map replace_type_param params)
 	| _ -> t
 
+let in_runtime_class gen =
+	match gen.gcurrent_class with
+	| Some { cl_path = ["haxe";"lang"],"Runtime"} -> true
+	| _ -> false
+
 let is_java_basic_type t =
 	match follow t with
 		| TInst( { cl_path = (["haxe"], "Int32") }, [] )
@@ -600,17 +605,10 @@ struct
 
 	let configure gen runtime_cl =
 		let cl_boolean = get_cl (get_type gen (["java";"lang"],"Boolean")) in
-		let cl_double = get_cl (get_type gen (["java";"lang"],"Double")) in
-		let cl_integer = get_cl (get_type gen (["java";"lang"],"Integer")) in
-		let cl_byte = get_cl (get_type gen (["java";"lang"],"Byte")) in
-		let cl_short = get_cl (get_type gen (["java";"lang"],"Short")) in
-		let cl_character = get_cl (get_type gen (["java";"lang"],"Character")) in
-		let cl_float = get_cl (get_type gen (["java";"lang"],"Float")) in
-		let cl_long = get_cl (get_type gen (["java";"lang"],"Long")) in
+		let cl_number = get_cl (get_type gen (["java";"lang"],"Number")) in
 
 		(if java_hash "Testing string hashCode implementation from haXe" <> (Int32.of_int 545883604) then assert false);
 		let basic = gen.gcon.basic in
-		let tchar = mt_to_t_dyn ( get_type gen (["java"], "Char16") ) in
 		let tbyte = mt_to_t_dyn ( get_type gen (["java"], "Int8") ) in
 		let tshort = mt_to_t_dyn ( get_type gen (["java"], "Int16") ) in
 		let tsingle = mt_to_t_dyn ( get_type gen ([], "Single") ) in
@@ -678,6 +676,32 @@ struct
 				}
 		in
 
+		let mk_dyn_box boxed_t expr =
+			let name = match boxed_t with
+				| TInst({ cl_path = (["java";"lang"],"Integer") },[]) ->
+					"numToInteger"
+				| TInst({ cl_path = (["java";"lang"],"Double") },[]) ->
+					"numToDouble"
+				| TInst({ cl_path = (["java";"lang"],"Float") },[]) ->
+					"numToFloat"
+				| TInst({ cl_path = (["java";"lang"],"Byte") },[]) ->
+					"numToByte"
+				| TInst({ cl_path = (["java";"lang"],"Long") },[]) ->
+					"numToLong"
+				| TInst({ cl_path = (["java";"lang"],"Short") },[]) ->
+					"numToShort"
+				| _ -> gen.gcon.error ("Invalid boxed type " ^ (debug_type boxed_t)) expr.epos; assert false
+			in
+			{
+				eexpr = TCall(
+					mk_static_field_access_infer runtime_cl name expr.epos [],
+					[ mk_cast (TInst(cl_number,[])) expr ]
+				);
+				etype = boxed_t;
+				epos = expr.epos
+			}
+		in
+
 		let rec run e =
 			match e.eexpr with
 				(* for new NativeArray<T> issues *)
@@ -708,8 +732,6 @@ struct
 						| _ ->
 							{ e with eexpr = TCall(run efield, List.map run args) }
 					)
-(*				 | TCall( { eexpr = TField(ef, FInstance({ cl_path = [], "String" }, { cf_name = ("toString") })) }, [] ) ->
-					run ef *)
 
 				| TCast(expr, _) when is_boxed_number (gen.greal_type expr.etype) && is_unboxed_number (gen.greal_type e.etype) ->
 					let to_t = gen.greal_type e.etype in
@@ -728,22 +750,22 @@ struct
 									{ e with eexpr = TCast(run expr, md) }
 								else
 									run expr
-							end else begin
-								let box_cl, unboxed_t = get_unboxed_from_boxed to_t in
-								mk_valueof_call to_t (mk_unbox to_t (run expr))
-							end
+							end else
+								mk_dyn_box (gen.greal_type e.etype) (run expr)
 						else begin
-							let box_cl, unboxed_t = get_unboxed_from_boxed to_t in
-							mk_valueof_call to_t (run (mk_cast unboxed_t expr))
+							if in_runtime_class gen then
+								mk_cast e.etype (run expr)
+							else
+								mk_dyn_box (gen.greal_type e.etype) (run expr)
 						end
 					in
 					ret
 
-				| TCast(expr, _) when is_bool e.etype && is_dynamic gen expr.etype ->
+				| TCast(expr, _) when is_bool e.etype ->
 					{
 						eexpr = TCall(
 							mk_static_field_access_infer runtime_cl "toBool" expr.epos [],
-							[ run expr ]
+							[ mk_cast_if_needed (TInst(cl_boolean,[])) (run expr) ]
 						);
 						etype = basic.tbool;
 						epos = e.epos

+ 0 - 3
std/haxe/CallStack.hx

@@ -208,9 +208,6 @@ class CallStack {
 					stack.push( method );
 				}
 			}
-			// stack.shift();
-			stack.shift();
-			stack.pop();
 			return stack;
 		#elseif cs
 			return makeStack(new cs.system.diagnostics.StackTrace(cs.internal.Exceptions.exception, true));

+ 44 - 105
std/java/_std/Type.hx

@@ -124,121 +124,60 @@ enum ValueType {
 		return resolveClass(name);
 	}
 
-	@:functionCode('
-			int len = args.length;
-			java.lang.Class[] cls = new java.lang.Class[len];
-			java.lang.Object[] objs = new java.lang.Object[len];
-
-			java.lang.reflect.Constructor[] ms = cl.getConstructors();
-			int msl = ms.length;
-			int realMsl = 0;
-			for(int i =0; i < msl; i++)
-			{
-				if (!ms[i].isVarArgs() && ms[i].getParameterTypes().length != len)
-				{
-					ms[i] = null;
-				} else {
-					ms[realMsl] = ms[i];
-					if (realMsl != i)
-						ms[i] = null;
-					realMsl++;
-				}
-			}
-
-			boolean hasNumber = false;
-
-			for (int i = 0; i < len; i++)
-			{
-				Object o = args.__get(i);
-				objs[i]= o;
-				cls[i] = o.getClass();
-				boolean isNum = false;
-
-				if (o instanceof java.lang.Number)
-				{
-					cls[i] = java.lang.Number.class;
-					isNum = hasNumber = true;
-				}
+	public static function createInstance<T>( cl : Class<T>, args : Array<Dynamic> ) : T
+	{
+		var nargs = args.length,
+				callArguments = new java.NativeArray<Dynamic>(nargs);
 
-				msl = realMsl;
-				realMsl = 0;
-
-				for (int j = 0; j < msl; j++)
-				{
-					java.lang.Class[] allcls = ms[j].getParameterTypes();
-					if (i < allcls.length)
-					{
-						if (! ((isNum && allcls[i].isPrimitive()) || allcls[i].isAssignableFrom(cls[i])) )
-						{
-							ms[j] = null;
-						} else {
-							ms[realMsl] = ms[j];
-							if (realMsl != j)
-								ms[j] = null;
-							realMsl++;
-						}
-					}
-				}
+		var ctors = java.Lib.toNativeType(cl).getConstructors(),
+				totalCtors = ctors.length,
+				validCtors = 0;
 
+		for (i in 0...totalCtors) {
+			var ctor = ctors[i];
+			var ptypes = ctor.getParameterTypes();
+			if (ptypes.length != nargs && !ctor.isVarArgs()) {
+				continue;
 			}
 
-			java.lang.reflect.Constructor found = ms[0];
-
-			if (hasNumber)
-			{
-				java.lang.Class[] allcls = found.getParameterTypes();
-
-				for (int i = 0; i < len; i++)
-				{
-					java.lang.Object o = objs[i];
-					if (o instanceof java.lang.Number)
-					{
-						java.lang.Class curCls = null;
-						if (i < allcls.length)
-						{
-							curCls = allcls[i];
-							if (!curCls.isAssignableFrom(o.getClass()))
-							{
-								String name = curCls.getName();
-								if (name.equals("double") || name.equals("java.lang.Double"))
-								{
-									objs[i] = ((java.lang.Number)o).doubleValue();
-								} else if (name.equals("int") || name.equals("java.lang.Integer"))
-								{
-									objs[i] = ((java.lang.Number)o).intValue();
-								} else if (name.equals("float") || name.equals("java.lang.Float"))
-								{
-									objs[i] = ((java.lang.Number)o).floatValue();
-								} else if (name.equals("byte") || name.equals("java.lang.Byte"))
-								{
-									objs[i] = ((java.lang.Number)o).byteValue();
-								} else if (name.equals("short") || name.equals("java.lang.Short"))
-								{
-									objs[i] = ((java.lang.Number)o).shortValue();
-								}
-							}
-						} //else varargs not handled TODO
+			var argNum = -1,
+					valid = true;
+			for (arg in args) {
+				argNum++;
+				var expectedType = argNum < ptypes.length ? ptypes[argNum] : ptypes[ptypes.length - 1]; // varags
+				if (arg == null || expectedType.isAssignableFrom(java.Lib.toNativeType(Type.getClass(arg)))) {
+					callArguments[argNum] = arg;
+				} else if (Std.is(arg, java.lang.Number)) {
+					var name = expectedType.getName();
+					switch(name) {
+						case 'double' | 'java.lang.Double':
+							callArguments[argNum] = (cast arg : java.lang.Number).doubleValue();
+						case 'int' | 'java.lang.Integer':
+							callArguments[argNum] = (cast arg : java.lang.Number).intValue();
+						case 'float' | 'java.lang.Float':
+							callArguments[argNum] = (cast arg : java.lang.Number).floatValue();
+						case 'byte' | 'java.lang.Byte':
+							callArguments[argNum] = (cast arg : java.lang.Number).byteValue();
+						case 'short' | 'java.lang.Short':
+							callArguments[argNum] = (cast arg : java.lang.Number).shortValue();
+						case _:
+							throw 'Unknown expected number subclass of type $name';
 					}
+				} else {
+					valid = false;
+					break;
 				}
 			}
+			if (!valid) {
+				continue;
+			}
 
-		try {
-			found.setAccessible(true);
-			return (T) found.newInstance(objs);
-		}
-		catch (java.lang.reflect.InvocationTargetException e)
-		{
-			throw haxe.lang.HaxeException.wrap(e.getCause());
+			// the current constructor was found and it is valid - call it
+			ctor.setAccessible(true);
+			return cast ctor.newInstance(callArguments);
 		}
 
-		catch (Throwable t)
-		{
-			throw haxe.lang.HaxeException.wrap(t);
-		}
-	')
-	public static function createInstance<T>( cl : Class<T>, args : Array<Dynamic> ) : T untyped
-	{
-		return null;
+		throw 'Could not find any constructor that matches the provided arguments for class $cl';
 	}
 
 	// cache empty constructor arguments so we don't allocate it on each createEmptyInstance call

+ 26 - 5
std/java/internal/Runtime.hx

@@ -127,12 +127,9 @@ package java.internal;
 		return 0.0;
 	}
 
-	@:functionCode('
-		return (obj == null) ? false : ((java.lang.Boolean) obj).booleanValue();
-	')
-	public static function toBool(obj:Dynamic):Bool
+	public static function toBool(obj:java.lang.Boolean):Bool
 	{
-		return false;
+		return obj == null ? false : obj.booleanValue();
 	}
 
 	@:functionCode('
@@ -594,6 +591,30 @@ package java.internal;
 	public static function getInt64FromNumber(n:java.lang.Number):java.StdTypes.Int64 {
 		return n == null ? 0.0 : n.longValue();
 	}
+
+	public static function numToInteger(num:java.lang.Number):java.lang.Integer {
+		return num == null ? null : (Std.is(num, java.lang.Integer.IntegerClass) ? cast num : java.lang.Integer.valueOf(num.intValue()));
+	}
+
+	public static function numToDouble(num:java.lang.Number):java.lang.Double {
+		return num == null ? null : (Std.is(num, java.lang.Double.DoubleClass) ? cast num : java.lang.Double.valueOf(num.doubleValue()));
+	}
+
+	public static function numToFloat(num:java.lang.Number):java.lang.Float {
+		return num == null ? null : (Std.is(num, java.lang.Float.FloatClass) ? cast num : java.lang.Float.valueOf(num.floatValue()));
+	}
+
+	public static function numToByte(num:java.lang.Number):java.lang.Byte {
+		return num == null ? null : (Std.is(num, java.lang.Byte.ByteClass) ? cast num : java.lang.Byte.valueOf(num.byteValue()));
+	}
+
+	public static function numToLong(num:java.lang.Number):java.lang.Long {
+		return num == null ? null : (Std.is(num, java.lang.Long.LongClass) ? cast num : java.lang.Long.valueOf(num.longValue()));
+	}
+
+	public static function numToShort(num:java.lang.Number):java.lang.Short {
+		return num == null ? null : (Std.is(num, java.lang.Short.ShortClass) ? cast num : java.lang.Short.valueOf(num.shortValue()));
+	}
 }
 
 @:keep @:native("haxe.lang.EmptyObject") enum EmptyObject

+ 1 - 1
std/java/lang/Double.hx

@@ -61,6 +61,6 @@
 	@:overload @:throws("java.lang.NumberFormatException") static function parseDouble(param1 : String) : Float;
 	@:overload static function toHexString(param1 : Float) : String;
 	@:native("toString") @:overload static function _toString(param1 : Float) : String;
-	@:overload @:throws("java.lang.NumberFormatException") static function valueOf(param1 : String) : Double;
 	@:overload static function valueOf(param1 : Float) : Double;
+	@:overload @:throws("java.lang.NumberFormatException") static function valueOf(param1 : String) : Double;
 }

+ 1 - 1
std/java/lang/Float.hx

@@ -62,8 +62,8 @@
 	@:overload @:throws("java.lang.NumberFormatException") static function parseFloat(param1 : String) : Single;
 	@:overload static function toHexString(param1 : Single) : String;
 	@:native("toString") @:overload static function _toString(param1 : Single) : String;
-	@:overload @:throws("java.lang.NumberFormatException") static function valueOf(param1 : String) : Float;
 	@:overload static function valueOf(param1 : Single) : Float;
+	@:overload @:throws("java.lang.NumberFormatException") static function valueOf(param1 : String) : Float;
 
 }
 

+ 1 - 1
std/java/lang/Integer.hx

@@ -66,8 +66,8 @@
 	@:overload static function toOctalString(param1 : Int) : String;
 	@:native("toString") @:overload static function _toString(param1 : Int, param2 : Int) : String;
 	@:native("toString") @:overload static function _toString(param1 : Int) : String;
-	@:overload @:throws("java.lang.NumberFormatException") static function valueOf(param1 : String, param2 : Int) : Integer;
 	@:overload static function valueOf(param1 : Int) : Integer;
+	@:overload @:throws("java.lang.NumberFormatException") static function valueOf(param1 : String, param2 : Int) : Integer;
 	@:overload @:throws("java.lang.NumberFormatException") static function valueOf(param1 : String) : Integer;
 }
 

+ 1 - 1
std/java/lang/Short.hx

@@ -50,8 +50,8 @@
 	@:overload @:throws("java.lang.NumberFormatException") static function parseShort(param1 : String) : java.types.Int16;
 	@:overload static function reverseBytes(param1 : java.types.Int16) : java.types.Int16;
 	@:native("toString") @:overload static function _toString(param1 : java.types.Int16) : String;
-	@:overload @:throws("java.lang.NumberFormatException") static function valueOf(param1 : String, param2 : Int) : Short;
 	@:overload static function valueOf(param1 : java.types.Int16) : Short;
+	@:overload @:throws("java.lang.NumberFormatException") static function valueOf(param1 : String, param2 : Int) : Short;
 	@:overload @:throws("java.lang.NumberFormatException") static function valueOf(param1 : String) : Short;
 }
 

+ 1 - 1
tests/unit/compile-java.hxml

@@ -8,4 +8,4 @@ compile-each.hxml
 -java bin/java
 -java-lib native_java/native.jar
 -java-lib java_drivers/mysql-connector-java-5.1.32-bin.jar
--java-lib java_drivers/sqlite-jdbc-3.7.2.jar
+-java-lib java_drivers/sqlite-jdbc-3.7.2.jar

+ 9 - 0
tests/unit/src/unit/TestSpecification.hx

@@ -81,6 +81,15 @@ private class ClassWithCtorDefaultValuesChild extends ClassWithCtorDefaultValues
 
 }
 
+@:keep private class ClassWithCtorDefaultValues2 {
+	public var a : Null<Float>;
+	public var b : String;
+	public function new(a = 1.1, b = "foo") {
+		this.a = a;
+		this.b = b;
+	}
+}
+
 private enum SomeEnum<T> {
 	NoArguments;
 	OneArgument(t:T);

+ 3 - 0
tests/unit/src/unitstd/Type.unit.hx

@@ -58,6 +58,9 @@ Type.createInstance(C, []).v == "var";
 var c = Type.createInstance(ClassWithCtorDefaultValues, [2, "bar"]);
 c.a == 2;
 c.b == "bar";
+var c2 = Type.createInstance(ClassWithCtorDefaultValues2, [2, "bar"]);
+c2.a == 2;
+c2.b == "bar";
 //var t = Type.createInstance(ClassWithCtorDefaultValuesChild, [2, "bar"]);
 //t.a == 2;
 //t.b == "bar";