Przeglądaj źródła

[php] implemented direct method comparison

Alexander Kuzmenko 7 lat temu
rodzic
commit
f4b4a37578
4 zmienionych plików z 66 dodań i 4 usunięć
  1. 2 0
      extra/CHANGES.txt
  2. 37 4
      src/generators/genphp7.ml
  3. 5 0
      std/php/Boot.hx
  4. 22 0
      tests/unit/src/unit/TestPhp.hx

+ 2 - 0
extra/CHANGES.txt

@@ -6,6 +6,8 @@
 
 	General improvements and optimizations:
 
+	php : implemented direct method comparison. No need to use `Reflect.compareMethods()`
+
 	Removals:
 
 	Deprecations:

+ 37 - 4
src/generators/genphp7.ml

@@ -286,6 +286,15 @@ let is_int expr = match follow expr.etype with TAbstract ({ a_path = ([], "Int")
 *)
 let is_float expr = match follow expr.etype with TAbstract ({ a_path = ([], "Float") }, _) -> true | _ -> false
 
+(**
+	Check if specified expression is of `Int` or `Float` type
+*)
+let is_number expr =
+	match follow expr.etype with
+		| TAbstract ({ a_path = ([], "Float") }, _)
+		| TAbstract ({ a_path = ([], "Int") }, _) -> true
+		| _ -> false
+
 (**
 	Check if specified type is String
 *)
@@ -712,6 +721,18 @@ let is_magic expr =
 		)
 	| _ -> false
 
+(**
+	Check if `expr` is a closure created of a static or an instance method (except `dynamic` methods)
+*)
+let is_method_closure expr =
+	match (reveal_expr expr).eexpr with
+		| TField (_, access) ->
+			(match access with
+				| FClosure (_, field) -> not (is_dynamic_method field)
+				| _ -> false
+			)
+		| _ -> false
+
 (**
 	Check if `expr1` and `expr2` can be reliably checked for equality only with `Boot.equal()`
 *)
@@ -719,10 +740,22 @@ let need_boot_equal expr1 expr2 =
 	if is_constant_null expr1 || is_constant_null expr2 then
 		false
 	else
-		(is_int expr1 && (is_float expr2 || is_unknown_type expr2.etype))
-		|| (is_float expr1 && (is_float expr2 || is_int expr2 || is_unknown_type expr2.etype))
-		|| (is_unknown_type expr1.etype && (is_int expr2 || is_float expr2))
-		|| (is_unknown_type expr1.etype && is_unknown_type expr2.etype)
+		if is_method_closure expr1 || is_method_closure expr2 then
+			true
+		else
+			let unknown1 = is_unknown_type expr1.etype
+			and unknown2 = is_unknown_type expr2.etype in
+			if unknown1 && unknown2 then
+				true
+			else
+				let int1 = is_int expr1
+				and int2 = is_int expr2
+				and float1 = is_float expr1
+				and float2 = is_float expr2 in
+				(int1 && float2)
+				|| (float1 && (float2 || int2))
+				|| (unknown1 && (int2 || float2))
+				|| ((int1 || float1) && unknown2)
 
 (**
 	Adds `return` expression to block if it does not have one already

+ 5 - 0
std/php/Boot.hx

@@ -399,6 +399,9 @@ class Boot {
 		if (isNumber(left) && isNumber(right)) {
 			return Syntax.equal(left, right);
 		}
+		if (Std.is(left, HxClosure) && Std.is(right, HxClosure)) {
+			return (left:HxClosure).equals(right);
+		}
 		return Syntax.strictEqual(left, right);
 	}
 
@@ -572,6 +575,8 @@ private class HxClass {
 			return Global.constant('$phpClassName::$property');
 		} else if (Boot.hasGetter(phpClassName, property)) {
 			return Syntax.staticCall(phpClassName, 'get_$property');
+		} else if(phpClassName.method_exists(property)) {
+			return new HxClosure(phpClassName, property);
 		} else {
 			return Syntax.getStaticField(phpClassName, property);
 		}

+ 22 - 0
tests/unit/src/unit/TestPhp.hx

@@ -161,6 +161,28 @@ class TestPhp extends Test
 		eq(str.toUpperCase(), anon.toUpperCase());
 		eq(str.toString(), anon.toString());
 	}
+
+	function testClosureComparison() {
+		eq(ClosureDummy.testStatic, ClosureDummy.testStatic);
+		//Waiting for a fix: https://github.com/HaxeFoundation/haxe/issues/6719
+		// t(ClosureDummy.testStatic == ClosureDummy.testStatic);
+		t((ClosureDummy:Dynamic).testStatic == (ClosureDummy:Dynamic).testStatic);
+
+		var inst = new ClosureDummy();
+		eq(inst.test, inst.test);
+		//Waiting for a fix: https://github.com/HaxeFoundation/haxe/issues/6719
+		// t(inst.test == inst.test);
+		t((inst:Dynamic).test == (inst:Dynamic).test);
+		var inst2 = new ClosureDummy();
+		//Waiting for a fix: https://github.com/HaxeFoundation/haxe/issues/6719
+		// f(inst.test == inst2.test);
+	}
+}
+
+private class ClosureDummy {
+	static public function testStatic() {}
+	public function new() {}
+	public function test() {}
 }
 
 private class DummyForRef {