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()))

Check warning on line 1537 in gnovm/pkg/gnolang/preprocess.go

View check run for this annotation

Codecov / codecov/patch

gnovm/pkg/gnolang/preprocess.go#L1537

Added line #L1537 was not covered by tests
}

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()))

Check warning on line 2427 in gnovm/pkg/gnolang/preprocess.go

View check run for this annotation

Codecov / codecov/patch

gnovm/pkg/gnolang/preprocess.go#L2427

Added line #L2427 was not covered by tests
}
}
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()

This comment has been minimized.

Copy link
@ltzmaxwell

ltzmaxwell Sep 11, 2024

Contributor

Do you think we can check this on AssignStmt in preprocess stage? I have similar concern while reviewing this PR: #2695

This comment has been minimized.

Copy link
@deelawn

deelawn Sep 11, 2024

Author Contributor

I don't think this should cause an error in the preprocessor related to addressability -- the error should be related to a mismatch with the number of values. If that currently doesn't happen in the preprocessor, then that is not in scope here and should be another issue.

This comment has been minimized.

Copy link
@ltzmaxwell

ltzmaxwell Sep 11, 2024

Contributor

yeah and that's why I thought this is out of scope. I agree that should be in another fix.

}

// 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.