Skip to content

Commit

Permalink
Fixed methods for pointer type receivers
Browse files Browse the repository at this point in the history
  • Loading branch information
tuqqu committed Sep 13, 2024
1 parent c5cab3a commit 5e82555
Show file tree
Hide file tree
Showing 5 changed files with 135 additions and 21 deletions.
11 changes: 2 additions & 9 deletions src/GoValue/Func/Func.php
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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
Expand Down Expand Up @@ -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 {
Expand Down
8 changes: 5 additions & 3 deletions src/Interpreter.php
Original file line number Diff line number Diff line change
Expand Up @@ -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(),
);
}

Expand Down
20 changes: 20 additions & 0 deletions src/utils.php
Original file line number Diff line number Diff line change
Expand Up @@ -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;

/**
Expand Down Expand Up @@ -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;
}
83 changes: 74 additions & 9 deletions tests/Functional/files/method.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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() {
Expand All @@ -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")

Expand All @@ -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
}
34 changes: 34 additions & 0 deletions tests/Functional/output/method.out
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
test_method_1
called methodInt1
20
called methodInt1
20
10
10
called methodMyBool1
false
test_method_2
called methodEmpty2
2
Expand All @@ -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

0 comments on commit 5e82555

Please sign in to comment.