Explorar el Código

lose gencommon -> typeload dependency

Simon Krajewski hace 9 años
padre
commit
9408aded48
Se han modificado 6 ficheros con 298 adiciones y 292 borrados
  1. 6 4
      Makefile
  2. 0 195
      src/generators/codegen.ml
  3. 9 8
      src/generators/gencommon.ml
  4. 274 0
      src/typing/overloads.ml
  5. 7 83
      src/typing/typeload.ml
  6. 2 2
      src/typing/typer.ml

+ 6 - 4
Makefile

@@ -54,7 +54,7 @@ RELDIR=../../..
 
 MODULES=json version globals path syntax/ast display/displayTypes typing/type syntax/lexer typing/common generators/genxml syntax/parser \
 	typing/typecore display/display \
-	optimization/optimizer typing/typeload generators/codegen generators/gencommon generators/genas3 \
+	optimization/optimizer typing/overloads typing/typeload generators/codegen generators/gencommon generators/genas3 \
 	generators/gencpp generators/genjs generators/genneko generators/genphp generators/genswf9 \
 	generators/genswf generators/genjava generators/gencs generators/genpy macro/interp generators/genhl \
 	generators/genlua \
@@ -146,7 +146,7 @@ src/generators/codegen.$(MODULE_EXT): src/typing/typecore.$(MODULE_EXT) src/typi
 
 src/generators/genas3.$(MODULE_EXT): src/typing/type.$(MODULE_EXT) src/typing/common.$(MODULE_EXT) src/generators/codegen.$(MODULE_EXT) src/syntax/ast.$(MODULE_EXT)
 
-src/generators/gencommon.$(MODULE_EXT): src/path.$(MODULE_EXT) src/typing/type.$(MODULE_EXT) src/typing/common.$(MODULE_EXT) src/generators/codegen.$(MODULE_EXT) src/syntax/ast.$(MODULE_EXT) src/typing/typeload.$(MODULE_EXT) libs/ilib/il.$(LIB_EXT)
+src/generators/gencommon.$(MODULE_EXT):src/typing/overloads.$(MODULE_EXT) src/path.$(MODULE_EXT) src/typing/type.$(MODULE_EXT) src/typing/common.$(MODULE_EXT) src/generators/codegen.$(MODULE_EXT) src/syntax/ast.$(MODULE_EXT) libs/ilib/il.$(LIB_EXT)
 
 src/generators/gencpp.$(MODULE_EXT): src/path.$(MODULE_EXT) src/typing/type.$(MODULE_EXT) src/syntax/lexer.$(MODULE_EXT) src/typing/common.$(MODULE_EXT) src/generators/codegen.$(MODULE_EXT) src/syntax/ast.$(MODULE_EXT)
 
@@ -209,13 +209,15 @@ src/typing/common.$(MODULE_EXT): src/typing/type.$(MODULE_EXT) src/syntax/ast.$(
 
 src/typing/matcher.$(MODULE_EXT): src/optimization/optimizer.$(MODULE_EXT) src/generators/codegen.$(MODULE_EXT) src/typing/typecore.$(MODULE_EXT) src/typing/type.$(MODULE_EXT) src/typing/typer.$(MODULE_EXT) src/typing/common.$(MODULE_EXT) src/syntax/ast.$(MODULE_EXT)
 
+src/typing/overloads.$(MODULE_EXT): src/syntax/ast.$(MODULE_EXT) src/typing/type.$(MODULE_EXT) src/typing/typecore.$(MODULE_EXT)
+
 src/typing/type.$(MODULE_EXT): src/syntax/ast.$(MODULE_EXT) src/json.$(MODULE_EXT)
 
 src/typing/typecore.$(MODULE_EXT): src/path.$(MODULE_EXT) src/typing/type.$(MODULE_EXT) src/typing/common.$(MODULE_EXT) src/syntax/ast.$(MODULE_EXT)
 
-src/typing/typeload.$(MODULE_EXT): src/path.$(MODULE_EXT) src/typing/typecore.$(MODULE_EXT) src/typing/type.$(MODULE_EXT) src/syntax/parser.$(MODULE_EXT) src/optimization/optimizer.$(MODULE_EXT) src/syntax/lexer.$(MODULE_EXT) src/typing/common.$(MODULE_EXT) src/syntax/ast.$(MODULE_EXT) src/json.$(MODULE_EXT) src/display/display.$(MODULE_EXT)
+src/typing/typeload.$(MODULE_EXT): src/typing/overloads.$(MODULE_EXT) src/path.$(MODULE_EXT) src/typing/typecore.$(MODULE_EXT) src/typing/type.$(MODULE_EXT) src/syntax/parser.$(MODULE_EXT) src/optimization/optimizer.$(MODULE_EXT) src/syntax/lexer.$(MODULE_EXT) src/typing/common.$(MODULE_EXT) src/syntax/ast.$(MODULE_EXT) src/json.$(MODULE_EXT) src/display/display.$(MODULE_EXT)
 
-src/typing/typer.$(MODULE_EXT): src/path.$(MODULE_EXT) src/typing/typeload.$(MODULE_EXT) src/typing/typecore.$(MODULE_EXT) src/typing/type.$(MODULE_EXT) src/syntax/parser.$(MODULE_EXT) src/optimization/optimizer.$(MODULE_EXT) src/syntax/lexer.$(MODULE_EXT) src/macro/interp.$(MODULE_EXT) src/typing/common.$(MODULE_EXT) src/generators/codegen.$(MODULE_EXT) src/syntax/ast.$(MODULE_EXT) src/optimization/filters.$(MODULE_EXT) src/generators/genjs.$(MODULE_EXT) src/generators/genlua.$(MODULE_EXT) src/display/display.$(MODULE_EXT)
+src/typing/typer.$(MODULE_EXT): src/typing/overloads.$(MODULE_EXT) src/path.$(MODULE_EXT) src/typing/typeload.$(MODULE_EXT) src/typing/typecore.$(MODULE_EXT) src/typing/type.$(MODULE_EXT) src/syntax/parser.$(MODULE_EXT) src/optimization/optimizer.$(MODULE_EXT) src/syntax/lexer.$(MODULE_EXT) src/macro/interp.$(MODULE_EXT) src/typing/common.$(MODULE_EXT) src/generators/codegen.$(MODULE_EXT) src/syntax/ast.$(MODULE_EXT) src/optimization/filters.$(MODULE_EXT) src/generators/genjs.$(MODULE_EXT) src/generators/genlua.$(MODULE_EXT) src/display/display.$(MODULE_EXT)
 
 # main
 

+ 0 - 195
src/generators/codegen.ml

@@ -1018,201 +1018,6 @@ let default_cast ?(vtmp="$t") com e texpr t p =
 	let check = mk (TIf (mk_parent is,mk (TCast (vexpr,None)) t p,Some exc)) t p in
 	mk (TBlock [var;check;vexpr]) t p
 
-(** Overload resolution **)
-module Overloads =
-struct
-	let rec simplify_t t = match t with
-		| TAbstract(a,_) when Meta.has Meta.CoreType a.a_meta ->
-			t
-		| TInst _ | TEnum _ ->
-			t
-		| TAbstract(a,tl) -> simplify_t (Abstract.get_underlying_type a tl)
-		| TType(({ t_path = [],"Null" } as t), [t2]) -> (match simplify_t t2 with
-			| (TAbstract(a,_) as t2) when Meta.has Meta.CoreType a.a_meta ->
-				TType(t, [simplify_t t2])
-			| (TEnum _ as t2) ->
-				TType(t, [simplify_t t2])
-			| t2 -> t2)
-		| TType(t, tl) ->
-			simplify_t (apply_params t.t_params tl t.t_type)
-		| TMono r -> (match !r with
-			| Some t -> simplify_t t
-			| None -> t_dynamic)
-		| TAnon _ -> t_dynamic
-		| TDynamic _ -> t
-		| TLazy f -> simplify_t (!f())
-		| TFun _ -> t
-
-	(* rate type parameters *)
-	let rate_tp tlfun tlarg =
-		let acc = ref 0 in
-		List.iter2 (fun f a -> if not (type_iseq f a) then incr acc) tlfun tlarg;
-		!acc
-
-	(**
-		The rate function returns an ( int * int ) type.
-		The smaller the int, the best rated the caller argument is in comparison with the callee.
-
-		The first int refers to how many "conversions" would be necessary to convert from the callee to the caller type, and
-		the second refers to the type parameters.
-	**)
-	let rec rate_conv cacc tfun targ =
-		match simplify_t tfun, simplify_t targ with
-		| TInst({ cl_interface = true } as cf, tlf), TInst(ca, tla) ->
-			(* breadth-first *)
-			let stack = ref [0,ca,tla] in
-			let cur = ref (0, ca,tla) in
-			let rec loop () =
-				match !stack with
-				| [] -> (let acc, ca, tla = !cur in match ca.cl_super with
-					| None -> raise Not_found
-					| Some (sup,tls) ->
-						cur := (acc+1,sup,List.map (apply_params ca.cl_params tla) tls);
-						stack := [!cur];
-						loop())
-				| (acc,ca,tla) :: _ when ca == cf ->
-					acc,tla
-				| (acc,ca,tla) :: s ->
-					stack := s @ List.map (fun (c,tl) -> (acc+1,c,List.map (apply_params ca.cl_params tla) tl)) ca.cl_implements;
-					loop()
-			in
-			let acc, tla = loop() in
-			(cacc + acc, rate_tp tlf tla)
-		| TInst(cf,tlf), TInst(ca,tla) ->
-			let rec loop acc ca tla =
-				if cf == ca then
-					acc, tla
-				else match ca.cl_super with
-				| None -> raise Not_found
-				| Some(sup,stl) ->
-					loop (acc+1) sup (List.map (apply_params ca.cl_params tla) stl)
-			in
-			let acc, tla = loop 0 ca tla in
-			(cacc + acc, rate_tp tlf tla)
-		| TEnum(ef,tlf), TEnum(ea, tla) ->
-			if ef != ea then raise Not_found;
-			(cacc, rate_tp tlf tla)
-		| TDynamic _, TDynamic _ ->
-			(cacc, 0)
-		| TDynamic _, _ ->
-			(max_int, 0) (* a function with dynamic will always be worst of all *)
-		| TAbstract(a, _), TDynamic _ when Meta.has Meta.CoreType a.a_meta ->
-			(cacc + 2, 0) (* a dynamic to a basic type will have an "unboxing" penalty *)
-		| _, TDynamic _ ->
-			(cacc + 1, 0)
-		| TAbstract(af,tlf), TAbstract(aa,tla) ->
-			(if af == aa then
-				(cacc, rate_tp tlf tla)
-			else
-				let ret = ref None in
-				if List.exists (fun t -> try
-					ret := Some (rate_conv (cacc+1) (apply_params af.a_params tlf t) targ);
-					true
-				with | Not_found ->
-					false
-				) af.a_from then
-					Option.get !ret
-			else
-				if List.exists (fun t -> try
-					ret := Some (rate_conv (cacc+1) tfun (apply_params aa.a_params tla t));
-					true
-				with | Not_found ->
-					false
-				) aa.a_to then
-					Option.get !ret
-			else
-				raise Not_found)
-		| TType({ t_path = [], "Null" }, [tf]), TType({ t_path = [], "Null" }, [ta]) ->
-			rate_conv (cacc+0) tf ta
-		| TType({ t_path = [], "Null" }, [tf]), ta ->
-			rate_conv (cacc+1) tf ta
-		| tf, TType({ t_path = [], "Null" }, [ta]) ->
-			rate_conv (cacc+1) tf ta
-		| TFun _, TFun _ -> (* unify will make sure they are compatible *)
-			cacc,0
-		| tfun,targ ->
-			raise Not_found
-
-	let is_best arg1 arg2 =
-		(List.for_all2 (fun v1 v2 ->
-			v1 <= v2)
-		arg1 arg2) && (List.exists2 (fun v1 v2 ->
-			v1 < v2)
-		arg1 arg2)
-
-	let rec rm_duplicates acc ret = match ret with
-		| [] -> acc
-		| ( el, t, _ ) :: ret when List.exists (fun (_,t2,_) -> type_iseq t t2) acc ->
-			rm_duplicates acc ret
-		| r :: ret ->
-			rm_duplicates (r :: acc) ret
-
-	let s_options rated =
-		String.concat ",\n" (List.map (fun ((elist,t,_),rate) ->
-			"( " ^ (String.concat "," (List.map (fun(e,_) -> s_expr (s_type (print_context())) e) elist)) ^ " ) => " ^
-			"( " ^ (String.concat "," (List.map (fun (i,i2) -> string_of_int i ^ ":" ^ string_of_int i2) rate)) ^ " ) => " ^ (s_type (print_context()) t)
-		) rated)
-
-	let count_optionals elist =
-		List.fold_left (fun acc (_,is_optional) -> if is_optional then acc + 1 else acc) 0 elist
-
-	let rec fewer_optionals acc compatible = match acc, compatible with
-		| _, [] -> acc
-		| [], c :: comp -> fewer_optionals [c] comp
-		| (elist_acc, _, _) :: _, ((elist, _, _) as cur) :: comp ->
-			let acc_opt = count_optionals elist_acc in
-			let comp_opt = count_optionals elist in
-			if acc_opt = comp_opt then
-				fewer_optionals (cur :: acc) comp
-			else if acc_opt < comp_opt then
-				fewer_optionals acc comp
-			else
-				fewer_optionals [cur] comp
-
-	let reduce_compatible compatible = match fewer_optionals [] (rm_duplicates [] compatible) with
-		| [] -> []
-		| [v] -> [v]
-		| compatible ->
-			(* convert compatible into ( rate * compatible_type ) list *)
-			let rec mk_rate acc elist args = match elist, args with
-				| [], [] -> acc
-				| (_,true) :: elist, _ :: args -> mk_rate acc elist args
-				| (e,false) :: elist, (n,o,t) :: args ->
-					(* if the argument is an implicit cast, we need to start with a penalty *)
-					(* The penalty should be higher than any other implicit cast - other than Dynamic *)
-					(* since Dynamic has a penalty of max_int, we'll impose max_int - 1 to it *)
-					(match e.eexpr with
-						| TMeta( (Meta.ImplicitCast,_,_), _) ->
-							mk_rate ((max_int - 1, 0) :: acc) elist args
-						| _ ->
-							mk_rate (rate_conv 0 t e.etype :: acc) elist args)
-				| _ -> assert false
-			in
-
-			let rated = ref [] in
-			List.iter (function
-				| (elist,TFun(args,ret),d) -> (try
-					rated := ( (elist,TFun(args,ret),d), mk_rate [] elist args ) :: !rated
-					with | Not_found -> ())
-				| _ -> assert false
-			) compatible;
-
-			let rec loop best rem = match best, rem with
-				| _, [] -> best
-				| [], r1 :: rem -> loop [r1] rem
-				| (bover, bargs) :: b1, (rover, rargs) :: rem ->
-					if is_best bargs rargs then
-						loop best rem
-					else if is_best rargs bargs then
-						loop (loop b1 [rover,rargs]) rem
-					else (* equally specific *)
-						loop ( (rover,rargs) :: best ) rem
-			in
-
-			let r = loop [] !rated in
-			List.map fst r
-end;;
-
 module UnificationCallback = struct
 	let tf_stack = ref []
 

+ 9 - 8
src/generators/gencommon.ml

@@ -60,6 +60,7 @@ open Option
 open Printf
 open ExtString
 open Codegen
+open Overloads
 
 let alloc_var n t = alloc_var n t null_pos
 
@@ -1200,7 +1201,7 @@ let find_first_declared_field gen orig_cl ?get_vmtype ?exact_field field =
 			| _, Some f2 ->
 				List.iter (fun f ->
 					let declared_t = apply_params c.cl_params tl f.cf_type in
-					if Typeload.same_overload_args ~get_vmtype declared_t f2.cf_type f f2 then
+					if same_overload_args ~get_vmtype declared_t f2.cf_type f f2 then
 						chosen := Some(depth,f,c,tl,tlch)
 				) (ret :: ret.cf_overloads)
 		with | Not_found -> ());
@@ -6004,9 +6005,9 @@ struct
 						| FInstance(c,_,cf) | FClosure(Some (c,_),cf) ->
 							(* get from overloads *)
 							(* FIXME: this is a workaround for issue #1743 . Uncomment this code after it was solved *)
-							(* let t, cf = List.find (fun (t,cf2) -> cf == cf2) (Typeload.get_overloads cl (field_name f)) in *)
+							(* let t, cf = List.find (fun (t,cf2) -> cf == cf2) (Overloads.get_overloads cl (field_name f)) in *)
 							(* cf, t, false *)
-							select_overload gen e1.etype (Typeload.get_overloads cl (field_name f)) cl.cl_params params, false
+							select_overload gen e1.etype (Overloads.get_overloads cl (field_name f)) cl.cl_params params, false
 						| FStatic(c,f) ->
 							(* workaround for issue #1743 *)
 							(* f,f.cf_type, false *)
@@ -9870,14 +9871,14 @@ struct
 						let ftype = apply_params iface.cl_params itl f.cf_type in
 						let real_ftype = get_real_fun gen (apply_params iface.cl_params real_itl f.cf_type) in
 						replace_mono real_ftype;
-						let overloads = Typeload.get_overloads c f.cf_name in
+						let overloads = Overloads.get_overloads c f.cf_name in
 						try
 							let t2, f2 =
 								match overloads with
 								| (_, cf) :: _ when Meta.has Meta.Overload cf.cf_meta -> (* overloaded function *)
 									(* try to find exact function *)
 									List.find (fun (t,f2) ->
-										Typeload.same_overload_args ~get_vmtype ftype t f f2
+										Overloads.same_overload_args ~get_vmtype ftype t f f2
 									) overloads
 								| _ :: _ ->
 									(match field_access gen (TInst(c, List.map snd c.cl_params)) f.cf_name with
@@ -9893,7 +9894,7 @@ struct
 								if List.length f.cf_params <> List.length f2.cf_params then raise Not_found;
 								replace_mono t2;
 								match follow (apply_params f2.cf_params (List.map snd f.cf_params) t2), follow real_ftype with
-								| TFun(a1,r1), TFun(a2,r2) when not implement_explicitly && not (type_iseq r1 r2) && Typeload.same_overload_args ~get_vmtype real_ftype t2 f f2 ->
+								| TFun(a1,r1), TFun(a2,r2) when not implement_explicitly && not (type_iseq r1 r2) && Overloads.same_overload_args ~get_vmtype real_ftype t2 f f2 ->
 									(* different return types are the trickiest cases to deal with *)
 									(* check for covariant return type *)
 									let is_covariant = match follow r1, follow r2 with
@@ -9919,7 +9920,7 @@ struct
 								| TFun(a1,r1), TFun(a2,r2) ->
 									(* just implement a function that will call the main one *)
 									let name, is_explicit = match explicit_fn_name with
-										| Some fn when not (type_iseq r1 r2) && Typeload.same_overload_args ~get_vmtype real_ftype t2 f f2 ->
+										| Some fn when not (type_iseq r1 r2) && Overloads.same_overload_args ~get_vmtype real_ftype t2 f f2 ->
 												fn iface itl f.cf_name, true
 										| _ -> f.cf_name, false
 									in
@@ -9970,7 +9971,7 @@ struct
 					in
 					match decl with
 					| Some(f2,actual_t,_,t,declared_cl,_,_)
-						when not (Typeload.same_overload_args ~get_vmtype actual_t (get_real_fun gen f.cf_type) f2 f) ->
+						when not (Overloads.same_overload_args ~get_vmtype actual_t (get_real_fun gen f.cf_type) f2 f) ->
 							(match f.cf_expr with
 							| Some({ eexpr = TFunction(tf) } as e) ->
 								let actual_args, _ = get_fun (get_real_fun gen actual_t) in

+ 274 - 0
src/typing/overloads.ml

@@ -0,0 +1,274 @@
+open Ast
+open Type
+
+let same_overload_args ?(get_vmtype) t1 t2 f1 f2 =
+	let get_vmtype = match get_vmtype with
+		| None -> (fun f -> f)
+		| Some f -> f
+	in
+	if List.length f1.cf_params <> List.length f2.cf_params then
+		false
+	else
+	let rec follow_skip_null t = match t with
+		| TMono r ->
+			(match !r with
+			| Some t -> follow_skip_null t
+			| _ -> t)
+		| TLazy f ->
+			follow_skip_null (!f())
+		| TType ({ t_path = [],"Null" } as t, [p]) ->
+			TType(t,[follow p])
+		| TType (t,tl) ->
+			follow_skip_null (apply_params t.t_params tl t.t_type)
+		| _ -> t
+	in
+	let same_arg t1 t2 =
+		let t1 = get_vmtype (follow_skip_null t1) in
+		let t2 = get_vmtype (follow_skip_null t2) in
+		match t1, t2 with
+			| TType _, TType _ -> type_iseq t1 t2
+			| TType _, _
+			| _, TType _ -> false
+			| _ -> type_iseq t1 t2
+	in
+
+	match follow (apply_params f1.cf_params (List.map (fun (_,t) -> t) f2.cf_params) t1), follow t2 with
+		| TFun(a1,_), TFun(a2,_) ->
+			(try
+				List.for_all2 (fun (_,_,t1) (_,_,t2) ->
+				same_arg t1 t2) a1 a2
+			with | Invalid_argument("List.for_all2") ->
+				false)
+		| _ -> assert false
+
+
+(** retrieves all overloads from class c and field i, as (Type.t * tclass_field) list *)
+let rec get_overloads c i =
+	let ret = try
+			let f = PMap.find i c.cl_fields in
+			match f.cf_kind with
+				| Var _ ->
+					(* @:libType may generate classes that have a variable field in a superclass of an overloaded method *)
+					[]
+				| Method _ ->
+					(f.cf_type, f) :: (List.map (fun f -> f.cf_type, f) f.cf_overloads)
+		with | Not_found -> []
+	in
+	let rsup = match c.cl_super with
+	| None when c.cl_interface ->
+			let ifaces = List.concat (List.map (fun (c,tl) ->
+				List.map (fun (t,f) -> apply_params c.cl_params tl t, f) (get_overloads c i)
+			) c.cl_implements) in
+			ret @ ifaces
+	| None -> ret
+	| Some (c,tl) ->
+			ret @ ( List.map (fun (t,f) -> apply_params c.cl_params tl t, f) (get_overloads c i) )
+	in
+	ret @ (List.filter (fun (t,f) -> not (List.exists (fun (t2,f2) -> same_overload_args t t2 f f2) ret)) rsup)
+
+
+let check_overloads ctx c =
+	(* check if field with same signature was declared more than once *)
+	List.iter (fun f ->
+		if Meta.has Meta.Overload f.cf_meta then
+			List.iter (fun f2 ->
+				try
+					ignore (List.find (fun f3 -> f3 != f2 && same_overload_args f2.cf_type f3.cf_type f2 f3) (f :: f.cf_overloads));
+					Typecore.display_error ctx ("Another overloaded field of same signature was already declared : " ^ f2.cf_name) f2.cf_pos
+				with | Not_found -> ()
+		) (f :: f.cf_overloads)) (c.cl_ordered_fields @ c.cl_ordered_statics)
+
+(** Overload resolution **)
+module Resolution =
+struct
+	let rec simplify_t t = match t with
+		| TAbstract(a,_) when Meta.has Meta.CoreType a.a_meta ->
+			t
+		| TInst _ | TEnum _ ->
+			t
+		| TAbstract(a,tl) -> simplify_t (Abstract.get_underlying_type a tl)
+		| TType(({ t_path = [],"Null" } as t), [t2]) -> (match simplify_t t2 with
+			| (TAbstract(a,_) as t2) when Meta.has Meta.CoreType a.a_meta ->
+				TType(t, [simplify_t t2])
+			| (TEnum _ as t2) ->
+				TType(t, [simplify_t t2])
+			| t2 -> t2)
+		| TType(t, tl) ->
+			simplify_t (apply_params t.t_params tl t.t_type)
+		| TMono r -> (match !r with
+			| Some t -> simplify_t t
+			| None -> t_dynamic)
+		| TAnon _ -> t_dynamic
+		| TDynamic _ -> t
+		| TLazy f -> simplify_t (!f())
+		| TFun _ -> t
+
+	(* rate type parameters *)
+	let rate_tp tlfun tlarg =
+		let acc = ref 0 in
+		List.iter2 (fun f a -> if not (type_iseq f a) then incr acc) tlfun tlarg;
+		!acc
+
+	(**
+		The rate function returns an ( int * int ) type.
+		The smaller the int, the best rated the caller argument is in comparison with the callee.
+
+		The first int refers to how many "conversions" would be necessary to convert from the callee to the caller type, and
+		the second refers to the type parameters.
+	**)
+	let rec rate_conv cacc tfun targ =
+		match simplify_t tfun, simplify_t targ with
+		| TInst({ cl_interface = true } as cf, tlf), TInst(ca, tla) ->
+			(* breadth-first *)
+			let stack = ref [0,ca,tla] in
+			let cur = ref (0, ca,tla) in
+			let rec loop () =
+				match !stack with
+				| [] -> (let acc, ca, tla = !cur in match ca.cl_super with
+					| None -> raise Not_found
+					| Some (sup,tls) ->
+						cur := (acc+1,sup,List.map (apply_params ca.cl_params tla) tls);
+						stack := [!cur];
+						loop())
+				| (acc,ca,tla) :: _ when ca == cf ->
+					acc,tla
+				| (acc,ca,tla) :: s ->
+					stack := s @ List.map (fun (c,tl) -> (acc+1,c,List.map (apply_params ca.cl_params tla) tl)) ca.cl_implements;
+					loop()
+			in
+			let acc, tla = loop() in
+			(cacc + acc, rate_tp tlf tla)
+		| TInst(cf,tlf), TInst(ca,tla) ->
+			let rec loop acc ca tla =
+				if cf == ca then
+					acc, tla
+				else match ca.cl_super with
+				| None -> raise Not_found
+				| Some(sup,stl) ->
+					loop (acc+1) sup (List.map (apply_params ca.cl_params tla) stl)
+			in
+			let acc, tla = loop 0 ca tla in
+			(cacc + acc, rate_tp tlf tla)
+		| TEnum(ef,tlf), TEnum(ea, tla) ->
+			if ef != ea then raise Not_found;
+			(cacc, rate_tp tlf tla)
+		| TDynamic _, TDynamic _ ->
+			(cacc, 0)
+		| TDynamic _, _ ->
+			(max_int, 0) (* a function with dynamic will always be worst of all *)
+		| TAbstract(a, _), TDynamic _ when Meta.has Meta.CoreType a.a_meta ->
+			(cacc + 2, 0) (* a dynamic to a basic type will have an "unboxing" penalty *)
+		| _, TDynamic _ ->
+			(cacc + 1, 0)
+		| TAbstract(af,tlf), TAbstract(aa,tla) ->
+			(if af == aa then
+				(cacc, rate_tp tlf tla)
+			else
+				let ret = ref None in
+				if List.exists (fun t -> try
+					ret := Some (rate_conv (cacc+1) (apply_params af.a_params tlf t) targ);
+					true
+				with | Not_found ->
+					false
+				) af.a_from then
+					Option.get !ret
+			else
+				if List.exists (fun t -> try
+					ret := Some (rate_conv (cacc+1) tfun (apply_params aa.a_params tla t));
+					true
+				with | Not_found ->
+					false
+				) aa.a_to then
+					Option.get !ret
+			else
+				raise Not_found)
+		| TType({ t_path = [], "Null" }, [tf]), TType({ t_path = [], "Null" }, [ta]) ->
+			rate_conv (cacc+0) tf ta
+		| TType({ t_path = [], "Null" }, [tf]), ta ->
+			rate_conv (cacc+1) tf ta
+		| tf, TType({ t_path = [], "Null" }, [ta]) ->
+			rate_conv (cacc+1) tf ta
+		| TFun _, TFun _ -> (* unify will make sure they are compatible *)
+			cacc,0
+		| tfun,targ ->
+			raise Not_found
+
+	let is_best arg1 arg2 =
+		(List.for_all2 (fun v1 v2 ->
+			v1 <= v2)
+		arg1 arg2) && (List.exists2 (fun v1 v2 ->
+			v1 < v2)
+		arg1 arg2)
+
+	let rec rm_duplicates acc ret = match ret with
+		| [] -> acc
+		| ( el, t, _ ) :: ret when List.exists (fun (_,t2,_) -> type_iseq t t2) acc ->
+			rm_duplicates acc ret
+		| r :: ret ->
+			rm_duplicates (r :: acc) ret
+
+	let s_options rated =
+		String.concat ",\n" (List.map (fun ((elist,t,_),rate) ->
+			"( " ^ (String.concat "," (List.map (fun(e,_) -> s_expr (s_type (print_context())) e) elist)) ^ " ) => " ^
+			"( " ^ (String.concat "," (List.map (fun (i,i2) -> string_of_int i ^ ":" ^ string_of_int i2) rate)) ^ " ) => " ^ (s_type (print_context()) t)
+		) rated)
+
+	let count_optionals elist =
+		List.fold_left (fun acc (_,is_optional) -> if is_optional then acc + 1 else acc) 0 elist
+
+	let rec fewer_optionals acc compatible = match acc, compatible with
+		| _, [] -> acc
+		| [], c :: comp -> fewer_optionals [c] comp
+		| (elist_acc, _, _) :: _, ((elist, _, _) as cur) :: comp ->
+			let acc_opt = count_optionals elist_acc in
+			let comp_opt = count_optionals elist in
+			if acc_opt = comp_opt then
+				fewer_optionals (cur :: acc) comp
+			else if acc_opt < comp_opt then
+				fewer_optionals acc comp
+			else
+				fewer_optionals [cur] comp
+
+	let reduce_compatible compatible = match fewer_optionals [] (rm_duplicates [] compatible) with
+		| [] -> []
+		| [v] -> [v]
+		| compatible ->
+			(* convert compatible into ( rate * compatible_type ) list *)
+			let rec mk_rate acc elist args = match elist, args with
+				| [], [] -> acc
+				| (_,true) :: elist, _ :: args -> mk_rate acc elist args
+				| (e,false) :: elist, (n,o,t) :: args ->
+					(* if the argument is an implicit cast, we need to start with a penalty *)
+					(* The penalty should be higher than any other implicit cast - other than Dynamic *)
+					(* since Dynamic has a penalty of max_int, we'll impose max_int - 1 to it *)
+					(match e.eexpr with
+						| TMeta( (Meta.ImplicitCast,_,_), _) ->
+							mk_rate ((max_int - 1, 0) :: acc) elist args
+						| _ ->
+							mk_rate (rate_conv 0 t e.etype :: acc) elist args)
+				| _ -> assert false
+			in
+
+			let rated = ref [] in
+			List.iter (function
+				| (elist,TFun(args,ret),d) -> (try
+					rated := ( (elist,TFun(args,ret),d), mk_rate [] elist args ) :: !rated
+					with | Not_found -> ())
+				| _ -> assert false
+			) compatible;
+
+			let rec loop best rem = match best, rem with
+				| _, [] -> best
+				| [], r1 :: rem -> loop [r1] rem
+				| (bover, bargs) :: b1, (rover, rargs) :: rem ->
+					if is_best bargs rargs then
+						loop best rem
+					else if is_best rargs bargs then
+						loop (loop b1 [rover,rargs]) rem
+					else (* equally specific *)
+						loop ( (rover,rargs) :: best ) rem
+			in
+
+			let r = loop [] !rated in
+			List.map fst r
+end

+ 7 - 83
src/typing/typeload.ml

@@ -852,82 +852,6 @@ let copy_meta meta_src meta_target sl =
 	) meta_src;
 	!meta
 
-let same_overload_args ?(get_vmtype) t1 t2 f1 f2 =
-	let get_vmtype = match get_vmtype with
-		| None -> (fun f -> f)
-		| Some f -> f
-	in
-	if List.length f1.cf_params <> List.length f2.cf_params then
-		false
-	else
-	let rec follow_skip_null t = match t with
-		| TMono r ->
-			(match !r with
-			| Some t -> follow_skip_null t
-			| _ -> t)
-		| TLazy f ->
-			follow_skip_null (!f())
-		| TType ({ t_path = [],"Null" } as t, [p]) ->
-			TType(t,[follow p])
-		| TType (t,tl) ->
-			follow_skip_null (apply_params t.t_params tl t.t_type)
-		| _ -> t
-	in
-	let same_arg t1 t2 =
-		let t1 = get_vmtype (follow_skip_null t1) in
-		let t2 = get_vmtype (follow_skip_null t2) in
-		match t1, t2 with
-			| TType _, TType _ -> type_iseq t1 t2
-			| TType _, _
-			| _, TType _ -> false
-			| _ -> type_iseq t1 t2
-	in
-
-	match follow (apply_params f1.cf_params (List.map (fun (_,t) -> t) f2.cf_params) t1), follow t2 with
-		| TFun(a1,_), TFun(a2,_) ->
-			(try
-				List.for_all2 (fun (_,_,t1) (_,_,t2) ->
-				same_arg t1 t2) a1 a2
-			with | Invalid_argument("List.for_all2") ->
-				false)
-		| _ -> assert false
-
-(** retrieves all overloads from class c and field i, as (Type.t * tclass_field) list *)
-let rec get_overloads c i =
-	let ret = try
-			let f = PMap.find i c.cl_fields in
-			match f.cf_kind with
-				| Var _ ->
-					(* @:libType may generate classes that have a variable field in a superclass of an overloaded method *)
-					[]
-				| Method _ ->
-					(f.cf_type, f) :: (List.map (fun f -> f.cf_type, f) f.cf_overloads)
-		with | Not_found -> []
-	in
-	let rsup = match c.cl_super with
-	| None when c.cl_interface ->
-			let ifaces = List.concat (List.map (fun (c,tl) ->
-				List.map (fun (t,f) -> apply_params c.cl_params tl t, f) (get_overloads c i)
-			) c.cl_implements) in
-			ret @ ifaces
-	| None -> ret
-	| Some (c,tl) ->
-			ret @ ( List.map (fun (t,f) -> apply_params c.cl_params tl t, f) (get_overloads c i) )
-	in
-	ret @ (List.filter (fun (t,f) -> not (List.exists (fun (t2,f2) -> same_overload_args t t2 f f2) ret)) rsup)
-
-
-let check_overloads ctx c =
-	(* check if field with same signature was declared more than once *)
-	List.iter (fun f ->
-		if Meta.has Meta.Overload f.cf_meta then
-			List.iter (fun f2 ->
-				try
-					ignore (List.find (fun f3 -> f3 != f2 && same_overload_args f2.cf_type f3.cf_type f2 f3) (f :: f.cf_overloads));
-					display_error ctx ("Another overloaded field of same signature was already declared : " ^ f2.cf_name) f2.cf_pos
-				with | Not_found -> ()
-		) (f :: f.cf_overloads)) (c.cl_ordered_fields @ c.cl_ordered_statics)
-
 let check_overriding ctx c =
 	match c.cl_super with
 	| None ->
@@ -981,7 +905,7 @@ let check_overriding ctx c =
 						display_error ctx msg p
 			in
 			if ctx.com.config.pf_overload && Meta.has Meta.Overload f.cf_meta then begin
-				let overloads = get_overloads csup i in
+				let overloads = Overloads.get_overloads csup i in
 				List.iter (fun (t,f2) ->
 					(* check if any super class fields are vars *)
 					match f2.cf_kind with
@@ -993,7 +917,7 @@ let check_overriding ctx c =
 					(* find the exact field being overridden *)
 					check_field f (fun csup i ->
 						List.find (fun (t,f2) ->
-							same_overload_args f.cf_type (apply_params csup.cl_params params t) f f2
+							Overloads.same_overload_args f.cf_type (apply_params csup.cl_params params t) f f2
 						) overloads
 					) true
 				) (f :: f.cf_overloads)
@@ -1400,10 +1324,10 @@ module Inheritance = struct
 				let t2, f2 = class_field_no_interf c i in
 				let t2, f2 =
 					if ctx.com.config.pf_overload && (f2.cf_overloads <> [] || Meta.has Meta.Overload f2.cf_meta) then
-						let overloads = get_overloads c i in
+						let overloads = Overloads.get_overloads c i in
 						is_overload := true;
 						let t = (apply_params intf.cl_params params f.cf_type) in
-						List.find (fun (t1,f1) -> same_overload_args t t1 f f1) overloads
+						List.find (fun (t1,f1) -> Overloads.same_overload_args t t1 f f1) overloads
 					else
 						t2, f2
 				in
@@ -2666,7 +2590,7 @@ module ClassInitializer = struct
 							let f = PMap.find m c.cl_statics in
 							(f.cf_type, f) :: (List.map (fun f -> f.cf_type, f) f.cf_overloads)
 						else
-							get_overloads c m
+							Overloads.get_overloads c m
 					else
 						[ if fctx.is_static then
 							let f = PMap.find m c.cl_statics in
@@ -2797,7 +2721,7 @@ module ClassInitializer = struct
 		if cctx.is_core_api && ctx.com.display.dms_check_core_api then delay ctx PForce (fun() -> init_core_api ctx c);
 		if not cctx.is_lib then begin
 			(match c.cl_super with None -> () | Some _ -> delay_late ctx PForce (fun() -> check_overriding ctx c));
-			if ctx.com.config.pf_overload then delay ctx PForce (fun() -> check_overloads ctx c)
+			if ctx.com.config.pf_overload then delay ctx PForce (fun() -> Overloads.check_overloads ctx c)
 		end;
 		let rec has_field f = function
 			| None -> false
@@ -2906,7 +2830,7 @@ module ClassInitializer = struct
 				List.iter (fun f ->
 					try
 						(* TODO: consider making a broader check, and treat some types, like TAnon and type parameters as Dynamic *)
-						ignore(List.find (fun f2 -> f != f2 && same_overload_args f.cf_type f2.cf_type f f2) (ctor :: ctor.cf_overloads));
+						ignore(List.find (fun f2 -> f != f2 && Overloads.same_overload_args f.cf_type f2.cf_type f f2) (ctor :: ctor.cf_overloads));
 						display_error ctx ("Another overloaded field of same signature was already declared : " ^ f.cf_name) f.cf_pos;
 					with Not_found -> ()
 				) (ctor :: ctor.cf_overloads)

+ 2 - 2
src/typing/typer.ml

@@ -665,7 +665,7 @@ let unify_field_call ctx fa el args ret p inline =
 			let cfl = if cf.cf_name = "new" || not (Meta.has Meta.Overload cf.cf_meta && ctx.com.config.pf_overload) then
 				List.map (map_cf cf map) cf.cf_overloads
 			else
-				List.map (fun (t,cf) -> map (monomorphs cf.cf_params t),cf) (Typeload.get_overloads c cf.cf_name)
+				List.map (fun (t,cf) -> map (monomorphs cf.cf_params t),cf) (Overloads.get_overloads c cf.cf_name)
 			in
 			(TFun(args,ret),cf) :: cfl,Some c,cf,(fun cf -> FInstance(c,tl,cf))
 		| FClosure(co,cf) ->
@@ -733,7 +733,7 @@ let unify_field_call ctx fa el args ret p inline =
 				error "End of overload failure reasons" p
 			end
 		in
-		if is_overload && ctx.com.config.pf_overload then begin match Codegen.Overloads.reduce_compatible candidates with
+		if is_overload && ctx.com.config.pf_overload then begin match Overloads.Resolution.reduce_compatible candidates with
 			| [] -> fail()
 			| [el,tf,mk_call] -> List.map fst el,tf,mk_call
 			| _ -> error "Ambiguous overload" p