Browse Source

[cs] improved rest args handling (closes #10315)

Aleksandr Kuzmenko 4 years ago
parent
commit
18086b9c62
2 changed files with 45 additions and 7 deletions
  1. 29 7
      src/codegen/gencommon/castDetect.ml
  2. 16 0
      tests/unit/src/unit/issues/Issue10315.hx

+ 29 - 7
src/codegen/gencommon/castDetect.ml

@@ -669,6 +669,7 @@ let choose_ctor gen cl tparams etl maybe_empty_t p =
 			is_overload, List.find check_cf ctors, sup, ret_stl
 
 let change_rest tfun elist =
+	let expects_rest_args = ref false in
 	let rec loop acc arglist elist = match arglist, elist with
 		| (_,_,t) as arg :: [], elist when ExtType.is_rest t ->
 			(match elist with
@@ -681,8 +682,11 @@ let change_rest tfun elist =
 						Type.fast_eq (Abstract.follow_with_abstracts t) (Abstract.follow_with_abstracts e.etype)
 					in
 					(match elist with
-					| [e] when is_rest_array e -> List.rev (("rest",false,t) :: acc)
-					| _ -> List.rev (List.map (fun _ -> "rest",false,t1) elist @ acc)
+					| [e] when is_rest_array e ->
+						List.rev (("rest",false,t) :: acc)
+					| _ ->
+						expects_rest_args := true;
+						List.rev (List.map (fun _ -> "rest",false,t1) elist @ acc)
 					)
 				| _ -> die "" __LOC__)
 			)
@@ -692,7 +696,8 @@ let change_rest tfun elist =
 			List.rev acc
 	in
 	let args,ret = get_fun tfun in
-	TFun(loop [] args elist, ret)
+	let args_types = loop [] args elist in
+	!expects_rest_args,TFun(args_types, ret)
 
 let fastcast_if_needed gen expr real_to_t real_from_t =
 	if Common.defined gen.gcon Define.FastCast then begin
@@ -850,7 +855,7 @@ let handle_type_parameter gen e e1 ef ~clean_ef ~overloads_cast_to_base f elist
 			in
 
 			(* take off Rest param *)
-			let actual_t = change_rest actual_t elist in
+			let _,actual_t = change_rest actual_t elist in
 			(* set the real (selected) class field *)
 			let f = match f with
 				| FInstance(c,tl,_) -> FInstance(c,tl,cf)
@@ -868,7 +873,7 @@ let handle_type_parameter gen e e1 ef ~clean_ef ~overloads_cast_to_base f elist
 				(* infer arguments *)
 				(* let called_t = TFun(List.map (fun e -> "arg",false,e.etype) elist, ecall.etype) in *)
 				let called_t = match follow e1.etype with | TFun _ -> e1.etype | _ -> TFun(List.map (fun e -> "arg",false,e.etype) elist, ecall.etype)	in (* workaround for issue #1742 *)
-				let called_t = change_rest called_t elist in
+				let expects_rest_args,called_t = change_rest called_t elist in
 				let original = (get_fun (apply_params cl.cl_params params actual_t)) in
 				let applied = (get_fun called_t) in
 				let fparams = infer_params ecall.epos original applied cf.cf_params calls_parameters_explicitly in
@@ -887,7 +892,7 @@ let handle_type_parameter gen e e1 ef ~clean_ef ~overloads_cast_to_base f elist
 				let applied = elist in
 				(* check types list *)
 				let new_ecall, elist = try
-					let elist = List.map2 (fun applied (_,_,funct) ->
+					let fn = fun funct applied  ->
 						match is_overload || real_fparams <> [], applied.eexpr with
 						| true, TConst TNull ->
 							mk_castfast (gen.greal_type funct) applied
@@ -898,7 +903,24 @@ let handle_type_parameter gen e e1 ef ~clean_ef ~overloads_cast_to_base f elist
 							| _ -> local_mk_cast (funct) ret)
 						| _ ->
 							handle_cast gen applied (funct) (gen.greal_type applied.etype)
-					) applied args_ft in
+					in
+					let rec loop args_ft applied =
+						match args_ft, applied with
+						| [], [] -> []
+						| [(_,_,funct)], _ when expects_rest_args ->
+							(match funct, applied with
+							| TInst({ cl_path = (_,"NativeArray") },[_]),[a] when Type.does_unify funct a.etype ->
+								[fn funct a]
+							| TInst({ cl_path = (_,"NativeArray") },[funct]),_ ->
+								List.map (fn funct) applied
+							| _ ->
+								raise (Invalid_argument "Unexpected rest arguments type")
+							)
+						| (_,_,funct)::args_ft, a::applied ->
+							(fn funct a) :: loop args_ft applied
+						| _ -> raise (Invalid_argument "Args length mismatch")
+					in
+					let elist = loop args_ft applied in
 					{ ecall with
 						eexpr = TCall(
 							{ e1 with eexpr = TField(!ef, f) },

+ 16 - 0
tests/unit/src/unit/issues/Issue10315.hx

@@ -0,0 +1,16 @@
+package unit.issues;
+
+class Issue10315 extends Test {
+	function test() {
+		var o = new Obj();
+		eq('a', o.call('a'));
+	}
+}
+
+
+private class Obj {
+	public function new() {}
+	public function call(...args:Any) {
+		return args[0];
+	}
+}