Merge pull request #5978 from ethereum/fix-broken-hint

Fix error msg hint for non-payable contracts
This commit is contained in:
chriseth 2019-02-18 11:49:07 +01:00 committed by GitHub
commit db7b38e3c4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 41 additions and 32 deletions

View File

@ -2051,20 +2051,18 @@ bool TypeChecker::visit(MemberAccess const& _memberAccess)
errorMsg.pop_back();
errorMsg += " - did you forget the \"payable\" modifier?";
}
else if (exprType->category() == Type::Category::Function)
else if (auto const& funType = dynamic_pointer_cast<FunctionType const>(exprType))
{
if (auto const& funType = dynamic_pointer_cast<FunctionType const>(exprType))
{
auto const& t = funType->returnParameterTypes();
if (t.size() == 1)
if (
t.front()->category() == Type::Category::Contract ||
t.front()->category() == Type::Category::Struct
)
errorMsg += " Did you intend to call the function?";
}
auto const& t = funType->returnParameterTypes();
if (t.size() == 1)
if (
t.front()->category() == Type::Category::Contract ||
t.front()->category() == Type::Category::Struct
)
errorMsg += " Did you intend to call the function?";
}
if (exprType->category() == Type::Category::Contract)
else if (exprType->category() == Type::Category::Contract)
{
for (auto const& addressMember: AddressType::addressPayable().nativeMembers(nullptr))
if (addressMember.name == memberName)
{
@ -2073,6 +2071,21 @@ bool TypeChecker::visit(MemberAccess const& _memberAccess)
errorMsg += " Use \"address(" + varName + ")." + memberName + "\" to access this address member.";
break;
}
}
else if (auto addressType = dynamic_cast<AddressType const*>(exprType.get()))
{
// Trigger error when using send or transfer with a non-payable fallback function.
if (memberName == "send" || memberName == "transfer")
{
solAssert(
addressType->stateMutability() != StateMutability::Payable,
"Expected address not-payable as members were not found"
);
errorMsg = "\"send\" and \"transfer\" are only available for objects of type \"address payable\", not \"" + exprType->toString() + "\".";
}
}
m_errorReporter.fatalTypeError(
_memberAccess.location(),
errorMsg
@ -2115,26 +2128,6 @@ bool TypeChecker::visit(MemberAccess const& _memberAccess)
annotation.isLValue = annotation.referencedDeclaration->isLValue();
}
if (exprType->category() == Type::Category::Contract)
{
// Warn about using send or transfer with a non-payable fallback function.
if (auto callType = dynamic_cast<FunctionType const*>(type(_memberAccess).get()))
{
auto kind = callType->kind();
auto contractType = dynamic_cast<ContractType const*>(exprType.get());
solAssert(!!contractType, "Should be contract type.");
if (
(kind == FunctionType::Kind::Send || kind == FunctionType::Kind::Transfer) &&
!contractType->isPayable()
)
m_errorReporter.typeError(
_memberAccess.location(),
"Value transfer to a contract without a payable fallback function."
);
}
}
// TODO some members might be pure, but for example `address(0x123).balance` is not pure
// although every subexpression is, so leaving this limited for now.
if (auto tt = dynamic_cast<TypeType const*>(exprType.get()))

View File

@ -0,0 +1,8 @@
contract C {
function f() public {
address(this).send(10);
}
}
// ----
// TypeError: (47-65): "send" and "transfer" are only available for objects of type "address payable", not "address".

View File

@ -0,0 +1,8 @@
contract C {
function f() public {
address(this).transfer(10);
}
}
// ----
// TypeError: (47-69): "send" and "transfer" are only available for objects of type "address payable", not "address".