瀏覽代碼

[java][jvm] switch `haxe.Rest` to `NativeArray<T>` instead of `NativeArray<Object>`

Aleksandr Kuzmenko 4 年之前
父節點
當前提交
8a1381b3ff

+ 18 - 16
src/codegen/gencommon/castDetect.ml

@@ -625,22 +625,24 @@ let choose_ctor gen cl tparams etl maybe_empty_t p =
 		match arglist, elist with
 		| [], [] -> true
 		| [(_,_,t)], elist when ExtType.is_rest (follow t) ->
-			let is_rest_array arg_t =
-				Type.fast_eq (Abstract.follow_with_abstracts t) (Abstract.follow_with_abstracts arg_t)
-			in
-			(match elist with
-			| [arg_t] when is_rest_array arg_t -> true
-			| _ ->
-				match follow t with
-				| TAbstract ({ a_path = ["haxe"],"Rest" }, [t1]) ->
-					let t1 = run_follow gen t1 in
-					(try
-						List.iter (fun et -> unify et t1) elist;
-						true
-					with Unify_error _ ->
-						false
-					)
-				| _ -> die "" __LOC__
+			(match follow t with
+			| TAbstract ({ a_path = ["haxe"],"Rest" } as a, [t1]) ->
+				let is_rest_array arg_t =
+					let boxed = TAbstract (a, [get_boxed gen t1]) in
+					Type.fast_eq (Abstract.follow_with_abstracts boxed) (Abstract.follow_with_abstracts arg_t)
+				in
+				(match elist with
+				| [arg_t] when is_rest_array arg_t -> true
+				| _ ->
+						let t1 = run_follow gen t1 in
+						(try
+							List.iter (fun et -> unify et t1) elist;
+							true
+						with Unify_error _ ->
+							false
+						)
+				)
+			| _ -> die "" __LOC__
 			)
 		| (_,_,t) :: arglist, et :: elist ->
 			(try

+ 25 - 1
src/codegen/gencommon/gencommon.ml

@@ -997,6 +997,30 @@ let mk_nativearray_decl gen t el pos =
 	mk (TCall (mk (TIdent "__array__") t_dynamic pos, el)) (gen.gclasses.nativearray t) pos
 
 
+let get_boxed gen t =
+	let get path =
+		try type_of_module_type (Hashtbl.find gen.gtypes path)
+		with Not_found -> t
+	in
+	match follow t with
+	| TAbstract({ a_path = ([],"Bool") }, []) ->
+		get (["java";"lang"], "Boolean")
+	| TAbstract({ a_path = ([],"Float") }, []) ->
+		get (["java";"lang"], "Double")
+	| TAbstract({ a_path = ([],"Int") }, []) ->
+		get (["java";"lang"], "Integer")
+	| TAbstract({ a_path = (["java"],"Int8") }, []) ->
+		get (["java";"lang"], "Byte")
+	| TAbstract({ a_path = (["java"],"Int16") }, []) ->
+		get (["java";"lang"], "Short")
+	| TAbstract({ a_path = (["java"],"Char16") }, []) ->
+		get (["java";"lang"], "Character")
+	| TAbstract({ a_path = ([],"Single") }, []) ->
+		get (["java";"lang"], "Float")
+	| TAbstract({ a_path = (["java"],"Int64") }, []) ->
+		get (["java";"lang"], "Long")
+	| _ -> t
+
 (**
 	Wraps rest arguments into a native array.
 	E.g. transforms params from `callee(param, rest1, rest2, ..., restN)` into
@@ -1016,7 +1040,7 @@ let wrap_rest_args gen callee_type params p =
 				| _ ->
 					match Abstract.follow_with_abstracts t with
 					| TInst ({ cl_path = _,"NativeArray" }, [t1]) ->
-						let t1 = if Common.defined gen.gcon Define.EraseGenerics then t_dynamic else t1 in
+						let t1 = if Common.defined gen.gcon Define.EraseGenerics then t_dynamic else get_boxed gen t1 in
 						[mk_nativearray_decl gen t1 params (punion_el p params)]
 					| _ ->
 						die ~p "Unexpected rest arguments type" __LOC__

+ 17 - 1
src/codegen/gencommon/overloadingConstructor.ml

@@ -201,6 +201,22 @@ let create_static_ctor com ~empty_ctor_expr cl ctor follow_type =
 			| None -> [], ctor.cf_pos
 			| Some super -> [super], super.epos
 			in
+			let el_args =
+				let rec loop fn_args cur_args =
+					match cur_args with
+					| [] -> []
+					| (v,_) :: cur_args ->
+						let local = mk_local v p in
+						match fn_args, cur_args with
+						| [_,_,t], [] when ExtType.is_rest (follow t) ->
+							[mk (TUnop(Spread,Prefix,local)) v.v_type p]
+						| [], _ ->
+							local :: loop fn_args cur_args
+						| _ :: fn_args, _ ->
+							local :: loop fn_args cur_args
+				in
+				loop fn_args cur_tf_args
+			in
 			let block_contents = block_contents @ [{
 				eexpr = TCall(
 					{
@@ -211,7 +227,7 @@ let create_static_ctor com ~empty_ctor_expr cl ctor follow_type =
 						epos = p
 					},
 					[{ eexpr = TConst TThis; etype = TInst(cl, List.map snd cl.cl_params); epos = p }]
-					@ List.map (fun (v,_) -> mk_local v p) cur_tf_args
+					@ el_args
 				);
 				etype = com.basic.tvoid;
 				epos = p

+ 9 - 0
src/generators/genjava.ml

@@ -1084,6 +1084,10 @@ let generate con =
 					Some t
 			| TAbstract (({ a_path = [],"Null" } as tab),[t2]) ->
 					Some (TAbstract(tab,[gen.gfollow#run_f t2]))
+			| TType ({ t_path = ["haxe";"_Rest"],"NativeRest" } as td, [t2]) ->
+					Some (gen.gfollow#run_f (follow (TType (td,[get_boxed gen t2]))))
+			| TAbstract ({ a_path = ["haxe"],"Rest" } as a, [t2]) ->
+					Some (gen.gfollow#run_f ( Abstract.get_underlying_type a [get_boxed gen t2]) )
 			| TAbstract (a, pl) when not (Meta.has Meta.CoreType a.a_meta) ->
 					Some (gen.gfollow#run_f ( Abstract.get_underlying_type a pl) )
 			| TAbstract( { a_path = ([], "EnumValue") }, _ )
@@ -1530,6 +1534,11 @@ let generate con =
 					| _ -> die "" __LOC__)
 				| TMeta (_,e) ->
 					expr_s w e
+				| TCall ({ eexpr = TField(_, FStatic({ cl_path = (["haxe";"_Rest"],"Rest_Impl_") }, { cf_name = "createNative" })) }, el) ->
+					(match follow e.etype with
+					| TInst (cls, params) ->
+						expr_s w { e with eexpr = TNew(cls,params,el) }
+					| _ -> die ~p:e.epos "Unexpected return type of haxe.Rest.createNative" __LOC__)
 				| TCall ({ eexpr = TIdent "__array__" }, el)
 				| TCall ({ eexpr = TField(_, FStatic({ cl_path = (["java"],"NativeArray") }, { cf_name = "make" })) }, el)
 				| TArrayDecl el when t_has_type_param e.etype ->

+ 24 - 2
src/generators/genjvm.ml

@@ -129,7 +129,12 @@ let rec jsignature_of_type gctx stack t =
 				| [t] -> TArray(jsignature_of_type t,None)
 				| _ -> die "" __LOC__
 				end
-			| ["haxe"],"Rest" -> TArray(object_sig,None)
+			| ["haxe"],"Rest" ->
+				begin match tl with
+				| [t] -> TArray(get_boxed_type (jsignature_of_type t),None)
+				| _ -> die "" __LOC__
+				end
+			(* | ["haxe"],"Rest" -> TArray(object_sig,None) *)
 			| [],"Dynamic" ->
 				object_sig
 			| [],("Class" | "Enum") ->
@@ -171,6 +176,8 @@ let rec jsignature_of_type gctx stack t =
 		jsig
 	) tl) (return_of_type gctx stack tr)
 	| TAnon an -> object_sig
+	| TType({ t_path = ["haxe"],"Rest$NativeRest" },[t]) ->
+		TArray(get_boxed_type (jsignature_of_type t),None)
 	| TType(td,tl) ->
 		begin match gctx.typedef_interfaces#get_interface_class td.t_path with
 		| Some c -> TObject(c.cl_path,[])
@@ -1514,6 +1521,16 @@ class texpr_to_jvm gctx (jc : JvmClass.builder) (jm : JvmMethod.builder) (return
 			| _ ->
 				Error.error (Printf.sprintf "Bad __array__ type: %s" (s_type (print_context()) tr)) e1.epos;
 			end
+		| TField(_,FStatic({cl_path = (["haxe"],"Rest$Rest_Impl_")},{cf_name = "createNative"})) ->
+			begin match tr, el with
+			| TType({ t_path = ["haxe"],"Rest$NativeRest" },[t]), [e2] ->
+				self#texpr (if need_val ret then rvalue_any else RVoid) e2;
+				let jsig = get_boxed_type (self#vtype t) in
+				ignore(NativeArray.create jm#get_code jc#get_pool jsig);
+				Some (array_sig jsig)
+			| _ ->
+				Error.error (Printf.sprintf "Bad __array__ type: %s" (s_type (print_context()) tr)) e1.epos;
+			end
 		| TField(e1,FStatic(c,({cf_kind = Method (MethNormal | MethInline)} as cf))) ->
 			let tl,tr = self#call_arguments cf.cf_type el in
 			jm#invokestatic c.cl_path cf.cf_name (method_sig tl tr);
@@ -1948,7 +1965,12 @@ class texpr_to_jvm gctx (jc : JvmClass.builder) (jm : JvmMethod.builder) (return
 			| TInst({cl_path = (["java"],"NativeArray")},[t]) ->
 				self#texpr rvalue_any e1;
 				let vt = self#vtype e1.etype in
-				let vte = self#vtype t in
+				let vte =
+					let vte = self#vtype t in
+					match e1.etype with
+					| TType ({ t_path = ["haxe"],"Rest$NativeRest" },_) -> get_boxed_type vte
+					| _ -> vte
+				in
 				self#texpr rvalue_any e2;
 				self#read_native_array vt vte
 			| t ->

+ 1 - 1
std/haxe/Rest.hx

@@ -7,7 +7,7 @@ private typedef NativeRest<T> = Array<T>;
 
 /**
 	A special type that represents a "rest" function argument.
-	
+
 	The special `...` syntax can be used for convenience and improved readability:
 
 	```haxe

+ 27 - 16
std/java/_std/haxe/Rest.hx

@@ -7,7 +7,7 @@ import java.lang.System;
 import java.lang.Object;
 import java.util.Arrays;
 
-private typedef NativeRest<T> = NativeArray<Object>;
+private typedef NativeRest<T> = NativeArray<T>;
 
 @:coreApi
 abstract Rest<T>(NativeRest<T>) {
@@ -15,27 +15,34 @@ abstract Rest<T>(NativeRest<T>) {
 	inline function get_length():Int
 		return this.length;
 
+	#if jvm
 	@:from static public function of<T>(array:Array<T>):Rest<T> {
-		var native = @:privateAccess array.__a;
-		var result:NativeRest<T>;
-		#if jvm
-			result = (cast native:Object).clone();
-		#else
-			result = new NativeRest<T>(native.length);
-			for(i in 0...native.length)
-				result[i] = cast native[i];
-		#end
+		return new Rest(@:privateAccess array.__a);
+	}
+	#else
+	@:from extern inline static public function of<T>(array:Array<T>):Rest<T> {
+		var result = createNative(array.length);
+		var src:NativeArray<Object> = cast @:privateAccess array.__a;
+		for(i in 0...src.length)
+			result[i] = cast src[i];
 		return new Rest(result);
 	}
+	#end
 
 	inline function new(a:NativeRest<T>):Void
 		this = a;
 
+	/**
+	 * Implemented in genjvm (to auto-box primitive types) and genjava
+	 */
+	static function createNative<T>(length:Int):NativeRest<T>
+		return new NativeRest<T>(length);
+
 	@:arrayAccess inline function get(index:Int):T
-		return cast this[index];
+		return this[index];
 
 	@:to public function toArray():Array<T> {
-		return [for(i in 0...this.length) cast this[i]];
+		return [for(i in 0...this.length) this[i]];
 	}
 
 	public inline function iterator():RestIterator<T>
@@ -44,15 +51,19 @@ abstract Rest<T>(NativeRest<T>) {
 	public inline function keyValueIterator():RestKeyValueIterator<T>
 		return new RestKeyValueIterator<T>(this);
 
-	public function append(item:T):Rest<T> {
-		var result = new NativeRest<T>(this.length + 1);
+	extern inline public function append(item:T):Rest<T> {
+		return _append(createNative(this.length + 1), item);
+	}
+	function _append(result:NativeRest<T>, item:T):Rest<T> {
 		System.arraycopy(this, 0, result, 0, this.length);
 		result[this.length] = cast item;
 		return new Rest(result);
 	}
 
-	public function prepend(item:T):Rest<T> {
-		var result = new NativeRest<T>(this.length + 1);
+	extern inline public function prepend(item:T):Rest<T> {
+		return _prepend(createNative(this.length + 1), item);
+	}
+	function _prepend(result:NativeRest<T>, item:T):Rest<T> {
 		System.arraycopy(this, 0, result, 1, this.length);
 		result[0] = cast item;
 		return new Rest(result);

+ 12 - 1
tests/unit/src/unit/TestRest.hx

@@ -67,6 +67,17 @@ class TestRest extends Test {
 		aeq([1, 2, 9], result.appended);
 	}
 
+	@:depends(testToArray)
+	function testPrepend() {
+		function rest(...r:Int) {
+			var prepended = r.prepend(9);
+			return {initial:r.toArray(), prepended:prepended.toArray()}
+		}
+		var result = rest(1, 2);
+		aeq([1, 2], result.initial);
+		aeq([9, 1, 2], result.prepended);
+	}
+
 	@:depends(testToArray)
 	function testSpread() {
 		function rest(...r:Int) {
@@ -80,7 +91,7 @@ class TestRest extends Test {
 		aeq([1, 2, 3], new Parent(...[1, 2, 3]).ctorArgs.toArray());
 	}
 
-	@:depends(testToArray, testRestReturn)
+	@:depends(testToArray, testRestReturn, testAppend)
 	function testInheritance() {
 		var p = new Parent(1, 2, 3);
 		var c = new Child(4, 5, 6);