Allow structs containing mappings in memory.

This commit is contained in:
chriseth 2015-07-16 01:06:19 +02:00
parent d747f34466
commit a2796c3d15
3 changed files with 48 additions and 17 deletions

30
AST.cpp
View File

@ -830,11 +830,14 @@ void FunctionCall::checkTypeRequirements(TypePointers const*)
return; return;
} }
/// For error message: Struct members that were removed during conversion to memory.
set<string> membersRemovedForStructConstructor;
if (isStructConstructorCall()) if (isStructConstructorCall())
{ {
TypeType const& type = dynamic_cast<TypeType const&>(*expressionType); TypeType const& type = dynamic_cast<TypeType const&>(*expressionType);
auto const& structType = dynamic_cast<StructType const&>(*type.getActualType()); auto const& structType = dynamic_cast<StructType const&>(*type.getActualType());
functionType = structType.constructorType(); functionType = structType.constructorType();
membersRemovedForStructConstructor = structType.membersMissingInMemory();
} }
else else
functionType = dynamic_pointer_cast<FunctionType const>(expressionType); functionType = dynamic_pointer_cast<FunctionType const>(expressionType);
@ -847,13 +850,22 @@ void FunctionCall::checkTypeRequirements(TypePointers const*)
// function parameters // function parameters
TypePointers const& parameterTypes = functionType->getParameterTypes(); TypePointers const& parameterTypes = functionType->getParameterTypes();
if (!functionType->takesArbitraryParameters() && parameterTypes.size() != m_arguments.size()) if (!functionType->takesArbitraryParameters() && parameterTypes.size() != m_arguments.size())
BOOST_THROW_EXCEPTION(createTypeError( {
string msg =
"Wrong argument count for function call: " + "Wrong argument count for function call: " +
toString(m_arguments.size()) + toString(m_arguments.size()) +
" arguments given but expected " + " arguments given but expected " +
toString(parameterTypes.size()) + toString(parameterTypes.size()) +
"." ".";
)); // Extend error message in case we try to construct a struct with mapping member.
if (isStructConstructorCall() && !membersRemovedForStructConstructor.empty())
{
msg += " Members that have to be skipped in memory:";
for (auto const& member: membersRemovedForStructConstructor)
msg += " " + member;
}
BOOST_THROW_EXCEPTION(createTypeError(msg));
}
if (isPositionalCall) if (isPositionalCall)
{ {
@ -972,10 +984,22 @@ void MemberAccess::checkTypeRequirements(TypePointers const* _argumentTypes)
++it; ++it;
} }
if (possibleMembers.size() == 0) if (possibleMembers.size() == 0)
{
auto storageType = ReferenceType::copyForLocationIfReference(
DataLocation::Storage,
m_expression->getType()
);
if (!storageType->getMembers().membersByName(*m_memberName).empty())
BOOST_THROW_EXCEPTION(createTypeError(
"Member \"" + *m_memberName + "\" is not available in " +
type.toString() +
" outside of storage."
));
BOOST_THROW_EXCEPTION(createTypeError( BOOST_THROW_EXCEPTION(createTypeError(
"Member \"" + *m_memberName + "\" not found or not visible " "Member \"" + *m_memberName + "\" not found or not visible "
"after argument-dependent lookup in " + type.toString() "after argument-dependent lookup in " + type.toString()
)); ));
}
else if (possibleMembers.size() > 1) else if (possibleMembers.size() > 1)
BOOST_THROW_EXCEPTION(createTypeError( BOOST_THROW_EXCEPTION(createTypeError(
"Member \"" + *m_memberName + "\" not unique " "Member \"" + *m_memberName + "\" not unique "

View File

@ -1040,14 +1040,6 @@ u256 StructType::getStorageSize() const
return max<u256>(1, getMembers().getStorageSize()); return max<u256>(1, getMembers().getStorageSize());
} }
bool StructType::canLiveOutsideStorage() const
{
for (auto const& member: getMembers())
if (!member.type->canLiveOutsideStorage())
return false;
return true;
}
string StructType::toString(bool _short) const string StructType::toString(bool _short) const
{ {
string ret = "struct " + m_struct.getName(); string ret = "struct " + m_struct.getName();
@ -1064,9 +1056,13 @@ MemberList const& StructType::getMembers() const
MemberList::MemberMap members; MemberList::MemberMap members;
for (ASTPointer<VariableDeclaration> const& variable: m_struct.getMembers()) for (ASTPointer<VariableDeclaration> const& variable: m_struct.getMembers())
{ {
TypePointer type = variable->getType();
// Skip all mapping members if we are not in storage.
if (location() != DataLocation::Storage && !type->canLiveOutsideStorage())
continue;
members.push_back(MemberList::Member( members.push_back(MemberList::Member(
variable->getName(), variable->getName(),
copyForLocationIfReference(variable->getType()), copyForLocationIfReference(type),
variable.get()) variable.get())
); );
} }
@ -1077,8 +1073,7 @@ MemberList const& StructType::getMembers() const
TypePointer StructType::copyForLocation(DataLocation _location, bool _isPointer) const TypePointer StructType::copyForLocation(DataLocation _location, bool _isPointer) const
{ {
auto copy = make_shared<StructType>(m_struct); auto copy = make_shared<StructType>(m_struct, _location);
copy->m_location = _location;
copy->m_isPointer = _isPointer; copy->m_isPointer = _isPointer;
return copy; return copy;
} }
@ -1122,6 +1117,15 @@ u256 StructType::memoryOffsetOfMember(string const& _name) const
return 0; return 0;
} }
set<string> StructType::membersMissingInMemory() const
{
set<string> missing;
for (ASTPointer<VariableDeclaration> const& variable: m_struct.getMembers())
if (!variable->getType()->canLiveOutsideStorage())
missing.insert(variable->getName());
return missing;
}
TypePointer EnumType::unaryOperatorResult(Token::Value _operator) const TypePointer EnumType::unaryOperatorResult(Token::Value _operator) const
{ {
return _operator == Token::Delete ? make_shared<VoidType>() : TypePointer(); return _operator == Token::Delete ? make_shared<VoidType>() : TypePointer();

View File

@ -574,14 +574,14 @@ class StructType: public ReferenceType
{ {
public: public:
virtual Category getCategory() const override { return Category::Struct; } virtual Category getCategory() const override { return Category::Struct; }
explicit StructType(StructDefinition const& _struct): explicit StructType(StructDefinition const& _struct, DataLocation _location = DataLocation::Storage):
ReferenceType(DataLocation::Storage), m_struct(_struct) {} ReferenceType(_location), m_struct(_struct) {}
virtual bool isImplicitlyConvertibleTo(const Type& _convertTo) const override; virtual bool isImplicitlyConvertibleTo(const Type& _convertTo) const override;
virtual bool operator==(Type const& _other) const override; virtual bool operator==(Type const& _other) const override;
virtual unsigned getCalldataEncodedSize(bool _padded) const override; virtual unsigned getCalldataEncodedSize(bool _padded) const override;
u256 memorySize() const; u256 memorySize() const;
virtual u256 getStorageSize() const override; virtual u256 getStorageSize() const override;
virtual bool canLiveOutsideStorage() const override; virtual bool canLiveOutsideStorage() const override { return true; }
virtual std::string toString(bool _short) const override; virtual std::string toString(bool _short) const override;
virtual MemberList const& getMembers() const override; virtual MemberList const& getMembers() const override;
@ -597,6 +597,9 @@ public:
StructDefinition const& structDefinition() const { return m_struct; } StructDefinition const& structDefinition() const { return m_struct; }
/// @returns the set of all members that are removed in the memory version (typically mappings).
std::set<std::string> membersMissingInMemory() const;
private: private:
StructDefinition const& m_struct; StructDefinition const& m_struct;
/// List of member types, will be lazy-initialized because of recursive references. /// List of member types, will be lazy-initialized because of recursive references.