Sfoglia il codice sorgente

Bugfix 2689 (#7594)

* [#2689] overload not allowed for java

* fixed overloading, more specific message

* made .gitignore ignore local history

* improve error messages; optimize traversing overloads
Jakobeha 6 anni fa
parent
commit
6052555bf7

+ 1 - 0
.gitignore

@@ -120,6 +120,7 @@ tmp.tmp
 dev-display.hxml
 
 .DS_Store
+.history
 tests/sourcemaps/bin
 /*_plugin.ml
 tests/benchs/export/

+ 42 - 12
src/codegen/overloads.ml

@@ -1,13 +1,29 @@
+open Globals
 open Type
+open Typecore
 
-let same_overload_args ?(get_vmtype) t1 t2 f1 f2 =
+type overload_args_comparison =
+  | Same
+  | Different
+  | Impl_conflict
+
+let distinguishes_funs_as_params ctx =
+  	match ctx.com.platform with
+  	| Java -> false
+  	| _ -> true
+
+let compare_overload_args ?(get_vmtype) ?(ctx) 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
+		Different
 	else
+	let amb_funs =
+		match ctx with
+		| None -> false
+		| Some ctx -> not (distinguishes_funs_as_params ctx) in
 	let rec follow_skip_null t = match t with
 		| TMono r ->
 			(match !r with
@@ -21,25 +37,39 @@ let same_overload_args ?(get_vmtype) t1 t2 f1 f2 =
 			follow_skip_null (apply_params t.t_params tl t.t_type)
 		| _ -> t
 	in
-	let same_arg t1 t2 =
+	let compare_type t1 t2 =
+		(if type_iseq t1 t2 then
+			Same
+		else if amb_funs && type_iseq (ambiguate_funs t1) (ambiguate_funs t2) then
+			Impl_conflict
+		else
+			Different) in
+	let compare_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 _ -> compare_type t1 t2
 			| TType _, _
-			| _, TType _ -> false
-			| _ -> type_iseq t1 t2
+			| _, TType _ -> Different
+			| _ -> compare_type 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 _ ->
-				false)
+			let rec loop args1 args2 =
+				match args1, args2 with
+				| [], [] -> Same
+				| [], _ | _, [] -> Different
+				| (_,_,t1) :: rest1, (_,_,t2) :: rest2 ->
+					match compare_arg t1 t2 with
+					| Same -> loop rest1 rest2
+					| result -> result
+			in
+			loop a1 a2
 		| _ -> assert false
 
+let same_overload_args ?(get_vmtype) t1 t2 f1 f2 =
+	compare_overload_args ?get_vmtype t1 t2 f1 f2 <> Different
 
 (** retrieves all overloads from class c and field i, as (Type.t * tclass_field) list *)
 let rec get_overloads c i =
@@ -258,4 +288,4 @@ struct
 
 			let r = loop [] !rated in
 			List.map fst r
-end
+end

+ 24 - 1
src/core/type.ml

@@ -807,6 +807,29 @@ let rec follow t =
 		follow t
 	| _ -> t
 
+(** Assumes `follow` has already been applied *)
+let rec ambiguate_funs t =
+	match t with
+	| TFun _ -> TFun ([], t_dynamic)
+	| TMono r ->
+		(match !r with
+		| Some _ -> assert false
+		| _ -> t)
+	| TInst (a, pl) ->
+	    TInst (a, List.map ambiguate_funs pl)
+	| TEnum (a, pl) ->
+	    TEnum (a, List.map ambiguate_funs pl)
+	| TAbstract (a, pl) ->
+	    TAbstract (a, List.map ambiguate_funs pl)
+	| TType (a, pl) ->
+	    TType (a, List.map ambiguate_funs pl)
+	| TDynamic _ -> t
+	| TAnon a ->
+	    TAnon { a with a_fields =
+		    PMap.map (fun af -> { af with cf_type =
+				ambiguate_funs af.cf_type }) a.a_fields }
+	| TLazy _ -> assert false
+
 let rec is_nullable = function
 	| TMono r ->
 		(match !r with None -> false | Some t -> is_nullable t)
@@ -3094,4 +3117,4 @@ let s_class_path c =
 		| KAbstractImpl a -> a.a_path
 		| _ -> c.cl_path
 	in
-	s_type_path path
+	s_type_path path

+ 31 - 12
src/typing/typeloadFields.ml

@@ -1347,16 +1347,38 @@ let init_field (ctx,cctx,fctx) f =
 	| FProp (get,set,t,eo) ->
 		create_property (ctx,cctx,fctx) c f (get,set,t,eo) p
 
+let check_overload ctx f fs =
+	try
+		let f2 =
+			List.find (fun f2 ->
+				f != f2 &&
+				Overloads.compare_overload_args ~ctx f.cf_type f2.cf_type f f2 = Overloads.Same
+			) fs
+		in
+		display_error ctx ("Another overloaded field of same signature was already declared : " ^ f.cf_name) f.cf_pos;
+		display_error ctx ("The second field is declared here") f2.cf_pos
+	with Not_found ->
+		try
+			let f2 =
+				List.find (fun f2 ->
+					f != f2 &&
+					Overloads.compare_overload_args ~ctx f.cf_type f2.cf_type f f2 = Overloads.Impl_conflict
+				) fs
+			in
+			display_error ctx (
+				"Another overloaded field of similar signature was already declared : " ^
+				f.cf_name ^
+				"\nThe signatures are different in Haxe, but not in the target language"
+			) f.cf_pos;
+			display_error ctx ("The second field is declared here") f2.cf_pos
+		with | Not_found -> ()
+
 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 && Overloads.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)
+			check_overload ctx f (f :: f.cf_overloads)
+	) (c.cl_ordered_fields @ c.cl_ordered_statics)
 
 let init_class ctx c p context_init herits fields =
 	let ctx,cctx = create_class_context ctx c context_init p in
@@ -1509,13 +1531,10 @@ let init_class ctx c p context_init herits fields =
 	(* check overloaded constructors *)
 	(if ctx.com.config.pf_overload && not cctx.is_lib then match c.cl_constructor with
 	| Some ctor ->
-		delay ctx PTypeField (fun() ->
+		delay ctx PTypeField (fun () ->
+			(* TODO: consider making a broader check, and treat some types, like TAnon and type parameters as Dynamic *)
 			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 && 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 -> ()
+				check_overload ctx f (ctor :: ctor.cf_overloads)
 			) (ctor :: ctor.cf_overloads)
 		)
 	| _ -> ());

+ 9 - 0
tests/misc/java/projects/Issue2689/Main.hx

@@ -0,0 +1,9 @@
+class Main {
+	static function main() {}
+
+	@:overload static function conflict(fn:(Int)->String) {}
+	@:overload static function conflict(fn:(Bool)->String) {}
+
+	@:overload static function same(fn:(Int)->String) {}
+	@:overload static function same(fn:(Int)->String) {}
+}

+ 3 - 0
tests/misc/java/projects/Issue2689/compile-fail.hxml

@@ -0,0 +1,3 @@
+-main Main
+-java bin
+--no-output

+ 5 - 0
tests/misc/java/projects/Issue2689/compile-fail.hxml.stderr

@@ -0,0 +1,5 @@
+Main.hx:4: characters 13-58 : Another overloaded field of similar signature was already declared : conflict
+Main.hx:4: characters 13-58 : The signatures are different in Haxe, but not in the target language
+Main.hx:5: characters 13-59 : The second field is declared here
+Main.hx:7: characters 13-54 : Another overloaded field of same signature was already declared : same
+Main.hx:8: characters 13-54 : The second field is declared here