-
Notifications
You must be signed in to change notification settings - Fork 5.6k
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
Require with custom error #14913
Require with custom error #14913
Conversation
3f1416d
to
b823fda
Compare
I'm not sure how many of these we may already have, but since we're changing the return type of the error constructor calls, it'd be good to have a few more tests like calsuchling as a standalone statement |
Also maybe a small AST test with just a require-with error call, s.t. we can see if and how the new type shows up there. EDIT: I just saw that there's already one at least where it shows up. |
@@ -336,27 +342,38 @@ struct EventOutsideEmitErrorOutsideRevertChecker: public PostTypeChecker::Checke | |||
if (*_functionCall.annotation().kind == FunctionCallKind::FunctionCall) | |||
if (auto const* functionType = dynamic_cast<FunctionType const*>(_functionCall.expression().annotation().type)) | |||
{ | |||
if (!m_inRequire && functionType->kind() == FunctionType::Kind::Require) | |||
m_inRequire = true; |
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.
We might also instead reuse m_currentStatement
here, i.e. set that here to the outer call? Well, not sure which is better. If you flip m_currentStatement
we might be able to assert that it's nullptr
when we hit this - since revert and emit statements should only allow errors and events after earlier analysis I guess? But yeah, whatever is easiest to make sure we don't get weird combinations of things slipping through.
I haven't fully thought this through in nested cases yet - might be worthwhile to check for pathological things like revert SomeError(require(false,AnotherError()));
or so - none of this should be valid (that example should e.g. be rejected at the very least as an invalid argument type to SomeError
), but worthwhile to think about whether there can be a case that slips through.
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.
Sure; the reason I did it this way is precisely because I couldn't think of a situation where a require would be within a nested call.
f14a712
to
ac94abe
Compare
For the docs by the way, it's important to be clear about the fact that the arguments to the error are evaluated unconditionally (like for any regular function call). We should also have a pathological test case for that like:
Both calling We can also point out that that's consistent with a require we already have that takes a string. We can also further point out that the allocation of the memory for the error-based revert reason will only happen in the reverting pass and that constants and string literals will become optimized, so the "expected" use should remain cheap. |
d86807e
to
dbcf2db
Compare
5c3d17a
to
3bbfe0a
Compare
3bbfe0a
to
8fec950
Compare
69f5d1c
to
8fec950
Compare
00948a9
to
3704710
Compare
// @returns function that has equivalent logic of a require statement, but with a custom | ||
// error constructor parameter. |
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.
// @returns function that has equivalent logic of a require statement, but with a custom | |
// error constructor parameter. | |
// @returns function that has equivalent logic of a require function, but with a custom | |
// error constructor parameter. |
af62b85
to
f32a443
Compare
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.
Just a bunch of nitpicks. I am still looking at the code, but can't see anything wrong.
@@ -1,6 +1,7 @@ | |||
### 0.8.26 (unreleased) | |||
|
|||
Language Features: | |||
* Introduce a new overload ``require(bool, Error)`` that allows usage of ``require`` functions with custom errors. This feature is available in the ``via-ir`` pipeline only. |
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.
* Introduce a new overload ``require(bool, Error)`` that allows usage of ``require`` functions with custom errors. This feature is available in the ``via-ir`` pipeline only. | |
* Introduce a new usage of ``require`` functions with custom errors. This feature is available in the ``via-ir`` pipeline only. |
Maybe omitting this detail makes it simpler to the general user?
f32a443
to
ba2e7c8
Compare
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 have a few small corrections and final nitpicks, but nothing serious. None of this should really take more than a few minutes to fix and when it's dealt with I'm going to approve and we can merge.
{ | ||
solAssert(arg->annotation().type); | ||
if (arg->annotation().type->sizeOnStack() > 0) | ||
errorArgumentVars += IRVariable(*arg).stackSlots(); |
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.
One thing that I only realized now is that you generate names for the require function's parameters based on the expressions used in the call rather than on the error definition (which has no names for parameters, so fair enough). In other cases, e.g. abi.encode()
, we don't do this and we instead generate a sequence of numbered names with suffixedVariableNameList()
. In your case we get parameters named like expr_29
, which looks a bit odd to me because that's how I expect locals to be named.
I see that it was already in your initial implementation, but back then it was up to you how you name them. Now revertWithError()
actually expects this naming pattern so I guess it's fine and maybe better than the alternative of having to explicitly pass those parameter names to it. But I think it's at least worth a comment here pointing out that this is happening. The fact that the variable here is named errorArgumentVars
and not errorParameterVars
is a hint but it's too subtle. Also, I'd rename the errorArguments
template var to something like functionParameterNames
, because that's more accurate.
I also started wondering it this won't cause some naming conflicts with locals, but I guess it shouldn't because the name counter is global. Old names won't appear here and the new ones will get higher numbers...
This comment was marked as resolved.
This comment was marked as resolved.
This comment was marked as resolved.
This comment was marked as resolved.
61ef53d
to
7afe8e1
Compare
7afe8e1
to
fca8489
Compare
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 see that #14913 (comment) was still not addressed.
I'm going to tentatively approve the PR because it's the last thing to do there, but please apply my suggestion below before merging it.
Disallow require with error in legacy More tests Docs Use AST ID in generated Yul helper function names Changelog Review comments
fca8489
to
287a95a
Compare
287a95a
to
1bf0f38
Compare
available: balances[msg.sender] | ||
}); | ||
|
||
require(amount > balances[msg.sender], InsufficientBalance(amount, balances[msg.sender])); |
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 require(amount <= balances[msg.sender]
?
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.
Ha, you're totally right; I'll open a PR to fix it. Thanks!
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.
Opened a pr actually #15055
Fixes: #14442