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

fix: solve problem that variable (of declaredType) is not assigned with correct type #674

Closed
wants to merge 15 commits into from
42 changes: 30 additions & 12 deletions gnovm/pkg/gnolang/preprocess.go
Original file line number Diff line number Diff line change
Expand Up @@ -1008,10 +1008,16 @@ func Preprocess(store Store, ctx BlockNode, n Node) Node {
}
} else if fv.PkgPath == uversePkgPath && fv.Name == "copy" {
if len(n.Args) == 2 {
args0T := evalStaticTypeOf(store, last, n.Args[0])
args1T := evalStaticTypeOf(store, last, n.Args[1])
if args0T.Elem().TypeID() != args1T.Elem().TypeID() {
panic(fmt.Sprintf(
"arguments to copy have different element types, want %s, got %s", args0T.Elem().TypeID(), args1T.Elem().TypeID()))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what prompted this? seems like this could/should be a separate PR for complete discussion. seems correct though.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's a fix of copy function. According to the Go specification, "The core types of both arguments must be slices with identical element types". Our previous implementation lacked this necessary check.

I'll put it into another PR. Thank you~

}
// If the second argument is a string,
// convert to byteslice.
args1 := n.Args[1]
if evalStaticTypeOf(store, last, args1).Kind() == StringKind {
if args1T.Kind() == StringKind {
bsx := constType(nil, gByteSliceType)
args1 = Call(bsx, args1)
args1 = Preprocess(nil, last, args1).(Expr)
Expand Down Expand Up @@ -1119,12 +1125,12 @@ func Preprocess(store Store, ctx BlockNode, n Node) Node {
for i, tv := range argTVs {
if hasVarg {
if (len(spts) - 1) <= i {
checkType(tv.T, spts[len(spts)-1].Type.Elem(), true)
checkType(tv.T, spts[len(spts)-1].Type.Elem(), true, nil)
} else {
checkType(tv.T, spts[i].Type, true)
checkType(tv.T, spts[i].Type, true, nil)
}
} else {
checkType(tv.T, spts[i].Type, true)
checkType(tv.T, spts[i].Type, true, nil)
}
}
} else {
Expand Down Expand Up @@ -2309,9 +2315,12 @@ func checkOrConvertType(store Store, last BlockNode, x *Expr, t Type, autoNative
checkOrConvertType(store, last, &bx.Left, t, autoNative)
} else if *x != nil { // XXX if x != nil && t != nil {
xt := evalStaticTypeOf(store, last, *x)
var conversionNeeded bool
if t != nil {
checkType(xt, t, autoNative)
// TODO: shall convert here?
checkType(xt, t, autoNative, &conversionNeeded)
}

if isUntyped(xt) {
if t == nil {
t = defaultTypeOf(xt)
Expand All @@ -2337,6 +2346,12 @@ func checkOrConvertType(store Store, last BlockNode, x *Expr, t Type, autoNative
cx = Preprocess(store, last, cx).(Expr)
*x = cx
}
// cover all declared type case
if conversionNeeded {
cx := Expr(Call(constType(nil, t), *x))
cx = Preprocess(store, last, cx).(Expr)
*x = cx
}
}
}

Expand Down Expand Up @@ -2364,7 +2379,7 @@ func convertConst(store Store, last BlockNode, cx *ConstExpr, t Type) {
// Assert that xt can be assigned as dt (dest type).
// If autoNative is true, a broad range of xt can match against
// a target native dt type, if and only if dt is a native type.
func checkType(xt Type, dt Type, autoNative bool) {
func checkType(xt Type, dt Type, autoNative bool, conversionNeeded *bool) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

right, right. this would make sense (or it could just return the value as a bool, i think is simpler) to get the information out of the function. we will need this later for the full unroll solution (e.g. the second pr after ray's), but I suggest a return bool value instead.

// Special case if dt is interface kind:
if dt.Kind() == InterfaceKind {
if idt, ok := baseOf(dt).(*InterfaceType); ok {
Expand Down Expand Up @@ -2480,9 +2495,12 @@ func checkType(xt Type, dt Type, autoNative bool) {
"cannot use %s as %s without explicit conversion",
xt.String(),
ddt.String()))
} else {
} else { // implies unnamed composite
// carry on with baseOf(ddt)
dt = ddt.Base
if conversionNeeded != nil {
*conversionNeeded = true
}
}
}
// General cases.
Expand Down Expand Up @@ -2527,23 +2545,23 @@ func checkType(xt Type, dt Type, autoNative bool) {
}
case *PointerType:
if pt, ok := xt.(*PointerType); ok {
checkType(pt.Elt, cdt.Elt, false)
checkType(pt.Elt, cdt.Elt, false, conversionNeeded)
return // ok
}
case *ArrayType:
if at, ok := xt.(*ArrayType); ok {
checkType(at.Elt, cdt.Elt, false)
checkType(at.Elt, cdt.Elt, false, conversionNeeded)
return // ok
}
case *SliceType:
if st, ok := xt.(*SliceType); ok {
checkType(st.Elt, cdt.Elt, false)
checkType(st.Elt, cdt.Elt, false, conversionNeeded)
return // ok
}
case *MapType:
if mt, ok := xt.(*MapType); ok {
checkType(mt.Key, cdt.Key, false)
checkType(mt.Value, cdt.Value, false)
checkType(mt.Key, cdt.Key, false, conversionNeeded)
checkType(mt.Value, cdt.Value, false, conversionNeeded)
return // ok
}
case *FuncType:
Expand Down
4 changes: 2 additions & 2 deletions gnovm/pkg/gnolang/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -2363,7 +2363,7 @@ func specifyType(store Store, lookup map[Name]Type, tmpl Type, spec Type, specTy
generic := ct.Generic[:len(ct.Generic)-len(".Elem()")]
match, ok := lookup[generic]
if ok {
checkType(spec, match.Elem(), false)
checkType(spec, match.Elem(), false, nil)
return // ok
} else {
// Panic here, because we don't know whether T
Expand All @@ -2377,7 +2377,7 @@ func specifyType(store Store, lookup map[Name]Type, tmpl Type, spec Type, specTy
} else {
match, ok := lookup[ct.Generic]
if ok {
checkType(spec, match, false)
checkType(spec, match, false, nil)
return // ok
} else {
if isUntyped(spec) {
Expand Down
14 changes: 14 additions & 0 deletions gnovm/tests/files/declaredType0.gno
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package main

type word uint
type nat []word

func (n nat) add() bool {
return true
}

func main() {
var abs nat
abs = []word{0} // unname-Composit to named DeclaredTypes
println(abs.add())
}
25 changes: 25 additions & 0 deletions gnovm/tests/files/declaredType1.gno
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package main

type word uint
type nat []word

// structLit
type Int struct {
neg bool
abs nat
}

func (n nat) add() bool {
return true
}

func main() {
z := &Int{
neg: true,
abs: []word{0},
}
println(z.abs.add())
}

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

type word uint
type nat []word

type Int struct {
neg bool
abs nat
}

func (n nat) add() bool {
return true
}

func main() {
z := &Int{
neg: true,
}

z.abs = []word{0}
println(z.abs.add())
}

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

type word uint
type nat []word

func (n nat) add() bool {
return true
}

// map
func main() {
items := map[string]nat{}

n := []word{0}

items["test"] = n

r := items["test"]

println(r.add())
}
24 changes: 24 additions & 0 deletions gnovm/tests/files/declaredType2b.gno
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package main

type word uint
type nat []word

func (n nat) add() bool {
return true
}

// mapLit
func main() {
n := []word{0}

items := map[string]nat{
"test": n,
}

r := items["test"]

println(r.add())
}

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

type word uint
type nat []word

func (n nat) add() bool {
return true
}

// sliceLit
func main() {
items := []nat{[]word{0}, []word{1}}

r := items[0]

println(r.add())
}

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

type word uint
type nat []word

func (n nat) add() bool {
return true
}

// sliceLit2
func main() {
items := []nat{1:[]word{0}, 2:[]word{1}}

r := items[1]

println(r.add())
}

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

type word uint
type nat []word

func (n nat) add() bool {
return true
}

// slice append
func main() {
var items []nat

n := []word{0}

items = append(items, n)

r := items[0]

println(r.add())
}

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

type word uint
type nat []word

func (n nat) add() bool {
return true
}

// ArrayLit
func main() {
items := [3]nat{[]word{0}, []word{1}}

r := items[0]

println(r.add())
}

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


type word uint
type nat []word

func (n nat) add(x, y nat) bool {
return true
}

// parameter
func main() {
var abs nat
abs = []word{0}
x := []word{1}
y := []word{2}

println(abs.add(x, y))
}

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

type BasicFunc func(int, int) int
type MyFunc BasicFunc

func (f MyFunc) Apply(a, b int) int {
return f(a, b)
}

func main() {
basicAdd := func(a, b int) int {
return a + b
}
var myAdd MyFunc
myAdd = basicAdd

result := myAdd.Apply(2, 3)
println(result)
}

// Output:
// 5
Loading