aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorchriseth <c@ethdev.com>2015-10-02 19:11:38 +0800
committerchriseth <c@ethdev.com>2015-10-06 20:19:56 +0800
commit9cc7402c9583ca3bfc9fcb234443d2f90b890190 (patch)
treeb69181225de53fefc5df93dd64e6885db9d85eb0
parentd2332769d3e87b3500638591c23241ebd942fbb1 (diff)
downloaddexon-solidity-9cc7402c9583ca3bfc9fcb234443d2f90b890190.tar.gz
dexon-solidity-9cc7402c9583ca3bfc9fcb234443d2f90b890190.tar.zst
dexon-solidity-9cc7402c9583ca3bfc9fcb234443d2f90b890190.zip
Split external type into ecoding and interface type.
-rw-r--r--libsolidity/Compiler.cpp11
-rw-r--r--libsolidity/CompilerUtils.cpp2
-rw-r--r--libsolidity/InterfaceHandler.cpp6
-rw-r--r--libsolidity/ReferencesResolver.cpp54
-rw-r--r--libsolidity/TypeChecker.cpp7
-rw-r--r--libsolidity/Types.cpp35
-rw-r--r--libsolidity/Types.h68
7 files changed, 128 insertions, 55 deletions
diff --git a/libsolidity/Compiler.cpp b/libsolidity/Compiler.cpp
index 969c8f74..21eab230 100644
--- a/libsolidity/Compiler.cpp
+++ b/libsolidity/Compiler.cpp
@@ -280,15 +280,13 @@ void Compiler::appendCalldataUnpacker(TypePointers const& _typeParameters, bool
// Retain the offset pointer as base_offset, the point from which the data offsets are computed.
m_context << eth::Instruction::DUP1;
- for (TypePointer const& type: _typeParameters)
+ for (TypePointer const& parameterType: _typeParameters)
{
// stack: v1 v2 ... v(k-1) base_offset current_offset
- switch (type->category())
- {
- case Type::Category::Array:
+ TypePointer type = parameterType->encodingType();
+ if (type->category() == Type::Category::Array)
{
auto const& arrayType = dynamic_cast<ArrayType const&>(*type);
- solAssert(arrayType.location() != DataLocation::Storage, "");
solAssert(!arrayType.baseType()->isDynamicallySized(), "Nested arrays not yet implemented.");
if (_fromMemory)
{
@@ -344,7 +342,8 @@ void Compiler::appendCalldataUnpacker(TypePointers const& _typeParameters, bool
}
break;
}
- default:
+ else
+ {
solAssert(!type->isDynamicallySized(), "Unknown dynamically sized type: " + type->toString());
CompilerUtils(m_context).loadFromMemoryDynamic(*type, !_fromMemory, true);
CompilerUtils(m_context).moveToStackTop(1 + type->sizeOnStack());
diff --git a/libsolidity/CompilerUtils.cpp b/libsolidity/CompilerUtils.cpp
index d6624ca4..31000f0b 100644
--- a/libsolidity/CompilerUtils.cpp
+++ b/libsolidity/CompilerUtils.cpp
@@ -160,7 +160,7 @@ void CompilerUtils::encodeToMemory(
TypePointers targetTypes = _targetTypes.empty() ? _givenTypes : _targetTypes;
solAssert(targetTypes.size() == _givenTypes.size(), "");
for (TypePointer& t: targetTypes)
- t = t->mobileType()->externalType();
+ t = t->mobileType()->encodingType();
// Stack during operation:
// <v1> <v2> ... <vn> <mem_start> <dyn_head_1> ... <dyn_head_r> <end_of_mem>
diff --git a/libsolidity/InterfaceHandler.cpp b/libsolidity/InterfaceHandler.cpp
index 50006caf..4837fcfe 100644
--- a/libsolidity/InterfaceHandler.cpp
+++ b/libsolidity/InterfaceHandler.cpp
@@ -57,7 +57,7 @@ string InterfaceHandler::abiInterface(ContractDefinition const& _contractDef)
for (auto it: _contractDef.interfaceFunctions())
{
- auto externalFunctionType = it.second->externalFunctionType();
+ auto externalFunctionType = it.second->interfaceFunctionType();
Json::Value method;
method["type"] = "function";
method["name"] = it.second->declaration().name();
@@ -76,7 +76,7 @@ string InterfaceHandler::abiInterface(ContractDefinition const& _contractDef)
{
Json::Value method;
method["type"] = "constructor";
- auto externalFunction = FunctionType(*_contractDef.constructor()).externalFunctionType();
+ auto externalFunction = FunctionType(*_contractDef.constructor()).interfaceFunctionType();
solAssert(!!externalFunction, "");
method["inputs"] = populateParameters(
externalFunction->parameterNames(),
@@ -120,7 +120,7 @@ string InterfaceHandler::ABISolidityInterface(ContractDefinition const& _contrac
};
if (_contractDef.constructor())
{
- auto externalFunction = FunctionType(*_contractDef.constructor()).externalFunctionType();
+ auto externalFunction = FunctionType(*_contractDef.constructor()).interfaceFunctionType();
solAssert(!!externalFunction, "");
ret +=
"function " +
diff --git a/libsolidity/ReferencesResolver.cpp b/libsolidity/ReferencesResolver.cpp
index 623ac8f7..cb34c47e 100644
--- a/libsolidity/ReferencesResolver.cpp
+++ b/libsolidity/ReferencesResolver.cpp
@@ -106,27 +106,45 @@ void ReferencesResolver::endVisit(VariableDeclaration const& _variable)
// References are forced to calldata for external function parameters (not return)
// and memory for parameters (also return) of publicly visible functions.
// They default to memory for function parameters and storage for local variables.
+ // As an exception, "storage" is allowed for library functions.
if (auto ref = dynamic_cast<ReferenceType const*>(type.get()))
{
- if (_variable.isExternalCallableParameter())
+ if (_variable.isCallableParameter())
{
- // force location of external function parameters (not return) to calldata
- if (loc != Location::Default)
- BOOST_THROW_EXCEPTION(_variable.createTypeError(
- "Location has to be calldata for external functions "
- "(remove the \"memory\" or \"storage\" keyword)."
- ));
- type = ref->copyForLocation(DataLocation::CallData, true);
- }
- else if (_variable.isCallableParameter() && _variable.scope()->isPublic())
- {
- // force locations of public or external function (return) parameters to memory
- if (loc == VariableDeclaration::Location::Storage)
- BOOST_THROW_EXCEPTION(_variable.createTypeError(
- "Location has to be memory for publicly visible functions "
- "(remove the \"storage\" keyword)."
- ));
- type = ref->copyForLocation(DataLocation::Memory, true);
+ auto const& contract = dynamic_cast<ContractDefinition const&>(*_variable.scope()->scope());
+ if (_variable.isExternalCallableParameter())
+ {
+ if (contract.isLibrary())
+ {
+ if (loc == Location::Memory)
+ BOOST_THROW_EXCEPTION(_variable.createTypeError(
+ "Location has to be calldata or storage for external "
+ "library functions (remove the \"memory\" keyword)."
+ ));
+ }
+ else
+ {
+ // force location of external function parameters (not return) to calldata
+ if (loc != Location::Default)
+ BOOST_THROW_EXCEPTION(_variable.createTypeError(
+ "Location has to be calldata for external functions "
+ "(remove the \"memory\" or \"storage\" keyword)."
+ ));
+ }
+ if (loc == Location::Default)
+ type = ref->copyForLocation(DataLocation::CallData, true);
+ }
+ else if (_variable.isCallableParameter() && _variable.scope()->isPublic())
+ {
+ // force locations of public or external function (return) parameters to memory
+ if (loc == Location::Storage && !contract.isLibrary())
+ BOOST_THROW_EXCEPTION(_variable.createTypeError(
+ "Location has to be memory for publicly visible functions "
+ "(remove the \"storage\" keyword)."
+ ));
+ if (loc == Location::Default)
+ type = ref->copyForLocation(DataLocation::Memory, true);
+ }
}
else
{
diff --git a/libsolidity/TypeChecker.cpp b/libsolidity/TypeChecker.cpp
index 48a8a536..74347e1f 100644
--- a/libsolidity/TypeChecker.cpp
+++ b/libsolidity/TypeChecker.cpp
@@ -397,11 +397,12 @@ bool TypeChecker::visit(StructDefinition const& _struct)
bool TypeChecker::visit(FunctionDefinition const& _function)
{
+ bool isLibraryFunction = dynamic_cast<ContractDefinition const&>(*_function.scope()).isLibrary();
for (ASTPointer<VariableDeclaration> const& var: _function.parameters() + _function.returnParameters())
{
if (!type(*var)->canLiveOutsideStorage())
typeError(*var, "Type is required to live outside storage.");
- if (_function.visibility() >= FunctionDefinition::Visibility::Public && !(type(*var)->externalType()))
+ if (_function.visibility() >= FunctionDefinition::Visibility::Public && !(type(*var)->interfaceType(isLibraryFunction)))
typeError(*var, "Internal type is not allowed for public and external functions.");
}
for (ASTPointer<ModifierInvocation> const& modifier: _function.modifiers())
@@ -490,7 +491,7 @@ bool TypeChecker::visit(VariableDeclaration const& _variable)
}
else if (
_variable.visibility() >= VariableDeclaration::Visibility::Public &&
- !FunctionType(_variable).externalType()
+ !FunctionType(_variable).interfaceFunctionType()
)
typeError(_variable, "Internal type is not allowed for public state variables.");
return false;
@@ -557,7 +558,7 @@ bool TypeChecker::visit(EventDefinition const& _eventDef)
typeError(_eventDef, "More than 3 indexed arguments for event.");
if (!type(*var)->canLiveOutsideStorage())
typeError(*var, "Type is required to live outside storage.");
- if (!type(*var)->externalType())
+ if (!type(*var)->interfaceType(false))
typeError(*var, "Internal type is not allowed as event parameter type.");
}
return false;
diff --git a/libsolidity/Types.cpp b/libsolidity/Types.cpp
index 435385e6..f7e67696 100644
--- a/libsolidity/Types.cpp
+++ b/libsolidity/Types.cpp
@@ -839,11 +839,22 @@ string ArrayType::toString(bool _short) const
return ret;
}
-TypePointer ArrayType::externalType() const
+TypePointer ArrayType::encodingType() const
{
+ if (location() == DataLocation::Storage)
+ return make_shared<IntegerType>(256);
+ else
+ return this->copyForLocation(DataLocation::Memory, true);
+}
+
+TypePointer ArrayType::interfaceType(bool _inLibrary) const
+{
+ if (_inLibrary && location() == DataLocation::Storage)
+ return shared_from_this();
+
if (m_arrayKind != ArrayKind::Ordinary)
return this->copyForLocation(DataLocation::Memory, true);
- TypePointer baseExt = m_baseType->externalType();
+ TypePointer baseExt = m_baseType->interfaceType(_inLibrary);
if (!baseExt)
return TypePointer();
if (m_baseType->category() == Category::Array && m_baseType->isDynamicallySized())
@@ -1059,6 +1070,14 @@ MemberList const& StructType::members() const
return *m_members;
}
+TypePointer StructType::interfaceType(bool _inLibrary) const
+{
+ if (_inLibrary && location() == DataLocation::Storage)
+ return shared_from_this();
+ else
+ return TypePointer();
+}
+
TypePointer StructType::copyForLocation(DataLocation _location, bool _isPointer) const
{
auto copy = make_shared<StructType>(m_struct, _location);
@@ -1330,21 +1349,25 @@ unsigned FunctionType::sizeOnStack() const
return size;
}
-FunctionTypePointer FunctionType::externalFunctionType() const
+FunctionTypePointer FunctionType::interfaceFunctionType() const
{
+ // Note that m_declaration might also be a state variable!
+ solAssert(m_declaration, "Declaration needed to determine interface function type.");
+ bool isLibraryFunction = dynamic_cast<ContractDefinition const&>(*m_declaration->scope()).isLibrary();
+
TypePointers paramTypes;
TypePointers retParamTypes;
for (auto type: m_parameterTypes)
{
- if (auto ext = type->externalType())
+ if (auto ext = type->interfaceType(isLibraryFunction))
paramTypes.push_back(ext);
else
return FunctionTypePointer();
}
for (auto type: m_returnParameterTypes)
{
- if (auto ext = type->externalType())
+ if (auto ext = type->interfaceType(isLibraryFunction))
retParamTypes.push_back(ext);
else
return FunctionTypePointer();
@@ -1462,7 +1485,7 @@ string FunctionType::externalSignature(std::string const& _name) const
}
string ret = funcName + "(";
- FunctionTypePointer external = externalFunctionType();
+ FunctionTypePointer external = interfaceFunctionType();
solAssert(!!external, "External function type requested.");
TypePointers externalParameterTypes = external->parameterTypes();
for (auto it = externalParameterTypes.cbegin(); it != externalParameterTypes.cend(); ++it)
diff --git a/libsolidity/Types.h b/libsolidity/Types.h
index 73111e48..972876e9 100644
--- a/libsolidity/Types.h
+++ b/libsolidity/Types.h
@@ -226,9 +226,16 @@ public:
);
}
- /// @returns a type suitable for outside of Solidity, i.e. for contract types it returns address.
+ /// @returns a (simpler) type that is encoded in the same way for external function calls.
+ /// This for example returns address for contract types.
/// If there is no such type, returns an empty shared pointer.
- virtual TypePointer externalType() const { return TypePointer(); }
+ virtual TypePointer encodingType() const { return TypePointer(); }
+ /// @returns a type that will be used outside of Solidity for e.g. function signatures.
+ /// This for example returns address for contract types.
+ /// If there is no such type, returns an empty shared pointer.
+ /// @param _inLibrary if set, returns types as used in a library, e.g. struct and contract types
+ /// are returned without modification.
+ virtual TypePointer interfaceType(bool /*_inLibrary*/) const { return TypePointer(); }
protected:
/// Convenience object used when returning an empty member list.
@@ -264,7 +271,8 @@ public:
virtual std::string toString(bool _short) const override;
- virtual TypePointer externalType() const override { return shared_from_this(); }
+ virtual TypePointer encodingType() const override { return shared_from_this(); }
+ virtual TypePointer interfaceType(bool) const override { return shared_from_this(); }
int numBits() const { return m_bits; }
bool isAddress() const { return m_modifier == Modifier::Address; }
@@ -369,7 +377,8 @@ public:
virtual bool isValueType() const override { return true; }
virtual std::string toString(bool) const override { return "bytes" + dev::toString(m_bytes); }
- virtual TypePointer externalType() const override { return shared_from_this(); }
+ virtual TypePointer encodingType() const override { return shared_from_this(); }
+ virtual TypePointer interfaceType(bool) const override { return shared_from_this(); }
int numBytes() const { return m_bytes; }
@@ -395,7 +404,8 @@ public:
virtual std::string toString(bool) const override { return "bool"; }
virtual u256 literalValue(Literal const* _literal) const override;
- virtual TypePointer externalType() const override { return shared_from_this(); }
+ virtual TypePointer encodingType() const override { return shared_from_this(); }
+ virtual TypePointer interfaceType(bool) const override { return shared_from_this(); }
};
/**
@@ -493,7 +503,8 @@ public:
{
return isString() ? EmptyMemberList : s_arrayTypeMemberList;
}
- virtual TypePointer externalType() const override;
+ virtual TypePointer encodingType() const override;
+ virtual TypePointer interfaceType(bool _inLibrary) const override;
/// @returns true if this is a byte array or a string
bool isByteArray() const { return m_arrayKind != ArrayKind::Ordinary; }
@@ -534,7 +545,7 @@ public:
virtual bool operator==(Type const& _other) const override;
virtual unsigned calldataEncodedSize(bool _padded ) const override
{
- return externalType()->calldataEncodedSize(_padded);
+ return encodingType()->calldataEncodedSize(_padded);
}
virtual unsigned storageBytes() const override { return 20; }
virtual bool canLiveOutsideStorage() const override { return true; }
@@ -542,10 +553,14 @@ public:
virtual std::string toString(bool _short) const override;
virtual MemberList const& members() const override;
- virtual TypePointer externalType() const override
+ virtual TypePointer encodingType() const override
{
return std::make_shared<IntegerType>(160, IntegerType::Modifier::Address);
}
+ virtual TypePointer interfaceType(bool _inLibrary) const override
+ {
+ return _inLibrary ? shared_from_this() : encodingType();
+ }
bool isSuper() const { return m_super; }
ContractDefinition const& contractDefinition() const { return m_contract; }
@@ -566,7 +581,7 @@ private:
ContractDefinition const& m_contract;
/// If true, it is the "super" type of the current contract, i.e. it contains only inherited
/// members.
- bool m_super;
+ bool m_super = false;
/// Type of the constructor, @see constructorType. Lazily initialized.
mutable FunctionTypePointer m_constructorType;
/// List of member types, will be lazy-initialized because of recursive references.
@@ -591,6 +606,11 @@ public:
virtual std::string toString(bool _short) const override;
virtual MemberList const& members() const override;
+ virtual TypePointer encodingType() const override
+ {
+ return location() == DataLocation::Storage ? std::make_shared<IntegerType>(256) : TypePointer();
+ }
+ virtual TypePointer interfaceType(bool _inLibrary) const override;
TypePointer copyForLocation(DataLocation _location, bool _isPointer) const override;
@@ -624,7 +644,7 @@ public:
virtual bool operator==(Type const& _other) const override;
virtual unsigned calldataEncodedSize(bool _padded) const override
{
- return externalType()->calldataEncodedSize(_padded);
+ return encodingType()->calldataEncodedSize(_padded);
}
virtual unsigned storageBytes() const override;
virtual bool canLiveOutsideStorage() const override { return true; }
@@ -632,10 +652,14 @@ public:
virtual bool isValueType() const override { return true; }
virtual bool isExplicitlyConvertibleTo(Type const& _convertTo) const override;
- virtual TypePointer externalType() const override
+ virtual TypePointer encodingType() const override
{
return std::make_shared<IntegerType>(8 * int(storageBytes()));
}
+ virtual TypePointer interfaceType(bool _inLibrary) const override
+ {
+ return _inLibrary ? shared_from_this() : encodingType();
+ }
EnumDefinition const& enumDefinition() const { return m_enum; }
/// @returns the value that the string has in the Enum
@@ -684,13 +708,6 @@ public:
virtual Category category() const override { return Category::Function; }
- /// @returns TypePointer of a new FunctionType object. All input/return parameters are an
- /// appropriate external types of input/return parameters of current function.
- /// Returns an empty shared pointer if one of the input/return parameters does not have an
- /// external type.
- FunctionTypePointer externalFunctionType() const;
- virtual TypePointer externalType() const override { return externalFunctionType(); }
-
/// Creates the type of a function.
explicit FunctionType(FunctionDefinition const& _function, bool _isInternal = true);
/// Creates the accessor function type of a state variable.
@@ -749,6 +766,13 @@ public:
virtual unsigned sizeOnStack() const override;
virtual MemberList const& members() const override;
+ /// @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
+ /// current function.
+ /// Returns an empty shared pointer if one of the input/return parameters does not have an
+ /// external type.
+ FunctionTypePointer interfaceFunctionType() const;
+
/// @returns true if this function can take the given argument types (possibly
/// after implicit conversion).
bool canTakeArguments(TypePointers const& _arguments) const;
@@ -823,6 +847,14 @@ public:
virtual bool operator==(Type const& _other) const override;
virtual std::string toString(bool _short) const override;
virtual bool canLiveOutsideStorage() const override { return false; }
+ virtual TypePointer encodingType() const override
+ {
+ return std::make_shared<IntegerType>(256);
+ }
+ virtual TypePointer interfaceType(bool _inLibrary) const override
+ {
+ return _inLibrary ? shared_from_this() : TypePointer();
+ }
TypePointer const& keyType() const { return m_keyType; }
TypePointer const& valueType() const { return m_valueType; }