Refactoring of errors and fixes for various ICEs.

This commit is contained in:
Daniel Kirchner
2020-04-16 16:42:12 +02:00
parent df1809f8da
commit b744a56801
16 changed files with 127 additions and 38 deletions
+7 -12
View File
@@ -518,19 +518,14 @@ bool TypeChecker::visit(VariableDeclaration const& _variable)
m_errorReporter.typeError(_variable.location(), "Internal or recursive type is not allowed for public state variables.");
}
switch (varType->category())
if (auto referenceType = dynamic_cast<ReferenceType const*>(varType))
{
case Type::Category::Array:
if (auto arrayType = dynamic_cast<ArrayType const*>(varType))
if (
((arrayType->location() == DataLocation::Memory) ||
(arrayType->location() == DataLocation::CallData)) &&
!arrayType->validForCalldata()
)
m_errorReporter.typeError(_variable.location(), "Array is too large to be encoded.");
break;
default:
break;
auto result = referenceType->validForLocation(referenceType->location());
if (!result)
{
solAssert(!result.message().empty(), "Expected detailed error message");
m_errorReporter.typeError(_variable.location(), result.message());
}
}
return false;
+14 -6
View File
@@ -617,12 +617,20 @@ set<VariableDeclaration::Location> VariableDeclaration::allowedDataLocations() c
else if (isLocalVariable())
{
solAssert(typeName(), "");
solAssert(typeName()->annotation().type, "Can only be called after reference resolution");
if (typeName()->annotation().type->category() == Type::Category::Mapping)
return set<Location>{ Location::Storage };
else
// TODO: add Location::Calldata once implemented for local variables.
return set<Location>{ Location::Memory, Location::Storage };
auto getDataLocations = [](TypePointer _type, auto&& _recursion) -> set<Location> {
solAssert(_type, "Can only be called after reference resolution");
switch (_type->category())
{
case Type::Category::Array:
return _recursion(dynamic_cast<ArrayType const*>(_type)->baseType(), _recursion);
case Type::Category::Mapping:
return set<Location>{ Location::Storage };
default:
// TODO: add Location::Calldata once implemented for local variables.
return set<Location>{ Location::Memory, Location::Storage };
}
};
return getDataLocations(typeName()->annotation().type, getDataLocations);
}
else
// Struct members etc.
+39 -4
View File
@@ -1649,12 +1649,35 @@ bool ArrayType::operator==(Type const& _other) const
return isDynamicallySized() || length() == other.length();
}
bool ArrayType::validForCalldata() const
BoolResult ArrayType::validForLocation(DataLocation _loc) const
{
if (auto arrayBaseType = dynamic_cast<ArrayType const*>(baseType()))
if (!arrayBaseType->validForCalldata())
return false;
return isDynamicallySized() || unlimitedStaticCalldataSize(true) <= numeric_limits<unsigned>::max();
{
BoolResult result = arrayBaseType->validForLocation(_loc);
if (!result)
return result;
}
if (isDynamicallySized())
return true;
switch (_loc)
{
case DataLocation::Memory:
{
bigint size = bigint(length()) * m_baseType->memoryHeadSize();
if (size >= numeric_limits<unsigned>::max())
return BoolResult::err("Type too large for memory.");
break;
}
case DataLocation::CallData:
{
if (unlimitedStaticCalldataSize(true) >= numeric_limits<unsigned>::max())
return BoolResult::err("Type too large for calldata.");
break;
}
case DataLocation::Storage:
break;
}
return true;
}
bigint ArrayType::unlimitedStaticCalldataSize(bool _padded) const
@@ -2272,6 +2295,18 @@ TypeResult StructType::interfaceType(bool _inLibrary) const
return *m_interfaceType_library;
}
BoolResult StructType::validForLocation(DataLocation _loc) const
{
for (auto const& member: m_struct.members())
if (auto referenceType = dynamic_cast<ReferenceType const*>(member->annotation().type))
{
BoolResult result = referenceType->validForLocation(_loc);
if (!result)
return result;
}
return true;
}
bool StructType::recursive() const
{
solAssert(m_struct.annotation().recursive.has_value(), "Called StructType::recursive() before DeclarationTypeChecker.");
+7 -4
View File
@@ -706,6 +706,9 @@ public:
/// never change the contents of the original value.
bool isPointer() const;
/// @returns true if this is valid to be stored in data location _loc
virtual BoolResult validForLocation(DataLocation _loc) const = 0;
bool operator==(ReferenceType const& _other) const
{
return location() == _other.location() && isPointer() == _other.isPointer();
@@ -772,8 +775,7 @@ public:
TypePointer decodingType() const override;
TypeResult interfaceType(bool _inLibrary) const override;
/// @returns true if this is valid to be stored in calldata
bool validForCalldata() const;
BoolResult validForLocation(DataLocation _loc) const override;
/// @returns true if this is a byte array or a string
bool isByteArray() const { return m_arrayKind != ArrayKind::Ordinary; }
@@ -827,8 +829,7 @@ public:
bool canLiveOutsideStorage() const override { return m_arrayType.canLiveOutsideStorage(); }
std::string toString(bool _short) const override;
/// @returns true if this is valid to be stored in calldata
bool validForCalldata() const { return m_arrayType.validForCalldata(); }
BoolResult validForLocation(DataLocation _loc) const override { return m_arrayType.validForLocation(_loc); }
ArrayType const& arrayType() const { return m_arrayType; }
u256 memoryDataSize() const override { solAssert(false, ""); }
@@ -934,6 +935,8 @@ public:
Type const* encodingType() const override;
TypeResult interfaceType(bool _inLibrary) const override;
BoolResult validForLocation(DataLocation _loc) const override;
bool recursive() const;
std::unique_ptr<ReferenceType> copyForLocation(DataLocation _location, bool _isPointer) const override;