mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Function types.
This commit is contained in:
parent
c811691861
commit
cc8583ec7d
@ -83,6 +83,23 @@ void ReferencesResolver::endVisit(UserDefinedTypeName const& _typeName)
|
|||||||
fatalTypeError(_typeName.location(), "Name has to refer to a struct, enum or contract.");
|
fatalTypeError(_typeName.location(), "Name has to refer to a struct, enum or contract.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ReferencesResolver::endVisit(FunctionTypeName const& _typeName)
|
||||||
|
{
|
||||||
|
switch (_typeName.visibility())
|
||||||
|
{
|
||||||
|
case VariableDeclaration::Visibility::Default:
|
||||||
|
case VariableDeclaration::Visibility::Internal:
|
||||||
|
case VariableDeclaration::Visibility::External:
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
typeError(_typeName.location(), "Invalid visibility, can only be \"external\" or \"internal\".");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Do we allow storage references for external functions?
|
||||||
|
|
||||||
|
_typeName.annotation().type = make_shared<FunctionType>(_typeName);
|
||||||
|
}
|
||||||
|
|
||||||
void ReferencesResolver::endVisit(Mapping const& _typeName)
|
void ReferencesResolver::endVisit(Mapping const& _typeName)
|
||||||
{
|
{
|
||||||
TypePointer keyType = _typeName.keyType().annotation().type;
|
TypePointer keyType = _typeName.keyType().annotation().type;
|
||||||
|
@ -62,6 +62,7 @@ private:
|
|||||||
virtual bool visit(Identifier const& _identifier) override;
|
virtual bool visit(Identifier const& _identifier) override;
|
||||||
virtual bool visit(ElementaryTypeName const& _typeName) override;
|
virtual bool visit(ElementaryTypeName const& _typeName) override;
|
||||||
virtual void endVisit(UserDefinedTypeName const& _typeName) override;
|
virtual void endVisit(UserDefinedTypeName const& _typeName) override;
|
||||||
|
virtual void endVisit(FunctionTypeName const& _typeName) override;
|
||||||
virtual void endVisit(Mapping const& _typeName) override;
|
virtual void endVisit(Mapping const& _typeName) override;
|
||||||
virtual void endVisit(ArrayTypeName const& _typeName) override;
|
virtual void endVisit(ArrayTypeName const& _typeName) override;
|
||||||
virtual bool visit(InlineAssembly const& _inlineAssembly) override;
|
virtual bool visit(InlineAssembly const& _inlineAssembly) override;
|
||||||
|
@ -822,6 +822,41 @@ private:
|
|||||||
std::vector<ASTString> m_namePath;
|
std::vector<ASTString> m_namePath;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A literal function type. Its source form is "function (paramType1, paramType2) internal / external returns (retType1, retType2)"
|
||||||
|
*/
|
||||||
|
class FunctionTypeName: public TypeName
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
FunctionTypeName(
|
||||||
|
SourceLocation const& _location,
|
||||||
|
ASTPointer<ParameterList> const& _parameterTypes,
|
||||||
|
ASTPointer<ParameterList> const& _returnTypes,
|
||||||
|
Declaration::Visibility _visibility,
|
||||||
|
bool _isDeclaredConst,
|
||||||
|
bool _isPayable
|
||||||
|
):
|
||||||
|
TypeName(_location), m_parameterTypes(_parameterTypes), m_returnTypes(_returnTypes),
|
||||||
|
m_visibility(_visibility), m_isDeclaredConst(_isDeclaredConst), m_isPayable(_isPayable)
|
||||||
|
{}
|
||||||
|
virtual void accept(ASTVisitor& _visitor) override;
|
||||||
|
virtual void accept(ASTConstVisitor& _visitor) const override;
|
||||||
|
|
||||||
|
std::vector<ASTPointer<VariableDeclaration>> const& parameterTypes() const { return m_parameterTypes->parameters(); }
|
||||||
|
std::vector<ASTPointer<VariableDeclaration>> const& returnParameterTypes() const { return m_returnTypes->parameters(); }
|
||||||
|
|
||||||
|
Declaration::Visibility visibility() const { return m_visibility; }
|
||||||
|
bool isDeclaredConst() const { return m_isDeclaredConst; }
|
||||||
|
bool isPayable() const { return m_isPayable; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
ASTPointer<ParameterList> m_parameterTypes;
|
||||||
|
ASTPointer<ParameterList> m_returnTypes;
|
||||||
|
Declaration::Visibility m_visibility;
|
||||||
|
bool m_isDeclaredConst;
|
||||||
|
bool m_isPayable;
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A mapping type. Its source form is "mapping('keyType' => 'valueType')"
|
* A mapping type. Its source form is "mapping('keyType' => 'valueType')"
|
||||||
*/
|
*/
|
||||||
|
@ -54,6 +54,7 @@ class MagicVariableDeclaration;
|
|||||||
class TypeName;
|
class TypeName;
|
||||||
class ElementaryTypeName;
|
class ElementaryTypeName;
|
||||||
class UserDefinedTypeName;
|
class UserDefinedTypeName;
|
||||||
|
class FunctionTypeName;
|
||||||
class Mapping;
|
class Mapping;
|
||||||
class ArrayTypeName;
|
class ArrayTypeName;
|
||||||
class Statement;
|
class Statement;
|
||||||
|
@ -226,6 +226,15 @@ bool ASTJsonConverter::visit(UserDefinedTypeName const& _node)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool ASTJsonConverter::visit(FunctionTypeName const& _node)
|
||||||
|
{
|
||||||
|
addJsonNode(_node, "FunctionTypeName", {
|
||||||
|
make_pair("payable", _node.isPayable()),
|
||||||
|
make_pair("constant", _node.isDeclaredConst())
|
||||||
|
});
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
bool ASTJsonConverter::visit(Mapping const& _node)
|
bool ASTJsonConverter::visit(Mapping const& _node)
|
||||||
{
|
{
|
||||||
addJsonNode(_node, "Mapping", {}, true);
|
addJsonNode(_node, "Mapping", {}, true);
|
||||||
@ -507,6 +516,11 @@ void ASTJsonConverter::endVisit(UserDefinedTypeName const&)
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ASTJsonConverter::endVisit(FunctionTypeName const&)
|
||||||
|
{
|
||||||
|
goUp();
|
||||||
|
}
|
||||||
|
|
||||||
void ASTJsonConverter::endVisit(Mapping const&)
|
void ASTJsonConverter::endVisit(Mapping const&)
|
||||||
{
|
{
|
||||||
goUp();
|
goUp();
|
||||||
|
@ -69,6 +69,7 @@ public:
|
|||||||
bool visit(TypeName const& _node) override;
|
bool visit(TypeName const& _node) override;
|
||||||
bool visit(ElementaryTypeName const& _node) override;
|
bool visit(ElementaryTypeName const& _node) override;
|
||||||
bool visit(UserDefinedTypeName const& _node) override;
|
bool visit(UserDefinedTypeName const& _node) override;
|
||||||
|
bool visit(FunctionTypeName const& _node) override;
|
||||||
bool visit(Mapping const& _node) override;
|
bool visit(Mapping const& _node) override;
|
||||||
bool visit(ArrayTypeName const& _node) override;
|
bool visit(ArrayTypeName const& _node) override;
|
||||||
bool visit(InlineAssembly const& _node) override;
|
bool visit(InlineAssembly const& _node) override;
|
||||||
@ -114,6 +115,7 @@ public:
|
|||||||
void endVisit(TypeName const&) override;
|
void endVisit(TypeName const&) override;
|
||||||
void endVisit(ElementaryTypeName const&) override;
|
void endVisit(ElementaryTypeName const&) override;
|
||||||
void endVisit(UserDefinedTypeName const&) override;
|
void endVisit(UserDefinedTypeName const&) override;
|
||||||
|
void endVisit(FunctionTypeName const&) override;
|
||||||
void endVisit(Mapping const&) override;
|
void endVisit(Mapping const&) override;
|
||||||
void endVisit(ArrayTypeName const&) override;
|
void endVisit(ArrayTypeName const&) override;
|
||||||
void endVisit(InlineAssembly const&) override;
|
void endVisit(InlineAssembly const&) override;
|
||||||
|
@ -164,6 +164,13 @@ bool ASTPrinter::visit(UserDefinedTypeName const& _node)
|
|||||||
return goDeeper();
|
return goDeeper();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool ASTPrinter::visit(FunctionTypeName const& _node)
|
||||||
|
{
|
||||||
|
writeLine("FunctionTypeName");
|
||||||
|
printSourcePart(_node);
|
||||||
|
return goDeeper();
|
||||||
|
}
|
||||||
|
|
||||||
bool ASTPrinter::visit(Mapping const& _node)
|
bool ASTPrinter::visit(Mapping const& _node)
|
||||||
{
|
{
|
||||||
writeLine("Mapping");
|
writeLine("Mapping");
|
||||||
@ -442,6 +449,11 @@ void ASTPrinter::endVisit(UserDefinedTypeName const&)
|
|||||||
m_indentation--;
|
m_indentation--;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ASTPrinter::endVisit(FunctionTypeName const&)
|
||||||
|
{
|
||||||
|
m_indentation--;
|
||||||
|
}
|
||||||
|
|
||||||
void ASTPrinter::endVisit(Mapping const&)
|
void ASTPrinter::endVisit(Mapping const&)
|
||||||
{
|
{
|
||||||
m_indentation--;
|
m_indentation--;
|
||||||
|
@ -63,6 +63,7 @@ public:
|
|||||||
bool visit(TypeName const& _node) override;
|
bool visit(TypeName const& _node) override;
|
||||||
bool visit(ElementaryTypeName const& _node) override;
|
bool visit(ElementaryTypeName const& _node) override;
|
||||||
bool visit(UserDefinedTypeName const& _node) override;
|
bool visit(UserDefinedTypeName const& _node) override;
|
||||||
|
bool visit(FunctionTypeName const& _node) override;
|
||||||
bool visit(Mapping const& _node) override;
|
bool visit(Mapping const& _node) override;
|
||||||
bool visit(ArrayTypeName const& _node) override;
|
bool visit(ArrayTypeName const& _node) override;
|
||||||
bool visit(InlineAssembly const& _node) override;
|
bool visit(InlineAssembly const& _node) override;
|
||||||
@ -106,6 +107,7 @@ public:
|
|||||||
void endVisit(TypeName const&) override;
|
void endVisit(TypeName const&) override;
|
||||||
void endVisit(ElementaryTypeName const&) override;
|
void endVisit(ElementaryTypeName const&) override;
|
||||||
void endVisit(UserDefinedTypeName const&) override;
|
void endVisit(UserDefinedTypeName const&) override;
|
||||||
|
void endVisit(FunctionTypeName const&) override;
|
||||||
void endVisit(Mapping const&) override;
|
void endVisit(Mapping const&) override;
|
||||||
void endVisit(ArrayTypeName const&) override;
|
void endVisit(ArrayTypeName const&) override;
|
||||||
void endVisit(InlineAssembly const&) override;
|
void endVisit(InlineAssembly const&) override;
|
||||||
|
@ -61,6 +61,7 @@ public:
|
|||||||
virtual bool visit(TypeName& _node) { return visitNode(_node); }
|
virtual bool visit(TypeName& _node) { return visitNode(_node); }
|
||||||
virtual bool visit(ElementaryTypeName& _node) { return visitNode(_node); }
|
virtual bool visit(ElementaryTypeName& _node) { return visitNode(_node); }
|
||||||
virtual bool visit(UserDefinedTypeName& _node) { return visitNode(_node); }
|
virtual bool visit(UserDefinedTypeName& _node) { return visitNode(_node); }
|
||||||
|
virtual bool visit(FunctionTypeName& _node) { return visitNode(_node); }
|
||||||
virtual bool visit(Mapping& _node) { return visitNode(_node); }
|
virtual bool visit(Mapping& _node) { return visitNode(_node); }
|
||||||
virtual bool visit(ArrayTypeName& _node) { return visitNode(_node); }
|
virtual bool visit(ArrayTypeName& _node) { return visitNode(_node); }
|
||||||
virtual bool visit(InlineAssembly& _node) { return visitNode(_node); }
|
virtual bool visit(InlineAssembly& _node) { return visitNode(_node); }
|
||||||
@ -106,6 +107,7 @@ public:
|
|||||||
virtual void endVisit(TypeName& _node) { endVisitNode(_node); }
|
virtual void endVisit(TypeName& _node) { endVisitNode(_node); }
|
||||||
virtual void endVisit(ElementaryTypeName& _node) { endVisitNode(_node); }
|
virtual void endVisit(ElementaryTypeName& _node) { endVisitNode(_node); }
|
||||||
virtual void endVisit(UserDefinedTypeName& _node) { endVisitNode(_node); }
|
virtual void endVisit(UserDefinedTypeName& _node) { endVisitNode(_node); }
|
||||||
|
virtual void endVisit(FunctionTypeName& _node) { endVisitNode(_node); }
|
||||||
virtual void endVisit(Mapping& _node) { endVisitNode(_node); }
|
virtual void endVisit(Mapping& _node) { endVisitNode(_node); }
|
||||||
virtual void endVisit(ArrayTypeName& _node) { endVisitNode(_node); }
|
virtual void endVisit(ArrayTypeName& _node) { endVisitNode(_node); }
|
||||||
virtual void endVisit(InlineAssembly& _node) { endVisitNode(_node); }
|
virtual void endVisit(InlineAssembly& _node) { endVisitNode(_node); }
|
||||||
@ -163,6 +165,7 @@ public:
|
|||||||
virtual bool visit(TypeName const& _node) { return visitNode(_node); }
|
virtual bool visit(TypeName const& _node) { return visitNode(_node); }
|
||||||
virtual bool visit(ElementaryTypeName const& _node) { return visitNode(_node); }
|
virtual bool visit(ElementaryTypeName const& _node) { return visitNode(_node); }
|
||||||
virtual bool visit(UserDefinedTypeName const& _node) { return visitNode(_node); }
|
virtual bool visit(UserDefinedTypeName const& _node) { return visitNode(_node); }
|
||||||
|
virtual bool visit(FunctionTypeName const& _node) { return visitNode(_node); }
|
||||||
virtual bool visit(Mapping const& _node) { return visitNode(_node); }
|
virtual bool visit(Mapping const& _node) { return visitNode(_node); }
|
||||||
virtual bool visit(ArrayTypeName const& _node) { return visitNode(_node); }
|
virtual bool visit(ArrayTypeName const& _node) { return visitNode(_node); }
|
||||||
virtual bool visit(Block const& _node) { return visitNode(_node); }
|
virtual bool visit(Block const& _node) { return visitNode(_node); }
|
||||||
@ -208,6 +211,7 @@ public:
|
|||||||
virtual void endVisit(TypeName const& _node) { endVisitNode(_node); }
|
virtual void endVisit(TypeName const& _node) { endVisitNode(_node); }
|
||||||
virtual void endVisit(ElementaryTypeName const& _node) { endVisitNode(_node); }
|
virtual void endVisit(ElementaryTypeName const& _node) { endVisitNode(_node); }
|
||||||
virtual void endVisit(UserDefinedTypeName const& _node) { endVisitNode(_node); }
|
virtual void endVisit(UserDefinedTypeName const& _node) { endVisitNode(_node); }
|
||||||
|
virtual void endVisit(FunctionTypeName const& _node) { endVisitNode(_node); }
|
||||||
virtual void endVisit(Mapping const& _node) { endVisitNode(_node); }
|
virtual void endVisit(Mapping const& _node) { endVisitNode(_node); }
|
||||||
virtual void endVisit(ArrayTypeName const& _node) { endVisitNode(_node); }
|
virtual void endVisit(ArrayTypeName const& _node) { endVisitNode(_node); }
|
||||||
virtual void endVisit(Block const& _node) { endVisitNode(_node); }
|
virtual void endVisit(Block const& _node) { endVisitNode(_node); }
|
||||||
|
@ -327,6 +327,26 @@ void UserDefinedTypeName::accept(ASTConstVisitor& _visitor) const
|
|||||||
_visitor.endVisit(*this);
|
_visitor.endVisit(*this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void FunctionTypeName::accept(ASTVisitor& _visitor)
|
||||||
|
{
|
||||||
|
if (_visitor.visit(*this))
|
||||||
|
{
|
||||||
|
m_parameterTypes->accept(_visitor);
|
||||||
|
m_returnTypes->accept(_visitor);
|
||||||
|
}
|
||||||
|
_visitor.endVisit(*this);
|
||||||
|
}
|
||||||
|
|
||||||
|
void FunctionTypeName::accept(ASTConstVisitor& _visitor) const
|
||||||
|
{
|
||||||
|
if (_visitor.visit(*this))
|
||||||
|
{
|
||||||
|
m_parameterTypes->accept(_visitor);
|
||||||
|
m_returnTypes->accept(_visitor);
|
||||||
|
}
|
||||||
|
_visitor.endVisit(*this);
|
||||||
|
}
|
||||||
|
|
||||||
void Mapping::accept(ASTVisitor& _visitor)
|
void Mapping::accept(ASTVisitor& _visitor)
|
||||||
{
|
{
|
||||||
if (_visitor.visit(*this))
|
if (_visitor.visit(*this))
|
||||||
|
@ -1805,6 +1805,23 @@ FunctionType::FunctionType(EventDefinition const& _event):
|
|||||||
swap(paramNames, m_parameterNames);
|
swap(paramNames, m_parameterNames);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
FunctionType::FunctionType(FunctionTypeName const& _typeName):
|
||||||
|
m_location(_typeName.visibility() == VariableDeclaration::Visibility::External ? Location::External : Location::Internal),
|
||||||
|
m_isConstant(_typeName.isDeclaredConst()),
|
||||||
|
m_isPayable(_typeName.isPayable())
|
||||||
|
{
|
||||||
|
for (auto const& t: _typeName.parameterTypes())
|
||||||
|
{
|
||||||
|
solAssert(t->annotation().type, "Type not set for parameter.");
|
||||||
|
m_parameterTypes.push_back(t->annotation().type);
|
||||||
|
}
|
||||||
|
for (auto const& t: _typeName.returnParameterTypes())
|
||||||
|
{
|
||||||
|
solAssert(t->annotation().type, "Type not set for return parameter.");
|
||||||
|
m_returnParameterTypes.push_back(t->annotation().type);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
FunctionTypePointer FunctionType::newExpressionType(ContractDefinition const& _contract)
|
FunctionTypePointer FunctionType::newExpressionType(ContractDefinition const& _contract)
|
||||||
{
|
{
|
||||||
FunctionDefinition const* constructor = _contract.constructor();
|
FunctionDefinition const* constructor = _contract.constructor();
|
||||||
@ -1885,14 +1902,44 @@ string FunctionType::toString(bool _short) const
|
|||||||
string name = "function (";
|
string name = "function (";
|
||||||
for (auto it = m_parameterTypes.begin(); it != m_parameterTypes.end(); ++it)
|
for (auto it = m_parameterTypes.begin(); it != m_parameterTypes.end(); ++it)
|
||||||
name += (*it)->toString(_short) + (it + 1 == m_parameterTypes.end() ? "" : ",");
|
name += (*it)->toString(_short) + (it + 1 == m_parameterTypes.end() ? "" : ",");
|
||||||
name += ") returns (";
|
name += ") ";
|
||||||
|
if (m_isConstant)
|
||||||
|
name += "constant ";
|
||||||
|
if (m_isPayable)
|
||||||
|
name += "payable ";
|
||||||
|
if (m_location == Location::External)
|
||||||
|
name += "external ";
|
||||||
|
name += "returns (";
|
||||||
for (auto it = m_returnParameterTypes.begin(); it != m_returnParameterTypes.end(); ++it)
|
for (auto it = m_returnParameterTypes.begin(); it != m_returnParameterTypes.end(); ++it)
|
||||||
name += (*it)->toString(_short) + (it + 1 == m_returnParameterTypes.end() ? "" : ",");
|
name += (*it)->toString(_short) + (it + 1 == m_returnParameterTypes.end() ? "" : ",");
|
||||||
return name + ")";
|
return name + ")";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
unsigned FunctionType::calldataEncodedSize(bool _padded) const
|
||||||
|
{
|
||||||
|
unsigned size = storageBytes();
|
||||||
|
if (_padded)
|
||||||
|
size = ((size + 31) / 32) * 32;
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
|
||||||
u256 FunctionType::storageSize() const
|
u256 FunctionType::storageSize() const
|
||||||
{
|
{
|
||||||
|
if (m_location == Location::External || m_location == Location::Internal)
|
||||||
|
return 1;
|
||||||
|
else
|
||||||
|
BOOST_THROW_EXCEPTION(
|
||||||
|
InternalCompilerError()
|
||||||
|
<< errinfo_comment("Storage size of non-storable function type requested."));
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned FunctionType::storageBytes() const
|
||||||
|
{
|
||||||
|
if (m_location == Location::External)
|
||||||
|
return 20 + 4;
|
||||||
|
else if (m_location == Location::Internal)
|
||||||
|
return 8; // it should really not be possible to create larger programs
|
||||||
|
else
|
||||||
BOOST_THROW_EXCEPTION(
|
BOOST_THROW_EXCEPTION(
|
||||||
InternalCompilerError()
|
InternalCompilerError()
|
||||||
<< errinfo_comment("Storage size of non-storable function type requested."));
|
<< errinfo_comment("Storage size of non-storable function type requested."));
|
||||||
@ -2018,6 +2065,16 @@ MemberList::MemberMap FunctionType::nativeMembers(ContractDefinition const*) con
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TypePointer FunctionType::interfaceType(bool _inLibrary) const
|
||||||
|
{
|
||||||
|
if (m_location != Location::External && m_location != Location::Internal)
|
||||||
|
return TypePointer();
|
||||||
|
if (_inLibrary)
|
||||||
|
return shared_from_this();
|
||||||
|
else
|
||||||
|
return make_shared<FixedBytesType>(storageBytes());
|
||||||
|
}
|
||||||
|
|
||||||
bool FunctionType::canTakeArguments(TypePointers const& _argumentTypes, TypePointer const& _selfType) const
|
bool FunctionType::canTakeArguments(TypePointers const& _argumentTypes, TypePointer const& _selfType) const
|
||||||
{
|
{
|
||||||
solAssert(!bound() || _selfType, "");
|
solAssert(!bound() || _selfType, "");
|
||||||
|
@ -821,6 +821,8 @@ public:
|
|||||||
explicit FunctionType(VariableDeclaration const& _varDecl);
|
explicit FunctionType(VariableDeclaration const& _varDecl);
|
||||||
/// Creates the function type of an event.
|
/// Creates the function type of an event.
|
||||||
explicit FunctionType(EventDefinition const& _event);
|
explicit FunctionType(EventDefinition const& _event);
|
||||||
|
/// Creates the type of a function type name.
|
||||||
|
explicit FunctionType(FunctionTypeName const& _typeName);
|
||||||
/// Function type constructor to be used for a plain type (not derived from a declaration).
|
/// Function type constructor to be used for a plain type (not derived from a declaration).
|
||||||
FunctionType(
|
FunctionType(
|
||||||
strings const& _parameterTypes,
|
strings const& _parameterTypes,
|
||||||
@ -891,11 +893,15 @@ public:
|
|||||||
|
|
||||||
virtual bool operator==(Type const& _other) const override;
|
virtual bool operator==(Type const& _other) const override;
|
||||||
virtual std::string toString(bool _short) const override;
|
virtual std::string toString(bool _short) const override;
|
||||||
virtual bool canBeStored() const override { return false; }
|
virtual unsigned calldataEncodedSize(bool _padded) const override;
|
||||||
|
virtual bool canBeStored() const override { return m_location == Location::Internal || m_location == Location::External; }
|
||||||
virtual u256 storageSize() const override;
|
virtual u256 storageSize() const override;
|
||||||
virtual bool canLiveOutsideStorage() const override { return false; }
|
virtual unsigned storageBytes() const override;
|
||||||
|
virtual bool isValueType() const override { return true; }
|
||||||
|
virtual bool canLiveOutsideStorage() const override { return m_location == Location::Internal || m_location == Location::External; }
|
||||||
virtual unsigned sizeOnStack() const override;
|
virtual unsigned sizeOnStack() const override;
|
||||||
virtual MemberList::MemberMap nativeMembers(ContractDefinition const* _currentScope) const override;
|
virtual MemberList::MemberMap nativeMembers(ContractDefinition const* _currentScope) const override;
|
||||||
|
virtual TypePointer interfaceType(bool _inLibrary) const override;
|
||||||
|
|
||||||
/// @returns TypePointer of a new FunctionType object. All input/return parameters are an
|
/// @returns TypePointer of a new FunctionType object. All input/return parameters are an
|
||||||
/// appropriate external types (i.e. the interfaceType()s) of input/return parameters of
|
/// appropriate external types (i.e. the interfaceType()s) of input/return parameters of
|
||||||
|
@ -288,6 +288,52 @@ Declaration::Visibility Parser::parseVisibilitySpecifier(Token::Value _token)
|
|||||||
return visibility;
|
return visibility;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Parser::FunctionHeaderParserResult Parser::parseFunctionHeader(bool _forceEmptyName, bool _allowModifiers)
|
||||||
|
{
|
||||||
|
FunctionHeaderParserResult result;
|
||||||
|
expectToken(Token::Function);
|
||||||
|
if (_forceEmptyName || m_scanner->currentToken() == Token::LParen)
|
||||||
|
result.name = make_shared<ASTString>(); // anonymous function
|
||||||
|
else
|
||||||
|
result.name = expectIdentifierToken();
|
||||||
|
VarDeclParserOptions options;
|
||||||
|
options.allowLocationSpecifier = true;
|
||||||
|
result.parameters = parseParameterList(options);
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
Token::Value token = m_scanner->currentToken();
|
||||||
|
if (token == Token::Const)
|
||||||
|
{
|
||||||
|
result.isDeclaredConst = true;
|
||||||
|
m_scanner->next();
|
||||||
|
}
|
||||||
|
else if (m_scanner->currentToken() == Token::Payable)
|
||||||
|
{
|
||||||
|
result.isPayable = true;
|
||||||
|
m_scanner->next();
|
||||||
|
}
|
||||||
|
else if (_allowModifiers && token == Token::Identifier)
|
||||||
|
result.modifiers.push_back(parseModifierInvocation());
|
||||||
|
else if (Token::isVisibilitySpecifier(token))
|
||||||
|
{
|
||||||
|
if (result.visibility != Declaration::Visibility::Default)
|
||||||
|
fatalParserError(string("Multiple visibility specifiers."));
|
||||||
|
result.visibility = parseVisibilitySpecifier(token);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (m_scanner->currentToken() == Token::Returns)
|
||||||
|
{
|
||||||
|
bool const permitEmptyParameterList = false;
|
||||||
|
m_scanner->next();
|
||||||
|
result.returnParameters = parseParameterList(options, permitEmptyParameterList);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
result.returnParameters = createEmptyParameterList();
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
ASTPointer<FunctionDefinition> Parser::parseFunctionDefinition(ASTString const* _contractName)
|
ASTPointer<FunctionDefinition> Parser::parseFunctionDefinition(ASTString const* _contractName)
|
||||||
{
|
{
|
||||||
ASTNodeFactory nodeFactory(*this);
|
ASTNodeFactory nodeFactory(*this);
|
||||||
@ -295,52 +341,8 @@ ASTPointer<FunctionDefinition> Parser::parseFunctionDefinition(ASTString const*
|
|||||||
if (m_scanner->currentCommentLiteral() != "")
|
if (m_scanner->currentCommentLiteral() != "")
|
||||||
docstring = make_shared<ASTString>(m_scanner->currentCommentLiteral());
|
docstring = make_shared<ASTString>(m_scanner->currentCommentLiteral());
|
||||||
|
|
||||||
expectToken(Token::Function);
|
FunctionHeaderParserResult header = parseFunctionHeader(false, true);
|
||||||
ASTPointer<ASTString> name;
|
|
||||||
if (m_scanner->currentToken() == Token::LParen)
|
|
||||||
name = make_shared<ASTString>(); // anonymous function
|
|
||||||
else
|
|
||||||
name = expectIdentifierToken();
|
|
||||||
VarDeclParserOptions options;
|
|
||||||
options.allowLocationSpecifier = true;
|
|
||||||
ASTPointer<ParameterList> parameters(parseParameterList(options));
|
|
||||||
bool isDeclaredConst = false;
|
|
||||||
bool isPayable = false;
|
|
||||||
Declaration::Visibility visibility(Declaration::Visibility::Default);
|
|
||||||
vector<ASTPointer<ModifierInvocation>> modifiers;
|
|
||||||
while (true)
|
|
||||||
{
|
|
||||||
Token::Value token = m_scanner->currentToken();
|
|
||||||
if (token == Token::Const)
|
|
||||||
{
|
|
||||||
isDeclaredConst = true;
|
|
||||||
m_scanner->next();
|
|
||||||
}
|
|
||||||
else if (m_scanner->currentToken() == Token::Payable)
|
|
||||||
{
|
|
||||||
isPayable = true;
|
|
||||||
m_scanner->next();
|
|
||||||
}
|
|
||||||
else if (token == Token::Identifier)
|
|
||||||
modifiers.push_back(parseModifierInvocation());
|
|
||||||
else if (Token::isVisibilitySpecifier(token))
|
|
||||||
{
|
|
||||||
if (visibility != Declaration::Visibility::Default)
|
|
||||||
fatalParserError(string("Multiple visibility specifiers."));
|
|
||||||
visibility = parseVisibilitySpecifier(token);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
ASTPointer<ParameterList> returnParameters;
|
|
||||||
if (m_scanner->currentToken() == Token::Returns)
|
|
||||||
{
|
|
||||||
bool const permitEmptyParameterList = false;
|
|
||||||
m_scanner->next();
|
|
||||||
returnParameters = parseParameterList(options, permitEmptyParameterList);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
returnParameters = createEmptyParameterList();
|
|
||||||
ASTPointer<Block> block = ASTPointer<Block>();
|
ASTPointer<Block> block = ASTPointer<Block>();
|
||||||
nodeFactory.markEndPosition();
|
nodeFactory.markEndPosition();
|
||||||
if (m_scanner->currentToken() != Token::Semicolon)
|
if (m_scanner->currentToken() != Token::Semicolon)
|
||||||
@ -350,17 +352,17 @@ ASTPointer<FunctionDefinition> Parser::parseFunctionDefinition(ASTString const*
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
m_scanner->next(); // just consume the ';'
|
m_scanner->next(); // just consume the ';'
|
||||||
bool const c_isConstructor = (_contractName && *name == *_contractName);
|
bool const c_isConstructor = (_contractName && *header.name == *_contractName);
|
||||||
return nodeFactory.createNode<FunctionDefinition>(
|
return nodeFactory.createNode<FunctionDefinition>(
|
||||||
name,
|
header.name,
|
||||||
visibility,
|
header.visibility,
|
||||||
c_isConstructor,
|
c_isConstructor,
|
||||||
docstring,
|
docstring,
|
||||||
parameters,
|
header.parameters,
|
||||||
isDeclaredConst,
|
header.isDeclaredConst,
|
||||||
modifiers,
|
header.modifiers,
|
||||||
returnParameters,
|
header.returnParameters,
|
||||||
isPayable,
|
header.isPayable,
|
||||||
block
|
block
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -631,6 +633,8 @@ ASTPointer<TypeName> Parser::parseTypeName(bool _allowVar)
|
|||||||
fatalParserError(string("Expected explicit type name."));
|
fatalParserError(string("Expected explicit type name."));
|
||||||
m_scanner->next();
|
m_scanner->next();
|
||||||
}
|
}
|
||||||
|
else if (token == Token::Function)
|
||||||
|
type = parseFunctionType();
|
||||||
else if (token == Token::Mapping)
|
else if (token == Token::Mapping)
|
||||||
type = parseMapping();
|
type = parseMapping();
|
||||||
else if (token == Token::Identifier)
|
else if (token == Token::Identifier)
|
||||||
@ -653,6 +657,19 @@ ASTPointer<TypeName> Parser::parseTypeName(bool _allowVar)
|
|||||||
return type;
|
return type;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ASTPointer<FunctionTypeName> Parser::parseFunctionType()
|
||||||
|
{
|
||||||
|
ASTNodeFactory nodeFactory(*this);
|
||||||
|
FunctionHeaderParserResult header = parseFunctionHeader(true, false);
|
||||||
|
return nodeFactory.createNode<FunctionTypeName>(
|
||||||
|
header.parameters,
|
||||||
|
header.returnParameters,
|
||||||
|
header.visibility,
|
||||||
|
header.isDeclaredConst,
|
||||||
|
header.isPayable
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
ASTPointer<Mapping> Parser::parseMapping()
|
ASTPointer<Mapping> Parser::parseMapping()
|
||||||
{
|
{
|
||||||
ASTNodeFactory nodeFactory(*this);
|
ASTNodeFactory nodeFactory(*this);
|
||||||
@ -1278,7 +1295,7 @@ Parser::LookAheadInfo Parser::peekStatementType() const
|
|||||||
Token::Value token(m_scanner->currentToken());
|
Token::Value token(m_scanner->currentToken());
|
||||||
bool mightBeTypeName = (Token::isElementaryTypeName(token) || token == Token::Identifier);
|
bool mightBeTypeName = (Token::isElementaryTypeName(token) || token == Token::Identifier);
|
||||||
|
|
||||||
if (token == Token::Mapping || token == Token::Var)
|
if (token == Token::Mapping || token == Token::Function || token == Token::Var)
|
||||||
return LookAheadInfo::VariableDeclarationStatement;
|
return LookAheadInfo::VariableDeclarationStatement;
|
||||||
if (mightBeTypeName)
|
if (mightBeTypeName)
|
||||||
{
|
{
|
||||||
|
@ -53,6 +53,18 @@ private:
|
|||||||
bool allowLocationSpecifier = false;
|
bool allowLocationSpecifier = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/// This struct is shared for parsing a function header and a function type.
|
||||||
|
struct FunctionHeaderParserResult
|
||||||
|
{
|
||||||
|
ASTPointer<ASTString> name;
|
||||||
|
ASTPointer<ParameterList> parameters;
|
||||||
|
ASTPointer<ParameterList> returnParameters;
|
||||||
|
Declaration::Visibility visibility = Declaration::Visibility::Default;
|
||||||
|
bool isDeclaredConst = false;
|
||||||
|
bool isPayable = false;
|
||||||
|
std::vector<ASTPointer<ModifierInvocation>> modifiers;
|
||||||
|
};
|
||||||
|
|
||||||
///@{
|
///@{
|
||||||
///@name Parsing functions for the AST nodes
|
///@name Parsing functions for the AST nodes
|
||||||
ASTPointer<PragmaDirective> parsePragmaDirective();
|
ASTPointer<PragmaDirective> parsePragmaDirective();
|
||||||
@ -60,6 +72,7 @@ private:
|
|||||||
ASTPointer<ContractDefinition> parseContractDefinition(bool _isLibrary);
|
ASTPointer<ContractDefinition> parseContractDefinition(bool _isLibrary);
|
||||||
ASTPointer<InheritanceSpecifier> parseInheritanceSpecifier();
|
ASTPointer<InheritanceSpecifier> parseInheritanceSpecifier();
|
||||||
Declaration::Visibility parseVisibilitySpecifier(Token::Value _token);
|
Declaration::Visibility parseVisibilitySpecifier(Token::Value _token);
|
||||||
|
FunctionHeaderParserResult parseFunctionHeader(bool _forceEmptyName, bool _allowModifiers);
|
||||||
ASTPointer<FunctionDefinition> parseFunctionDefinition(ASTString const* _contractName);
|
ASTPointer<FunctionDefinition> parseFunctionDefinition(ASTString const* _contractName);
|
||||||
ASTPointer<StructDefinition> parseStructDefinition();
|
ASTPointer<StructDefinition> parseStructDefinition();
|
||||||
ASTPointer<EnumDefinition> parseEnumDefinition();
|
ASTPointer<EnumDefinition> parseEnumDefinition();
|
||||||
@ -75,6 +88,7 @@ private:
|
|||||||
ASTPointer<Identifier> parseIdentifier();
|
ASTPointer<Identifier> parseIdentifier();
|
||||||
ASTPointer<UserDefinedTypeName> parseUserDefinedTypeName();
|
ASTPointer<UserDefinedTypeName> parseUserDefinedTypeName();
|
||||||
ASTPointer<TypeName> parseTypeName(bool _allowVar);
|
ASTPointer<TypeName> parseTypeName(bool _allowVar);
|
||||||
|
ASTPointer<FunctionTypeName> parseFunctionType();
|
||||||
ASTPointer<Mapping> parseMapping();
|
ASTPointer<Mapping> parseMapping();
|
||||||
ASTPointer<ParameterList> parseParameterList(
|
ASTPointer<ParameterList> parseParameterList(
|
||||||
VarDeclParserOptions const& _options,
|
VarDeclParserOptions const& _options,
|
||||||
|
@ -7606,6 +7606,24 @@ BOOST_AUTO_TEST_CASE(mem_resize_is_not_paid_at_call)
|
|||||||
BOOST_CHECK(callContractFunction("f(address)", cAddrOpt) == encodeArgs(u256(7)));
|
BOOST_CHECK(callContractFunction("f(address)", cAddrOpt) == encodeArgs(u256(7)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
BOOST_AUTO_TEST_CASE(pass_function_types_internally)
|
||||||
|
{
|
||||||
|
char const* sourceCode = R"(
|
||||||
|
contract C {
|
||||||
|
function f(uint x) returns (uint) {
|
||||||
|
return eval(g, x);
|
||||||
|
}
|
||||||
|
function eval(function(uint) returns (uint) x, uint a) returns (uint) {
|
||||||
|
return x(a);
|
||||||
|
}
|
||||||
|
function g(uint x) returns (uint) { return x + 1; }
|
||||||
|
}
|
||||||
|
)";
|
||||||
|
|
||||||
|
compileAndRun(sourceCode, 0, "C");
|
||||||
|
BOOST_CHECK(callContractFunction("f(uint256)", 7) == encodeArgs(u256(8)));
|
||||||
|
}
|
||||||
|
|
||||||
BOOST_AUTO_TEST_CASE(shift_constant_left)
|
BOOST_AUTO_TEST_CASE(shift_constant_left)
|
||||||
{
|
{
|
||||||
char const* sourceCode = R"(
|
char const* sourceCode = R"(
|
||||||
|
@ -4132,6 +4132,55 @@ BOOST_AUTO_TEST_CASE(using_directive_for_missing_selftype)
|
|||||||
BOOST_CHECK(expectError(text, false) == Error::Type::TypeError);
|
BOOST_CHECK(expectError(text, false) == Error::Type::TypeError);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
BOOST_AUTO_TEST_CASE(function_type)
|
||||||
|
{
|
||||||
|
char const* text = R"(
|
||||||
|
contract C {
|
||||||
|
function f() {
|
||||||
|
function(uint) returns (uint) x;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)";
|
||||||
|
BOOST_CHECK(success(text));
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOST_AUTO_TEST_CASE(function_type_parameter)
|
||||||
|
{
|
||||||
|
char const* text = R"(
|
||||||
|
contract C {
|
||||||
|
function f(function(uint) returns (uint) g) returns (function(uint) returns (uint)) {
|
||||||
|
return g;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)";
|
||||||
|
BOOST_CHECK(success(text));
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOST_AUTO_TEST_CASE(private_function_type)
|
||||||
|
{
|
||||||
|
char const* text = R"(
|
||||||
|
contract C {
|
||||||
|
function f() {
|
||||||
|
function(uint) private returns (uint) x;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)";
|
||||||
|
BOOST_CHECK(expectError(text) == Error::Type::TypeError);
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOST_AUTO_TEST_CASE(public_function_type)
|
||||||
|
{
|
||||||
|
char const* text = R"(
|
||||||
|
contract C {
|
||||||
|
function f() {
|
||||||
|
function(uint) public returns (uint) x;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)";
|
||||||
|
BOOST_CHECK(expectError(text) == Error::Type::TypeError);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
BOOST_AUTO_TEST_CASE(invalid_fixed_point_literal)
|
BOOST_AUTO_TEST_CASE(invalid_fixed_point_literal)
|
||||||
{
|
{
|
||||||
char const* text = R"(
|
char const* text = R"(
|
||||||
|
@ -1241,6 +1241,57 @@ BOOST_AUTO_TEST_CASE(payable_accessor)
|
|||||||
BOOST_CHECK(!successParse(text));
|
BOOST_CHECK(!successParse(text));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
BOOST_AUTO_TEST_CASE(function_type_in_expression)
|
||||||
|
{
|
||||||
|
char const* text = R"(
|
||||||
|
contract test {
|
||||||
|
function f(uint x, uint y) returns (uint a) {}
|
||||||
|
function g() {
|
||||||
|
function (uint, uint) internal returns (uint) f1 = f;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)";
|
||||||
|
BOOST_CHECK(successParse(text));
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOST_AUTO_TEST_CASE(function_type_as_storage_variable)
|
||||||
|
{
|
||||||
|
// TODO disambiguate from fallback function
|
||||||
|
char const* text = R"(
|
||||||
|
contract test {
|
||||||
|
function f(uint x, uint y) returns (uint a) {}
|
||||||
|
function (uint, uint) internal returns (uint) f1 = f;
|
||||||
|
}
|
||||||
|
)";
|
||||||
|
BOOST_CHECK(successParse(text));
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOST_AUTO_TEST_CASE(function_type_in_struct)
|
||||||
|
{
|
||||||
|
char const* text = R"(
|
||||||
|
contract test {
|
||||||
|
struct S {
|
||||||
|
function (uint x, uint y) internal returns (uint a) f;
|
||||||
|
function (uint, uint) external returns (uint) g;
|
||||||
|
uint d;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)";
|
||||||
|
BOOST_CHECK(successParse(text));
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOST_AUTO_TEST_CASE(function_type_as_parameter)
|
||||||
|
{
|
||||||
|
char const* text = R"(
|
||||||
|
contract test {
|
||||||
|
function f(function(uint) external returns (uint) g) internal returns (uint a) {
|
||||||
|
return g(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)";
|
||||||
|
BOOST_CHECK(successParse(text));
|
||||||
|
}
|
||||||
|
|
||||||
BOOST_AUTO_TEST_SUITE_END()
|
BOOST_AUTO_TEST_SUITE_END()
|
||||||
|
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user