aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorchriseth <c@ethdev.com>2015-07-01 03:08:34 +0800
committerchriseth <c@ethdev.com>2015-07-03 23:25:30 +0800
commite2d6e34f9c37488179ba5e3e9ae5dbe106bd57f0 (patch)
treeccb6bfd31cbd2d2a25e6866ed7a0ed86ce1eaf22
parent6059d2075075885e60e1ee63f37985ccbddab7d9 (diff)
downloaddexon-solidity-e2d6e34f9c37488179ba5e3e9ae5dbe106bd57f0.tar.gz
dexon-solidity-e2d6e34f9c37488179ba5e3e9ae5dbe106bd57f0.tar.zst
dexon-solidity-e2d6e34f9c37488179ba5e3e9ae5dbe106bd57f0.zip
Struct constructors.
-rw-r--r--AST.cpp162
-rw-r--r--AST.h6
-rw-r--r--ExpressionCompiler.cpp74
-rw-r--r--Types.cpp30
-rw-r--r--Types.h4
5 files changed, 171 insertions, 105 deletions
diff --git a/AST.cpp b/AST.cpp
index fac4360f..161a7d35 100644
--- a/AST.cpp
+++ b/AST.cpp
@@ -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*)
diff --git a/AST.h b/AST.h
index ff0d708f..658b3de9 100644
--- a/AST.h
+++ b/AST.h
@@ -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:
diff --git a/Types.cpp b/Types.cpp
index ef70f0e0..96cf3f7e 100644
--- a/Types.cpp
+++ b/Types.cpp
@@ -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."));
}
}
-
-}
-}
diff --git a/Types.h b/Types.h
index b64b1d9b..ba53a913 100644
--- a/Types.h
+++ b/Types.h
@@ -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;