mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Allow explicit conversion from address to address payable
This commit is contained in:
@@ -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
@@ -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;
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@@ -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));
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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".
|
||||
|
||||
@@ -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 ||
|
||||
|
||||
@@ -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
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user