Skip to content

Commit

Permalink
introduce concept of addressability not applicable
Browse files Browse the repository at this point in the history
  • Loading branch information
deelawn committed Aug 29, 2024
1 parent 6940714 commit 3f4f1b6
Show file tree
Hide file tree
Showing 6 changed files with 123 additions and 63 deletions.
9 changes: 9 additions & 0 deletions gnovm/pkg/gnolang/addressability.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package gnolang

type Addressability int

const (
AddressabilityNotApplicable Addressability = iota
AddressabilitySatisfied
AddressabilityUnsatisfied
)
134 changes: 77 additions & 57 deletions gnovm/pkg/gnolang/nodes.go
Original file line number Diff line number Diff line change
Expand Up @@ -328,7 +328,7 @@ var (
type Expr interface {
Node
assertExpr()
isAddressable() bool
addressability() Addressability
}

type Exprs []Expr
Expand Down Expand Up @@ -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
Expand All @@ -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)
Expand All @@ -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<Varg?...>)
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]
Expand All @@ -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
Expand All @@ -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]
Expand All @@ -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
Expand All @@ -468,17 +480,17 @@ 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
Attributes
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)
Expand All @@ -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
Expand All @@ -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{<key>:<value>} struct, array, slice, and map
Expand All @@ -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.
Expand Down Expand Up @@ -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
Expand All @@ -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
Expand All @@ -578,8 +598,8 @@ type ConstExpr struct {
TypedValue
}

func (x *ConstExpr) isAddressable() bool {
return false
func (x *ConstExpr) addressability() Addressability {
return AddressabilityUnsatisfied
}

// ----------------------------------------
Expand Down Expand Up @@ -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
Expand All @@ -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 {
Expand All @@ -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 {
Expand All @@ -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
Expand All @@ -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 {
Expand All @@ -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 {
Expand All @@ -735,17 +755,17 @@ type MapTypeExpr struct {
Value Expr // value type
}

func (x *MapTypeExpr) isAddressable() bool {
return false
func (x *MapTypeExpr) addressability() Addressability {
return AddressabilityNotApplicable
}

type StructTypeExpr struct {
Attributes
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.
Expand All @@ -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
Expand All @@ -765,8 +785,8 @@ type MaybeNativeTypeExpr struct {
Type Expr
}

func (x *MaybeNativeTypeExpr) isAddressable() bool {
return false
func (x *MaybeNativeTypeExpr) addressability() Addressability {
return AddressabilityNotApplicable
}

// ----------------------------------------
Expand Down
14 changes: 8 additions & 6 deletions gnovm/pkg/gnolang/preprocess.go
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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
}
}

Expand Down Expand Up @@ -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()))
}

Expand Down Expand Up @@ -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()))
}
}
Expand Down
12 changes: 12 additions & 0 deletions gnovm/tests/files/addressable_7a_err.gno
Original file line number Diff line number Diff line change
@@ -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)
9 changes: 9 additions & 0 deletions gnovm/tests/files/addressable_7b_err.gno
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package main

type MyInt int

func main() {
_ = &MyInt
}

// Error:
Loading

0 comments on commit 3f4f1b6

Please sign in to comment.