mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Allow structs containing mappings in memory.
This commit is contained in:
parent
d747f34466
commit
a2796c3d15
30
AST.cpp
30
AST.cpp
@ -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 "
|
||||
|
26
Types.cpp
26
Types.cpp
@ -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();
|
||||
|
9
Types.h
9
Types.h
@ -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.
|
||||
|
Loading…
Reference in New Issue
Block a user