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
Add abi.encodeError #14974
Add abi.encodeError #14974
Changes from 14 commits
c62d1b7
eeff11d
800b934
2a7250c
48e6e89
513ea59
a33001b
f822c13
9fd94c9
67f3b1d
1960a3f
66f0833
90c6943
9c2845a
e53f81d
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 |
---|---|---|
|
@@ -2203,6 +2203,7 @@ void TypeChecker::typeCheckABIEncodeFunctions( | |
_functionType->kind() == FunctionType::Kind::ABIEncodePacked || | ||
_functionType->kind() == FunctionType::Kind::ABIEncodeWithSelector || | ||
_functionType->kind() == FunctionType::Kind::ABIEncodeCall || | ||
_functionType->kind() == FunctionType::Kind::ABIEncodeError || | ||
_functionType->kind() == FunctionType::Kind::ABIEncodeWithSignature, | ||
"ABI function has unexpected FunctionType::Kind." | ||
); | ||
|
@@ -2227,10 +2228,13 @@ void TypeChecker::typeCheckABIEncodeFunctions( | |
// Perform standard function call type checking | ||
typeCheckFunctionGeneralChecks(_functionCall, _functionType); | ||
|
||
// No further generic checks needed as we do a precise check for ABIEncodeCall | ||
if (_functionType->kind() == FunctionType::Kind::ABIEncodeCall) | ||
// No further generic checks needed as we do a precise check for ABIEncodeCall and ABIEncodeError | ||
if ( | ||
_functionType->kind() == FunctionType::Kind::ABIEncodeCall || | ||
_functionType->kind() == FunctionType::Kind::ABIEncodeError | ||
) | ||
{ | ||
typeCheckABIEncodeCallFunction(_functionCall); | ||
typeCheckABIEncodeCallFunctionOrError(_functionCall, _functionType); | ||
return; | ||
} | ||
|
||
|
@@ -2292,19 +2296,34 @@ void TypeChecker::typeCheckABIEncodeFunctions( | |
} | ||
} | ||
|
||
void TypeChecker::typeCheckABIEncodeCallFunction(FunctionCall const& _functionCall) | ||
void TypeChecker::typeCheckABIEncodeCallFunctionOrError( | ||
FunctionCall const& _functionCall, | ||
FunctionTypePointer _functionType | ||
) | ||
{ | ||
std::vector<ASTPointer<Expression const>> const& arguments = _functionCall.arguments(); | ||
|
||
// Expecting first argument to be the function pointer and second to be a tuple. | ||
if (arguments.size() != 2) | ||
{ | ||
m_errorReporter.typeError( | ||
6219_error, | ||
_functionCall.location(), | ||
"Expected two arguments: a function pointer followed by a tuple." | ||
); | ||
return; | ||
switch (_functionType->kind()) { | ||
case FunctionType::Kind::ABIEncodeCall: | ||
m_errorReporter.typeError( | ||
6219_error, | ||
_functionCall.location(), | ||
"Expected two arguments: a function pointer followed by a tuple." | ||
); | ||
return; | ||
case FunctionType::Kind::ABIEncodeError: | ||
m_errorReporter.typeError( | ||
6220_error, | ||
_functionCall.location(), | ||
"Expected two arguments: a custom error followed by a tuple." | ||
); | ||
return; | ||
default: | ||
solAssert(false); | ||
} | ||
} | ||
|
||
FunctionType const* externalFunctionType = nullptr; | ||
|
@@ -2316,17 +2335,32 @@ void TypeChecker::typeCheckABIEncodeCallFunction(FunctionCall const& _functionCa | |
} | ||
else | ||
{ | ||
m_errorReporter.typeError( | ||
5511_error, | ||
arguments.front()->location(), | ||
"Expected first argument to be a function pointer, not \"" + | ||
type(*arguments.front())->humanReadableName() + | ||
"\"." | ||
); | ||
return; | ||
switch (_functionType->kind()) { | ||
case FunctionType::Kind::ABIEncodeCall: | ||
m_errorReporter.typeError( | ||
5511_error, | ||
arguments.front()->location(), | ||
"Expected first argument to be a function pointer, not \"" + | ||
type(*arguments.front())->humanReadableName() + | ||
"\"." | ||
); | ||
return; | ||
case FunctionType::Kind::ABIEncodeError: | ||
m_errorReporter.typeError( | ||
5512_error, | ||
arguments.front()->location(), | ||
"Expected first argument to be a custom error, not \"" + | ||
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 was trying to think of some test cases and when I try something like: error E(uint a, uint b);
contract C {
function g() public view returns (bytes memory) {
bytes memory b1 = abi.encodeError(E(1, 2), (1, 2));
return b1;
}
} The following error message is generated: |
||
type(*arguments.front())->humanReadableName() + | ||
"\"." | ||
); | ||
return; | ||
default: | ||
solAssert(false); | ||
} | ||
} | ||
|
||
if ( | ||
_functionType->kind() == FunctionType::Kind::ABIEncodeCall && | ||
externalFunctionType->kind() != FunctionType::Kind::External && | ||
externalFunctionType->kind() != FunctionType::Kind::Declaration | ||
) | ||
|
@@ -2378,6 +2412,34 @@ void TypeChecker::typeCheckABIEncodeCallFunction(FunctionCall const& _functionCa | |
m_errorReporter.typeError(3509_error, arguments[0]->location(), ssl, msg); | ||
return; | ||
} | ||
if ( | ||
_functionType->kind() == FunctionType::Kind::ABIEncodeError && | ||
externalFunctionType->kind() != FunctionType::Kind::Error | ||
) | ||
{ | ||
std::string msg = "Expected an error type."; | ||
|
||
switch (externalFunctionType->kind()) | ||
{ | ||
case FunctionType::Kind::Internal: | ||
case FunctionType::Kind::External: | ||
case FunctionType::Kind::Declaration: | ||
case FunctionType::Kind::DelegateCall: | ||
msg += " Cannot use functions for abi.encodeError."; | ||
break; | ||
case FunctionType::Kind::Creation: | ||
msg += " Provided creation function."; | ||
break; | ||
case FunctionType::Kind::Event: | ||
msg += " Cannot use events for abi.encodeError."; | ||
break; | ||
default: | ||
msg += " Cannot use special function."; | ||
} | ||
|
||
m_errorReporter.typeError(3510_error, arguments[0]->location(), msg); | ||
return; | ||
} | ||
solAssert(!externalFunctionType->takesArbitraryParameters(), "Function must have fixed parameters."); | ||
// Tuples with only one component become that component | ||
std::vector<ASTPointer<Expression const>> callArguments; | ||
|
@@ -2386,7 +2448,7 @@ void TypeChecker::typeCheckABIEncodeCallFunction(FunctionCall const& _functionCa | |
if (tupleType) | ||
{ | ||
if (TupleExpression const* argumentTuple = dynamic_cast<TupleExpression const*>(arguments[1].get())) | ||
callArguments = decltype(callArguments){argumentTuple->components().begin(), argumentTuple->components().end()}; | ||
callArguments = {argumentTuple->components().begin(), argumentTuple->components().end()}; | ||
else | ||
{ | ||
m_errorReporter.typeError( | ||
|
@@ -2445,7 +2507,6 @@ void TypeChecker::typeCheckABIEncodeCallFunction(FunctionCall const& _functionCa | |
} | ||
} | ||
|
||
|
||
void TypeChecker::typeCheckStringConcatFunction( | ||
FunctionCall const& _functionCall, | ||
FunctionType const* _functionType | ||
|
@@ -2903,6 +2964,7 @@ bool TypeChecker::visit(FunctionCall const& _functionCall) | |
case FunctionType::Kind::ABIEncodeWithSelector: | ||
case FunctionType::Kind::ABIEncodeWithSignature: | ||
case FunctionType::Kind::ABIEncodeCall: | ||
case FunctionType::Kind::ABIEncodeError: | ||
{ | ||
typeCheckABIEncodeFunctions(_functionCall, functionType); | ||
returnTypes = functionType->returnParameterTypes(); | ||
|
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 a minor imprecision that was fixed recently in the previous entry for
abi.encodeCall
:)I will already commit this suggestion via github interface;Actually, there were another instances which I already fixed via a commit.