Merge pull request #12423 from ethereum/develop

Merge develop into breaking.
This commit is contained in:
chriseth
2021-12-20 11:40:40 +01:00
committed by GitHub
77 changed files with 3206 additions and 592 deletions
+113
View File
@@ -1996,6 +1996,7 @@ void TypeChecker::typeCheckABIEncodeFunctions(
_functionType->kind() == FunctionType::Kind::ABIEncode ||
_functionType->kind() == FunctionType::Kind::ABIEncodePacked ||
_functionType->kind() == FunctionType::Kind::ABIEncodeWithSelector ||
_functionType->kind() == FunctionType::Kind::ABIEncodeCall ||
_functionType->kind() == FunctionType::Kind::ABIEncodeWithSignature,
"ABI function has unexpected FunctionType::Kind."
);
@@ -2020,6 +2021,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)
{
typeCheckABIEncodeCallFunction(_functionCall);
return;
}
// Check additional arguments for variadic functions
vector<ASTPointer<Expression const>> const& arguments = _functionCall.arguments();
for (size_t i = 0; i < arguments.size(); ++i)
@@ -2078,6 +2086,110 @@ void TypeChecker::typeCheckABIEncodeFunctions(
}
}
void TypeChecker::typeCheckABIEncodeCallFunction(FunctionCall const& _functionCall)
{
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;
}
auto const functionPointerType = dynamic_cast<FunctionTypePointer>(type(*arguments.front()));
if (!functionPointerType)
{
m_errorReporter.typeError(
5511_error,
arguments.front()->location(),
"Expected first argument to be a function pointer, not \"" +
type(*arguments.front())->canonicalName() +
"\"."
);
return;
}
if (functionPointerType->kind() != FunctionType::Kind::External)
{
string msg = "Function must be \"public\" or \"external\".";
SecondarySourceLocation ssl{};
if (functionPointerType->hasDeclaration())
{
ssl.append("Function is declared here:", functionPointerType->declaration().location());
if (functionPointerType->declaration().scope() == m_currentContract)
msg += " Did you forget to prefix \"this.\"?";
}
m_errorReporter.typeError(3509_error, arguments[0]->location(), ssl, msg);
return;
}
solAssert(!functionPointerType->takesArbitraryParameters(), "Function must have fixed parameters.");
// Tuples with only one component become that component
vector<ASTPointer<Expression const>> callArguments;
auto const* tupleType = dynamic_cast<TupleType const*>(type(*arguments[1]));
if (tupleType)
{
auto const& argumentTuple = dynamic_cast<TupleExpression const&>(*arguments[1].get());
callArguments = decltype(callArguments){argumentTuple.components().begin(), argumentTuple.components().end()};
}
else
callArguments.push_back(arguments[1]);
if (functionPointerType->parameterTypes().size() != callArguments.size())
{
if (tupleType)
m_errorReporter.typeError(
7788_error,
_functionCall.location(),
"Expected " +
to_string(functionPointerType->parameterTypes().size()) +
" instead of " +
to_string(callArguments.size()) +
" components for the tuple parameter."
);
else
m_errorReporter.typeError(
7515_error,
_functionCall.location(),
"Expected a tuple with " +
to_string(functionPointerType->parameterTypes().size()) +
" components instead of a single non-tuple parameter."
);
}
// Use min() to check as much as we can before failing fatally
size_t const numParameters = min(callArguments.size(), functionPointerType->parameterTypes().size());
for (size_t i = 0; i < numParameters; i++)
{
Type const& argType = *type(*callArguments[i]);
BoolResult result = argType.isImplicitlyConvertibleTo(*functionPointerType->parameterTypes()[i]);
if (!result)
m_errorReporter.typeError(
5407_error,
callArguments[i]->location(),
"Cannot implicitly convert component at position " +
to_string(i) +
" from \"" +
argType.canonicalName() +
"\" to \"" +
functionPointerType->parameterTypes()[i]->canonicalName() +
"\"" +
(result.message().empty() ? "." : ": " + result.message())
);
}
}
void TypeChecker::typeCheckBytesConcatFunction(
FunctionCall const& _functionCall,
FunctionType const* _functionType
@@ -2507,6 +2619,7 @@ bool TypeChecker::visit(FunctionCall const& _functionCall)
case FunctionType::Kind::ABIEncodePacked:
case FunctionType::Kind::ABIEncodeWithSelector:
case FunctionType::Kind::ABIEncodeWithSignature:
case FunctionType::Kind::ABIEncodeCall:
{
typeCheckABIEncodeFunctions(_functionCall, functionType);
returnTypes = functionType->returnParameterTypes();
+3
View File
@@ -110,6 +110,9 @@ private:
FunctionTypePointer _functionType
);
/// Performs checks specific to the ABI encode functions of type ABIEncodeCall
void typeCheckABIEncodeCallFunction(FunctionCall const& _functionCall);
/// Performs general checks and checks specific to bytes concat function call
void typeCheckBytesConcatFunction(
FunctionCall const& _functionCall,
+1
View File
@@ -367,6 +367,7 @@ void ViewPureChecker::endVisit(MemberAccess const& _memberAccess)
{MagicType::Kind::ABI, "encode"},
{MagicType::Kind::ABI, "encodePacked"},
{MagicType::Kind::ABI, "encodeWithSelector"},
{MagicType::Kind::ABI, "encodeCall"},
{MagicType::Kind::ABI, "encodeWithSignature"},
{MagicType::Kind::Message, "data"},
{MagicType::Kind::Message, "sig"},