Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add support for type declarations on pointer types #1733

Merged
merged 13 commits into from
Apr 10, 2024
2 changes: 1 addition & 1 deletion gnovm/pkg/gnolang/op_expressions.go
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,7 @@ func (m *Machine) doOpStar() {
case *PointerType:
pv := xv.V.(PointerValue)
if pv.TV.T == DataByteType {
tv := TypedValue{T: xv.T.(*PointerType).Elt}
tv := TypedValue{T: bt.Elt}
dbv := pv.TV.V.(DataByteValue)
tv.SetUint8(dbv.GetByte())
m.PushValue(tv)
Expand Down
4 changes: 2 additions & 2 deletions gnovm/pkg/gnolang/op_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -467,7 +467,7 @@ func (m *Machine) doOpStaticTypeOf() {
m.PushOp(OpStaticTypeOf)
m.Run() // XXX replace
xt := m.ReapValues(start)[0].V.(TypeValue).Type
if pt, ok := xt.(*PointerType); ok {
if pt, ok := baseOf(xt).(*PointerType); ok {
m.PushValue(asValue(&SliceType{
Elt: pt.Elt.Elem(),
}))
Expand All @@ -485,7 +485,7 @@ func (m *Machine) doOpStaticTypeOf() {
m.PushOp(OpStaticTypeOf)
m.Run() // XXX replace
xt := m.ReapValues(start)[0].GetType()
if pt, ok := xt.(*PointerType); ok {
if pt, ok := baseOf(xt).(*PointerType); ok {
m.PushValue(asValue(pt.Elt))
} else if _, ok := xt.(*TypeType); ok {
m.PushValue(asValue(gTypeType))
Expand Down
29 changes: 26 additions & 3 deletions gnovm/pkg/gnolang/preprocess.go
Original file line number Diff line number Diff line change
Expand Up @@ -2474,7 +2474,7 @@ func checkType(xt Type, dt Type, autoNative bool) {
// Special case if xt or dt is *PointerType to *NativeType,
// convert to *NativeType of pointer kind.
if pxt, ok := xt.(*PointerType); ok {
// *gonative{x} is gonative{*x}
// *gonative{x} is(to) gonative{*x}
//nolint:misspell
if enxt, ok := pxt.Elt.(*NativeType); ok {
xt = &NativeType{
Expand Down Expand Up @@ -2953,11 +2953,32 @@ func predefineNow2(store Store, last BlockNode, d Decl, m map[Name]struct{}) (De
ft := evalStaticType(store, last, &cd.Type).(*FuncType)
ft = ft.UnboundType(rft)
dt := (*DeclaredType)(nil)

// check base type of receiver type, should not be pointer type or interface type
assertValidReceiverType := func(t Type) {
if _, ok := t.(*PointerType); ok {
panic(fmt.Sprintf("invalid receiver type %v (base type is pointer type)\n", rt))
}
if _, ok := t.(*InterfaceType); ok {
panic(fmt.Sprintf("invalid receiver type %v (base type is interface type)\n", rt))
}
}

if pt, ok := rt.(*PointerType); ok {
dt = pt.Elem().(*DeclaredType)
assertValidReceiverType(pt.Elem())
if ddt, ok := pt.Elem().(*DeclaredType); ok {
assertValidReceiverType(baseOf(ddt))
dt = ddt
} else {
panic("should not happen")
}
} else if ddt, ok := rt.(*DeclaredType); ok {
assertValidReceiverType(baseOf(ddt))
dt = ddt
} else {
dt = rt.(*DeclaredType)
panic("should not happen")
}

if !dt.TryDefineMethod(&FuncValue{
Type: ft,
IsMethod: true,
Expand Down Expand Up @@ -3096,6 +3117,8 @@ func tryPredefine(store Store, last BlockNode, d Decl) (un Name) {
t = &MapType{}
case *StructTypeExpr:
t = &StructType{}
case *StarExpr:
t = &PointerType{}
case *NameExpr:
if tv := last.GetValueRef(store, tx.Name); tv != nil {
// (file) block name
Expand Down
28 changes: 28 additions & 0 deletions gnovm/tests/files/type33.gno
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package main

import "fmt"

// Define a base type
type Base int

// Declare a new type that is a pointer to the base type
type PtrToBase *Base

func main() {
var b Base = 42 // Initialize a variable of the base type
var p PtrToBase = &b // Initialize a variable of the new pointer type with the address of b

fmt.Printf("The value of b is: %d\n", b)

// Using the new pointer type
fmt.Printf("The value pointed to by p is: %d\n", *p)

// Modifying the value pointed to by p
*p = 100
fmt.Printf("The new value of b after modification through p is: %d\n", b)
}

// Output:
// The value of b is: 42
// The value pointed to by p is: 42
// The new value of b after modification through p is: 100
12 changes: 12 additions & 0 deletions gnovm/tests/files/type34.gno
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package main

type BytePtr *byte

func main() {
bs := []byte("hello")
var p BytePtr = &bs[0]
println(*p)
}

// Output:
// 104
15 changes: 15 additions & 0 deletions gnovm/tests/files/type35.gno
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package main

type IntPtr *int

func main() {
var a, b int
a = 1 // Set a to 104
s := []IntPtr{}
s = append(s, &a)
s = append(s, &b)
println(*s[0])
}

// Output:
// 1
17 changes: 17 additions & 0 deletions gnovm/tests/files/type36.gno
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package main

type Arr [2]int
type Ptr *Arr

func main() {
var arr Arr
arr[0] = 0
arr[1] = 1

p := Ptr(&arr)

println(p[:])
}

// Output:
// slice[(0 int),(1 int)]
20 changes: 20 additions & 0 deletions gnovm/tests/files/type37.gno
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package main

import "fmt"

type IntArray []int
type Arr *IntArray
deelawn marked this conversation as resolved.
Show resolved Hide resolved

func (a Arr) Add(x int) { // receiver is val, not ptr
*a = append(*a, x)
}

func main() {
a := new(IntArray)
Arr(a).Add(4)

fmt.Println(*a)
}

// Error:
// main/files/type37.gno:8: invalid receiver type main.Arr (base type is pointer type)
19 changes: 19 additions & 0 deletions gnovm/tests/files/type37a.gno
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package main

import "fmt"

type IntArray []int

func (a *IntArray) Add(x int) { // receiver is val, not ptr
*a = append(*a, x)
}

func main() {
a := new(IntArray)
a.Add(4)

fmt.Println(*a)
}

// Output:
// [4]
22 changes: 22 additions & 0 deletions gnovm/tests/files/type37b.gno
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package main

import "fmt"

type Integer int

func (i **Integer) Add(x int) {
**i += Integer(x) // Dereference twice to get to the actual Integer value and modify it
}

func main() {
a := new(Integer) // a is a pointer to Integer
b := &a // b is a pointer to a pointer to Integer

// Since Add is defined on **Integer, you need to pass b
b.Add(4) // Adds 4 to the value **b points to

fmt.Println(**b) // Should print 4, as **b is the same as *a
}

// Error:
// main/files/type37b.gno:7: invalid receiver type **main.Integer (base type is pointer type)
20 changes: 20 additions & 0 deletions gnovm/tests/files/type37c.gno
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package main

import "fmt"

type Integer int

func (i *Integer) Add(x int) { // receiver is val, not ptr
println(int(*i) + x)
}

func main() {
a := new(Integer)
a.Add(4)

fmt.Println(*a)
}

// Output:
// 4
// 0
16 changes: 16 additions & 0 deletions gnovm/tests/files/type37d.gno
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package main

type IntPtr *int

var ip IntPtr = new(int)

func (p IntPtr) Int() int {
return *p
}

func main() {
println(ip.Int())
}

// Error:
// main/files/type37d.gno:7: invalid receiver type main.IntPtr (base type is pointer type)
17 changes: 17 additions & 0 deletions gnovm/tests/files/type37e.gno
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package main

type IntPtr *int
type Int2 IntPtr

var ip IntPtr = new(int)

func (i2 Int2) Int() int {
return *i2
}

func main() {
println(Int2(ip).Int())
}

// Error:
// main/files/type37e.gno:8: invalid receiver type main.Int2 (base type is pointer type)
16 changes: 16 additions & 0 deletions gnovm/tests/files/type37f.gno
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package main

type IntPtr *int

var ip IntPtr = new(int)

func (p *IntPtr) Int() int {
return **p
}

func main() {
println((&ip).Int())
}

// Error:
// main/files/type37f.gno:7: invalid receiver type *main.IntPtr (base type is pointer type)
26 changes: 26 additions & 0 deletions gnovm/tests/files/type38.gno
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package main

import "fmt"

type IntArray []int
type Arr *IntArray

func add(arr Arr) { // receiver is val, not ptr
*arr = append(*arr, 1)
}

func main() {
a := new(IntArray)
add(a)

fmt.Println(a)
fmt.Println(*a)
fmt.Println(len(*a))
fmt.Println((*a)[0])
}

// Output:
// &[1]
// [1]
// 1
// 1
22 changes: 22 additions & 0 deletions gnovm/tests/files/type39.gno
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package main

type foo interface {
say()
}

func (f foo) echo() int {
return 1
}

type Bar struct{}

func (b *Bar) say() {}

func main() {
var f foo
f = &Bar{}
println(f.echo())
}

// Error:
// main/files/type39.gno:7: invalid receiver type main.foo (base type is interface type)
24 changes: 24 additions & 0 deletions gnovm/tests/files/type39a.gno
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package main

type foo interface {
say()
}

type FF foo

func (f FF) echo() int {
return 1
}

type Bar struct{}

func (b *Bar) say() {}

func main() {
var f foo
f = &Bar{}
println(f.echo())
}

// Error:
// main/files/type39a.gno:9: invalid receiver type main.FF (base type is interface type)
22 changes: 22 additions & 0 deletions gnovm/tests/files/type39b.gno
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package main

type foo interface {
say()
}

func (f *foo) echo() int {
return 1
}

type Bar struct{}

func (b *Bar) say() {}

func main() {
var f *foo
*f = &Bar{}
println(f.echo())
}

// Error:
// main/files/type39b.gno:7: invalid receiver type *main.foo (base type is interface type)
Loading