diff options
author | chriseth <c@ethdev.com> | 2015-07-01 03:08:34 +0800 |
---|---|---|
committer | chriseth <c@ethdev.com> | 2015-07-03 23:25:30 +0800 |
commit | e2d6e34f9c37488179ba5e3e9ae5dbe106bd57f0 (patch) | |
tree | ccb6bfd31cbd2d2a25e6866ed7a0ed86ce1eaf22 | |
parent | 6059d2075075885e60e1ee63f37985ccbddab7d9 (diff) | |
download | dexon-solidity-e2d6e34f9c37488179ba5e3e9ae5dbe106bd57f0.tar.gz dexon-solidity-e2d6e34f9c37488179ba5e3e9ae5dbe106bd57f0.tar.zst dexon-solidity-e2d6e34f9c37488179ba5e3e9ae5dbe106bd57f0.zip |
Struct constructors.
-rw-r--r-- | AST.cpp | 162 | ||||
-rw-r--r-- | AST.h | 6 | ||||
-rw-r--r-- | ExpressionCompiler.cpp | 74 | ||||
-rw-r--r-- | Types.cpp | 30 | ||||
-rw-r--r-- | Types.h | 4 |
5 files changed, 171 insertions, 105 deletions
@@ -802,12 +802,11 @@ void FunctionCall::checkTypeRequirements(TypePointers const*) m_expression->checkTypeRequirements(isPositionalCall ? &argumentTypes : nullptr); - Type const* expressionType = m_expression->getType().get(); + TypePointer const& expressionType = m_expression->getType(); + FunctionTypePointer functionType; if (isTypeConversion()) { TypeType const& type = dynamic_cast<TypeType const&>(*expressionType); - //@todo for structs, we have to check the number of arguments to be equal to the - // number of non-mapping members if (m_arguments.size() != 1) BOOST_THROW_EXCEPTION(createTypeError("Exactly one argument expected for explicit type conversion.")); if (!isPositionalCall) @@ -815,87 +814,106 @@ void FunctionCall::checkTypeRequirements(TypePointers const*) if (!m_arguments.front()->getType()->isExplicitlyConvertibleTo(*type.getActualType())) BOOST_THROW_EXCEPTION(createTypeError("Explicit type conversion not allowed.")); m_type = type.getActualType(); + return; } - else if (FunctionType const* functionType = dynamic_cast<FunctionType const*>(expressionType)) + + if (isStructConstructorCall()) { - //@todo would be nice to create a struct type from the arguments - // and then ask if that is implicitly convertible to the struct represented by the - // function parameters - TypePointers const& parameterTypes = functionType->getParameterTypes(); - if (!functionType->takesArbitraryParameters() && parameterTypes.size() != m_arguments.size()) - BOOST_THROW_EXCEPTION(createTypeError("Wrong argument count for function call.")); + TypeType const& type = dynamic_cast<TypeType const&>(*expressionType); + auto const& structType = dynamic_cast<StructType const&>(*type.getActualType()); + functionType = structType.constructorType(); + } + else + functionType = dynamic_pointer_cast<FunctionType const>(expressionType); - if (isPositionalCall) - { - // call by positional arguments - for (size_t i = 0; i < m_arguments.size(); ++i) - if ( - !functionType->takesArbitraryParameters() && - !m_arguments[i]->getType()->isImplicitlyConvertibleTo(*parameterTypes[i]) - ) - BOOST_THROW_EXCEPTION(m_arguments[i]->createTypeError( - "Invalid type for argument in function call. " - "Invalid implicit conversion from " + - m_arguments[i]->getType()->toString() + - " to " + - parameterTypes[i]->toString() + - " requested." - )); - } - else - { - // call by named arguments - if (functionType->takesArbitraryParameters()) - BOOST_THROW_EXCEPTION(createTypeError("Named arguments cannnot be used for functions " - "that take arbitrary parameters.")); - auto const& parameterNames = functionType->getParameterNames(); - if (parameterNames.size() != m_names.size()) - BOOST_THROW_EXCEPTION(createTypeError("Some argument names are missing.")); - - // check duplicate names - for (size_t i = 0; i < m_names.size(); i++) - for (size_t j = i + 1; j < m_names.size(); j++) - if (*m_names[i] == *m_names[j]) - BOOST_THROW_EXCEPTION(m_arguments[i]->createTypeError("Duplicate named argument.")); - - for (size_t i = 0; i < m_names.size(); i++) { - bool found = false; - for (size_t j = 0; j < parameterNames.size(); j++) { - if (parameterNames[j] == *m_names[i]) { - // check type convertible - if (!m_arguments[i]->getType()->isImplicitlyConvertibleTo(*parameterTypes[j])) - BOOST_THROW_EXCEPTION(m_arguments[i]->createTypeError( - "Invalid type for argument in function call. " - "Invalid implicit conversion from " + - m_arguments[i]->getType()->toString() + - " to " + - parameterTypes[i]->toString() + - " requested." - )); - - found = true; - break; - } + if (!functionType) + BOOST_THROW_EXCEPTION(createTypeError("Type is not callable.")); + + //@todo would be nice to create a struct type from the arguments + // and then ask if that is implicitly convertible to the struct represented by the + // function parameters + TypePointers const& parameterTypes = functionType->getParameterTypes(); + if (!functionType->takesArbitraryParameters() && parameterTypes.size() != m_arguments.size()) + BOOST_THROW_EXCEPTION(createTypeError("Wrong argument count for function call.")); + + if (isPositionalCall) + { + // call by positional arguments + for (size_t i = 0; i < m_arguments.size(); ++i) + if ( + !functionType->takesArbitraryParameters() && + !m_arguments[i]->getType()->isImplicitlyConvertibleTo(*parameterTypes[i]) + ) + BOOST_THROW_EXCEPTION(m_arguments[i]->createTypeError( + "Invalid type for argument in function call. " + "Invalid implicit conversion from " + + m_arguments[i]->getType()->toString() + + " to " + + parameterTypes[i]->toString() + + " requested." + )); + } + else + { + // call by named arguments + if (functionType->takesArbitraryParameters()) + BOOST_THROW_EXCEPTION(createTypeError( + "Named arguments cannnot be used for functions that take arbitrary parameters." + )); + auto const& parameterNames = functionType->getParameterNames(); + if (parameterNames.size() != m_names.size()) + BOOST_THROW_EXCEPTION(createTypeError("Some argument names are missing.")); + + // check duplicate names + for (size_t i = 0; i < m_names.size(); i++) + for (size_t j = i + 1; j < m_names.size(); j++) + if (*m_names[i] == *m_names[j]) + BOOST_THROW_EXCEPTION(m_arguments[i]->createTypeError("Duplicate named argument.")); + + for (size_t i = 0; i < m_names.size(); i++) { + bool found = false; + for (size_t j = 0; j < parameterNames.size(); j++) { + if (parameterNames[j] == *m_names[i]) { + // check type convertible + if (!m_arguments[i]->getType()->isImplicitlyConvertibleTo(*parameterTypes[j])) + BOOST_THROW_EXCEPTION(m_arguments[i]->createTypeError( + "Invalid type for argument in function call. " + "Invalid implicit conversion from " + + m_arguments[i]->getType()->toString() + + " to " + + parameterTypes[i]->toString() + + " requested." + )); + + found = true; + break; } - if (!found) - BOOST_THROW_EXCEPTION(createTypeError("Named argument does not match function declaration.")); } + if (!found) + BOOST_THROW_EXCEPTION(createTypeError("Named argument does not match function declaration.")); } - - // @todo actually the return type should be an anonymous struct, - // but we change it to the type of the first return value until we have structs - if (functionType->getReturnParameterTypes().empty()) - m_type = make_shared<VoidType>(); - else - m_type = functionType->getReturnParameterTypes().front(); } + + // @todo actually the return type should be an anonymous struct, + // but we change it to the type of the first return value until we have anonymous + // structs and tuples + if (functionType->getReturnParameterTypes().empty()) + m_type = make_shared<VoidType>(); else - BOOST_THROW_EXCEPTION(createTypeError("Type is not callable.")); + m_type = functionType->getReturnParameterTypes().front(); } bool FunctionCall::isTypeConversion() const { - return m_expression->getType()->getCategory() == Type::Category::TypeType; + return m_expression->getType()->getCategory() == Type::Category::TypeType && !isStructConstructorCall(); +} + +bool FunctionCall::isStructConstructorCall() const +{ + if (auto const* type = dynamic_cast<TypeType const*>(m_expression->getType().get())) + return type->getActualType()->getCategory() == Type::Category::Struct; + else + return false; } void NewExpression::checkTypeRequirements(TypePointers const*) @@ -1136,9 +1136,11 @@ public: std::vector<ASTPointer<Expression const>> getArguments() const { return {m_arguments.begin(), m_arguments.end()}; } std::vector<ASTPointer<ASTString>> const& getNames() const { return m_names; } - /// Returns true if this is not an actual function call, but an explicit type conversion - /// or constructor call. + /// @returns true if this is not an actual function call, but an explicit type conversion. + /// Returns false for struct constructor calls. bool isTypeConversion() const; + /// @return true if this is a constructor call for a struct, i.e. StructName(...). + bool isStructConstructorCall() const; private: ASTPointer<Expression> m_expression; diff --git a/ExpressionCompiler.cpp b/ExpressionCompiler.cpp index b36c7283..81f5d08a 100644 --- a/ExpressionCompiler.cpp +++ b/ExpressionCompiler.cpp @@ -313,38 +313,66 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall) using Location = FunctionType::Location; if (_functionCall.isTypeConversion()) { - //@todo struct construction solAssert(_functionCall.getArguments().size() == 1, ""); solAssert(_functionCall.getNames().empty(), ""); Expression const& firstArgument = *_functionCall.getArguments().front(); firstArgument.accept(*this); utils().convertType(*firstArgument.getType(), *_functionCall.getType()); + return false; } + + FunctionTypePointer functionType; + if (_functionCall.isStructConstructorCall()) + { + TypeType const& type = dynamic_cast<TypeType const&>(*_functionCall.getExpression().getType()); + auto const& structType = dynamic_cast<StructType const&>(*type.getActualType()); + functionType = structType.constructorType(); + } + else + functionType = dynamic_pointer_cast<FunctionType const>(_functionCall.getExpression().getType()); + + TypePointers const& parameterTypes = functionType->getParameterTypes(); + vector<ASTPointer<Expression const>> const& callArguments = _functionCall.getArguments(); + vector<ASTPointer<ASTString>> const& callArgumentNames = _functionCall.getNames(); + if (!functionType->takesArbitraryParameters()) + solAssert(callArguments.size() == parameterTypes.size(), ""); + + vector<ASTPointer<Expression const>> arguments; + if (callArgumentNames.empty()) + // normal arguments + arguments = callArguments; else + // named arguments + for (auto const& parameterName: functionType->getParameterNames()) + { + bool found = false; + for (size_t j = 0; j < callArgumentNames.size() && !found; j++) + if ((found = (parameterName == *callArgumentNames[j]))) + // we found the actual parameter position + arguments.push_back(callArguments[j]); + solAssert(found, ""); + } + + if (_functionCall.isStructConstructorCall()) { - FunctionType const& function = dynamic_cast<FunctionType const&>(*_functionCall.getExpression().getType()); - TypePointers const& parameterTypes = function.getParameterTypes(); - vector<ASTPointer<Expression const>> const& callArguments = _functionCall.getArguments(); - vector<ASTPointer<ASTString>> const& callArgumentNames = _functionCall.getNames(); - if (!function.takesArbitraryParameters()) - solAssert(callArguments.size() == parameterTypes.size(), ""); - - vector<ASTPointer<Expression const>> arguments; - if (callArgumentNames.empty()) - // normal arguments - arguments = callArguments; - else - // named arguments - for (auto const& parameterName: function.getParameterNames()) - { - bool found = false; - for (size_t j = 0; j < callArgumentNames.size() && !found; j++) - if ((found = (parameterName == *callArgumentNames[j]))) - // we found the actual parameter position - arguments.push_back(callArguments[j]); - solAssert(found, ""); - } + TypeType const& type = dynamic_cast<TypeType const&>(*_functionCall.getExpression().getType()); + auto const& structType = dynamic_cast<StructType const&>(*type.getActualType()); + + m_context << u256(max(32u, structType.getCalldataEncodedSize(true))); + utils().allocateMemory(); + m_context << eth::Instruction::DUP1; + for (unsigned i = 0; i < arguments.size(); ++i) + { + arguments[i]->accept(*this); + utils().convertType(*arguments[i]->getType(), *functionType->getParameterTypes()[i]); + utils().storeInMemoryDynamic(*functionType->getParameterTypes()[i]); + } + m_context << eth::Instruction::POP; + } + else + { + FunctionType const& function = *functionType; switch (function.getLocation()) { case Location::Internal: @@ -30,11 +30,8 @@ #include <libsolidity/AST.h> using namespace std; - -namespace dev -{ -namespace solidity -{ +using namespace dev; +using namespace dev::solidity; void StorageOffsets::computeOffsets(TypePointers const& _types) { @@ -1067,6 +1064,26 @@ TypePointer StructType::copyForLocation(DataLocation _location, bool _isPointer) return copy; } +FunctionTypePointer StructType::constructorType() const +{ + TypePointers paramTypes; + strings paramNames; + for (auto const& member: getMembers()) + { + if (!member.type->canLiveOutsideStorage()) + continue; + paramNames.push_back(member.name); + paramTypes.push_back(copyForLocationIfReference(DataLocation::Memory, member.type)); + } + return make_shared<FunctionType>( + paramTypes, + TypePointers{copyForLocation(DataLocation::Memory, false)}, + paramNames, + strings(), + FunctionType::Location::Internal + ); +} + pair<u256, unsigned> const& StructType::getStorageOffsetsOfMember(string const& _name) const { auto const* offsets = getMembers().getMemberStorageOffset(_name); @@ -1695,6 +1712,3 @@ string MagicType::toString(bool) const BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Unknown kind of magic.")); } } - -} -} @@ -557,6 +557,10 @@ public: TypePointer copyForLocation(DataLocation _location, bool _isPointer) const override; + /// @returns a function that peforms the type conversion between a list of struct members + /// and a memory struct of this type. + FunctionTypePointer constructorType() const; + std::pair<u256, unsigned> const& getStorageOffsetsOfMember(std::string const& _name) const; u256 memoryOffsetOfMember(std::string const& _name) const; |