-
Notifications
You must be signed in to change notification settings - Fork 139
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
[Compiler] Support compilation for before statements #3763
base: feature/compiler
Are you sure you want to change the base?
Conversation
Cadence Benchstat comparisonThis branch with compared with the base branch onflow:feature/compiler commit d861cc4 Collapsed results for better readability
|
Great work! I haven't looked too deep into the code yet, but how does this handle the case where the post-conditions in the interfaces refer to different expressions, e.g. struct interface Foo {
var i: Int
fun test() {
post {
before(self.i) == 2
}
}
}
struct interface Bar: Foo {
var j: Int
fun test() {
post {
before(self.j) == 3
}
}
}
struct Test: Bar {
var i: Int
var j: Int
init() {
self.i = 2
self.j = 3
}
fun test() {
self.i = 4
self.j = 5
}
} In the the example above the two interfaces referred to the same expression ( I guess there's no potential for confusion, as the IDs are distinct ( |
It's pretty much the same. Regardless of the type of the expression, whatever the expression that is inside struct interface Foo {
var i: Int
access(all)
view fun $Foo.test.�exp�0(): AnyStruct {
return self.i
}
...
}
struct interface Bar: Foo {
var j: Int
access(all)
view fun $Bar.test.exp�1(): AnyStruct {
return self.j
}
...
} And then in the post condition,
Yes, the IDs are distinct (the counter is per-type). Before-extractor in type-checker generate these counters ( The generated complete code for your example is: struct interface Foo {
var i: Int
access(all)
view fun $Foo.test.�exp�0(): AnyStruct {
return self.i
}
access(all)
view fun $Foo.test.postConditions(_ �exp�0: AnyStruct): Void {
if !(�exp�0 == 2) {
panic("pre/post condition failed")
}
return
}
}
struct interface Bar: Foo {
var j: Int
access(all)
view fun $Bar.test.�exp�1(): AnyStruct {
return self.j
}
access(all)
view fun $Bar.test.postConditions(_ �exp�1: AnyStruct): Void {
if !(�exp�1 == 3) {
panic("pre/post condition failed")
}
return
}
}
struct Test: Bar {
var i: Int
var j: Int
init() {
self.i = 2
self.j = 3
}
fun test() {
var $_before0 = self.$Foo.test.�exp�0()
var $_before1 = self.$Bar.test.�exp�1()
var $_result =
self.i = 4
self.j = 5
self.$Foo.test.postConditions($_before0)
self.$Bar.test.postConditions($_before1)
return
}
} |
Happy to walk-through the idea in detail in the next implementation sync |
It seems like the pre-conditions and the post-conditions should be called in opposite orders. fun test() {
var $_before0 = self.$Foo.test.�exp�0()
var $_before1 = self.$Bar.test.�exp�1()
var $_result =
self.i = 4
self.j = 5
self.$Bar.test.postConditions($_before1)
self.$Foo.test.postConditions($_before0)
return
} And the order in which they are called should be well documented. I believe that C++ and Swift use different orders for constructors and destructors. Should the pre-conditions of the grandparent be called before or after the parent's pre-conditions? |
Should the grandparent's post-condition even be called if the parent's condition fails? |
@jsproz conditions are linearized in a "depth-first pre-ordered" manner. It is already documented under the interface section: https://cadence-lang.org/docs/language/interfaces#linearizing-conditions
Given a failed condition would panic the runtime, it will terminate the execution, and would not call any conditions to follow (grandparent's post-condition in this case) |
The language reference does indicate the post-conditions are executed in the reverse order: "Similarly, for post-conditions, the same linearization of interfaces would be used, and the post-conditions are executed in the reverse order." |
Work towards #3742
Description
Before functions/statements are treated similar to pre/post conditions.
For concrete type functions
Before-statements are inlined and added to the beginning of the function.
becomes:
For interface methods
Would eventually become something like:
master
branchFiles changed
in the Github PR explorer