diff options
author | chriseth <c@ethdev.com> | 2015-10-02 19:11:38 +0800 |
---|---|---|
committer | chriseth <c@ethdev.com> | 2015-10-06 20:19:56 +0800 |
commit | 9cc7402c9583ca3bfc9fcb234443d2f90b890190 (patch) | |
tree | b69181225de53fefc5df93dd64e6885db9d85eb0 | |
parent | d2332769d3e87b3500638591c23241ebd942fbb1 (diff) | |
download | dexon-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.cpp | 11 | ||||
-rw-r--r-- | libsolidity/CompilerUtils.cpp | 2 | ||||
-rw-r--r-- | libsolidity/InterfaceHandler.cpp | 6 | ||||
-rw-r--r-- | libsolidity/ReferencesResolver.cpp | 54 | ||||
-rw-r--r-- | libsolidity/TypeChecker.cpp | 7 | ||||
-rw-r--r-- | libsolidity/Types.cpp | 35 | ||||
-rw-r--r-- | libsolidity/Types.h | 68 |
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; } |