Browse Source

[jvm] fix functional interfaces some more

closes #11390
Simon Krajewski 1 year ago
parent
commit
7665333b6c

+ 18 - 12
src/generators/jvm/jvmFunctions.ml

@@ -317,6 +317,8 @@ module JavaFunctionalInterfaces = struct
 	let unify jfi args ret =
 	let unify jfi args ret =
 		let params = ref [] in
 		let params = ref [] in
 		let rec unify jsig1 jsig2 = match jsig1,jsig2 with
 		let rec unify jsig1 jsig2 = match jsig1,jsig2 with
+			| TObject _,TObject((["java";"lang"],"Object"),[]) ->
+				true
 			| TObject(path1,params1),TObject(path2,params2) ->
 			| TObject(path1,params1),TObject(path2,params2) ->
 				path1 = path2 &&
 				path1 = path2 &&
 				unify_params params1 params2
 				unify_params params1 params2
@@ -362,7 +364,7 @@ module JavaFunctionalInterfaces = struct
 		| None,None ->
 		| None,None ->
 			loop jfi.jargs args
 			loop jfi.jargs args
 		| Some jsig1,Some jsig2 ->
 		| Some jsig1,Some jsig2 ->
-			if unify jsig1 jsig2 then loop jfi.jargs args
+			if unify jsig2 jsig1 then loop jfi.jargs args
 			else None
 			else None
 		| _ ->
 		| _ ->
 			None
 			None
@@ -441,24 +443,28 @@ class typed_function
 				Hashtbl.add implemented_interfaces path true;
 				Hashtbl.add implemented_interfaces path true;
 			end
 			end
 		in
 		in
+		let spawn_invoke_next name msig is_bridge =
+			let flags = [MPublic] in
+			let flags = if is_bridge then MBridge :: MSynthetic :: flags else flags in
+			jc_closure#spawn_method name msig flags
+		in
 		let spawn_forward_function meth_from meth_to is_bridge =
 		let spawn_forward_function meth_from meth_to is_bridge =
 			let msig = method_sig meth_from.dargs meth_from.dret in
 			let msig = method_sig meth_from.dargs meth_from.dret in
 			if not (jc_closure#has_method meth_from.name msig) then begin
 			if not (jc_closure#has_method meth_from.name msig) then begin
-				let flags = [MPublic] in
-				let flags = if is_bridge then MBridge :: MSynthetic :: flags else flags in
-				let jm_invoke_next = jc_closure#spawn_method meth_from.name msig flags in
+				let jm_invoke_next = spawn_invoke_next meth_from.name msig is_bridge in
 				functions#make_forward_method jc_closure jm_invoke_next meth_from meth_to;
 				functions#make_forward_method jc_closure jm_invoke_next meth_from meth_to;
 			end
 			end
 		in
 		in
 		let check_functional_interfaces meth =
 		let check_functional_interfaces meth =
-			try
-				let l = JavaFunctionalInterfaces.find_compatible meth.dargs meth.dret functional_interface_filter in
-				List.iter (fun (jfi,params) ->
-					add_interface jfi.jpath params;
-					spawn_forward_function {meth with name=jfi.jname} meth false;
-				) l
-			with Not_found ->
-				()
+			let l = JavaFunctionalInterfaces.find_compatible meth.dargs meth.dret functional_interface_filter in
+			List.iter (fun (jfi,params) ->
+				add_interface jfi.jpath params;
+				let msig = method_sig jfi.jargs jfi.jret in
+				if not (jc_closure#has_method jfi.jname msig) then begin
+					let jm_invoke_next = spawn_invoke_next jfi.jname msig false in
+					functions#make_forward_method_jsig jc_closure jm_invoke_next meth.name jfi.jargs jfi.jret meth.dargs meth.dret
+				end
+			) l
 		in
 		in
 		let rec loop meth =
 		let rec loop meth =
 			check_functional_interfaces meth;
 			check_functional_interfaces meth;

+ 32 - 0
tests/misc/java/projects/Issue11390/Main.hx

@@ -0,0 +1,32 @@
+package;
+
+import test.Robot;
+import test.RobotFactory;
+
+class Main {
+	public static function main() {
+		var robot1 = RobotFactory.buildMathRobot();
+		var robot2 = RobotFactory.buildGreetRobot(robot1);
+		var robot3 = RobotFactory.buildManufactureRobot();
+
+		robot1.performTask(add);
+		robot1.performTask(function(a:Int, b:Int):Int {
+			return a - b;
+		});
+
+		robot2.performTask(function (target:Robot) {
+            trace('Hello, ${target.toString()}!');
+        }, () -> {
+			trace('Cleanup...');
+		});
+
+		robot3.performTask(function (robotType:String) {
+			trace('Manufacturing ${robotType}...');
+			return robot2;
+		});
+	}
+
+	static function add(a:Int, b:Int):Int {
+		return a + b;
+	}
+}

+ 6 - 0
tests/misc/java/projects/Issue11390/Setup.hx

@@ -0,0 +1,6 @@
+function main() {
+	Sys.setCwd("./project");
+	Sys.command("javac", ["-d", "out", "test/Robot.java", "test/RobotFactory.java", "-g"]);
+	Sys.setCwd("./out");
+	Sys.command("jar", ["cf", "test.jar", "test/Robot.class", "test/Robot$CleanupTask.class", "test/Robot$MathOperation.class", "test/Robot$GreetRobot.class", "test/Robot$ManufactureRobot.class", "test/RobotFactory.class", "test/RobotFactory$1.class", "test/RobotFactory$2.class", "test/RobotFactory$3.class"]);
+}

+ 12 - 0
tests/misc/java/projects/Issue11390/compile.hxml

@@ -0,0 +1,12 @@
+--main Setup
+--interp
+
+--next
+
+--main Main
+--java-lib project/out/test.jar
+--jvm run.jar
+
+--next
+
+--cmd java -jar run.jar

+ 10 - 0
tests/misc/java/projects/Issue11390/compile.hxml.stdout

@@ -0,0 +1,10 @@
+Robot.performTask() called!
+Result: 7
+Robot.performTask() called!
+Result: -1
+Robot.performTask() called!
+Main.hx:18: Hello, Robot!
+Main.hx:20: Cleanup...
+Robot.performTask() called!
+Main.hx:24: Manufacturing Greet...
+Output: Robot

+ 42 - 0
tests/misc/java/projects/Issue11390/project/test/Robot.java

@@ -0,0 +1,42 @@
+package test;
+
+public abstract class Robot<T> {
+    public Robot() {}
+
+    public void performTask(T listener) {
+        System.out.println("Robot.performTask() called!");
+    }
+
+    public void performTask(T listener, CleanupTask cleanupTask) {
+        System.out.println("Robot.performTask() called!");
+        cleanupTask.cleanup();
+    }
+
+    /**
+     * MathOperation
+     */
+    @FunctionalInterface
+    public interface MathOperation {
+        public int operate(int a, int b);
+    }
+
+    @FunctionalInterface
+    public interface GreetRobot {
+        public void greet(Robot robot);
+    }
+
+    @FunctionalInterface
+    public interface ManufactureRobot<T extends Robot> {
+        public T manufacture(String robotType);
+    }
+
+    @FunctionalInterface
+    public interface CleanupTask {
+        public void cleanup();
+    }
+
+    @Override
+    public String toString() {
+        return "Robot";
+    }
+}

+ 56 - 0
tests/misc/java/projects/Issue11390/project/test/RobotFactory.java

@@ -0,0 +1,56 @@
+package test;
+
+import test.Robot.GreetRobot;
+import test.Robot.ManufactureRobot;
+import test.Robot.MathOperation;
+
+public class RobotFactory {
+    public static Robot<MathOperation> buildMathRobot() {
+        return new Robot<MathOperation>() {
+            public void performTask(MathOperation listener) {
+                System.out.println("Robot.performTask() called!");
+                int result = listener.operate(3, 4);
+                System.out.println("Result: " + result);
+            }
+
+            public void performTask(MathOperation listener, CleanupTask cleanupTask) {
+                System.out.println("Robot.performTask() called!");
+                int result = listener.operate(3, 4);
+                System.out.println("Result: " + result);
+                cleanupTask.cleanup();
+            }
+        };
+    }
+
+    public static Robot<GreetRobot> buildGreetRobot(Robot target) {
+        return new Robot<GreetRobot>() {
+            public void performTask(GreetRobot listener) {
+                System.out.println("Robot.performTask() called!");
+                listener.greet(target);
+            }
+
+            public void performTask(GreetRobot listener, CleanupTask cleanupTask) {
+                System.out.println("Robot.performTask() called!");
+                listener.greet(target);
+                cleanupTask.cleanup();
+            }
+        };
+    }
+
+    public static Robot<ManufactureRobot<Robot<GreetRobot>>> buildManufactureRobot() {
+        return new Robot<ManufactureRobot<Robot<GreetRobot>>>() {
+            public void performTask(ManufactureRobot<Robot<GreetRobot>> listener) {
+                System.out.println("Robot.performTask() called!");
+                Robot<GreetRobot> output = listener.manufacture("Greet");
+                System.out.println("Output: " + output.toString());
+            }
+
+            public void performTask(ManufactureRobot<Robot<GreetRobot>> listener, CleanupTask cleanupTask) {
+                System.out.println("Robot.performTask() called!");
+                Robot<GreetRobot> output = listener.manufacture("Greet");
+                System.out.println("Output: " + output.toString());
+                cleanupTask.cleanup();
+            }
+        };
+    }
+}