diff options
author | Daniel Kirchner <daniel@ekpyron.org> | 2018-09-05 23:59:55 +0800 |
---|---|---|
committer | Daniel Kirchner <daniel@ekpyron.org> | 2018-09-13 21:15:49 +0800 |
commit | 12aaca16458861e9b622818d49a82c1a7026594e (patch) | |
tree | 7b51c4893c6646134618b6c20574317ec014f225 /libsolidity/analysis | |
parent | 9214c7c34f5e4501a50cb29de964bbf04131f9a3 (diff) | |
download | dexon-solidity-12aaca16458861e9b622818d49a82c1a7026594e.tar.gz dexon-solidity-12aaca16458861e9b622818d49a82c1a7026594e.tar.zst dexon-solidity-12aaca16458861e9b622818d49a82c1a7026594e.zip |
Add payable and non-payable state mutability to AddressType.
Diffstat (limited to 'libsolidity/analysis')
-rw-r--r-- | libsolidity/analysis/GlobalContext.cpp | 4 | ||||
-rw-r--r-- | libsolidity/analysis/ReferencesResolver.cpp | 18 | ||||
-rw-r--r-- | libsolidity/analysis/TypeChecker.cpp | 48 |
3 files changed, 53 insertions, 17 deletions
diff --git a/libsolidity/analysis/GlobalContext.cpp b/libsolidity/analysis/GlobalContext.cpp index 3ac8fd47..cba2655c 100644 --- a/libsolidity/analysis/GlobalContext.cpp +++ b/libsolidity/analysis/GlobalContext.cpp @@ -56,10 +56,10 @@ m_magicVariables(vector<shared_ptr<MagicVariableDeclaration const>>{ make_shared<MagicVariableDeclaration>("revert", make_shared<FunctionType>(strings(), strings(), FunctionType::Kind::Revert, false, StateMutability::Pure)), make_shared<MagicVariableDeclaration>("revert", make_shared<FunctionType>(strings{"string memory"}, strings(), FunctionType::Kind::Revert, false, StateMutability::Pure)), make_shared<MagicVariableDeclaration>("ripemd160", make_shared<FunctionType>(strings{"bytes memory"}, strings{"bytes20"}, FunctionType::Kind::RIPEMD160, false, StateMutability::Pure)), - make_shared<MagicVariableDeclaration>("selfdestruct", make_shared<FunctionType>(strings{"address"}, strings{}, FunctionType::Kind::Selfdestruct)), + make_shared<MagicVariableDeclaration>("selfdestruct", make_shared<FunctionType>(strings{"address payable"}, strings{}, FunctionType::Kind::Selfdestruct)), make_shared<MagicVariableDeclaration>("sha256", make_shared<FunctionType>(strings{"bytes memory"}, strings{"bytes32"}, FunctionType::Kind::SHA256, false, StateMutability::Pure)), make_shared<MagicVariableDeclaration>("sha3", make_shared<FunctionType>(strings{"bytes memory"}, strings{"bytes32"}, FunctionType::Kind::KECCAK256, false, StateMutability::Pure)), - make_shared<MagicVariableDeclaration>("suicide", make_shared<FunctionType>(strings{"address"}, strings{}, FunctionType::Kind::Selfdestruct)), + make_shared<MagicVariableDeclaration>("suicide", make_shared<FunctionType>(strings{"address payable"}, strings{}, FunctionType::Kind::Selfdestruct)), make_shared<MagicVariableDeclaration>("tx", make_shared<MagicType>(MagicType::Kind::Transaction)) }) { diff --git a/libsolidity/analysis/ReferencesResolver.cpp b/libsolidity/analysis/ReferencesResolver.cpp index 4b678c3b..8a576e2e 100644 --- a/libsolidity/analysis/ReferencesResolver.cpp +++ b/libsolidity/analysis/ReferencesResolver.cpp @@ -119,11 +119,19 @@ bool ReferencesResolver::visit(ElementaryTypeName const& _typeName) { // for non-address types this was already caught by the parser solAssert(_typeName.annotation().type->category() == Type::Category::Address, ""); - if (!( - *_typeName.stateMutability() == StateMutability::Payable || - *_typeName.stateMutability() == StateMutability::NonPayable - )) - m_errorReporter.typeError(_typeName.location(), "Address types can only be payable or non-payable."); + switch(*_typeName.stateMutability()) + { + case StateMutability::Payable: + case StateMutability::NonPayable: + _typeName.annotation().type = make_shared<AddressType>(*_typeName.stateMutability()); + break; + default: + m_errorReporter.typeError( + _typeName.location(), + "Address types can only be payable or non-payable." + ); + break; + } } } return true; diff --git a/libsolidity/analysis/TypeChecker.cpp b/libsolidity/analysis/TypeChecker.cpp index 143ac109..e023dc38 100644 --- a/libsolidity/analysis/TypeChecker.cpp +++ b/libsolidity/analysis/TypeChecker.cpp @@ -571,6 +571,9 @@ TypePointers TypeChecker::typeCheckABIDecodeAndRetrieveReturnType(FunctionCall c // data locations. Furthermore, storage can be a little dangerous and // calldata is not really implemented anyway. actualType = ReferenceType::copyForLocationIfReference(DataLocation::Memory, actualType); + // We force address payable for address types. + if (actualType->category() == Type::Category::Address) + actualType = make_shared<AddressType>(StateMutability::Payable); solAssert( !actualType->dataStoredIn(DataLocation::CallData) && !actualType->dataStoredIn(DataLocation::Storage), @@ -1732,14 +1735,39 @@ bool TypeChecker::visit(FunctionCall const& _functionCall) dataLoc = argRefType->location(); resultType = ReferenceType::copyForLocationIfReference(dataLoc, resultType); if (!argType->isExplicitlyConvertibleTo(*resultType)) - m_errorReporter.typeError( - _functionCall.location(), - "Explicit type conversion not allowed from \"" + - argType->toString() + - "\" to \"" + - resultType->toString() + - "\"." - ); + { + if (resultType->category() == Type::Category::Contract && argType->category() == Type::Category::Address) + { + solAssert(dynamic_cast<ContractType const*>(resultType.get())->isPayable(), ""); + solAssert(dynamic_cast<AddressType const*>(argType.get())->stateMutability() < StateMutability::Payable, ""); + SecondarySourceLocation ssl; + if (auto const* identifier = dynamic_cast<Identifier const*>(arguments.front().get())) + if (auto const* variableDeclaration = dynamic_cast<VariableDeclaration const*>(identifier->annotation().referencedDeclaration)) + ssl.append("Did you mean to declare this variable as \"address payable\"?", variableDeclaration->location()); + m_errorReporter.typeError( + _functionCall.location(), ssl, + "Explicit type conversion not allowed from non-payable \"address\" to \"" + + resultType->toString() + + "\", which has a payable fallback function." + ); + } + else + m_errorReporter.typeError( + _functionCall.location(), + "Explicit type conversion not allowed from \"" + + argType->toString() + + "\" to \"" + + resultType->toString() + + "\"." + ); + } + if (resultType->category() == Type::Category::Address) + { + bool payable = true; + if (auto const* contractType = dynamic_cast<ContractType const*>(argType.get())) + payable = contractType->isPayable(); + resultType = make_shared<AddressType>(payable ? StateMutability::Payable : StateMutability::NonPayable); + } } _functionCall.annotation().type = resultType; _functionCall.annotation().isPure = isPure; @@ -2103,7 +2131,7 @@ bool TypeChecker::visit(MemberAccess const& _memberAccess) "after argument-dependent lookup in " + exprType->toString() + (memberName == "value" ? " - did you forget the \"payable\" modifier?" : "."); if (exprType->category() == Type::Category::Contract) - for (auto const& addressMember: AddressType().nativeMembers(nullptr)) + for (auto const& addressMember: AddressType(StateMutability::Payable).nativeMembers(nullptr)) if (addressMember.name == memberName) { Identifier const* var = dynamic_cast<Identifier const*>(&_memberAccess.expression()); @@ -2354,7 +2382,7 @@ void TypeChecker::endVisit(Literal const& _literal) if (_literal.looksLikeAddress()) { // Assign type here if it even looks like an address. This prevents double errors for invalid addresses - _literal.annotation().type = make_shared<AddressType>(); + _literal.annotation().type = make_shared<AddressType>(StateMutability::Payable); string msg; if (_literal.value().length() != 42) // "0x" + 40 hex digits |