Merge pull request #4895 from ethereum/abidecodesingle

Fix abi.decode returning single value.
This commit is contained in:
chriseth 2018-09-04 23:47:56 +02:00 committed by GitHub
commit e6aa15bae1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 37 additions and 21 deletions

View File

@ -525,7 +525,7 @@ void TypeChecker::checkDoubleStorageAssignment(Assignment const& _assignment)
);
}
TypePointer TypeChecker::typeCheckABIDecodeAndRetrieveReturnType(FunctionCall const& _functionCall, bool _abiEncoderV2)
TypePointers TypeChecker::typeCheckABIDecodeAndRetrieveReturnType(FunctionCall const& _functionCall, bool _abiEncoderV2)
{
vector<ASTPointer<Expression const>> arguments = _functionCall.arguments();
if (arguments.size() != 2)
@ -544,10 +544,8 @@ TypePointer TypeChecker::typeCheckABIDecodeAndRetrieveReturnType(FunctionCall co
" to bytes memory requested."
);
TypePointer returnType = make_shared<TupleType>();
if (arguments.size() < 2)
return returnType;
return {};
// The following is a rather syntactic restriction, but we check it here anyway:
// The second argument has to be a tuple expression containing type names.
@ -558,10 +556,10 @@ TypePointer TypeChecker::typeCheckABIDecodeAndRetrieveReturnType(FunctionCall co
arguments[1]->location(),
"The second argument to \"abi.decode\" has to be a tuple of types."
);
return returnType;
return {};
}
vector<TypePointer> components;
TypePointers components;
for (auto const& typeArgument: tupleExpression->components())
{
solAssert(typeArgument, "");
@ -591,7 +589,7 @@ TypePointer TypeChecker::typeCheckABIDecodeAndRetrieveReturnType(FunctionCall co
components.push_back(make_shared<TupleType>());
}
}
return make_shared<TupleType>(components);
return components;
}
void TypeChecker::endVisit(InheritanceSpecifier const& _inheritance)
@ -1782,15 +1780,6 @@ bool TypeChecker::visit(FunctionCall const& _functionCall)
if (functionType->kind() == FunctionType::Kind::BareStaticCall && !m_evmVersion.hasStaticCall())
m_errorReporter.typeError(_functionCall.location(), "\"staticcall\" is not supported by the VM version.");
auto returnTypes =
allowDynamicTypes ?
functionType->returnParameterTypes() :
functionType->returnParameterTypesWithoutDynamicTypes();
if (returnTypes.size() == 1)
_functionCall.annotation().type = returnTypes.front();
else
_functionCall.annotation().type = make_shared<TupleType>(returnTypes);
if (auto functionName = dynamic_cast<Identifier const*>(&_functionCall.expression()))
{
if (functionName->name() == "sha3" && functionType->kind() == FunctionType::Kind::KECCAK256)
@ -1826,8 +1815,14 @@ bool TypeChecker::visit(FunctionCall const& _functionCall)
bool const abiEncoderV2 = m_scope->sourceUnit().annotation().experimentalFeatures.count(ExperimentalFeature::ABIEncoderV2);
// Will be assigned to .type at the end (turning multi-elements into a tuple).
TypePointers returnTypes =
allowDynamicTypes ?
functionType->returnParameterTypes() :
functionType->returnParameterTypesWithoutDynamicTypes();
if (functionType->kind() == FunctionType::Kind::ABIDecode)
_functionCall.annotation().type = typeCheckABIDecodeAndRetrieveReturnType(_functionCall, abiEncoderV2);
returnTypes = typeCheckABIDecodeAndRetrieveReturnType(_functionCall, abiEncoderV2);
else if (functionType->takesArbitraryParameters() && arguments.size() < parameterTypes.size())
{
solAssert(_functionCall.annotation().kind == FunctionCallKind::FunctionCall, "");
@ -1985,6 +1980,11 @@ bool TypeChecker::visit(FunctionCall const& _functionCall)
}
}
if (returnTypes.size() == 1)
_functionCall.annotation().type = returnTypes.front();
else
_functionCall.annotation().type = make_shared<TupleType>(returnTypes);
return false;
}

View File

@ -92,9 +92,9 @@ private:
void checkExpressionAssignment(Type const& _type, Expression const& _expression);
/// Performs type checks for ``abi.decode(bytes memory, (...))`` and returns the
/// return type (which is basically the second argument) if successful. It returns
/// the empty tuple type or error.
TypePointer typeCheckABIDecodeAndRetrieveReturnType(FunctionCall const& _functionCall, bool _abiEncoderV2);
/// vector of return types (which is basically the second argument) if successful. It returns
/// the empty vector on error.
TypePointers typeCheckABIDecodeAndRetrieveReturnType(FunctionCall const& _functionCall, bool _abiEncoderV2);
virtual void endVisit(InheritanceSpecifier const& _inheritance) override;
virtual void endVisit(UsingForDirective const& _usingFor) override;

View File

@ -1074,7 +1074,11 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall)
{
arguments.front()->accept(*this);
TypePointer firstArgType = arguments.front()->annotation().type;
TypePointers const& targetTypes = dynamic_cast<TupleType const&>(*_functionCall.annotation().type).components();
TypePointers targetTypes;
if (TupleType const* targetTupleType = dynamic_cast<TupleType const*>(_functionCall.annotation().type.get()))
targetTypes = targetTupleType->components();
else
targetTypes = TypePointers{_functionCall.annotation().type};
if (
*firstArgType == ArrayType(DataLocation::CallData) ||
*firstArgType == ArrayType(DataLocation::CallData, true)

View File

@ -0,0 +1,7 @@
contract C {
function f() public pure {
abi.decode("abc", ());
}
}
// ----
// Warning: (52-73): Statement has no effect.

View File

@ -0,0 +1,5 @@
contract C {
function f() public pure returns (bool) {
return abi.decode("abc", (uint)) == 2;
}
}