-
Notifications
You must be signed in to change notification settings - Fork 385
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
feat(gnovm): align Gno constant handling with Go specifications #2828
base: master
Are you sure you want to change the base?
Conversation
Codecov ReportAttention: Patch coverage is
📢 Thoughts on this report? Let us know! |
c9b02d2
to
f49c088
Compare
355d799
to
e9a9be7
Compare
@omarsy , can you fix the lint-pr-title CI check? |
🛠 PR Checks Summary🔴 Maintainers must be able to edit this pull request (more info) Manual Checks (for Reviewers):
Read More🤖 This bot helps streamline PR reviews by verifying automated checks and providing guidance for contributors and reviewers. ✅ Automated Checks (for Contributors):🔴 Maintainers must be able to edit this pull request (more info) ☑️ Contributor Actions:
☑️ Reviewer Actions:
📚 Resources:Debug
|
I think it is better to handle it in another PR. WDYT ? |
gnovm/pkg/gnolang/type_check.go
Outdated
switch vx := vx.(type) { | ||
case *NameExpr: | ||
t := evalStaticTypeOf(store, last, vx) | ||
if _, ok := t.(*ArrayType); ok { |
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.
hmmm, this logic seems incorrect:
if _, ok := t.(*ArrayType); ok {
break Main
}
Due to this logic, the error in const43.gno
was not caught.
I guess your intention is to check len(arr), right? I think that needs additional context to know if the outer expr is a built func call: len
or max
?
Not so sure, but we need to focus on ensuring that the logic of this function is correct(not limited to the above-mentioned).
gnovm/pkg/gnolang/type_check.go
Outdated
assertValidConstantExprRecursively(store, last, expr, nil) | ||
} | ||
|
||
func assertValidConstantExprRecursively(store Store, last BlockNode, currExpr, parentExpr Expr) { |
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.
func assertValidConstantExprRecursively(store Store, last BlockNode, currExpr, parentExpr Expr) { | |
func assertValidConstValue(store Store, last BlockNode, currExpr, parentExpr Expr) { |
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.
should be done here 54878f0
@ltzmaxwell ping me if you approve and would like me to take a look as well, otherwise go ahead and merge after you've approved |
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.
trying to find more counter cases, please check.
case *TypeType: | ||
for _, arg := range currExpr.Args { | ||
assertValidConstValue(store, last, arg, currExpr) | ||
} |
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.
please check this:
package main
const a = interface{}(nil)
func main() {
println("ok")
}
seems also need to check the type, right?
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.
My bad break on my last refactoring when I move the check type
Nice catch ^^
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.
so the above clause: case *TypeType
is not needed? didn't see any test case targeting this.
gnovm/pkg/gnolang/type_check.go
Outdated
|
||
tt := pv.GetBlock(store).Source.GetStaticTypeOf(store, currExpr.Sel) | ||
panic(fmt.Sprintf("%s (variable of type %s) is not constant", currExpr.String(), tt)) | ||
case *PointerType, *DeclaredType, *StructType, *InterfaceType: |
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 is a counter case:
package main
type MyStruct struct {
arr [2]int
}
const a = len(MyStruct{arr: [2]int{1, 2}}.arr)
func main() {
println("ok")
}
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.
:o I miss this case. Thank you ^^
Done here c45f63e
} | ||
case *ConstExpr: | ||
case *BasicLitExpr: | ||
case *CompositeLitExpr: |
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.
can we just check parent and panic here?
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.
Since we verify the expression type before calling this function, this case should not occur. Removed for array: 4da7934
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.
will it be more straightforward that just check if parentExpr
exist, and the type of compositeLitExpr
is array type, otherwise panic?
|
||
tt := pv.GetBlock(store).Source.GetStaticTypeOf(store, currExpr.Sel) | ||
panic(fmt.Sprintf("%s (variable of type %s) is not constant", currExpr.String(), tt)) | ||
case *PointerType, *DeclaredType, *StructType, *InterfaceType, *TypeType, *NativeType: |
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.
seems *TypeType
does not apply. please double check.
|
||
func isParentCallExprWithArrayArg(currType Type, parentExpr Expr) bool { | ||
_, okArray := baseOf(currType).(*ArrayType) | ||
_, okCallExpr := parentExpr.(*CallExpr) |
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.
please add a comment.
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.
done here 29b6ab0
assertValidConstValue(store, last, expr, nil) | ||
} | ||
|
||
func assertValidConstValue(store Store, last BlockNode, currExpr, parentExpr Expr) { |
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.
At the same time, I’m wondering—many of the checks here are for functions like len and cap. So, is this recursive call really necessary? Could most of the cases be handled under callExpr instead? Please consider this.
Apologies for the continuous iterations in reviewing this PR. Thank you for understanding.
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.
Thank you for pointing this out! To clarify, we don't check only if the call expression has len
or cap
. Our implementation ensures that all expressions are validated for their correctness as constant expressions. For instance, a binary expression with a valid type we will check if it is a valid constant expression.
Here's an example to illustrate this:
package main
func main() {
v := 5
const a = 1 + 2 + len([2]int{1, 2}) + v
println("ok")
}
In this example, the constant expression 1 + 2 + len([2]int{1, 2})
is valid because all sub-expressions are constant and have valid types. However, the addition of v
, which is a variable, makes the entire expression invalid as a constant expression, and this is correctly flagged by our checks.
Related Issues:
Closes #2628
This PR aims to align Gno's constant handling with the Go specification regarding constant expressions (see Go Specification on Constants).
Primitive Type Requirement
Function Calls Disallowed
Only built-in functions should be allowed.
Constant Operands Requirement
Constant expressions may contain only constant operands and are evaluated at compile time.
Type Assertion Forbidden
Index Expression Forbidden
Contributors' checklist...
BREAKING CHANGE: xxx
message was included in the description