Move mapping key checks to ReferencesResolver and make them fatal.

This commit is contained in:
Daniel Kirchner 2020-02-11 13:35:23 +01:00
parent 5214cb0e76
commit 9c3151748e
5 changed files with 35 additions and 30 deletions

View File

@ -224,15 +224,36 @@ void ReferencesResolver::endVisit(FunctionTypeName const& _typeName)
_typeName.annotation().type = TypeProvider::function(_typeName);
}
void ReferencesResolver::endVisit(Mapping const& _typeName)
void ReferencesResolver::endVisit(Mapping const& _mapping)
{
TypePointer keyType = _typeName.keyType().annotation().type;
TypePointer valueType = _typeName.valueType().annotation().type;
if (auto const* typeName = dynamic_cast<UserDefinedTypeName const*>(&_mapping.keyType()))
{
if (auto const* contractType = dynamic_cast<ContractType const*>(typeName->annotation().type))
{
if (contractType->contractDefinition().isLibrary())
m_errorReporter.fatalTypeError(
typeName->location(),
"Library types cannot be used as mapping keys."
);
}
else if (typeName->annotation().type->category() != Type::Category::Enum)
m_errorReporter.fatalTypeError(
typeName->location(),
"Only elementary types, contract types or enums are allowed as mapping keys."
);
}
else
solAssert(dynamic_cast<ElementaryTypeName const*>(&_mapping.keyType()), "");
TypePointer keyType = _mapping.keyType().annotation().type;
TypePointer valueType = _mapping.valueType().annotation().type;
// Convert key type to memory.
keyType = TypeProvider::withLocationIfReference(DataLocation::Memory, keyType);
// Convert value type to storage reference.
valueType = TypeProvider::withLocationIfReference(DataLocation::Storage, valueType);
_typeName.annotation().type = TypeProvider::mapping(keyType, valueType);
_mapping.annotation().type = TypeProvider::mapping(keyType, valueType);
}
void ReferencesResolver::endVisit(ArrayTypeName const& _typeName)

View File

@ -81,7 +81,7 @@ private:
void endVisit(ModifierDefinition const& _modifierDefinition) override;
void endVisit(UserDefinedTypeName const& _typeName) override;
void endVisit(FunctionTypeName const& _typeName) override;
void endVisit(Mapping const& _typeName) override;
void endVisit(Mapping const& _mapping) override;
void endVisit(ArrayTypeName const& _typeName) override;
bool visit(InlineAssembly const& _inlineAssembly) override;
bool visit(Return const& _return) override;

View File

@ -2876,30 +2876,6 @@ void TypeChecker::endVisit(Literal const& _literal)
_literal.annotation().isPure = true;
}
bool TypeChecker::visit(Mapping const& _mapping)
{
if (auto const* keyType = dynamic_cast<UserDefinedTypeName const*>(&_mapping.keyType()))
{
if (auto const* contractType = dynamic_cast<ContractType const*>(keyType->annotation().type))
{
if (contractType->contractDefinition().isLibrary())
m_errorReporter.typeError(
keyType->location(),
"Library types cannot be used as mapping keys."
);
}
else if (keyType->annotation().type->category() != Type::Category::Enum)
m_errorReporter.typeError(
keyType->location(),
"Only elementary types, contract types or enums are allowed as mapping keys."
);
}
else
solAssert(dynamic_cast<ElementaryTypeName const*>(&_mapping.keyType()), "");
return true;
}
bool TypeChecker::contractDependenciesAreCyclic(
ContractDefinition const& _contract,
std::set<ContractDefinition const*> const& _seenContracts

View File

@ -143,7 +143,6 @@ private:
bool visit(Identifier const& _identifier) override;
void endVisit(ElementaryTypeNameExpression const& _expr) override;
void endVisit(Literal const& _literal) override;
bool visit(Mapping const& _mapping) override;
bool contractDependenciesAreCyclic(
ContractDefinition const& _contract,

View File

@ -0,0 +1,9 @@
// Used to segfault.
contract C {
struct S {
mapping(S => uint) a;
}
function g (S calldata) external view {}
}
// ----
// TypeError: (56-57): Only elementary types, contract types or enums are allowed as mapping keys.