-
Notifications
You must be signed in to change notification settings - Fork 10
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
Return and modifiers #113
Return and modifiers #113
Conversation
Example 1 (
|
Example 2 (
|
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.
Functionality looks good but I requested some changes related to choice of data structures and style. See my comments below.
libsolidity/codegen/IeleCompiler.h
Outdated
// Appends one layer of function modifier code of the current function, or the | ||
// function body itself if the last modifier was reached. | ||
void appendModifierOrFunctionCode(); | ||
unsigned ModifierDepth; | ||
|
||
// Maps each level of modifiers with a return target | ||
std::map<unsigned, iele::IeleBlock *> ReturnBlocks; |
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.
I don't think this has to be a map. Couldn't it be a std::vector or even a std::stack? Also there is no reseting or clearing this. Are you sure it would not cause any bugs? Using an actual stack would be more intuitive and safer I think.
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.
Actually, using a stack was my initial plan, but it didn't work; I tried a few things and, eventually, a map from Modifier Depth, which worked, so it stayed that way.
I tried again using a stack but it doesn't work.
I agree at this point it would be useful to get to the bottom of it and fully understand what's going on.
I'll investigate in more detail and post updates here.
PS: other 2 minor comments are now addressed.
libsolidity/codegen/IeleCompiler.cpp
Outdated
@@ -345,6 +345,8 @@ bool IeleCompiler::visit(const FunctionDefinition &function) { | |||
// We store the formal argument names, which we'll use when generating in-range | |||
// checks in case of a public function. | |||
std::vector<iele::IeleArgument *> parameters; | |||
returnParameters.clear(); // otherwise, stuff keep getting added, regardless | |||
// of which function we are in (i.e. it breaks) |
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.
to keep things uniform I think you should be clearing this at the end of the visitor together with the rest of the reset code (line 455 and after)
libsolidity/codegen/IeleCompiler.h
Outdated
// Return parameters of the current function | ||
// TODO: do we really want to have this here? | ||
std::vector<iele::IeleLocalVariable *> returnParameters; | ||
|
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.
I would rename this to CompilingFunctionReturnParameters
and reset it at the end of the function visitor as mentioned above.
@theo25 actually managed to replace the map with stack as suggested. Ready to review again. |
The changes look good to me. |
13c0a1e
to
a01eb4c
Compare
Jenkins: test this please |
Looks like we have 2 new failures after merge:
|
Jenkins: test this please |
This gives a different implementation to
return
so that it behaves as expected, especially in interaction with function modifiers.Previously, Solidity's
return
was simply compiled into IELE'sret
. Now things are a bit different; essentially, we compilereturn
into jumps (to appropriate targets that we generate), and only at the end we eventually reach aret
(of which there's only 1 per function).Before, we used to insert a "default" return at the end of each function, but only if the function didn't already have one; now, we always do this; indeed, this automatically inserted return is the one that will eventually be reached and perform the actual return operation; all other, user-defined returns will be compiled into jumps and assignments of the return value to the return parameters (declared in function definition).
To keep track of the return value, we use the explicit or implicit return parameters.
The idea is that "
return
behaves asbreak
" (see e.g. ethereum/solidity#686) so that when a function returns, the remaining statements (if any) in the modifier are still executed.See comments below for some examples of the kind of code it produces.