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;
|
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 "
|
||||||
|
26
Types.cpp
26
Types.cpp
@ -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();
|
||||||
|
9
Types.h
9
Types.h
@ -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.
|
||||||
|
Loading…
Reference in New Issue
Block a user