mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Accept `address payable` during parsing.
This commit is contained in:
@@ -112,7 +112,20 @@ bool ReferencesResolver::visit(Identifier const& _identifier)
|
||||
|
||||
bool ReferencesResolver::visit(ElementaryTypeName const& _typeName)
|
||||
{
|
||||
_typeName.annotation().type = Type::fromElementaryTypeName(_typeName.typeName());
|
||||
if (!_typeName.annotation().type)
|
||||
{
|
||||
_typeName.annotation().type = Type::fromElementaryTypeName(_typeName.typeName());
|
||||
if (_typeName.stateMutability().is_initialized())
|
||||
{
|
||||
// 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.");
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
+13
-5
@@ -876,23 +876,31 @@ public:
|
||||
};
|
||||
|
||||
/**
|
||||
* Any pre-defined type name represented by a single keyword, i.e. it excludes mappings,
|
||||
* contracts, functions, etc.
|
||||
* Any pre-defined type name represented by a single keyword (and possibly a state mutability for address types),
|
||||
* i.e. it excludes mappings, contracts, functions, etc.
|
||||
*/
|
||||
class ElementaryTypeName: public TypeName
|
||||
{
|
||||
public:
|
||||
ElementaryTypeName(SourceLocation const& _location, ElementaryTypeNameToken const& _elem):
|
||||
TypeName(_location), m_type(_elem)
|
||||
{}
|
||||
ElementaryTypeName(
|
||||
SourceLocation const& _location,
|
||||
ElementaryTypeNameToken const& _elem,
|
||||
boost::optional<StateMutability> _stateMutability = {}
|
||||
): TypeName(_location), m_type(_elem), m_stateMutability(_stateMutability)
|
||||
{
|
||||
solAssert(!_stateMutability.is_initialized() || _elem.token() == Token::Address, "");
|
||||
}
|
||||
|
||||
virtual void accept(ASTVisitor& _visitor) override;
|
||||
virtual void accept(ASTConstVisitor& _visitor) const override;
|
||||
|
||||
ElementaryTypeNameToken const& typeName() const { return m_type; }
|
||||
|
||||
boost::optional<StateMutability> const& stateMutability() const { return m_stateMutability; }
|
||||
|
||||
private:
|
||||
ElementaryTypeNameToken m_type;
|
||||
boost::optional<StateMutability> m_stateMutability; ///< state mutability for address type
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@@ -57,7 +57,7 @@ public:
|
||||
solAssert(m_location.sourceName, "");
|
||||
if (m_location.end < 0)
|
||||
markEndPosition();
|
||||
return make_shared<NodeType>(m_location, forward<Args>(_args)...);
|
||||
return make_shared<NodeType>(m_location, std::forward<Args>(_args)...);
|
||||
}
|
||||
|
||||
private:
|
||||
@@ -813,8 +813,24 @@ ASTPointer<TypeName> Parser::parseTypeName(bool _allowVar)
|
||||
unsigned secondSize;
|
||||
tie(firstSize, secondSize) = m_scanner->currentTokenInfo();
|
||||
ElementaryTypeNameToken elemTypeName(token, firstSize, secondSize);
|
||||
type = ASTNodeFactory(*this).createNode<ElementaryTypeName>(elemTypeName);
|
||||
ASTNodeFactory nodeFactory(*this);
|
||||
nodeFactory.markEndPosition();
|
||||
m_scanner->next();
|
||||
auto stateMutability = boost::make_optional(elemTypeName.token() == Token::Address, StateMutability::NonPayable);
|
||||
if (Token::isStateMutabilitySpecifier(m_scanner->currentToken(), false))
|
||||
{
|
||||
if (elemTypeName.token() == Token::Address)
|
||||
{
|
||||
nodeFactory.markEndPosition();
|
||||
stateMutability = parseStateMutability();
|
||||
}
|
||||
else
|
||||
{
|
||||
parserError("State mutability can only be specified for address types.");
|
||||
m_scanner->next();
|
||||
}
|
||||
}
|
||||
type = nodeFactory.createNode<ElementaryTypeName>(elemTypeName, stateMutability);
|
||||
}
|
||||
else if (token == Token::Var)
|
||||
{
|
||||
@@ -1615,8 +1631,8 @@ Parser::LookAheadInfo Parser::peekStatementType() const
|
||||
// Distinguish between variable declaration (and potentially assignment) and expression statement
|
||||
// (which include assignments to other expressions and pre-declared variables).
|
||||
// We have a variable declaration if we get a keyword that specifies a type name.
|
||||
// If it is an identifier or an elementary type name followed by an identifier, we also have
|
||||
// a variable declaration.
|
||||
// If it is an identifier or an elementary type name followed by an identifier
|
||||
// or a mutability specifier, we also have a variable declaration.
|
||||
// If we get an identifier followed by a "[" or ".", it can be both ("lib.type[9] a;" or "variable.el[9] = 7;").
|
||||
// In all other cases, we have an expression statement.
|
||||
Token::Value token(m_scanner->currentToken());
|
||||
@@ -1627,6 +1643,12 @@ Parser::LookAheadInfo Parser::peekStatementType() const
|
||||
if (mightBeTypeName)
|
||||
{
|
||||
Token::Value next = m_scanner->peekNextToken();
|
||||
// So far we only allow ``address payable`` in variable declaration statements and in no other
|
||||
// kind of statement. This means, for example, that we do not allow type expressions of the form
|
||||
// ``address payable;``.
|
||||
// If we want to change this in the future, we need to consider another scanner token here.
|
||||
if (Token::isElementaryTypeName(token) && Token::isStateMutabilitySpecifier(next, false))
|
||||
return LookAheadInfo::VariableDeclaration;
|
||||
if (next == Token::Identifier || Token::isLocationSpecifier(next))
|
||||
return LookAheadInfo::VariableDeclaration;
|
||||
if (next == Token::LBrack || next == Token::Period)
|
||||
|
||||
@@ -312,7 +312,12 @@ public:
|
||||
static bool isVisibilitySpecifier(Value op) { return isVariableVisibilitySpecifier(op) || op == External; }
|
||||
static bool isVariableVisibilitySpecifier(Value op) { return op == Public || op == Private || op == Internal; }
|
||||
static bool isLocationSpecifier(Value op) { return op == Memory || op == Storage || op == CallData; }
|
||||
static bool isStateMutabilitySpecifier(Value op) { return op == Pure || op == Constant || op == View || op == Payable; }
|
||||
static bool isStateMutabilitySpecifier(Value op, bool _allowConstant = true)
|
||||
{
|
||||
if (op == Constant && _allowConstant)
|
||||
return true;
|
||||
return op == Pure || op == View || op == Payable;
|
||||
}
|
||||
static bool isEtherSubdenomination(Value op) { return op == SubWei || op == SubSzabo || op == SubFinney || op == SubEther; }
|
||||
static bool isTimeSubdenomination(Value op) { return op == SubSecond || op == SubMinute || op == SubHour || op == SubDay || op == SubWeek || op == SubYear; }
|
||||
static bool isReservedKeyword(Value op) { return (Abstract <= op && op <= Unchecked); }
|
||||
|
||||
Reference in New Issue
Block a user