aboutsummaryrefslogtreecommitdiffstats
path: root/libsolidity/analysis
diff options
context:
space:
mode:
authorDaniel Kirchner <daniel@ekpyron.org>2018-09-05 23:59:55 +0800
committerDaniel Kirchner <daniel@ekpyron.org>2018-09-13 21:15:49 +0800
commit12aaca16458861e9b622818d49a82c1a7026594e (patch)
tree7b51c4893c6646134618b6c20574317ec014f225 /libsolidity/analysis
parent9214c7c34f5e4501a50cb29de964bbf04131f9a3 (diff)
downloaddexon-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.cpp4
-rw-r--r--libsolidity/analysis/ReferencesResolver.cpp18
-rw-r--r--libsolidity/analysis/TypeChecker.cpp48
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