diff --git a/src/GoValue/Func/Func.php b/src/GoValue/Func/Func.php index 3f3bad370..f5d114bd4 100644 --- a/src/GoValue/Func/Func.php +++ b/src/GoValue/Func/Func.php @@ -14,7 +14,6 @@ use GoPhp\GoType\SliceType; use GoPhp\GoValue\AddressableValue; use GoPhp\GoValue\GoValue; -use GoPhp\GoValue\PointerValue; use GoPhp\GoValue\Slice\SliceBuilder; use GoPhp\GoValue\TupleValue; use GoPhp\GoValue\VoidValue; @@ -26,6 +25,7 @@ use function GoPhp\assert_arg_type; use function GoPhp\assert_argc; use function GoPhp\assert_types_compatible; +use function GoPhp\deref; /** * @psalm-type FuncBody = Closure(Environment, string): StmtJump @@ -181,16 +181,9 @@ private function doBind(Environment $env): void throw InternalError::unreachable($this->receiver); } - $boundInstance = $this->boundInstance instanceof PointerValue - ? $this->boundInstance->deref() - : $this->boundInstance; - + $boundInstance = deref($this->boundInstance); $receiverType = $this->receiver->type; - if ($boundInstance instanceof PointerValue) { - $boundInstance = $boundInstance->deref(); - } - if ($receiverType instanceof PointerType) { $receiverType = $receiverType->pointsTo; } else { diff --git a/src/Interpreter.php b/src/Interpreter.php index 6dd1ca672..2380f4fc4 100644 --- a/src/Interpreter.php +++ b/src/Interpreter.php @@ -1491,15 +1491,17 @@ private function evalSelectorExpr(SelectorExpr $expr): GoValue throw InternalError::unexpectedValue($value::class, AddressableValue::class); } + $receiverValue = deref($value); + $method = $this->env->getMethod( $expr->selector->name, - $value->type(), + $receiverValue->type(), ); - if ($method == null && $value instanceof WrappedValue) { + if ($method == null && $receiverValue instanceof WrappedValue) { $method = $this->env->getMethod( $expr->selector->name, - $value->underlyingValue->type(), + $receiverValue->underlyingValue->type(), ); } diff --git a/src/utils.php b/src/utils.php index ae1ef2154..ec88b1e33 100644 --- a/src/utils.php +++ b/src/utils.php @@ -10,6 +10,8 @@ use GoPhp\GoType\GoType; use GoPhp\GoType\NamedType; use GoPhp\GoType\UntypedType; +use GoPhp\GoValue\AddressableValue; +use GoPhp\GoValue\PointerValue; use GoPhp\GoValue\Unwindable; /** @@ -117,3 +119,21 @@ function reify_untyped(GoType $type): GoType return $type; } + +/** + * Dereference a value if it is a pointer. + * + * @internal + * + * @template T of AddressableValue + * @psalm-param T $value + * @psalm-return ($value is PointerValue ? AddressableValue : T) + */ +function deref(AddressableValue $value): AddressableValue +{ + if ($value instanceof PointerValue) { + return $value->deref(); + } + + return $value; +} diff --git a/tests/Functional/files/method.go b/tests/Functional/files/method.go index 1f5f6a14f..d6f3d8e36 100644 --- a/tests/Functional/files/method.go +++ b/tests/Functional/files/method.go @@ -4,9 +4,12 @@ func main() { test_method_1() test_method_2() test_method_3() + test_method_4() } type int uint +type myBool bool + type empty struct{} type person struct { name string @@ -16,8 +19,19 @@ func test_method_1() { println("test_method_1") var i int = 10 - var res2 = i.methodInt1() + var res1 = i.methodInt1() + println(res1) + + var i2 *int = &i + var res2 = i2.methodInt1() println(res2) + println(*i2) + println(i) + + var s myBool + s = true + var res3 = s.methodMyBool1() + println(res3) } func test_method_2() { @@ -38,24 +52,75 @@ func test_method_3() { name: "test", } - var pp = &p + var p2 *person = &p - var res1 = p.methodPerson1() + var res1 = p.methodPerson1("test2") println(p.name) + println(p == *p2) println(res1) - var res2 = p.methodPerson2() + var res2 = p.methodPerson2("test2") println(p.name) - println(p == *pp) + println(p == *p2) println(res2) } +func test_method_4() { + println("test_method_4") + + var p person = person{ + name: "test", + } + + var p2 *person = &p + + var p3 **person = &p2 + + var res1 = p.methodPerson1("test2") + println(p.name) + println(p == *p2) + println(p == **p3) + println(res1) + + var res2 = p.methodPerson2("test3") + println(p.name) + println(p == *p2) + println(p == **p3) + println(res2) + + var res3 = p2.methodPerson1("test4") + println(p2.name) + println(res3) + + var res4 = p2.methodPerson2("test5") + println(p2.name) + println(res4) + + var res5 = (*p3).methodPerson1("test6") + println(p.name) + println(p2.name) + println((*p3).name) + println(res5) + + var res6 = (*p3).methodPerson2("test7") + println(p.name) + println(p2.name) + println((*p3).name) + println(res6) +} + func (i int) methodInt1() int { println("called methodInt1") return i * 2 } +func (s myBool) methodMyBool1() myBool { + println("called methodMyBool1") + + return !s +} + func (e empty) methodEmpty1() int { println("called methodEmpty1") @@ -68,18 +133,18 @@ func (e *empty) methodEmpty2() int { return 2 } -func (p person) methodPerson1() int { +func (p person) methodPerson1(name string) int { println("called methodPerson1") - p.name = "test2" + p.name = name return 1 } -func (p *person) methodPerson2() int { +func (p *person) methodPerson2(name string) int { println("called methodPerson2") - p.name = "test3" + p.name = name return 2 } diff --git a/tests/Functional/output/method.out b/tests/Functional/output/method.out index 04d538015..ae9d6be65 100644 --- a/tests/Functional/output/method.out +++ b/tests/Functional/output/method.out @@ -1,6 +1,12 @@ test_method_1 called methodInt1 20 +called methodInt1 +20 +10 +10 +called methodMyBool1 +false test_method_2 called methodEmpty2 2 @@ -9,8 +15,36 @@ called methodEmpty1 test_method_3 called methodPerson1 test +true +1 +called methodPerson2 +test2 +true +2 +test_method_4 +called methodPerson1 +test +true +true 1 called methodPerson2 test3 true +true +2 +called methodPerson1 +test3 +1 +called methodPerson2 +test5 +2 +called methodPerson1 +test5 +test5 +test5 +1 +called methodPerson2 +test7 +test7 +test7 2