mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Merge pull request #4895 from ethereum/abidecodesingle
Fix abi.decode returning single value.
This commit is contained in:
commit
e6aa15bae1
@ -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();
|
vector<ASTPointer<Expression const>> arguments = _functionCall.arguments();
|
||||||
if (arguments.size() != 2)
|
if (arguments.size() != 2)
|
||||||
@ -544,10 +544,8 @@ TypePointer TypeChecker::typeCheckABIDecodeAndRetrieveReturnType(FunctionCall co
|
|||||||
" to bytes memory requested."
|
" to bytes memory requested."
|
||||||
);
|
);
|
||||||
|
|
||||||
TypePointer returnType = make_shared<TupleType>();
|
|
||||||
|
|
||||||
if (arguments.size() < 2)
|
if (arguments.size() < 2)
|
||||||
return returnType;
|
return {};
|
||||||
|
|
||||||
// The following is a rather syntactic restriction, but we check it here anyway:
|
// 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.
|
// The second argument has to be a tuple expression containing type names.
|
||||||
@ -558,10 +556,10 @@ TypePointer TypeChecker::typeCheckABIDecodeAndRetrieveReturnType(FunctionCall co
|
|||||||
arguments[1]->location(),
|
arguments[1]->location(),
|
||||||
"The second argument to \"abi.decode\" has to be a tuple of types."
|
"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())
|
for (auto const& typeArgument: tupleExpression->components())
|
||||||
{
|
{
|
||||||
solAssert(typeArgument, "");
|
solAssert(typeArgument, "");
|
||||||
@ -591,7 +589,7 @@ TypePointer TypeChecker::typeCheckABIDecodeAndRetrieveReturnType(FunctionCall co
|
|||||||
components.push_back(make_shared<TupleType>());
|
components.push_back(make_shared<TupleType>());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return make_shared<TupleType>(components);
|
return components;
|
||||||
}
|
}
|
||||||
|
|
||||||
void TypeChecker::endVisit(InheritanceSpecifier const& _inheritance)
|
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())
|
if (functionType->kind() == FunctionType::Kind::BareStaticCall && !m_evmVersion.hasStaticCall())
|
||||||
m_errorReporter.typeError(_functionCall.location(), "\"staticcall\" is not supported by the VM version.");
|
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 (auto functionName = dynamic_cast<Identifier const*>(&_functionCall.expression()))
|
||||||
{
|
{
|
||||||
if (functionName->name() == "sha3" && functionType->kind() == FunctionType::Kind::KECCAK256)
|
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);
|
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)
|
if (functionType->kind() == FunctionType::Kind::ABIDecode)
|
||||||
_functionCall.annotation().type = typeCheckABIDecodeAndRetrieveReturnType(_functionCall, abiEncoderV2);
|
returnTypes = typeCheckABIDecodeAndRetrieveReturnType(_functionCall, abiEncoderV2);
|
||||||
else if (functionType->takesArbitraryParameters() && arguments.size() < parameterTypes.size())
|
else if (functionType->takesArbitraryParameters() && arguments.size() < parameterTypes.size())
|
||||||
{
|
{
|
||||||
solAssert(_functionCall.annotation().kind == FunctionCallKind::FunctionCall, "");
|
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;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -92,9 +92,9 @@ private:
|
|||||||
void checkExpressionAssignment(Type const& _type, Expression const& _expression);
|
void checkExpressionAssignment(Type const& _type, Expression const& _expression);
|
||||||
|
|
||||||
/// Performs type checks for ``abi.decode(bytes memory, (...))`` and returns the
|
/// Performs type checks for ``abi.decode(bytes memory, (...))`` and returns the
|
||||||
/// return type (which is basically the second argument) if successful. It returns
|
/// vector of return types (which is basically the second argument) if successful. It returns
|
||||||
/// the empty tuple type or error.
|
/// the empty vector on error.
|
||||||
TypePointer typeCheckABIDecodeAndRetrieveReturnType(FunctionCall const& _functionCall, bool _abiEncoderV2);
|
TypePointers typeCheckABIDecodeAndRetrieveReturnType(FunctionCall const& _functionCall, bool _abiEncoderV2);
|
||||||
|
|
||||||
virtual void endVisit(InheritanceSpecifier const& _inheritance) override;
|
virtual void endVisit(InheritanceSpecifier const& _inheritance) override;
|
||||||
virtual void endVisit(UsingForDirective const& _usingFor) override;
|
virtual void endVisit(UsingForDirective const& _usingFor) override;
|
||||||
|
@ -1074,7 +1074,11 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall)
|
|||||||
{
|
{
|
||||||
arguments.front()->accept(*this);
|
arguments.front()->accept(*this);
|
||||||
TypePointer firstArgType = arguments.front()->annotation().type;
|
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 (
|
if (
|
||||||
*firstArgType == ArrayType(DataLocation::CallData) ||
|
*firstArgType == ArrayType(DataLocation::CallData) ||
|
||||||
*firstArgType == ArrayType(DataLocation::CallData, true)
|
*firstArgType == ArrayType(DataLocation::CallData, true)
|
||||||
|
@ -0,0 +1,7 @@
|
|||||||
|
contract C {
|
||||||
|
function f() public pure {
|
||||||
|
abi.decode("abc", ());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// ----
|
||||||
|
// Warning: (52-73): Statement has no effect.
|
@ -0,0 +1,5 @@
|
|||||||
|
contract C {
|
||||||
|
function f() public pure returns (bool) {
|
||||||
|
return abi.decode("abc", (uint)) == 2;
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user