Browse Source

Allow `overload` on extern methods on all targets (#9793)

* [typer] lose some more pf_overload checks

* [typer] enable overloads
Simon Krajewski 5 years ago
parent
commit
975b58746c

+ 8 - 7
src/typing/typeloadCheck.ml

@@ -173,7 +173,7 @@ let check_overriding ctx c f =
 		let i = f.cf_name in
 		let i = f.cf_name in
 		let check_field f get_super_field is_overload = try
 		let check_field f get_super_field is_overload = try
 			(if is_overload && not (has_class_field_flag f CfOverload) then
 			(if is_overload && not (has_class_field_flag f CfOverload) then
-				display_error ctx ("Missing @:overload declaration for field " ^ i) p);
+				display_error ctx ("Missing overload declaration for field " ^ i) p);
 			let t, f2 = get_super_field csup i in
 			let t, f2 = get_super_field csup i in
 			check_native_name_override ctx f f2;
 			check_native_name_override ctx f f2;
 			(* allow to define fields that are not defined for this platform version in superclass *)
 			(* allow to define fields that are not defined for this platform version in superclass *)
@@ -181,10 +181,11 @@ let check_overriding ctx c f =
 			| Var { v_read = AccRequire _ } -> raise Not_found;
 			| Var { v_read = AccRequire _ } -> raise Not_found;
 			| _ -> ());
 			| _ -> ());
 			if (has_class_field_flag f2 CfOverload && not (has_class_field_flag f CfOverload)) then
 			if (has_class_field_flag f2 CfOverload && not (has_class_field_flag f CfOverload)) then
-				display_error ctx ("Field " ^ i ^ " should be declared with @:overload since it was already declared as @:overload in superclass") p
-			else if not (has_class_field_flag f CfOverride) then
-				display_error ctx ("Field " ^ i ^ " should be declared with 'override' since it is inherited from superclass " ^ s_type_path csup.cl_path) p
-			else if not (has_class_field_flag f CfPublic) && (has_class_field_flag f2 CfPublic) then
+				display_error ctx ("Field " ^ i ^ " should be declared with overload since it was already declared as overload in superclass") p
+			else if not (has_class_field_flag f CfOverride) then begin
+				if has_class_flag c CExtern then add_class_field_flag f CfOverride
+				else display_error ctx ("Field " ^ i ^ " should be declared with 'override' since it is inherited from superclass " ^ s_type_path csup.cl_path) p
+			end else if not (has_class_field_flag f CfPublic) && (has_class_field_flag f2 CfPublic) then
 				display_error ctx ("Field " ^ i ^ " has less visibility (public/private) than superclass one") p
 				display_error ctx ("Field " ^ i ^ " has less visibility (public/private) than superclass one") p
 			else (match f.cf_kind, f2.cf_kind with
 			else (match f.cf_kind, f2.cf_kind with
 			| _, Method MethInline ->
 			| _, Method MethInline ->
@@ -346,7 +347,7 @@ module Inheritance = struct
 			try
 			try
 				let t2, f2 = class_field_no_interf c i in
 				let t2, f2 = class_field_no_interf c i in
 				let t2, f2 =
 				let t2, f2 =
-					if ctx.com.config.pf_overload && (f2.cf_overloads <> [] || has_class_field_flag f2 CfOverload) then
+					if f2.cf_overloads <> [] || has_class_field_flag f2 CfOverload then
 						let overloads = Overloads.get_overloads ctx.com c i in
 						let overloads = Overloads.get_overloads ctx.com c i in
 						is_overload := true;
 						is_overload := true;
 						List.find (fun (t1,f1) -> Overloads.same_overload_args t t1 f f1) overloads
 						List.find (fun (t1,f1) -> Overloads.same_overload_args t t1 f f1) overloads
@@ -403,7 +404,7 @@ module Inheritance = struct
 		in
 		in
 		let check_field i cf =
 		let check_field i cf =
 			check_field i cf;
 			check_field i cf;
-			if ctx.com.config.pf_overload then
+			if has_class_field_flag cf CfOverload then
 				List.iter (check_field i) (List.rev cf.cf_overloads)
 				List.iter (check_field i) (List.rev cf.cf_overloads)
 		in
 		in
 		PMap.iter check_field intf.cl_fields
 		PMap.iter check_field intf.cl_fields

+ 16 - 24
src/typing/typeloadFields.ml

@@ -1214,8 +1214,12 @@ let create_method (ctx,cctx,fctx) c f fd p =
 	| Some p ->
 	| Some p ->
 		if ctx.com.config.pf_overload then
 		if ctx.com.config.pf_overload then
 			add_class_field_flag cf CfOverload
 			add_class_field_flag cf CfOverload
+		else if fctx.field_kind = FKConstructor then
+			display_error ctx "Constructors cannot be overloaded on this target" p
+		else if (has_class_flag c CExtern || fctx.is_extern) then
+			add_class_field_flag cf CfOverload
 		else
 		else
-			display_error ctx "This platform does not support this kind of overload declaration. Try @:overload(function()... {}) instead" p
+			display_error ctx "Only extern functions may be overloaded on this target" p
 	| None ->
 	| None ->
 		()
 		()
 	end;
 	end;
@@ -1269,19 +1273,11 @@ let create_property (ctx,cctx,fctx) c f (get,set,t,eo) p =
 		| _ -> tfun [] ret, TFun(["value",false,ret],ret)
 		| _ -> tfun [] ret, TFun(["value",false,ret],ret)
 	in
 	in
 	let find_accessor m =
 	let find_accessor m =
-		(* on pf_overload platforms, the getter/setter may have been defined as an overloaded function; get all overloads *)
-		if ctx.com.config.pf_overload then
-			if fctx.is_static then
-				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
-				Overloads.get_overloads ctx.com c m
-		else
-			[ if fctx.is_static then
-				let f = PMap.find m c.cl_statics in
-				f.cf_type, f
-			else match class_field c (List.map snd c.cl_params) m with
-				| _, t,f -> t,f ]
+		if fctx.is_static then begin
+			let cf = PMap.find m c.cl_statics in
+			(cf.cf_type,cf) :: (List.map (fun cf -> cf.cf_type,cf) cf.cf_overloads)
+		end else
+			Overloads.get_overloads ctx.com c m
 	in
 	in
 	let cf = {
 	let cf = {
 		(mk_field name ~public:(is_public (ctx,cctx) f.cff_access None) ret f.cff_pos (pos f.cff_name)) with
 		(mk_field name ~public:(is_public (ctx,cctx) f.cff_access None) ret f.cff_pos (pos f.cff_name)) with
@@ -1290,24 +1286,20 @@ let create_property (ctx,cctx,fctx) c f (get,set,t,eo) p =
 	} in
 	} in
 	if fctx.is_abstract_member then add_class_field_flag cf CfImpl;
 	if fctx.is_abstract_member then add_class_field_flag cf CfImpl;
 	let check_method m t is_getter =
 	let check_method m t is_getter =
-		if ctx.com.display.dms_error_policy = EPIgnore then () else
-		try
+		if ctx.com.display.dms_error_policy = EPIgnore then
+			()
+		else try
 			let overloads = find_accessor m in
 			let overloads = find_accessor m in
-			(* choose the correct overload if and only if there is more than one overload found *)
 			let rec get_overload overl = match overl with
 			let rec get_overload overl = match overl with
-				| [tf] -> tf
+				| [tf] ->
+					tf
 				| (t2,f2) :: overl ->
 				| (t2,f2) :: overl ->
 					if type_iseq t t2 then
 					if type_iseq t t2 then
 						(t2,f2)
 						(t2,f2)
 					else
 					else
 						get_overload overl
 						get_overload overl
 				| [] ->
 				| [] ->
-					if (has_class_flag c CInterface) || Diagnostics.is_diagnostics_run ctx.com f.cff_pos then
-						raise Not_found
-					else
-						raise (Error (Custom
-							(Printf.sprintf "No overloaded method named %s was compatible with the property %s with expected type %s" m (name) (s_type (print_context()) t)
-						), p))
+					raise Not_found
 			in
 			in
 			let t2, f2 = get_overload overloads in
 			let t2, f2 = get_overload overloads in
 			f2.cf_meta <- List.fold_left (fun acc ((m,_,_) as meta) -> match m with
 			f2.cf_meta <- List.fold_left (fun acc ((m,_,_) as meta) -> match m with

+ 4 - 0
tests/misc/projects/extern-overloads/ambiguous-static/Main.hx

@@ -0,0 +1,4 @@
+extern class Main {
+	overload static inline function f(i:Int):Void {}
+	overload static inline function f(i:Int):Void {}
+}

+ 2 - 0
tests/misc/projects/extern-overloads/ambiguous-static/compile-fail.hxml

@@ -0,0 +1,2 @@
+-main Main
+--interp

+ 2 - 0
tests/misc/projects/extern-overloads/ambiguous-static/compile-fail.hxml.stderr

@@ -0,0 +1,2 @@
+Main.hx:2: characters 2-50 : Another overloaded field of same signature was already declared : f
+Main.hx:3: characters 2-50 : ... The second field is declared here

+ 12 - 0
tests/misc/projects/extern-overloads/amgiuous-call-site/Main.hx

@@ -0,0 +1,12 @@
+extern class Ext {
+	function new():Void;
+	overload function f(s:String):Void;
+	overload function f(e:Ext):Void;
+}
+
+class Main {
+	static function main() {
+		var m = new Ext();
+		m.f(null);
+	}
+}

+ 2 - 0
tests/misc/projects/extern-overloads/amgiuous-call-site/compile-fail.hxml

@@ -0,0 +1,2 @@
+-main Main
+--interp

+ 3 - 0
tests/misc/projects/extern-overloads/amgiuous-call-site/compile-fail.hxml.stderr

@@ -0,0 +1,3 @@
+Main.hx:10: characters 3-12 : Ambiguous overload, candidates follow
+Main.hx:3: characters 20-21 : ... (s : String) -> Void
+Main.hx:4: characters 20-21 : ... (e : Ext) -> Void

+ 7 - 0
tests/misc/projects/extern-overloads/missing-override/Main.hx

@@ -0,0 +1,7 @@
+extern class Parent {
+	overload function f(i:Int):Void;
+}
+
+extern class Child extends Parent {
+	function f(i:Int):Void;
+}

+ 2 - 0
tests/misc/projects/extern-overloads/missing-override/compile-fail.hxml.disabled

@@ -0,0 +1,2 @@
+-main Main
+--interp

+ 1 - 0
tests/misc/projects/extern-overloads/missing-override/compile-fail.hxml.stderr

@@ -0,0 +1 @@
+Main.hx:6: characters 11-12 : Field f should be declared with overload since it was already declared as overload in superclass

+ 3 - 0
tests/misc/projects/extern-overloads/not-not-extern/Main.hx

@@ -0,0 +1,3 @@
+class Main {
+	overload function test() {}
+}

+ 2 - 0
tests/misc/projects/extern-overloads/not-not-extern/compile-fail.hxml

@@ -0,0 +1,2 @@
+-main Main
+--interp

+ 1 - 0
tests/misc/projects/extern-overloads/not-not-extern/compile-fail.hxml.stderr

@@ -0,0 +1 @@
+Main.hx:2: characters 2-10 : Only extern functions may be overloaded on this target

+ 3 - 0
tests/misc/projects/extern-overloads/not-on-constructor/Main.hx

@@ -0,0 +1,3 @@
+class Main {
+	overload function new() {}
+}

+ 2 - 0
tests/misc/projects/extern-overloads/not-on-constructor/compile-fail.hxml

@@ -0,0 +1,2 @@
+-main Main
+--interp

+ 1 - 0
tests/misc/projects/extern-overloads/not-on-constructor/compile-fail.hxml.stderr

@@ -0,0 +1 @@
+Main.hx:2: characters 2-10 : Constructors cannot be overloaded on this target

+ 1 - 0
tests/unit/src/unit/TestMain.hx

@@ -101,6 +101,7 @@ function main() {
 		#if (java || cs)
 		#if (java || cs)
 		new TestOverloads(),
 		new TestOverloads(),
 		#end
 		#end
+		new TestOverloadsForEveryone(),
 		new TestInterface(),
 		new TestInterface(),
 		new TestNaN(),
 		new TestNaN(),
 		#if ((dce == "full") && !interp)
 		#if ((dce == "full") && !interp)

+ 36 - 0
tests/unit/src/unit/TestOverloadsForEveryone.hx

@@ -0,0 +1,36 @@
+package unit;
+
+private class StaticOverloadClass {
+	overload extern static public inline function test(i:Int) {
+		return "Int: " + i;
+	}
+
+	overload extern static public inline function test(s:String) {
+		return "String: " + s;
+	}
+}
+
+private class MemberOverloadClass {
+	public function new() {
+
+	}
+
+	overload extern public inline function test(i:Int) {
+		return "Int: " + i;
+	}
+
+	overload extern public inline function test(s:String) {
+		return "String: " + s;
+	}
+}
+
+class TestOverloadsForEveryone extends Test {
+	function test() {
+		eq("Int: 12", StaticOverloadClass.test(12));
+		eq("String: foo", StaticOverloadClass.test("foo"));
+
+		var moc = new MemberOverloadClass();
+		eq("Int: 12", moc.test(12));
+		eq("String: foo", moc.test("foo"));
+	}
+}