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;
}
/// For error message: Struct members that were removed during conversion to memory.
set<string> membersRemovedForStructConstructor;
if (isStructConstructorCall())
{
TypeType const& type = dynamic_cast<TypeType const&>(*expressionType);
auto const& structType = dynamic_cast<StructType const&>(*type.getActualType());
functionType = structType.constructorType();
membersRemovedForStructConstructor = structType.membersMissingInMemory();
}
else
functionType = dynamic_pointer_cast<FunctionType const>(expressionType);
@ -847,13 +850,22 @@ void FunctionCall::checkTypeRequirements(TypePointers const*)
// function parameters
TypePointers const& parameterTypes = functionType->getParameterTypes();
if (!functionType->takesArbitraryParameters() && parameterTypes.size() != m_arguments.size())
BOOST_THROW_EXCEPTION(createTypeError(
{
string msg =
"Wrong argument count for function call: " +
toString(m_arguments.size()) +
" arguments given but expected " +
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)
{
@ -972,10 +984,22 @@ void MemberAccess::checkTypeRequirements(TypePointers const* _argumentTypes)
++it;
}
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(
"Member \"" + *m_memberName + "\" not found or not visible "
"after argument-dependent lookup in " + type.toString()
));
}
else if (possibleMembers.size() > 1)
BOOST_THROW_EXCEPTION(createTypeError(
"Member \"" + *m_memberName + "\" not unique "

View File

@ -1040,14 +1040,6 @@ u256 StructType::getStorageSize() const
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 ret = "struct " + m_struct.getName();
@ -1064,9 +1056,13 @@ MemberList const& StructType::getMembers() const
MemberList::MemberMap members;
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(
variable->getName(),
copyForLocationIfReference(variable->getType()),
copyForLocationIfReference(type),
variable.get())
);
}
@ -1077,8 +1073,7 @@ MemberList const& StructType::getMembers() const
TypePointer StructType::copyForLocation(DataLocation _location, bool _isPointer) const
{
auto copy = make_shared<StructType>(m_struct);
copy->m_location = _location;
auto copy = make_shared<StructType>(m_struct, _location);
copy->m_isPointer = _isPointer;
return copy;
}
@ -1122,6 +1117,15 @@ u256 StructType::memoryOffsetOfMember(string const& _name) const
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
{
return _operator == Token::Delete ? make_shared<VoidType>() : TypePointer();

View File

@ -574,14 +574,14 @@ class StructType: public ReferenceType
{
public:
virtual Category getCategory() const override { return Category::Struct; }
explicit StructType(StructDefinition const& _struct):
ReferenceType(DataLocation::Storage), m_struct(_struct) {}
explicit StructType(StructDefinition const& _struct, DataLocation _location = DataLocation::Storage):
ReferenceType(_location), m_struct(_struct) {}
virtual bool isImplicitlyConvertibleTo(const Type& _convertTo) const override;
virtual bool operator==(Type const& _other) const override;
virtual unsigned getCalldataEncodedSize(bool _padded) const override;
u256 memorySize() const;
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 MemberList const& getMembers() const override;
@ -597,6 +597,9 @@ public:
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:
StructDefinition const& m_struct;
/// List of member types, will be lazy-initialized because of recursive references.