Skip to content

Commit cc8583e

Browse files
committed
Function types.
1 parent c811691 commit cc8583e

17 files changed

+359
-39
lines changed

libsolidity/analysis/ReferencesResolver.cpp

+17
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,23 @@ void ReferencesResolver::endVisit(UserDefinedTypeName const& _typeName)
8383
fatalTypeError(_typeName.location(), "Name has to refer to a struct, enum or contract.");
8484
}
8585

86+
void ReferencesResolver::endVisit(FunctionTypeName const& _typeName)
87+
{
88+
switch (_typeName.visibility())
89+
{
90+
case VariableDeclaration::Visibility::Default:
91+
case VariableDeclaration::Visibility::Internal:
92+
case VariableDeclaration::Visibility::External:
93+
break;
94+
default:
95+
typeError(_typeName.location(), "Invalid visibility, can only be \"external\" or \"internal\".");
96+
}
97+
98+
// Do we allow storage references for external functions?
99+
100+
_typeName.annotation().type = make_shared<FunctionType>(_typeName);
101+
}
102+
86103
void ReferencesResolver::endVisit(Mapping const& _typeName)
87104
{
88105
TypePointer keyType = _typeName.keyType().annotation().type;

libsolidity/analysis/ReferencesResolver.h

+1
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@ class ReferencesResolver: private ASTConstVisitor
6262
virtual bool visit(Identifier const& _identifier) override;
6363
virtual bool visit(ElementaryTypeName const& _typeName) override;
6464
virtual void endVisit(UserDefinedTypeName const& _typeName) override;
65+
virtual void endVisit(FunctionTypeName const& _typeName) override;
6566
virtual void endVisit(Mapping const& _typeName) override;
6667
virtual void endVisit(ArrayTypeName const& _typeName) override;
6768
virtual bool visit(InlineAssembly const& _inlineAssembly) override;

libsolidity/ast/AST.h

+35
Original file line numberDiff line numberDiff line change
@@ -822,6 +822,41 @@ class UserDefinedTypeName: public TypeName
822822
std::vector<ASTString> m_namePath;
823823
};
824824

825+
/**
826+
* A literal function type. Its source form is "function (paramType1, paramType2) internal / external returns (retType1, retType2)"
827+
*/
828+
class FunctionTypeName: public TypeName
829+
{
830+
public:
831+
FunctionTypeName(
832+
SourceLocation const& _location,
833+
ASTPointer<ParameterList> const& _parameterTypes,
834+
ASTPointer<ParameterList> const& _returnTypes,
835+
Declaration::Visibility _visibility,
836+
bool _isDeclaredConst,
837+
bool _isPayable
838+
):
839+
TypeName(_location), m_parameterTypes(_parameterTypes), m_returnTypes(_returnTypes),
840+
m_visibility(_visibility), m_isDeclaredConst(_isDeclaredConst), m_isPayable(_isPayable)
841+
{}
842+
virtual void accept(ASTVisitor& _visitor) override;
843+
virtual void accept(ASTConstVisitor& _visitor) const override;
844+
845+
std::vector<ASTPointer<VariableDeclaration>> const& parameterTypes() const { return m_parameterTypes->parameters(); }
846+
std::vector<ASTPointer<VariableDeclaration>> const& returnParameterTypes() const { return m_returnTypes->parameters(); }
847+
848+
Declaration::Visibility visibility() const { return m_visibility; }
849+
bool isDeclaredConst() const { return m_isDeclaredConst; }
850+
bool isPayable() const { return m_isPayable; }
851+
852+
private:
853+
ASTPointer<ParameterList> m_parameterTypes;
854+
ASTPointer<ParameterList> m_returnTypes;
855+
Declaration::Visibility m_visibility;
856+
bool m_isDeclaredConst;
857+
bool m_isPayable;
858+
};
859+
825860
/**
826861
* A mapping type. Its source form is "mapping('keyType' => 'valueType')"
827862
*/

libsolidity/ast/ASTForward.h

+1
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ class MagicVariableDeclaration;
5454
class TypeName;
5555
class ElementaryTypeName;
5656
class UserDefinedTypeName;
57+
class FunctionTypeName;
5758
class Mapping;
5859
class ArrayTypeName;
5960
class Statement;

libsolidity/ast/ASTJsonConverter.cpp

+14
Original file line numberDiff line numberDiff line change
@@ -226,6 +226,15 @@ bool ASTJsonConverter::visit(UserDefinedTypeName const& _node)
226226
return true;
227227
}
228228

229+
bool ASTJsonConverter::visit(FunctionTypeName const& _node)
230+
{
231+
addJsonNode(_node, "FunctionTypeName", {
232+
make_pair("payable", _node.isPayable()),
233+
make_pair("constant", _node.isDeclaredConst())
234+
});
235+
return true;
236+
}
237+
229238
bool ASTJsonConverter::visit(Mapping const& _node)
230239
{
231240
addJsonNode(_node, "Mapping", {}, true);
@@ -507,6 +516,11 @@ void ASTJsonConverter::endVisit(UserDefinedTypeName const&)
507516
{
508517
}
509518

519+
void ASTJsonConverter::endVisit(FunctionTypeName const&)
520+
{
521+
goUp();
522+
}
523+
510524
void ASTJsonConverter::endVisit(Mapping const&)
511525
{
512526
goUp();

libsolidity/ast/ASTJsonConverter.h

+2
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@ class ASTJsonConverter: public ASTConstVisitor
6969
bool visit(TypeName const& _node) override;
7070
bool visit(ElementaryTypeName const& _node) override;
7171
bool visit(UserDefinedTypeName const& _node) override;
72+
bool visit(FunctionTypeName const& _node) override;
7273
bool visit(Mapping const& _node) override;
7374
bool visit(ArrayTypeName const& _node) override;
7475
bool visit(InlineAssembly const& _node) override;
@@ -114,6 +115,7 @@ class ASTJsonConverter: public ASTConstVisitor
114115
void endVisit(TypeName const&) override;
115116
void endVisit(ElementaryTypeName const&) override;
116117
void endVisit(UserDefinedTypeName const&) override;
118+
void endVisit(FunctionTypeName const&) override;
117119
void endVisit(Mapping const&) override;
118120
void endVisit(ArrayTypeName const&) override;
119121
void endVisit(InlineAssembly const&) override;

libsolidity/ast/ASTPrinter.cpp

+12
Original file line numberDiff line numberDiff line change
@@ -164,6 +164,13 @@ bool ASTPrinter::visit(UserDefinedTypeName const& _node)
164164
return goDeeper();
165165
}
166166

167+
bool ASTPrinter::visit(FunctionTypeName const& _node)
168+
{
169+
writeLine("FunctionTypeName");
170+
printSourcePart(_node);
171+
return goDeeper();
172+
}
173+
167174
bool ASTPrinter::visit(Mapping const& _node)
168175
{
169176
writeLine("Mapping");
@@ -442,6 +449,11 @@ void ASTPrinter::endVisit(UserDefinedTypeName const&)
442449
m_indentation--;
443450
}
444451

452+
void ASTPrinter::endVisit(FunctionTypeName const&)
453+
{
454+
m_indentation--;
455+
}
456+
445457
void ASTPrinter::endVisit(Mapping const&)
446458
{
447459
m_indentation--;

libsolidity/ast/ASTPrinter.h

+2
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@ class ASTPrinter: public ASTConstVisitor
6363
bool visit(TypeName const& _node) override;
6464
bool visit(ElementaryTypeName const& _node) override;
6565
bool visit(UserDefinedTypeName const& _node) override;
66+
bool visit(FunctionTypeName const& _node) override;
6667
bool visit(Mapping const& _node) override;
6768
bool visit(ArrayTypeName const& _node) override;
6869
bool visit(InlineAssembly const& _node) override;
@@ -106,6 +107,7 @@ class ASTPrinter: public ASTConstVisitor
106107
void endVisit(TypeName const&) override;
107108
void endVisit(ElementaryTypeName const&) override;
108109
void endVisit(UserDefinedTypeName const&) override;
110+
void endVisit(FunctionTypeName const&) override;
109111
void endVisit(Mapping const&) override;
110112
void endVisit(ArrayTypeName const&) override;
111113
void endVisit(InlineAssembly const&) override;

libsolidity/ast/ASTVisitor.h

+4
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@ class ASTVisitor
6161
virtual bool visit(TypeName& _node) { return visitNode(_node); }
6262
virtual bool visit(ElementaryTypeName& _node) { return visitNode(_node); }
6363
virtual bool visit(UserDefinedTypeName& _node) { return visitNode(_node); }
64+
virtual bool visit(FunctionTypeName& _node) { return visitNode(_node); }
6465
virtual bool visit(Mapping& _node) { return visitNode(_node); }
6566
virtual bool visit(ArrayTypeName& _node) { return visitNode(_node); }
6667
virtual bool visit(InlineAssembly& _node) { return visitNode(_node); }
@@ -106,6 +107,7 @@ class ASTVisitor
106107
virtual void endVisit(TypeName& _node) { endVisitNode(_node); }
107108
virtual void endVisit(ElementaryTypeName& _node) { endVisitNode(_node); }
108109
virtual void endVisit(UserDefinedTypeName& _node) { endVisitNode(_node); }
110+
virtual void endVisit(FunctionTypeName& _node) { endVisitNode(_node); }
109111
virtual void endVisit(Mapping& _node) { endVisitNode(_node); }
110112
virtual void endVisit(ArrayTypeName& _node) { endVisitNode(_node); }
111113
virtual void endVisit(InlineAssembly& _node) { endVisitNode(_node); }
@@ -163,6 +165,7 @@ class ASTConstVisitor
163165
virtual bool visit(TypeName const& _node) { return visitNode(_node); }
164166
virtual bool visit(ElementaryTypeName const& _node) { return visitNode(_node); }
165167
virtual bool visit(UserDefinedTypeName const& _node) { return visitNode(_node); }
168+
virtual bool visit(FunctionTypeName const& _node) { return visitNode(_node); }
166169
virtual bool visit(Mapping const& _node) { return visitNode(_node); }
167170
virtual bool visit(ArrayTypeName const& _node) { return visitNode(_node); }
168171
virtual bool visit(Block const& _node) { return visitNode(_node); }
@@ -208,6 +211,7 @@ class ASTConstVisitor
208211
virtual void endVisit(TypeName const& _node) { endVisitNode(_node); }
209212
virtual void endVisit(ElementaryTypeName const& _node) { endVisitNode(_node); }
210213
virtual void endVisit(UserDefinedTypeName const& _node) { endVisitNode(_node); }
214+
virtual void endVisit(FunctionTypeName const& _node) { endVisitNode(_node); }
211215
virtual void endVisit(Mapping const& _node) { endVisitNode(_node); }
212216
virtual void endVisit(ArrayTypeName const& _node) { endVisitNode(_node); }
213217
virtual void endVisit(Block const& _node) { endVisitNode(_node); }

libsolidity/ast/AST_accept.h

+20
Original file line numberDiff line numberDiff line change
@@ -327,6 +327,26 @@ void UserDefinedTypeName::accept(ASTConstVisitor& _visitor) const
327327
_visitor.endVisit(*this);
328328
}
329329

330+
void FunctionTypeName::accept(ASTVisitor& _visitor)
331+
{
332+
if (_visitor.visit(*this))
333+
{
334+
m_parameterTypes->accept(_visitor);
335+
m_returnTypes->accept(_visitor);
336+
}
337+
_visitor.endVisit(*this);
338+
}
339+
340+
void FunctionTypeName::accept(ASTConstVisitor& _visitor) const
341+
{
342+
if (_visitor.visit(*this))
343+
{
344+
m_parameterTypes->accept(_visitor);
345+
m_returnTypes->accept(_visitor);
346+
}
347+
_visitor.endVisit(*this);
348+
}
349+
330350
void Mapping::accept(ASTVisitor& _visitor)
331351
{
332352
if (_visitor.visit(*this))

libsolidity/ast/Types.cpp

+61-4
Original file line numberDiff line numberDiff line change
@@ -1805,6 +1805,23 @@ FunctionType::FunctionType(EventDefinition const& _event):
18051805
swap(paramNames, m_parameterNames);
18061806
}
18071807

1808+
FunctionType::FunctionType(FunctionTypeName const& _typeName):
1809+
m_location(_typeName.visibility() == VariableDeclaration::Visibility::External ? Location::External : Location::Internal),
1810+
m_isConstant(_typeName.isDeclaredConst()),
1811+
m_isPayable(_typeName.isPayable())
1812+
{
1813+
for (auto const& t: _typeName.parameterTypes())
1814+
{
1815+
solAssert(t->annotation().type, "Type not set for parameter.");
1816+
m_parameterTypes.push_back(t->annotation().type);
1817+
}
1818+
for (auto const& t: _typeName.returnParameterTypes())
1819+
{
1820+
solAssert(t->annotation().type, "Type not set for return parameter.");
1821+
m_returnParameterTypes.push_back(t->annotation().type);
1822+
}
1823+
}
1824+
18081825
FunctionTypePointer FunctionType::newExpressionType(ContractDefinition const& _contract)
18091826
{
18101827
FunctionDefinition const* constructor = _contract.constructor();
@@ -1885,17 +1902,47 @@ string FunctionType::toString(bool _short) const
18851902
string name = "function (";
18861903
for (auto it = m_parameterTypes.begin(); it != m_parameterTypes.end(); ++it)
18871904
name += (*it)->toString(_short) + (it + 1 == m_parameterTypes.end() ? "" : ",");
1888-
name += ") returns (";
1905+
name += ") ";
1906+
if (m_isConstant)
1907+
name += "constant ";
1908+
if (m_isPayable)
1909+
name += "payable ";
1910+
if (m_location == Location::External)
1911+
name += "external ";
1912+
name += "returns (";
18891913
for (auto it = m_returnParameterTypes.begin(); it != m_returnParameterTypes.end(); ++it)
18901914
name += (*it)->toString(_short) + (it + 1 == m_returnParameterTypes.end() ? "" : ",");
18911915
return name + ")";
18921916
}
18931917

1918+
unsigned FunctionType::calldataEncodedSize(bool _padded) const
1919+
{
1920+
unsigned size = storageBytes();
1921+
if (_padded)
1922+
size = ((size + 31) / 32) * 32;
1923+
return size;
1924+
}
1925+
18941926
u256 FunctionType::storageSize() const
18951927
{
1896-
BOOST_THROW_EXCEPTION(
1897-
InternalCompilerError()
1898-
<< errinfo_comment("Storage size of non-storable function type requested."));
1928+
if (m_location == Location::External || m_location == Location::Internal)
1929+
return 1;
1930+
else
1931+
BOOST_THROW_EXCEPTION(
1932+
InternalCompilerError()
1933+
<< errinfo_comment("Storage size of non-storable function type requested."));
1934+
}
1935+
1936+
unsigned FunctionType::storageBytes() const
1937+
{
1938+
if (m_location == Location::External)
1939+
return 20 + 4;
1940+
else if (m_location == Location::Internal)
1941+
return 8; // it should really not be possible to create larger programs
1942+
else
1943+
BOOST_THROW_EXCEPTION(
1944+
InternalCompilerError()
1945+
<< errinfo_comment("Storage size of non-storable function type requested."));
18991946
}
19001947

19011948
unsigned FunctionType::sizeOnStack() const
@@ -2018,6 +2065,16 @@ MemberList::MemberMap FunctionType::nativeMembers(ContractDefinition const*) con
20182065
}
20192066
}
20202067

2068+
TypePointer FunctionType::interfaceType(bool _inLibrary) const
2069+
{
2070+
if (m_location != Location::External && m_location != Location::Internal)
2071+
return TypePointer();
2072+
if (_inLibrary)
2073+
return shared_from_this();
2074+
else
2075+
return make_shared<FixedBytesType>(storageBytes());
2076+
}
2077+
20212078
bool FunctionType::canTakeArguments(TypePointers const& _argumentTypes, TypePointer const& _selfType) const
20222079
{
20232080
solAssert(!bound() || _selfType, "");

libsolidity/ast/Types.h

+8-2
Original file line numberDiff line numberDiff line change
@@ -821,6 +821,8 @@ class FunctionType: public Type
821821
explicit FunctionType(VariableDeclaration const& _varDecl);
822822
/// Creates the function type of an event.
823823
explicit FunctionType(EventDefinition const& _event);
824+
/// Creates the type of a function type name.
825+
explicit FunctionType(FunctionTypeName const& _typeName);
824826
/// Function type constructor to be used for a plain type (not derived from a declaration).
825827
FunctionType(
826828
strings const& _parameterTypes,
@@ -891,11 +893,15 @@ class FunctionType: public Type
891893

892894
virtual bool operator==(Type const& _other) const override;
893895
virtual std::string toString(bool _short) const override;
894-
virtual bool canBeStored() const override { return false; }
896+
virtual unsigned calldataEncodedSize(bool _padded) const override;
897+
virtual bool canBeStored() const override { return m_location == Location::Internal || m_location == Location::External; }
895898
virtual u256 storageSize() const override;
896-
virtual bool canLiveOutsideStorage() const override { return false; }
899+
virtual unsigned storageBytes() const override;
900+
virtual bool isValueType() const override { return true; }
901+
virtual bool canLiveOutsideStorage() const override { return m_location == Location::Internal || m_location == Location::External; }
897902
virtual unsigned sizeOnStack() const override;
898903
virtual MemberList::MemberMap nativeMembers(ContractDefinition const* _currentScope) const override;
904+
virtual TypePointer interfaceType(bool _inLibrary) const override;
899905

900906
/// @returns TypePointer of a new FunctionType object. All input/return parameters are an
901907
/// appropriate external types (i.e. the interfaceType()s) of input/return parameters of

0 commit comments

Comments
 (0)