-
Notifications
You must be signed in to change notification settings - Fork 362
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: addressability #2731
base: master
Are you sure you want to change the base?
fix: addressability #2731
Changes from 23 commits
c8462ec
ef97274
7fa9f50
08563c3
3b78ae9
a0e13b9
ae55b84
990017d
3621dc7
9faf3df
8671ea5
816dbd6
77caea9
89a041c
9956c26
6940714
3f4f1b6
c16e5e9
ac79f00
df764cd
af12ca1
e498f1c
bee868c
9698461
b284b56
dfe024f
0e80801
804c17e
44cc298
548af87
8bec242
8fe3b37
26e8529
3c120ae
feee13d
b33f0b0
a8827ff
71afb10
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
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 | ||
) |
Original file line number | Diff line number | Diff line change | ||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
@@ -328,6 +328,7 @@ | |||||||||||||||
type Expr interface { | ||||||||||||||||
Node | ||||||||||||||||
assertExpr() | ||||||||||||||||
addressability() Addressability | ||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
If Addressability is exported, so should the method to get it. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Neither should really be exported; I was just running short on names. I renamed it so this is no longer an issue. 0e80801 |
||||||||||||||||
} | ||||||||||||||||
|
||||||||||||||||
type Exprs []Expr | ||||||||||||||||
|
@@ -374,6 +375,10 @@ | |||||||||||||||
Name | ||||||||||||||||
} | ||||||||||||||||
|
||||||||||||||||
func (x *NameExpr) addressability() Addressability { | ||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I've been thinking about what's the best approach here. Part of me would prefer if this was just a
But I do think we should concentrate the rules for addressability in some code packed tightly together, so it can be easily cross-checked with the Go reference in hand. So what do you say about moving all of these methods underneath the block of There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think I was able to do even one better here and remove the |
||||||||||||||||
return AddressabilitySatisfied | ||||||||||||||||
} | ||||||||||||||||
|
||||||||||||||||
type NameExprs []NameExpr | ||||||||||||||||
|
||||||||||||||||
type BasicLitExpr struct { | ||||||||||||||||
|
@@ -385,33 +390,65 @@ | |||||||||||||||
Value string | ||||||||||||||||
} | ||||||||||||||||
|
||||||||||||||||
func (x *BasicLitExpr) addressability() Addressability { | ||||||||||||||||
return AddressabilityUnsatisfied | ||||||||||||||||
} | ||||||||||||||||
|
||||||||||||||||
type BinaryExpr struct { // (Left Op Right) | ||||||||||||||||
Attributes | ||||||||||||||||
Left Expr // left operand | ||||||||||||||||
Op Word // operator | ||||||||||||||||
Right Expr // right operand | ||||||||||||||||
} | ||||||||||||||||
|
||||||||||||||||
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) | ||||||||||||||||
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 | ||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. For the cases like this where the addressability is assigned during preprocess, what do you think about moving Addressability as an attribute? The reason why I say this is that we currently have a bunch of information which is not actually persisted, but recovered by using If addressability is an attribute, I also wonder if there's a way to remove the specific type and turn this into |
||||||||||||||||
} | ||||||||||||||||
|
||||||||||||||||
func (x *CallExpr) addressability() Addressability { | ||||||||||||||||
return x.Addressability | ||||||||||||||||
} | ||||||||||||||||
|
||||||||||||||||
type IndexExpr struct { // X[Index] | ||||||||||||||||
Attributes | ||||||||||||||||
X Expr // expression | ||||||||||||||||
Index Expr // index expression | ||||||||||||||||
HasOK bool // if true, is form: `value, ok := <X>[<Key>] | ||||||||||||||||
X Expr // expression | ||||||||||||||||
Index Expr // index expression | ||||||||||||||||
HasOK bool // if true, is form: `value, ok := <X>[<Key>] | ||||||||||||||||
Addressability Addressability | ||||||||||||||||
} | ||||||||||||||||
|
||||||||||||||||
func (x *IndexExpr) addressability() Addressability { | ||||||||||||||||
// In this case NotApplicable means that it wasn't set, the default value. | ||||||||||||||||
if x.Addressability == AddressabilityNotApplicable { | ||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. When does this happen? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This happens when it is not set in TRANS_LEAVE, here gno/gnovm/pkg/gnolang/preprocess.go Lines 1500 to 1506 in 804c17e
I've added a clarifying comment. 44cc298 |
||||||||||||||||
return x.X.addressability() | ||||||||||||||||
} | ||||||||||||||||
|
||||||||||||||||
return x.Addressability | ||||||||||||||||
} | ||||||||||||||||
|
||||||||||||||||
type SelectorExpr struct { // X.Sel | ||||||||||||||||
Attributes | ||||||||||||||||
X Expr // expression | ||||||||||||||||
Path ValuePath // set by preprocessor. | ||||||||||||||||
Sel Name // field selector | ||||||||||||||||
X Expr // expression | ||||||||||||||||
Path ValuePath // set by preprocessor. | ||||||||||||||||
Sel Name // field selector | ||||||||||||||||
IsAddressable bool // true if X is a pointer | ||||||||||||||||
} | ||||||||||||||||
|
||||||||||||||||
func (x *SelectorExpr) addressability() Addressability { | ||||||||||||||||
if x.IsAddressable || x.X.addressability() == AddressabilitySatisfied { | ||||||||||||||||
return AddressabilitySatisfied | ||||||||||||||||
} | ||||||||||||||||
|
||||||||||||||||
return AddressabilityUnsatisfied | ||||||||||||||||
} | ||||||||||||||||
|
||||||||||||||||
type SliceExpr struct { // X[Low:High:Max] | ||||||||||||||||
|
@@ -422,6 +459,10 @@ | |||||||||||||||
Max Expr // maximum capacity of slice; or nil; added in Go 1.2 | ||||||||||||||||
} | ||||||||||||||||
|
||||||||||||||||
func (x *SliceExpr) addressability() Addressability { | ||||||||||||||||
return AddressabilityUnsatisfied | ||||||||||||||||
} | ||||||||||||||||
|
||||||||||||||||
// A StarExpr node represents an expression of the form | ||||||||||||||||
// "*" Expression. Semantically it could be a unary "*" | ||||||||||||||||
// expression, or a pointer type. | ||||||||||||||||
|
@@ -430,16 +471,33 @@ | |||||||||||||||
X Expr // operand | ||||||||||||||||
} | ||||||||||||||||
|
||||||||||||||||
func (x *StarExpr) addressability() Addressability { | ||||||||||||||||
return x.X.addressability() | ||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can you follow the code coverage annotations to add more test cases? |
||||||||||||||||
} | ||||||||||||||||
|
||||||||||||||||
type RefExpr struct { // &X | ||||||||||||||||
Attributes | ||||||||||||||||
X Expr // operand | ||||||||||||||||
} | ||||||||||||||||
|
||||||||||||||||
func (x *RefExpr) addressability() Addressability { | ||||||||||||||||
return x.X.addressability() | ||||||||||||||||
} | ||||||||||||||||
|
||||||||||||||||
type TypeAssertExpr struct { // X.(Type) | ||||||||||||||||
Attributes | ||||||||||||||||
X Expr // expression. | ||||||||||||||||
Type Expr // asserted type, never nil. | ||||||||||||||||
HasOK bool // if true, is form: `_, ok := <X>.(<Type>)`. | ||||||||||||||||
X Expr // expression. | ||||||||||||||||
Type Expr // asserted type, never nil. | ||||||||||||||||
HasOK bool // if true, is form: `_, ok := <X>.(<Type>)`. | ||||||||||||||||
IsAddressable bool | ||||||||||||||||
} | ||||||||||||||||
|
||||||||||||||||
func (x *TypeAssertExpr) addressability() Addressability { | ||||||||||||||||
if x.IsAddressable { | ||||||||||||||||
return AddressabilitySatisfied | ||||||||||||||||
} | ||||||||||||||||
|
||||||||||||||||
return AddressabilityUnsatisfied | ||||||||||||||||
} | ||||||||||||||||
|
||||||||||||||||
// A UnaryExpr node represents a unary expression. Unary | ||||||||||||||||
|
@@ -452,12 +510,25 @@ | |||||||||||||||
Op Word // operator | ||||||||||||||||
} | ||||||||||||||||
|
||||||||||||||||
func (x *UnaryExpr) addressability() Addressability { | ||||||||||||||||
return x.X.addressability() | ||||||||||||||||
} | ||||||||||||||||
|
||||||||||||||||
// MyType{<key>:<value>} struct, array, slice, and map | ||||||||||||||||
// expressions. | ||||||||||||||||
type CompositeLitExpr struct { | ||||||||||||||||
Attributes | ||||||||||||||||
Type Expr // literal type; or nil | ||||||||||||||||
Elts KeyValueExprs // list of struct fields; if any | ||||||||||||||||
Type Expr // literal type; or nil | ||||||||||||||||
Elts KeyValueExprs // list of struct fields; if any | ||||||||||||||||
IsAddressable bool | ||||||||||||||||
} | ||||||||||||||||
|
||||||||||||||||
func (x *CompositeLitExpr) addressability() Addressability { | ||||||||||||||||
if x.IsAddressable { | ||||||||||||||||
return AddressabilitySatisfied | ||||||||||||||||
} | ||||||||||||||||
|
||||||||||||||||
return AddressabilityUnsatisfied | ||||||||||||||||
} | ||||||||||||||||
|
||||||||||||||||
// Returns true if any elements are keyed. | ||||||||||||||||
|
@@ -490,6 +561,10 @@ | |||||||||||||||
Value Expr // never nil | ||||||||||||||||
} | ||||||||||||||||
|
||||||||||||||||
func (x *KeyValueExpr) addressability() Addressability { | ||||||||||||||||
return AddressabilityNotApplicable | ||||||||||||||||
} | ||||||||||||||||
|
||||||||||||||||
type KeyValueExprs []KeyValueExpr | ||||||||||||||||
|
||||||||||||||||
// A FuncLitExpr node represents a function literal. Here one | ||||||||||||||||
|
@@ -502,6 +577,10 @@ | |||||||||||||||
Body // function body | ||||||||||||||||
} | ||||||||||||||||
|
||||||||||||||||
func (x *FuncLitExpr) addressability() Addressability { | ||||||||||||||||
return AddressabilityUnsatisfied | ||||||||||||||||
} | ||||||||||||||||
|
||||||||||||||||
// The preprocessor replaces const expressions | ||||||||||||||||
// with *ConstExpr nodes. | ||||||||||||||||
type ConstExpr struct { | ||||||||||||||||
|
@@ -510,6 +589,10 @@ | |||||||||||||||
TypedValue | ||||||||||||||||
} | ||||||||||||||||
|
||||||||||||||||
func (x *ConstExpr) addressability() Addressability { | ||||||||||||||||
return AddressabilityUnsatisfied | ||||||||||||||||
} | ||||||||||||||||
|
||||||||||||||||
// ---------------------------------------- | ||||||||||||||||
// Type(Expressions) | ||||||||||||||||
// | ||||||||||||||||
|
@@ -574,6 +657,10 @@ | |||||||||||||||
Tag Expr | ||||||||||||||||
} | ||||||||||||||||
|
||||||||||||||||
func (x *FieldTypeExpr) addressability() Addressability { | ||||||||||||||||
return AddressabilityNotApplicable | ||||||||||||||||
} | ||||||||||||||||
|
||||||||||||||||
type FieldTypeExprs []FieldTypeExpr | ||||||||||||||||
|
||||||||||||||||
func (ftxz FieldTypeExprs) IsNamed() bool { | ||||||||||||||||
|
@@ -598,18 +685,30 @@ | |||||||||||||||
Elt Expr // element type | ||||||||||||||||
} | ||||||||||||||||
|
||||||||||||||||
func (x *ArrayTypeExpr) addressability() Addressability { | ||||||||||||||||
return AddressabilityNotApplicable | ||||||||||||||||
} | ||||||||||||||||
|
||||||||||||||||
type SliceTypeExpr struct { | ||||||||||||||||
Attributes | ||||||||||||||||
Elt Expr // element type | ||||||||||||||||
Vrd bool // variadic arg expression | ||||||||||||||||
} | ||||||||||||||||
|
||||||||||||||||
func (x *SliceTypeExpr) addressability() Addressability { | ||||||||||||||||
return AddressabilityNotApplicable | ||||||||||||||||
} | ||||||||||||||||
|
||||||||||||||||
type InterfaceTypeExpr struct { | ||||||||||||||||
Attributes | ||||||||||||||||
Methods FieldTypeExprs // list of methods | ||||||||||||||||
Generic Name // for uverse generics | ||||||||||||||||
} | ||||||||||||||||
|
||||||||||||||||
func (x *InterfaceTypeExpr) addressability() Addressability { | ||||||||||||||||
return AddressabilityNotApplicable | ||||||||||||||||
} | ||||||||||||||||
|
||||||||||||||||
type ChanDir int | ||||||||||||||||
|
||||||||||||||||
const ( | ||||||||||||||||
|
@@ -627,36 +726,60 @@ | |||||||||||||||
Value Expr // value type | ||||||||||||||||
} | ||||||||||||||||
|
||||||||||||||||
func (x *ChanTypeExpr) addressability() Addressability { | ||||||||||||||||
return AddressabilityNotApplicable | ||||||||||||||||
} | ||||||||||||||||
|
||||||||||||||||
type FuncTypeExpr struct { | ||||||||||||||||
Attributes | ||||||||||||||||
Params FieldTypeExprs // (incoming) parameters, if any. | ||||||||||||||||
Results FieldTypeExprs // (outgoing) results, if any. | ||||||||||||||||
} | ||||||||||||||||
|
||||||||||||||||
func (x *FuncTypeExpr) addressability() Addressability { | ||||||||||||||||
return AddressabilityNotApplicable | ||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. For these cases where we just return NotApplicable, I wonder if we should just panic... There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. In the case of type expressions, yes, we should panic because it is unexpected to have this method called 8bec242 But we shouldn't get rid of NotApplicable altogether. There are some valid cases, for example, when there is code like this: func main() {
_ = &DoSomething()
}
func DoSomething() (int, int) { ... } In this case addressability is not applicable because it should fail with an error message referencing the fact that it is trying to take a reference, which requires one operand, on the result of a function that returns multiple values, so we don't want to trigger an addressability error here. In Go, this would panic with something like |
||||||||||||||||
} | ||||||||||||||||
|
||||||||||||||||
type MapTypeExpr struct { | ||||||||||||||||
Attributes | ||||||||||||||||
Key Expr // const | ||||||||||||||||
Value Expr // value type | ||||||||||||||||
} | ||||||||||||||||
|
||||||||||||||||
func (x *MapTypeExpr) addressability() Addressability { | ||||||||||||||||
return AddressabilityNotApplicable | ||||||||||||||||
} | ||||||||||||||||
|
||||||||||||||||
type StructTypeExpr struct { | ||||||||||||||||
Attributes | ||||||||||||||||
Fields FieldTypeExprs // list of field declarations | ||||||||||||||||
} | ||||||||||||||||
|
||||||||||||||||
func (x *StructTypeExpr) addressability() Addressability { | ||||||||||||||||
return AddressabilityNotApplicable | ||||||||||||||||
} | ||||||||||||||||
|
||||||||||||||||
// Like ConstExpr but for types. | ||||||||||||||||
type constTypeExpr struct { | ||||||||||||||||
Attributes | ||||||||||||||||
Source Expr | ||||||||||||||||
Type Type | ||||||||||||||||
} | ||||||||||||||||
|
||||||||||||||||
func (x *constTypeExpr) addressability() Addressability { | ||||||||||||||||
return AddressabilityNotApplicable | ||||||||||||||||
} | ||||||||||||||||
|
||||||||||||||||
// Only used for native func arguments | ||||||||||||||||
type MaybeNativeTypeExpr struct { | ||||||||||||||||
Attributes | ||||||||||||||||
Type Expr | ||||||||||||||||
} | ||||||||||||||||
|
||||||||||||||||
func (x *MaybeNativeTypeExpr) addressability() Addressability { | ||||||||||||||||
return AddressabilityNotApplicable | ||||||||||||||||
} | ||||||||||||||||
|
||||||||||||||||
// ---------------------------------------- | ||||||||||||||||
// Stmt | ||||||||||||||||
// | ||||||||||||||||
|
@@ -1484,6 +1607,7 @@ | |||||||||||||||
GetParentNode(Store) BlockNode | ||||||||||||||||
GetPathForName(Store, Name) ValuePath | ||||||||||||||||
GetIsConst(Store, Name) bool | ||||||||||||||||
GetIsConstAt(Store, ValuePath) bool | ||||||||||||||||
GetLocalIndex(Name) (uint16, bool) | ||||||||||||||||
GetValueRef(Store, Name, bool) *TypedValue | ||||||||||||||||
GetStaticTypeOf(Store, Name) Type | ||||||||||||||||
|
@@ -1671,6 +1795,17 @@ | |||||||||||||||
} | ||||||||||||||||
} | ||||||||||||||||
|
||||||||||||||||
func (sb *StaticBlock) GetIsConstAt(store Store, path ValuePath) bool { | ||||||||||||||||
for { | ||||||||||||||||
if path.Depth == 1 { | ||||||||||||||||
return sb.getLocalIsConst(path.Name) | ||||||||||||||||
} else { | ||||||||||||||||
sb = sb.GetParentNode(store).GetStaticBlock() | ||||||||||||||||
thehowl marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||||||||||||
path.Depth -= 1 | ||||||||||||||||
} | ||||||||||||||||
} | ||||||||||||||||
} | ||||||||||||||||
|
||||||||||||||||
// Returns true iff n is a local const defined name. | ||||||||||||||||
func (sb *StaticBlock) getLocalIsConst(n Name) bool { | ||||||||||||||||
for _, name := range sb.Consts { | ||||||||||||||||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should just be in nodes.go
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ideally
nodes.go
would b less than 2200 LOC, but I've moved this back here as you suggested since moving a single concept into a new file that is closely related to this may be premature; a larger reorganization is necessary here. 0e80801