Procházet zdrojové kódy

[php] direct methods comparison

Alexander Kuzmenko před 8 roky
rodič
revize
83665636c9

+ 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:

+ 20 - 4
src/generators/genphp7.ml

@@ -296,6 +296,11 @@ let is_string_type t = match follow t with TInst ({ cl_path = ([], "String") },
 *)
 let is_string expr = is_string_type expr.etype
 
+(**
+	Check if specified type represents a function
+*)
+let is_function_type t = match follow t with TFun _ -> true | _ -> false
+
 (**
 	Check if `expr` is an access to a method of special `php.PHP` class
 *)
@@ -719,10 +724,21 @@ 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)
+		let unknown1 = is_unknown_type expr1.etype
+		and unknown2 = is_unknown_type expr2.etype in
+		if unknown1 && unknown2 then
+			true
+		else if is_function_type expr1.etype || is_function_type expr2.etype 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);
 		}

+ 7 - 3
std/php/_std/Array.hx

@@ -47,7 +47,7 @@ class Array<T> implements ArrayAccess<Int,T> {
 	}
 
 	public function indexOf(x:T, ?fromIndex:Int):Int {
-		if (fromIndex == null) {
+		if (fromIndex == null && !Boot.isHxClosure(x) && !Boot.isNumber(x)) {
 			var index = Global.array_search(x, arr, true);
 			if (index == false) {
 				return -1;
@@ -55,8 +55,12 @@ class Array<T> implements ArrayAccess<Int,T> {
 				return index;
 			}
 		}
-		if (fromIndex < 0) fromIndex += length;
-		if (fromIndex < 0) fromIndex = 0;
+		if (fromIndex == null) {
+			fromIndex = 0;
+		} else {
+			if (fromIndex < 0) fromIndex += length;
+			if (fromIndex < 0) fromIndex = 0;
+		}
 		while (fromIndex < length) {
 			if (arr[fromIndex] == x)
 				return fromIndex;

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

@@ -161,6 +161,44 @@ class TestPhp extends Test
 		eq(str.toUpperCase(), anon.toUpperCase());
 		eq(str.toString(), anon.toString());
 	}
+
+	function testClosureComparison() {
+		var fn1:Void->Void;
+		var fn2:Void->Void;
+		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);
+		fn1 = (ClosureDummy:Dynamic).testStatic;
+		fn2 = (ClosureDummy:Dynamic).testStatic;
+		t(fn1 == fn2);
+
+		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);
+		fn1 = (inst:Dynamic).test;
+		fn2 = (inst:Dynamic).test;
+		t(fn1 == fn2);
+		var a = [fn1];
+		t(a.indexOf(fn2) == 0);
+		t(a.remove(fn2));
+
+		var inst2 = new ClosureDummy();
+		//Waiting for a fix: https://github.com/HaxeFoundation/haxe/issues/6719
+		// f(inst.test == inst2.test);
+		a = [fn1];
+		fn2 = (inst2:Dynamic).test;
+		t(a.indexOf(fn2) < 0);
+		f(a.remove(fn2));
+	}
+}
+
+private class ClosureDummy {
+	static public function testStatic() {}
+	public function new() {}
+	public function test() {}
 }
 
 private class DummyForRef {