Browse Source

don't loose typed arguments of a call to a var field as a static extension (closes #10144)

Aleksandr Kuzmenko 4 years ago
parent
commit
5f599bab53
3 changed files with 50 additions and 26 deletions
  1. 35 22
      src/typing/callUnification.ml
  2. 4 4
      src/typing/calls.ml
  3. 11 0
      tests/unit/src/unit/issues/Issue10144.hx

+ 35 - 22
src/typing/callUnification.ml

@@ -224,6 +224,32 @@ type overload_kind =
 	| OverloadMeta (* @:overload(function() {}) *)
 	| OverloadNone
 
+(**
+	Unifies `el_typed` against the types from `args` list starting at the beginning
+	of `args` list.
+
+	Returns a tuple of a part of `args` covered by `el_typed`, and a part of `args`
+	not used for `el_typed` unification.
+*)
+let unify_typed_args ctx tmap args el_typed call_pos =
+	let rec loop acc_args tmap args el =
+		match args,el with
+		| [], _ :: _ ->
+			let call_error = Call_error(Too_many_arguments) in
+			raise(Error(call_error,call_pos))
+		| _, [] ->
+			List.rev acc_args,args
+		| ((_,opt,t0) as arg) :: args,e :: el ->
+			begin try
+				unify_raise ctx (tmap e.etype) t0 e.epos;
+			with Error(Unify _ as msg,p) ->
+				let call_error = Call_error(Could_not_unify msg) in
+				raise(Error(call_error,p))
+			end;
+			loop (arg :: acc_args) (fun t -> t) args el
+	in
+	loop [] tmap args el_typed
+
 let unify_field_call ctx fa el_typed el p inline =
 	let expand_overloads cf =
 		cf :: cf.cf_overloads
@@ -302,22 +328,7 @@ let unify_field_call ctx fa el_typed el p inline =
 		let t = map (apply_params cf.cf_params monos cf.cf_type) in
 		match follow t with
 		| TFun(args,ret) ->
-			let rec loop acc_el acc_args tmap args el_typed = match args,el_typed with
-				| ((_,opt,t0) as arg) :: args,e :: el_typed ->
-					begin try
-						unify_raise ctx (tmap e.etype) t0 e.epos;
-					with Error(Unify _ as msg,p) ->
-						let call_error = Call_error(Could_not_unify msg) in
-						raise(Error(call_error,p))
-					end;
-					loop (e :: acc_el) (arg :: acc_args) (fun t -> t) args el_typed
-				| [],_ :: _ ->
-					let call_error = Call_error(Too_many_arguments) in
-					raise(Error(call_error,p))
-				| _ ->
-					List.rev acc_el,List.rev acc_args,args
-			in
-			let el_typed,args_typed,args = loop [] [] tmap args el_typed in
+			let args_typed,args = unify_typed_args ctx tmap args el_typed p in
 			let el,_ =
 				try
 					unify_call_args ctx el args ret p inline is_forced_inline in_overload
@@ -521,10 +532,10 @@ object(self)
 
 	(* Calls `e` with arguments `el`. Does not inspect the callee expression, so it should only be
 	   used with actual expression calls and not with something like field calls. *)
-	method expr_call (e : texpr) (el : expr list) =
+	method expr_call (e : texpr) (el_typed : texpr list) (el : expr list) =
 		check_assign();
 		let default t =
-			let el = List.map (fun e -> type_expr ctx e WithType.value) el in
+			let el = el_typed @ List.map (fun e -> type_expr ctx e WithType.value) el in
 			let t = if t == t_dynamic then
 				t_dynamic
 			else if ctx.untyped then
@@ -536,7 +547,9 @@ object(self)
 		in
 		let rec loop t = match follow t with
 		| TFun (args,r) ->
-			let el, tfunc = unify_call_args ctx el args r p false false false in
+			let args_typed,args_left = unify_typed_args ctx (fun t -> t) args el_typed p in
+			let el, tfunc = unify_call_args ctx el args_left r p false false false in
+			let el = el_typed @ el in
 			let r = match tfunc with TFun(_,r) -> r | _ -> die "" __LOC__ in
 			mk (TCall (e,el)) r p
 		| TAbstract(a,tl) as t ->
@@ -550,13 +563,13 @@ object(self)
 			| Some cf,Some c ->
 				let e_static = Builder.make_static_this c e.epos in
 				let fa = FieldAccess.create e_static cf (FHAbstract(a,tl,c)) false e.epos in
-				self#field_call fa [e] el
+				self#field_call fa (e :: el_typed) el
 			| _ ->
 				check_callable();
 			end
 		| TMono _ ->
 			let t = mk_mono() in
-			let el = List.map (fun e -> type_expr ctx e WithType.value) el in
+			let el = el_typed @ List.map (fun e -> type_expr ctx e WithType.value) el in
 			unify ctx (tfun (List.map (fun e -> e.etype) el) t) e.etype e.epos;
 			mk (TCall (e,el)) t p
 		| t ->
@@ -620,7 +633,7 @@ object(self)
 			| AccCall ->
 				self#accessor_call fa el_typed el
 			| _ ->
-				self#expr_call (FieldAccess.get_field_expr fa FCall) el
+				self#expr_call (FieldAccess.get_field_expr fa FCall) el_typed el
 			end
 end
 

+ 4 - 4
src/typing/calls.ml

@@ -254,18 +254,18 @@ let build_call ?(mode=MGet) ctx acc el (with_type:WithType.t) p =
 		let eparam = sea.se_this in
 		dispatch#field_call sea.se_access [eparam] el
 	| AKResolve(sea,name) ->
-		dispatch#expr_call (dispatch#resolve_call sea name) el
+		dispatch#expr_call (dispatch#resolve_call sea name) [] el
 	| AKNo _ | AKAccess _ ->
 		ignore(acc_get ctx acc p);
 		error ("Unexpected access mode, please report this: " ^ (s_access_kind acc)) p
 	| AKAccessor fa ->
 		let e = dispatch#field_call fa [] [] in
-		dispatch#expr_call e el
+		dispatch#expr_call e [] el
 	| AKUsingAccessor sea ->
 		let e = dispatch#field_call sea.se_access [sea.se_this] [] in
-		dispatch#expr_call e el
+		dispatch#expr_call e [] el
 	| AKExpr e ->
-		dispatch#expr_call e el
+		dispatch#expr_call e [] el
 
 let rec needs_temp_var e =
 	match e.eexpr with

+ 11 - 0
tests/unit/src/unit/issues/Issue10144.hx

@@ -0,0 +1,11 @@
+package unit.issues;
+
+using unit.issues.Issue10144;
+
+class Issue10144 extends Test {
+	static final foo = (a:Int) -> a * 2;
+
+	function test() {
+		eq(10, 5.foo());
+	}
+}