mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Added containsNestedMapping()
This commit is contained in:
parent
af0cd4ab98
commit
d41eaeba56
@ -112,18 +112,16 @@ bool DeclarationTypeChecker::visit(StructDefinition const& _struct)
|
||||
for (ASTPointer<VariableDeclaration> const& member: _struct.members())
|
||||
{
|
||||
Type const* memberType = member->annotation().type;
|
||||
while (auto arrayType = dynamic_cast<ArrayType const*>(memberType))
|
||||
{
|
||||
if (arrayType->isDynamicallySized())
|
||||
break;
|
||||
memberType = arrayType->baseType();
|
||||
}
|
||||
|
||||
if (auto arrayType = dynamic_cast<ArrayType const*>(memberType))
|
||||
memberType = arrayType->finalBaseType(true);
|
||||
|
||||
if (auto structType = dynamic_cast<StructType const*>(memberType))
|
||||
if (_cycleDetector.run(structType->structDefinition()))
|
||||
return;
|
||||
}
|
||||
};
|
||||
if (util::CycleDetector<StructDefinition>(visitor).run(_struct) != nullptr)
|
||||
if (util::CycleDetector<StructDefinition>(visitor).run(_struct))
|
||||
m_errorReporter.fatalTypeError(2046_error, _struct.location(), "Recursive struct definition.");
|
||||
|
||||
return false;
|
||||
|
@ -339,31 +339,21 @@ bool TypeChecker::visit(FunctionDefinition const& _function)
|
||||
m_errorReporter.typeError(5587_error, _function.location(), "Internal functions cannot be payable.");
|
||||
}
|
||||
auto checkArgumentAndReturnParameter = [&](VariableDeclaration const& var) {
|
||||
if (type(var)->category() == Type::Category::Mapping)
|
||||
if (type(var)->containsNestedMapping())
|
||||
if (var.referenceLocation() == VariableDeclaration::Location::Storage)
|
||||
solAssert(
|
||||
_function.libraryFunction() || !_function.isPublic(),
|
||||
"Mapping types for parameters or return variables "
|
||||
"can only be used in internal or library functions."
|
||||
);
|
||||
if (_function.isPublic())
|
||||
{
|
||||
if (var.referenceLocation() != VariableDeclaration::Location::Storage)
|
||||
{
|
||||
if (!_function.libraryFunction() && _function.isPublic())
|
||||
m_errorReporter.typeError(3442_error, var.location(), "Mapping types can only have a data location of \"storage\" and thus only be parameters or return variables for internal or library functions.");
|
||||
else
|
||||
m_errorReporter.typeError(5380_error, var.location(), "Mapping types can only have a data location of \"storage\"." );
|
||||
}
|
||||
else
|
||||
solAssert(_function.libraryFunction() || !_function.isPublic(), "Mapping types for parameters or return variables can only be used in internal or library functions.");
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!type(var)->canLiveOutsideStorage() && _function.isPublic())
|
||||
m_errorReporter.typeError(3312_error, var.location(), "Type is required to live outside storage.");
|
||||
if (_function.isPublic())
|
||||
{
|
||||
auto iType = type(var)->interfaceType(_function.libraryFunction());
|
||||
auto iType = type(var)->interfaceType(_function.libraryFunction());
|
||||
|
||||
if (!iType)
|
||||
{
|
||||
solAssert(!iType.message().empty(), "Expected detailed error message!");
|
||||
m_errorReporter.fatalTypeError(4103_error, var.location(), iType.message());
|
||||
}
|
||||
if (!iType)
|
||||
{
|
||||
solAssert(!iType.message().empty(), "Expected detailed error message!");
|
||||
m_errorReporter.typeError(4103_error, var.location(), iType.message());
|
||||
}
|
||||
}
|
||||
if (
|
||||
@ -457,9 +447,13 @@ bool TypeChecker::visit(VariableDeclaration const& _variable)
|
||||
m_errorReporter.typeError(1273_error, _variable.location(), "The type of a variable cannot be a library.");
|
||||
if (_variable.value())
|
||||
{
|
||||
if (_variable.isStateVariable() && dynamic_cast<MappingType const*>(varType))
|
||||
if (_variable.isStateVariable() && varType->containsNestedMapping())
|
||||
{
|
||||
m_errorReporter.typeError(6280_error, _variable.location(), "Mappings cannot be assigned to.");
|
||||
m_errorReporter.typeError(
|
||||
6280_error,
|
||||
_variable.location(),
|
||||
"Types in storage containing (nested) mappings cannot be assigned to."
|
||||
);
|
||||
_variable.value()->accept(*this);
|
||||
}
|
||||
else
|
||||
@ -499,9 +493,16 @@ bool TypeChecker::visit(VariableDeclaration const& _variable)
|
||||
|
||||
if (!_variable.isStateVariable())
|
||||
{
|
||||
if (varType->dataStoredIn(DataLocation::Memory) || varType->dataStoredIn(DataLocation::CallData))
|
||||
if (!varType->canLiveOutsideStorage())
|
||||
m_errorReporter.typeError(4061_error, _variable.location(), "Type " + varType->toString() + " is only valid in storage.");
|
||||
if (
|
||||
_variable.referenceLocation() == VariableDeclaration::Location::CallData ||
|
||||
_variable.referenceLocation() == VariableDeclaration::Location::Memory
|
||||
)
|
||||
if (varType->containsNestedMapping())
|
||||
m_errorReporter.fatalTypeError(
|
||||
4061_error,
|
||||
_variable.location(),
|
||||
"Type " + varType->toString(true) + " is only valid in storage because it contains a (nested) mapping."
|
||||
);
|
||||
}
|
||||
else if (_variable.visibility() >= Visibility::Public)
|
||||
{
|
||||
@ -612,8 +613,12 @@ bool TypeChecker::visit(EventDefinition const& _eventDef)
|
||||
{
|
||||
if (var->isIndexed())
|
||||
numIndexed++;
|
||||
if (!type(*var)->canLiveOutsideStorage())
|
||||
m_errorReporter.typeError(3448_error, var->location(), "Type is required to live outside storage.");
|
||||
if (type(*var)->containsNestedMapping())
|
||||
m_errorReporter.typeError(
|
||||
3448_error,
|
||||
var->location(),
|
||||
"Type containing a (nested) mapping is not allowed as event parameter type."
|
||||
);
|
||||
if (!type(*var)->interfaceType(false))
|
||||
m_errorReporter.typeError(3417_error, var->location(), "Internal or recursive type is not allowed as event parameter type.");
|
||||
if (
|
||||
@ -1386,7 +1391,7 @@ void TypeChecker::checkExpressionAssignment(Type const& _type, Expression const&
|
||||
checkExpressionAssignment(*types[i], *tupleExpression->components()[i]);
|
||||
}
|
||||
}
|
||||
else if (_type.category() == Type::Category::Mapping)
|
||||
else if (_type.nameable() && _type.containsNestedMapping())
|
||||
{
|
||||
bool isLocalOrReturn = false;
|
||||
if (auto const* identifier = dynamic_cast<Identifier const*>(&_expression))
|
||||
@ -1394,7 +1399,7 @@ void TypeChecker::checkExpressionAssignment(Type const& _type, Expression const&
|
||||
if (variableDeclaration->isLocalOrReturn())
|
||||
isLocalOrReturn = true;
|
||||
if (!isLocalOrReturn)
|
||||
m_errorReporter.typeError(9214_error, _expression.location(), "Mappings cannot be assigned to.");
|
||||
m_errorReporter.typeError(9214_error, _expression.location(), "Types in storage containing (nested) mappings cannot be assigned to.");
|
||||
}
|
||||
}
|
||||
|
||||
@ -1530,8 +1535,12 @@ bool TypeChecker::visit(TupleExpression const& _tuple)
|
||||
_tuple.location(),
|
||||
"Unable to deduce nameable type for array elements. Try adding explicit type conversion for the first element."
|
||||
);
|
||||
else if (!inlineArrayType->canLiveOutsideStorage())
|
||||
m_errorReporter.fatalTypeError(1545_error, _tuple.location(), "Type " + inlineArrayType->toString() + " is only valid in storage.");
|
||||
else if (inlineArrayType->containsNestedMapping())
|
||||
m_errorReporter.fatalTypeError(
|
||||
1545_error,
|
||||
_tuple.location(),
|
||||
"Type " + inlineArrayType->toString(true) + " is only valid in storage."
|
||||
);
|
||||
|
||||
_tuple.annotation().type = TypeProvider::array(DataLocation::Memory, inlineArrayType, types.size());
|
||||
}
|
||||
@ -2032,24 +2041,8 @@ void TypeChecker::typeCheckFunctionGeneralChecks(
|
||||
toString(parameterTypes.size()) +
|
||||
".";
|
||||
|
||||
// Extend error message in case we try to construct a struct with mapping member.
|
||||
if (isStructConstructorCall)
|
||||
{
|
||||
/// For error message: Struct members that were removed during conversion to memory.
|
||||
TypePointer const expressionType = type(_functionCall.expression());
|
||||
auto const& t = dynamic_cast<TypeType const&>(*expressionType);
|
||||
auto const& structType = dynamic_cast<StructType const&>(*t.actualType());
|
||||
set<string> membersRemovedForStructConstructor = structType.membersMissingInMemory();
|
||||
|
||||
if (!membersRemovedForStructConstructor.empty())
|
||||
{
|
||||
msg += " Members that have to be skipped in memory:";
|
||||
for (auto const& member: membersRemovedForStructConstructor)
|
||||
msg += " " + member;
|
||||
}
|
||||
|
||||
return { isVariadic ? 1123_error : 9755_error, msg };
|
||||
}
|
||||
else if (
|
||||
_functionType->kind() == FunctionType::Kind::BareCall ||
|
||||
_functionType->kind() == FunctionType::Kind::BareCallCode ||
|
||||
@ -2269,6 +2262,12 @@ bool TypeChecker::visit(FunctionCall const& _functionCall)
|
||||
|
||||
if (actualType->category() == Type::Category::Struct)
|
||||
{
|
||||
if (actualType->containsNestedMapping())
|
||||
m_errorReporter.fatalTypeError(
|
||||
9515_error,
|
||||
_functionCall.location(),
|
||||
"Struct containing a (nested) mapping cannot be constructed."
|
||||
);
|
||||
functionType = dynamic_cast<StructType const&>(*actualType).constructorType();
|
||||
funcCallAnno.kind = FunctionCallKind::StructConstructorCall;
|
||||
funcCallAnno.isPure = argumentsArePure;
|
||||
@ -2518,11 +2517,11 @@ void TypeChecker::endVisit(NewExpression const& _newExpression)
|
||||
}
|
||||
else if (type->category() == Type::Category::Array)
|
||||
{
|
||||
if (!type->canLiveOutsideStorage())
|
||||
if (type->containsNestedMapping())
|
||||
m_errorReporter.fatalTypeError(
|
||||
1164_error,
|
||||
_newExpression.typeName().location(),
|
||||
"Type cannot live outside storage."
|
||||
"Array containing a (nested) mapping cannot be constructed in memory."
|
||||
);
|
||||
if (!type->isDynamicallySized())
|
||||
m_errorReporter.typeError(
|
||||
|
@ -136,6 +136,9 @@ struct StructDeclarationAnnotation: TypeDeclarationAnnotation
|
||||
/// recursion immediately raises an error.
|
||||
/// Will be filled in by the DeclarationTypeChecker.
|
||||
std::optional<bool> recursive;
|
||||
/// Whether the struct contains a mapping type, either directly or, indirectly inside another
|
||||
/// struct or an array.
|
||||
std::optional<bool> containsNestedMapping;
|
||||
};
|
||||
|
||||
struct ContractDefinitionAnnotation: TypeDeclarationAnnotation, StructurallyDocumentedAnnotation
|
||||
|
@ -1985,6 +1985,20 @@ TypeResult ArrayType::interfaceType(bool _inLibrary) const
|
||||
return result;
|
||||
}
|
||||
|
||||
Type const* ArrayType::finalBaseType(bool _breakIfDynamicArrayType) const
|
||||
{
|
||||
Type const* finalBaseType = this;
|
||||
|
||||
while (auto arrayType = dynamic_cast<ArrayType const*>(finalBaseType))
|
||||
{
|
||||
if (_breakIfDynamicArrayType && arrayType->isDynamicallySized())
|
||||
break;
|
||||
finalBaseType = arrayType->baseType();
|
||||
}
|
||||
|
||||
return finalBaseType;
|
||||
}
|
||||
|
||||
u256 ArrayType::memoryDataSize() const
|
||||
{
|
||||
solAssert(!isDynamicallySized(), "");
|
||||
@ -2213,7 +2227,7 @@ unsigned StructType::calldataEncodedSize(bool) const
|
||||
unsigned size = 0;
|
||||
for (auto const& member: members(nullptr))
|
||||
{
|
||||
solAssert(member.type->canLiveOutsideStorage(), "");
|
||||
solAssert(!member.type->containsNestedMapping(), "");
|
||||
// Struct members are always padded.
|
||||
size += member.type->calldataEncodedSize();
|
||||
}
|
||||
@ -2228,7 +2242,7 @@ unsigned StructType::calldataEncodedTailSize() const
|
||||
unsigned size = 0;
|
||||
for (auto const& member: members(nullptr))
|
||||
{
|
||||
solAssert(member.type->canLiveOutsideStorage(), "");
|
||||
solAssert(!member.type->containsNestedMapping(), "");
|
||||
// Struct members are always padded.
|
||||
size += member.type->calldataHeadSize();
|
||||
}
|
||||
@ -2240,7 +2254,7 @@ unsigned StructType::calldataOffsetOfMember(std::string const& _member) const
|
||||
unsigned offset = 0;
|
||||
for (auto const& member: members(nullptr))
|
||||
{
|
||||
solAssert(member.type->canLiveOutsideStorage(), "");
|
||||
solAssert(!member.type->containsNestedMapping(), "");
|
||||
if (member.name == _member)
|
||||
return offset;
|
||||
// Struct members are always padded.
|
||||
@ -2277,6 +2291,42 @@ u256 StructType::storageSize() const
|
||||
return max<u256>(1, members(nullptr).storageSize());
|
||||
}
|
||||
|
||||
bool StructType::containsNestedMapping() const
|
||||
{
|
||||
if (!m_struct.annotation().containsNestedMapping.has_value())
|
||||
{
|
||||
bool hasNestedMapping = false;
|
||||
|
||||
util::BreadthFirstSearch<StructDefinition const*> breadthFirstSearch{{&m_struct}};
|
||||
|
||||
breadthFirstSearch.run(
|
||||
[&](StructDefinition const* _struct, auto&& _addChild)
|
||||
{
|
||||
for (auto const& member: _struct->members())
|
||||
{
|
||||
TypePointer memberType = member->annotation().type;
|
||||
solAssert(memberType, "");
|
||||
|
||||
if (auto arrayType = dynamic_cast<ArrayType const*>(memberType))
|
||||
memberType = arrayType->finalBaseType(false);
|
||||
|
||||
if (dynamic_cast<MappingType const*>(memberType))
|
||||
{
|
||||
hasNestedMapping = true;
|
||||
breadthFirstSearch.abort();
|
||||
}
|
||||
else if (auto structType = dynamic_cast<StructType const*>(memberType))
|
||||
_addChild(&structType->structDefinition());
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
m_struct.annotation().containsNestedMapping = hasNestedMapping;
|
||||
}
|
||||
|
||||
return m_struct.annotation().containsNestedMapping.value();
|
||||
}
|
||||
|
||||
string StructType::toString(bool _short) const
|
||||
{
|
||||
string ret = "struct " + m_struct.annotation().canonicalName;
|
||||
@ -2292,10 +2342,7 @@ MemberList::MemberMap StructType::nativeMembers(ASTNode const*) const
|
||||
{
|
||||
TypePointer type = variable->annotation().type;
|
||||
solAssert(type, "");
|
||||
// If we are not in storage, skip all members that cannot live outside of storage,
|
||||
// ex. mappings and array of mappings
|
||||
if (location() != DataLocation::Storage && !type->canLiveOutsideStorage())
|
||||
continue;
|
||||
solAssert(!(location() != DataLocation::Storage && type->containsNestedMapping()), "");
|
||||
members.emplace_back(
|
||||
variable->name(),
|
||||
copyForLocationIfReference(type),
|
||||
@ -2457,10 +2504,9 @@ FunctionTypePointer StructType::constructorType() const
|
||||
{
|
||||
TypePointers paramTypes;
|
||||
strings paramNames;
|
||||
solAssert(!containsNestedMapping(), "");
|
||||
for (auto const& member: members(nullptr))
|
||||
{
|
||||
if (!member.type->canLiveOutsideStorage())
|
||||
continue;
|
||||
paramNames.push_back(member.name);
|
||||
paramTypes.push_back(TypeProvider::withLocationIfReference(DataLocation::Memory, member.type));
|
||||
}
|
||||
@ -2494,20 +2540,12 @@ u256 StructType::memoryOffsetOfMember(string const& _name) const
|
||||
|
||||
TypePointers StructType::memoryMemberTypes() const
|
||||
{
|
||||
solAssert(!containsNestedMapping(), "");
|
||||
TypePointers types;
|
||||
for (ASTPointer<VariableDeclaration> const& variable: m_struct.members())
|
||||
if (variable->annotation().type->canLiveOutsideStorage())
|
||||
types.push_back(TypeProvider::withLocationIfReference(DataLocation::Memory, variable->annotation().type));
|
||||
return types;
|
||||
}
|
||||
types.push_back(TypeProvider::withLocationIfReference(DataLocation::Memory, variable->annotation().type));
|
||||
|
||||
set<string> StructType::membersMissingInMemory() const
|
||||
{
|
||||
set<string> missing;
|
||||
for (ASTPointer<VariableDeclaration> const& variable: m_struct.members())
|
||||
if (!variable->annotation().type->canLiveOutsideStorage())
|
||||
missing.insert(variable->name());
|
||||
return missing;
|
||||
return types;
|
||||
}
|
||||
|
||||
vector<tuple<string, TypePointer>> StructType::makeStackItems() const
|
||||
@ -3654,7 +3692,10 @@ TypeResult MappingType::interfaceType(bool _inLibrary) const
|
||||
}
|
||||
}
|
||||
else
|
||||
return TypeResult::err("Only libraries are allowed to use the mapping type in public or external functions.");
|
||||
return TypeResult::err(
|
||||
"Types containing (nested) mappings can only be parameters or "
|
||||
"return variables of internal or library functions."
|
||||
);
|
||||
|
||||
return this;
|
||||
}
|
||||
|
@ -259,7 +259,11 @@ public:
|
||||
/// Returns true if the type can be stored in storage.
|
||||
virtual bool canBeStored() const { return true; }
|
||||
/// Returns false if the type cannot live outside the storage, i.e. if it includes some mapping.
|
||||
virtual bool canLiveOutsideStorage() const { return true; }
|
||||
virtual bool containsNestedMapping() const
|
||||
{
|
||||
solAssert(nameable(), "Called for a non nameable type.");
|
||||
return false;
|
||||
}
|
||||
/// Returns true if the type can be stored as a value (as opposed to a reference) on the stack,
|
||||
/// i.e. it behaves differently in lvalue context and in value context.
|
||||
virtual bool isValueType() const { return false; }
|
||||
@ -549,7 +553,6 @@ public:
|
||||
bool operator==(Type const& _other) const override;
|
||||
|
||||
bool canBeStored() const override { return false; }
|
||||
bool canLiveOutsideStorage() const override { return false; }
|
||||
|
||||
std::string toString(bool _short) const override;
|
||||
u256 literalValue(Literal const* _literal) const override;
|
||||
@ -610,7 +613,6 @@ public:
|
||||
bool operator==(Type const& _other) const override;
|
||||
|
||||
bool canBeStored() const override { return false; }
|
||||
bool canLiveOutsideStorage() const override { return false; }
|
||||
|
||||
std::string toString(bool) const override;
|
||||
TypePointer mobileType() const override;
|
||||
@ -781,8 +783,9 @@ public:
|
||||
bool isDynamicallySized() const override { return m_hasDynamicLength; }
|
||||
bool isDynamicallyEncoded() const override;
|
||||
u256 storageSize() const override;
|
||||
bool canLiveOutsideStorage() const override { return m_baseType->canLiveOutsideStorage(); }
|
||||
bool containsNestedMapping() const override { return m_baseType->containsNestedMapping(); }
|
||||
bool nameable() const override { return true; }
|
||||
|
||||
std::string toString(bool _short) const override;
|
||||
std::string canonicalName() const override;
|
||||
std::string signatureInExternalFunction(bool _structsByName) const override;
|
||||
@ -798,6 +801,7 @@ public:
|
||||
/// @returns true if this is a string
|
||||
bool isString() const { return m_arrayKind == ArrayKind::String; }
|
||||
Type const* baseType() const { solAssert(!!m_baseType, ""); return m_baseType; }
|
||||
Type const* finalBaseType(bool breakIfDynamicArrayType) const;
|
||||
u256 const& length() const { return m_length; }
|
||||
u256 memoryDataSize() const override;
|
||||
|
||||
@ -842,7 +846,6 @@ public:
|
||||
unsigned calldataEncodedTailSize() const override { return 32; }
|
||||
bool isDynamicallySized() const override { return true; }
|
||||
bool isDynamicallyEncoded() const override { return true; }
|
||||
bool canLiveOutsideStorage() const override { return m_arrayType.canLiveOutsideStorage(); }
|
||||
std::string toString(bool _short) const override;
|
||||
TypePointer mobileType() const override;
|
||||
|
||||
@ -883,7 +886,6 @@ public:
|
||||
}
|
||||
unsigned storageBytes() const override { solAssert(!isSuper(), ""); return 20; }
|
||||
bool leftAligned() const override { solAssert(!isSuper(), ""); return false; }
|
||||
bool canLiveOutsideStorage() const override { return !isSuper(); }
|
||||
bool isValueType() const override { return !isSuper(); }
|
||||
bool nameable() const override { return !isSuper(); }
|
||||
std::string toString(bool _short) const override;
|
||||
@ -945,7 +947,7 @@ public:
|
||||
bool isDynamicallyEncoded() const override;
|
||||
u256 memoryDataSize() const override;
|
||||
u256 storageSize() const override;
|
||||
bool canLiveOutsideStorage() const override { return true; }
|
||||
bool containsNestedMapping() const override;
|
||||
bool nameable() const override { return true; }
|
||||
std::string toString(bool _short) const override;
|
||||
|
||||
@ -975,8 +977,6 @@ public:
|
||||
|
||||
/// @returns the vector of types of members available in memory.
|
||||
TypePointers memoryMemberTypes() const;
|
||||
/// @returns the set of all members that are removed in the memory version (typically mappings).
|
||||
std::set<std::string> membersMissingInMemory() const;
|
||||
|
||||
void clearCache() const override;
|
||||
|
||||
@ -1007,7 +1007,6 @@ public:
|
||||
}
|
||||
unsigned storageBytes() const override;
|
||||
bool leftAligned() const override { return false; }
|
||||
bool canLiveOutsideStorage() const override { return true; }
|
||||
std::string toString(bool _short) const override;
|
||||
std::string canonicalName() const override;
|
||||
bool isValueType() const override { return true; }
|
||||
@ -1047,7 +1046,6 @@ public:
|
||||
std::string toString(bool) const override;
|
||||
bool canBeStored() const override { return false; }
|
||||
u256 storageSize() const override;
|
||||
bool canLiveOutsideStorage() const override { return false; }
|
||||
bool hasSimpleZeroValueInMemory() const override { return false; }
|
||||
TypePointer mobileType() const override;
|
||||
/// Converts components to their temporary types and performs some wildcard matching.
|
||||
@ -1218,7 +1216,6 @@ public:
|
||||
unsigned storageBytes() const override;
|
||||
bool isValueType() const override { return true; }
|
||||
bool nameable() const override;
|
||||
bool canLiveOutsideStorage() const override { return m_kind == Kind::Internal || m_kind == Kind::External; }
|
||||
bool hasSimpleZeroValueInMemory() const override { return false; }
|
||||
MemberList::MemberMap nativeMembers(ASTNode const* _currentScope) const override;
|
||||
TypePointer encodingType() const override;
|
||||
@ -1351,7 +1348,7 @@ public:
|
||||
bool operator==(Type const& _other) const override;
|
||||
std::string toString(bool _short) const override;
|
||||
std::string canonicalName() const override;
|
||||
bool canLiveOutsideStorage() const override { return false; }
|
||||
bool containsNestedMapping() const override { return true; }
|
||||
TypeResult binaryOperatorResult(Token, Type const*) const override { return nullptr; }
|
||||
Type const* encodingType() const override;
|
||||
TypeResult interfaceType(bool _inLibrary) const override;
|
||||
@ -1386,7 +1383,6 @@ public:
|
||||
bool operator==(Type const& _other) const override;
|
||||
bool canBeStored() const override { return false; }
|
||||
u256 storageSize() const override;
|
||||
bool canLiveOutsideStorage() const override { return false; }
|
||||
bool hasSimpleZeroValueInMemory() const override { solAssert(false, ""); }
|
||||
std::string toString(bool _short) const override { return "type(" + m_actualType->toString(_short) + ")"; }
|
||||
MemberList::MemberMap nativeMembers(ASTNode const* _currentScope) const override;
|
||||
@ -1412,7 +1408,6 @@ public:
|
||||
TypeResult binaryOperatorResult(Token, Type const*) const override { return nullptr; }
|
||||
bool canBeStored() const override { return false; }
|
||||
u256 storageSize() const override;
|
||||
bool canLiveOutsideStorage() const override { return false; }
|
||||
bool hasSimpleZeroValueInMemory() const override { solAssert(false, ""); }
|
||||
std::string richIdentifier() const override;
|
||||
bool operator==(Type const& _other) const override;
|
||||
@ -1439,7 +1434,6 @@ public:
|
||||
std::string richIdentifier() const override;
|
||||
bool operator==(Type const& _other) const override;
|
||||
bool canBeStored() const override { return false; }
|
||||
bool canLiveOutsideStorage() const override { return true; }
|
||||
bool hasSimpleZeroValueInMemory() const override { solAssert(false, ""); }
|
||||
MemberList::MemberMap nativeMembers(ASTNode const*) const override;
|
||||
|
||||
@ -1479,7 +1473,6 @@ public:
|
||||
std::string richIdentifier() const override;
|
||||
bool operator==(Type const& _other) const override;
|
||||
bool canBeStored() const override { return false; }
|
||||
bool canLiveOutsideStorage() const override { return true; }
|
||||
bool hasSimpleZeroValueInMemory() const override { solAssert(false, ""); }
|
||||
MemberList::MemberMap nativeMembers(ASTNode const*) const override;
|
||||
|
||||
@ -1512,7 +1505,6 @@ public:
|
||||
TypeResult binaryOperatorResult(Token, Type const*) const override { return nullptr; }
|
||||
unsigned calldataEncodedSize(bool) const override { return 32; }
|
||||
bool canBeStored() const override { return false; }
|
||||
bool canLiveOutsideStorage() const override { return false; }
|
||||
bool isValueType() const override { return true; }
|
||||
bool hasSimpleZeroValueInMemory() const override { solAssert(false, ""); }
|
||||
std::string toString(bool) const override { return "inaccessible dynamic type"; }
|
||||
|
@ -860,8 +860,7 @@ string ABIFunctions::abiEncodingFunctionStruct(
|
||||
for (auto const& member: _to.members(nullptr))
|
||||
{
|
||||
solAssert(member.type, "");
|
||||
if (!member.type->canLiveOutsideStorage())
|
||||
continue;
|
||||
solAssert(!member.type->containsNestedMapping(), "");
|
||||
TypePointer memberTypeTo = member.type->fullEncodingType(_options.encodeAsLibraryTypes, true, false);
|
||||
solUnimplementedAssert(memberTypeTo, "Encoding type \"" + member.type->toString() + "\" not yet implemented.");
|
||||
auto memberTypeFrom = _from.memberType(member.name);
|
||||
@ -1340,7 +1339,7 @@ string ABIFunctions::abiDecodingFunctionStruct(StructType const& _type, bool _fr
|
||||
for (auto const& member: _type.members(nullptr))
|
||||
{
|
||||
solAssert(member.type, "");
|
||||
solAssert(member.type->canLiveOutsideStorage(), "");
|
||||
solAssert(!member.type->containsNestedMapping(), "");
|
||||
auto decodingType = member.type->decodingType();
|
||||
solAssert(decodingType, "");
|
||||
bool dynamic = decodingType->isDynamicallyEncoded();
|
||||
|
@ -1069,8 +1069,7 @@ void CompilerUtils::convertType(
|
||||
// stack: <memory ptr> <source ref> <memory ptr>
|
||||
for (auto const& member: typeOnStack->members(nullptr))
|
||||
{
|
||||
if (!member.type->canLiveOutsideStorage())
|
||||
continue;
|
||||
solAssert(!member.type->containsNestedMapping(), "");
|
||||
pair<u256, unsigned> const& offsets = typeOnStack->storageOffsetsOfMember(member.name);
|
||||
_context << offsets.first << Instruction::DUP3 << Instruction::ADD;
|
||||
_context << u256(offsets.second);
|
||||
|
@ -355,13 +355,13 @@ void StorageItem::storeValue(Type const& _sourceType, SourceLocation const& _loc
|
||||
structType.structDefinition() == sourceType.structDefinition(),
|
||||
"Struct assignment with conversion."
|
||||
);
|
||||
solAssert(!structType.containsNestedMapping(), "");
|
||||
solAssert(sourceType.location() != DataLocation::CallData, "Structs in calldata not supported.");
|
||||
for (auto const& member: structType.members(nullptr))
|
||||
{
|
||||
// assign each member that can live outside of storage
|
||||
TypePointer const& memberType = member.type;
|
||||
if (!memberType->canLiveOutsideStorage())
|
||||
continue;
|
||||
solAssert(memberType->nameable(), "");
|
||||
TypePointer sourceMemberType = sourceType.memberType(member.name);
|
||||
if (sourceType.location() == DataLocation::Storage)
|
||||
{
|
||||
|
Loading…
Reference in New Issue
Block a user