From 3f4f1b6ee9c516cd7c3a79aa8e1ada304fd2639a Mon Sep 17 00:00:00 2001 From: deelawn Date: Thu, 29 Aug 2024 16:30:01 -0700 Subject: [PATCH] introduce concept of addressability not applicable --- gnovm/pkg/gnolang/addressability.go | 9 ++ gnovm/pkg/gnolang/nodes.go | 134 +++++++++++++---------- gnovm/pkg/gnolang/preprocess.go | 14 ++- gnovm/tests/files/addressable_7a_err.gno | 12 ++ gnovm/tests/files/addressable_7b_err.gno | 9 ++ gnovm/tests/files/addressable_7c_err.gno | 8 ++ 6 files changed, 123 insertions(+), 63 deletions(-) create mode 100644 gnovm/pkg/gnolang/addressability.go create mode 100644 gnovm/tests/files/addressable_7a_err.gno create mode 100644 gnovm/tests/files/addressable_7b_err.gno create mode 100644 gnovm/tests/files/addressable_7c_err.gno diff --git a/gnovm/pkg/gnolang/addressability.go b/gnovm/pkg/gnolang/addressability.go new file mode 100644 index 00000000000..0f436ae3c0f --- /dev/null +++ b/gnovm/pkg/gnolang/addressability.go @@ -0,0 +1,9 @@ +package gnolang + +type Addressability int + +const ( + AddressabilityNotApplicable Addressability = iota + AddressabilitySatisfied + AddressabilityUnsatisfied +) diff --git a/gnovm/pkg/gnolang/nodes.go b/gnovm/pkg/gnolang/nodes.go index 414b6c6591b..0456ec3190f 100644 --- a/gnovm/pkg/gnolang/nodes.go +++ b/gnovm/pkg/gnolang/nodes.go @@ -328,7 +328,7 @@ var ( type Expr interface { Node assertExpr() - isAddressable() bool + addressability() Addressability } type Exprs []Expr @@ -375,8 +375,8 @@ type NameExpr struct { Name } -func (x *NameExpr) isAddressable() bool { - return true +func (x *NameExpr) addressability() Addressability { + return AddressabilitySatisfied } type NameExprs []NameExpr @@ -390,8 +390,8 @@ type BasicLitExpr struct { Value string } -func (x *BasicLitExpr) isAddressable() bool { - return false +func (x *BasicLitExpr) addressability() Addressability { + return AddressabilityUnsatisfied } type BinaryExpr struct { // (Left Op Right) @@ -401,21 +401,21 @@ type BinaryExpr struct { // (Left Op Right) Right Expr // right operand } -func (x *BinaryExpr) isAddressable() bool { - return false +func (x *BinaryExpr) addressability() Addressability { + return AddressabilityUnsatisfied } type CallExpr struct { // Func(Args) Attributes - Func Expr // function expression - Args Exprs // function arguments, if any. - Varg bool // if true, final arg is variadic. - NumArgs int // len(Args) or len(Args[0].Results) - IsAddressable bool + Func Expr // function expression + Args Exprs // function arguments, if any. + Varg bool // if true, final arg is variadic. + NumArgs int // len(Args) or len(Args[0].Results) + Addressability Addressability } -func (x *CallExpr) isAddressable() bool { - return x.IsAddressable +func (x *CallExpr) addressability() Addressability { + return x.Addressability } type IndexExpr struct { // X[Index] @@ -427,12 +427,16 @@ type IndexExpr struct { // X[Index] XIsString bool // true if X is a string (never addressable) } -func (x *IndexExpr) isAddressable() bool { +func (x *IndexExpr) addressability() Addressability { if x.XIsString { - return false + return AddressabilityUnsatisfied } - return x.IsAddressable || x.X.isAddressable() + if x.IsAddressable || x.X.addressability() == AddressabilitySatisfied { + return AddressabilitySatisfied + } + + return AddressabilityUnsatisfied } type SelectorExpr struct { // X.Sel @@ -443,8 +447,12 @@ type SelectorExpr struct { // X.Sel IsAddressable bool // true if X is a pointer } -func (x *SelectorExpr) isAddressable() bool { - return x.IsAddressable || x.X.isAddressable() +func (x *SelectorExpr) addressability() Addressability { + if x.IsAddressable || x.X.addressability() == AddressabilitySatisfied { + return AddressabilitySatisfied + } + + return AddressabilityUnsatisfied } type SliceExpr struct { // X[Low:High:Max] @@ -456,8 +464,12 @@ type SliceExpr struct { // X[Low:High:Max] IsAddressable bool } -func (x *SliceExpr) isAddressable() bool { - return x.IsAddressable +func (x *SliceExpr) addressability() Addressability { + if x.IsAddressable { + return AddressabilitySatisfied + } + + return AddressabilityUnsatisfied } // A StarExpr node represents an expression of the form @@ -468,8 +480,8 @@ type StarExpr struct { // *X X Expr // operand } -func (x *StarExpr) isAddressable() bool { - return x.X.isAddressable() +func (x *StarExpr) addressability() Addressability { + return x.X.addressability() } type RefExpr struct { // &X @@ -477,8 +489,8 @@ type RefExpr struct { // &X X Expr // operand } -func (x *RefExpr) isAddressable() bool { - return x.X.isAddressable() +func (x *RefExpr) addressability() Addressability { + return x.X.addressability() } type TypeAssertExpr struct { // X.(Type) @@ -489,8 +501,12 @@ type TypeAssertExpr struct { // X.(Type) IsAddressable bool } -func (x *TypeAssertExpr) isAddressable() bool { - return x.IsAddressable +func (x *TypeAssertExpr) addressability() Addressability { + if x.IsAddressable { + return AddressabilitySatisfied + } + + return AddressabilityUnsatisfied } // A UnaryExpr node represents a unary expression. Unary @@ -503,8 +519,8 @@ type UnaryExpr struct { // (Op X) Op Word // operator } -func (x *UnaryExpr) isAddressable() bool { - return x.X.isAddressable() +func (x *UnaryExpr) addressability() Addressability { + return x.X.addressability() } // MyType{:} struct, array, slice, and map @@ -516,8 +532,12 @@ type CompositeLitExpr struct { IsAddressable bool } -func (x *CompositeLitExpr) isAddressable() bool { - return x.IsAddressable +func (x *CompositeLitExpr) addressability() Addressability { + if x.IsAddressable { + return AddressabilitySatisfied + } + + return AddressabilityUnsatisfied } // Returns true if any elements are keyed. @@ -550,8 +570,8 @@ type KeyValueExpr struct { Value Expr // never nil } -func (x *KeyValueExpr) isAddressable() bool { - return false +func (x *KeyValueExpr) addressability() Addressability { + return AddressabilityNotApplicable } type KeyValueExprs []KeyValueExpr @@ -566,8 +586,8 @@ type FuncLitExpr struct { Body // function body } -func (x *FuncLitExpr) isAddressable() bool { - return false +func (x *FuncLitExpr) addressability() Addressability { + return AddressabilityUnsatisfied } // The preprocessor replaces const expressions @@ -578,8 +598,8 @@ type ConstExpr struct { TypedValue } -func (x *ConstExpr) isAddressable() bool { - return false +func (x *ConstExpr) addressability() Addressability { + return AddressabilityUnsatisfied } // ---------------------------------------- @@ -646,8 +666,8 @@ type FieldTypeExpr struct { Tag Expr } -func (x *FieldTypeExpr) isAddressable() bool { - return false +func (x *FieldTypeExpr) addressability() Addressability { + return AddressabilityNotApplicable } type FieldTypeExprs []FieldTypeExpr @@ -674,8 +694,8 @@ type ArrayTypeExpr struct { Elt Expr // element type } -func (x *ArrayTypeExpr) isAddressable() bool { - return false +func (x *ArrayTypeExpr) addressability() Addressability { + return AddressabilityNotApplicable } type SliceTypeExpr struct { @@ -684,8 +704,8 @@ type SliceTypeExpr struct { Vrd bool // variadic arg expression } -func (x *SliceTypeExpr) isAddressable() bool { - return false +func (x *SliceTypeExpr) addressability() Addressability { + return AddressabilityNotApplicable } type InterfaceTypeExpr struct { @@ -694,8 +714,8 @@ type InterfaceTypeExpr struct { Generic Name // for uverse generics } -func (x *InterfaceTypeExpr) isAddressable() bool { - return false +func (x *InterfaceTypeExpr) addressability() Addressability { + return AddressabilityNotApplicable } type ChanDir int @@ -715,8 +735,8 @@ type ChanTypeExpr struct { Value Expr // value type } -func (x *ChanTypeExpr) isAddressable() bool { - return false +func (x *ChanTypeExpr) addressability() Addressability { + return AddressabilityNotApplicable } type FuncTypeExpr struct { @@ -725,8 +745,8 @@ type FuncTypeExpr struct { Results FieldTypeExprs // (outgoing) results, if any. } -func (x *FuncTypeExpr) isAddressable() bool { - return false +func (x *FuncTypeExpr) addressability() Addressability { + return AddressabilityNotApplicable } type MapTypeExpr struct { @@ -735,8 +755,8 @@ type MapTypeExpr struct { Value Expr // value type } -func (x *MapTypeExpr) isAddressable() bool { - return false +func (x *MapTypeExpr) addressability() Addressability { + return AddressabilityNotApplicable } type StructTypeExpr struct { @@ -744,8 +764,8 @@ type StructTypeExpr struct { Fields FieldTypeExprs // list of field declarations } -func (x *StructTypeExpr) isAddressable() bool { - return false +func (x *StructTypeExpr) addressability() Addressability { + return AddressabilityNotApplicable } // Like ConstExpr but for types. @@ -755,8 +775,8 @@ type constTypeExpr struct { Type Type } -func (x *constTypeExpr) isAddressable() bool { - return false +func (x *constTypeExpr) addressability() Addressability { + return AddressabilityNotApplicable } // Only used for native func arguments @@ -765,8 +785,8 @@ type MaybeNativeTypeExpr struct { Type Expr } -func (x *MaybeNativeTypeExpr) isAddressable() bool { - return false +func (x *MaybeNativeTypeExpr) addressability() Addressability { + return AddressabilityNotApplicable } // ---------------------------------------- diff --git a/gnovm/pkg/gnolang/preprocess.go b/gnovm/pkg/gnolang/preprocess.go index 0a0bf1a0f87..f36fad0c5ec 100644 --- a/gnovm/pkg/gnolang/preprocess.go +++ b/gnovm/pkg/gnolang/preprocess.go @@ -1293,7 +1293,7 @@ func Preprocess(store Store, ctx BlockNode, n Node) Node { fv := cx.GetFunc() if fv.PkgPath == uversePkgPath && fv.Name == "append" { // append returns a slice and slices are always addressable. - n.IsAddressable = true + n.Addressability = AddressabilitySatisfied if n.Varg && len(n.Args) == 2 { // If the second argument is a string, // convert to byteslice. @@ -1342,15 +1342,17 @@ func Preprocess(store Store, ctx BlockNode, n Node) Node { } } else if fv.PkgPath == uversePkgPath && fv.Name == "new" { // new returns a pointer and pointers are always addressable. - n.IsAddressable = true + n.Addressability = AddressabilitySatisfied } } - if !n.IsAddressable && len(ft.Results) == 1 { + if n.Addressability != AddressabilitySatisfied && len(ft.Results) == 1 { baseType := baseOf(ft.Results[0].Type) switch baseType.(type) { case *PointerType, *SliceType: - n.IsAddressable = true + n.Addressability = AddressabilitySatisfied + default: + n.Addressability = AddressabilityUnsatisfied } } @@ -1531,7 +1533,7 @@ func Preprocess(store Store, ctx BlockNode, n Node) Node { // Slices and pointers are addressable. switch baseOf(t).(type) { case *ArrayType: - if !n.X.isAddressable() { + if n.X.addressability() == AddressabilityUnsatisfied { panic(fmt.Sprintf("cannot take address of %s", n.X.String())) } @@ -2421,7 +2423,7 @@ func Preprocess(store Store, ctx BlockNode, n Node) Node { n.Type = constType(n.Type, dst) case *RefExpr: - if !n.X.isAddressable() { + if n.X.addressability() == AddressabilityUnsatisfied { panic(fmt.Sprintf("cannot take address of %s", n.X.String())) } } diff --git a/gnovm/tests/files/addressable_7a_err.gno b/gnovm/tests/files/addressable_7a_err.gno new file mode 100644 index 00000000000..f3648b6b990 --- /dev/null +++ b/gnovm/tests/files/addressable_7a_err.gno @@ -0,0 +1,12 @@ +package main + +func foo() ([]int, []string) { + return []int{1, 2, 3}, []string{"a", "b", "c"} +} + +func main() { + _ = &foo() +} + +// Error: +// main/files/addressable_7a_err.gno:8:2: getTypeOf() only supports *CallExpr with 1 result, got ([]int,[]string) diff --git a/gnovm/tests/files/addressable_7b_err.gno b/gnovm/tests/files/addressable_7b_err.gno new file mode 100644 index 00000000000..1e7f3cb6e17 --- /dev/null +++ b/gnovm/tests/files/addressable_7b_err.gno @@ -0,0 +1,9 @@ +package main + +type MyInt int + +func main() { + _ = &MyInt +} + +// Error: diff --git a/gnovm/tests/files/addressable_7c_err.gno b/gnovm/tests/files/addressable_7c_err.gno new file mode 100644 index 00000000000..133d6f3af8b --- /dev/null +++ b/gnovm/tests/files/addressable_7c_err.gno @@ -0,0 +1,8 @@ +package main + +func main() { + _, _ = &int(9) +} + +// Error: +// main/files/addressable_7c_err.gno:4:9: cannot take address of (const (9 int))