diff --git a/gnovm/pkg/gnolang/op_expressions.go b/gnovm/pkg/gnolang/op_expressions.go index b3bf240aea1..bc21850bb8c 100644 --- a/gnovm/pkg/gnolang/op_expressions.go +++ b/gnovm/pkg/gnolang/op_expressions.go @@ -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) diff --git a/gnovm/pkg/gnolang/op_types.go b/gnovm/pkg/gnolang/op_types.go index a38010bac4e..850aa7a6e64 100644 --- a/gnovm/pkg/gnolang/op_types.go +++ b/gnovm/pkg/gnolang/op_types.go @@ -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(), })) @@ -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)) diff --git a/gnovm/pkg/gnolang/preprocess.go b/gnovm/pkg/gnolang/preprocess.go index fba01750a20..a09419637cf 100644 --- a/gnovm/pkg/gnolang/preprocess.go +++ b/gnovm/pkg/gnolang/preprocess.go @@ -2542,7 +2542,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{ @@ -3025,11 +3025,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, @@ -3168,6 +3189,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 diff --git a/gnovm/tests/files/type33.gno b/gnovm/tests/files/type33.gno new file mode 100644 index 00000000000..62d6696fafa --- /dev/null +++ b/gnovm/tests/files/type33.gno @@ -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 diff --git a/gnovm/tests/files/type34.gno b/gnovm/tests/files/type34.gno new file mode 100644 index 00000000000..20f53b78cd6 --- /dev/null +++ b/gnovm/tests/files/type34.gno @@ -0,0 +1,12 @@ +package main + +type BytePtr *byte + +func main() { + bs := []byte("hello") + var p BytePtr = &bs[0] + println(*p) +} + +// Output: +// 104 diff --git a/gnovm/tests/files/type35.gno b/gnovm/tests/files/type35.gno new file mode 100644 index 00000000000..9ade96ee9c8 --- /dev/null +++ b/gnovm/tests/files/type35.gno @@ -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 diff --git a/gnovm/tests/files/type36.gno b/gnovm/tests/files/type36.gno new file mode 100644 index 00000000000..8bb64118036 --- /dev/null +++ b/gnovm/tests/files/type36.gno @@ -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)] diff --git a/gnovm/tests/files/type37.gno b/gnovm/tests/files/type37.gno new file mode 100644 index 00000000000..1bc157b44ff --- /dev/null +++ b/gnovm/tests/files/type37.gno @@ -0,0 +1,20 @@ +package main + +import "fmt" + +type IntArray []int +type Arr *IntArray + +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) diff --git a/gnovm/tests/files/type37a.gno b/gnovm/tests/files/type37a.gno new file mode 100644 index 00000000000..16db1cc4dc2 --- /dev/null +++ b/gnovm/tests/files/type37a.gno @@ -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] diff --git a/gnovm/tests/files/type37b.gno b/gnovm/tests/files/type37b.gno new file mode 100644 index 00000000000..aea1b445ca1 --- /dev/null +++ b/gnovm/tests/files/type37b.gno @@ -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) diff --git a/gnovm/tests/files/type37c.gno b/gnovm/tests/files/type37c.gno new file mode 100644 index 00000000000..7cd8ac7367e --- /dev/null +++ b/gnovm/tests/files/type37c.gno @@ -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 diff --git a/gnovm/tests/files/type37d.gno b/gnovm/tests/files/type37d.gno new file mode 100644 index 00000000000..ada9541e64e --- /dev/null +++ b/gnovm/tests/files/type37d.gno @@ -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) diff --git a/gnovm/tests/files/type37e.gno b/gnovm/tests/files/type37e.gno new file mode 100644 index 00000000000..a2537c9cb8d --- /dev/null +++ b/gnovm/tests/files/type37e.gno @@ -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) diff --git a/gnovm/tests/files/type37f.gno b/gnovm/tests/files/type37f.gno new file mode 100644 index 00000000000..7bffa748314 --- /dev/null +++ b/gnovm/tests/files/type37f.gno @@ -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) diff --git a/gnovm/tests/files/type38.gno b/gnovm/tests/files/type38.gno new file mode 100644 index 00000000000..a3a03f1e248 --- /dev/null +++ b/gnovm/tests/files/type38.gno @@ -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 diff --git a/gnovm/tests/files/type39.gno b/gnovm/tests/files/type39.gno new file mode 100644 index 00000000000..aebcc226385 --- /dev/null +++ b/gnovm/tests/files/type39.gno @@ -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) diff --git a/gnovm/tests/files/type39a.gno b/gnovm/tests/files/type39a.gno new file mode 100644 index 00000000000..06f41897f93 --- /dev/null +++ b/gnovm/tests/files/type39a.gno @@ -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) diff --git a/gnovm/tests/files/type39b.gno b/gnovm/tests/files/type39b.gno new file mode 100644 index 00000000000..dbf5312a825 --- /dev/null +++ b/gnovm/tests/files/type39b.gno @@ -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)