Allow explicit conversion from address to address payable

This commit is contained in:
Leonardo Alt
2019-09-09 23:46:00 +02:00
parent b6b2a3b8be
commit 5cfe0b7670
23 changed files with 248 additions and 172 deletions
+9 -6
View File
@@ -1527,11 +1527,14 @@ TypePointer TypeChecker::typeCheckTypeConversionAndRetrieveReturnType(
"\"."
);
}
if (resultType->category() == Type::Category::Address)
{
bool const payable = argType->isExplicitlyConvertibleTo(*TypeProvider::payableAddress());
resultType = payable ? TypeProvider::payableAddress() : TypeProvider::address();
}
if (auto addressType = dynamic_cast<AddressType const*>(resultType))
if (addressType->stateMutability() != StateMutability::Payable)
{
bool payable = false;
if (argType->category() != Type::Category::Address)
payable = argType->isExplicitlyConvertibleTo(*TypeProvider::payableAddress());
resultType = payable ? TypeProvider::payableAddress() : TypeProvider::address();
}
}
return resultType;
}
@@ -2423,7 +2426,7 @@ bool TypeChecker::visit(Identifier const& _identifier)
void TypeChecker::endVisit(ElementaryTypeNameExpression const& _expr)
{
_expr.annotation().type = TypeProvider::typeType(TypeProvider::fromElementaryTypeName(_expr.typeName()));
_expr.annotation().type = TypeProvider::typeType(TypeProvider::fromElementaryTypeName(_expr.type().typeName(), _expr.type().stateMutability()));
_expr.annotation().isPure = true;
}
+10 -5
View File
@@ -1682,16 +1682,21 @@ private:
class ElementaryTypeNameExpression: public PrimaryExpression
{
public:
ElementaryTypeNameExpression(SourceLocation const& _location, ElementaryTypeNameToken const& _type):
PrimaryExpression(_location), m_typeToken(_type)
{}
ElementaryTypeNameExpression(
SourceLocation const& _location,
ASTPointer<ElementaryTypeName> const& _type
):
PrimaryExpression(_location),
m_type(_type)
{
}
void accept(ASTVisitor& _visitor) override;
void accept(ASTConstVisitor& _visitor) const override;
ElementaryTypeNameToken const& typeName() const { return m_typeToken; }
ElementaryTypeName const& type() const { return *m_type; }
private:
ElementaryTypeNameToken m_typeToken;
ASTPointer<ElementaryTypeName> m_type;
};
/**
+1 -1
View File
@@ -712,7 +712,7 @@ bool ASTJsonConverter::visit(Identifier const& _node)
bool ASTJsonConverter::visit(ElementaryTypeNameExpression const& _node)
{
std::vector<pair<string, Json::Value>> attributes = {
make_pair(m_legacy ? "value" : "typeName", _node.typeName().toString())
make_pair(m_legacy ? "value" : "typeName", _node.type().typeName().toString())
};
appendExpressionAttributes(attributes, _node.annotation());
setJsonNode(_node, "ElementaryTypeNameExpression", std::move(attributes));
+8 -1
View File
@@ -200,7 +200,7 @@ inline T const* TypeProvider::createAndGet(Args&& ... _args)
return static_cast<T const*>(instance().m_generalTypes.back().get());
}
Type const* TypeProvider::fromElementaryTypeName(ElementaryTypeNameToken const& _type)
Type const* TypeProvider::fromElementaryTypeName(ElementaryTypeNameToken const& _type, boost::optional<StateMutability> _stateMutability)
{
solAssert(
TokenTraits::isElementaryTypeName(_type.token()),
@@ -233,7 +233,14 @@ Type const* TypeProvider::fromElementaryTypeName(ElementaryTypeNameToken const&
case Token::UFixed:
return fixedPoint(128, 18, FixedPointType::Modifier::Unsigned);
case Token::Address:
{
if (_stateMutability)
{
solAssert(*_stateMutability == StateMutability::Payable, "");
return payableAddress();
}
return address();
}
case Token::Bool:
return boolean();
case Token::Bytes:
+1 -1
View File
@@ -54,7 +54,7 @@ public:
/// @name Factory functions
/// Factory functions that convert an AST @ref TypeName to a Type.
static Type const* fromElementaryTypeName(ElementaryTypeNameToken const& _type);
static Type const* fromElementaryTypeName(ElementaryTypeNameToken const& _type, boost::optional<StateMutability> _stateMutability = {});
/// Converts a given elementary type name with optional data location
/// suffix " storage", " calldata" or " memory" to a type pointer. If suffix not given, defaults to " storage".
+3 -1
View File
@@ -412,7 +412,9 @@ BoolResult AddressType::isImplicitlyConvertibleTo(Type const& _other) const
BoolResult AddressType::isExplicitlyConvertibleTo(Type const& _convertTo) const
{
if (auto const* contractType = dynamic_cast<ContractType const*>(&_convertTo))
if (_convertTo.category() == category())
return true;
else if (auto const* contractType = dynamic_cast<ContractType const*>(&_convertTo))
return (m_stateMutability >= StateMutability::Payable) || !contractType->isPayable();
return isImplicitlyConvertibleTo(_convertTo) ||
_convertTo.category() == Category::Integer ||
+20 -5
View File
@@ -1585,6 +1585,17 @@ ASTPointer<Expression> Parser::parseLeftHandSideExpression(
nodeFactory.markEndPosition();
expression = nodeFactory.createNode<NewExpression>(typeName);
}
else if (m_scanner->currentToken() == Token::Payable)
{
expectToken(Token::Payable);
nodeFactory.markEndPosition();
auto expressionType = nodeFactory.createNode<ElementaryTypeName>(
ElementaryTypeNameToken(Token::Address, 160, 0),
boost::make_optional(StateMutability::Payable)
);
expression = nodeFactory.createNode<ElementaryTypeNameExpression>(expressionType);
expectToken(Token::LParen, false);
}
else
expression = parsePrimaryExpression();
@@ -1725,8 +1736,10 @@ ASTPointer<Expression> Parser::parsePrimaryExpression()
unsigned firstSize;
unsigned secondSize;
tie(firstSize, secondSize) = m_scanner->currentTokenInfo();
ElementaryTypeNameToken elementaryExpression(m_scanner->currentToken(), firstSize, secondSize);
expression = nodeFactory.createNode<ElementaryTypeNameExpression>(elementaryExpression);
auto expressionType = nodeFactory.createNode<ElementaryTypeName>(
ElementaryTypeNameToken(m_scanner->currentToken(), firstSize, secondSize)
);
expression = nodeFactory.createNode<ElementaryTypeNameExpression>(expressionType);
m_scanner->next();
}
else
@@ -1838,8 +1851,10 @@ Parser::IndexAccessedPath Parser::parseIndexAccessedPath()
unsigned firstNum;
unsigned secondNum;
tie(firstNum, secondNum) = m_scanner->currentTokenInfo();
ElementaryTypeNameToken elemToken(m_scanner->currentToken(), firstNum, secondNum);
iap.path.push_back(ASTNodeFactory(*this).createNode<ElementaryTypeNameExpression>(elemToken));
auto expressionType = ASTNodeFactory(*this).createNode<ElementaryTypeName>(
ElementaryTypeNameToken(m_scanner->currentToken(), firstNum, secondNum)
);
iap.path.push_back(ASTNodeFactory(*this).createNode<ElementaryTypeNameExpression>(expressionType));
m_scanner->next();
}
while (m_scanner->currentToken() == Token::LBrack)
@@ -1872,7 +1887,7 @@ ASTPointer<TypeName> Parser::typeNameFromIndexAccessStructure(Parser::IndexAcces
if (auto typeName = dynamic_cast<ElementaryTypeNameExpression const*>(_iap.path.front().get()))
{
solAssert(_iap.path.size() == 1, "");
type = nodeFactory.createNode<ElementaryTypeName>(typeName->typeName());
type = nodeFactory.createNode<ElementaryTypeName>(typeName->type().typeName());
}
else
{