Allow user-defined types as mapping keys in parser and restrict to contracts during type checking.

This commit is contained in:
Daniel Kirchner
2020-02-04 17:22:03 +01:00
parent 7a194ffdab
commit d3cbfb0c5c
25 changed files with 808 additions and 18 deletions
+19
View File
@@ -2876,6 +2876,25 @@ 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 (
keyType->annotation().type->category() != Type::Category::Contract &&
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
+1
View File
@@ -143,6 +143,7 @@ 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,
+3 -3
View File
@@ -1152,18 +1152,18 @@ public:
Mapping(
int64_t _id,
SourceLocation const& _location,
ASTPointer<ElementaryTypeName> const& _keyType,
ASTPointer<TypeName> const& _keyType,
ASTPointer<TypeName> const& _valueType
):
TypeName(_id, _location), m_keyType(_keyType), m_valueType(_valueType) {}
void accept(ASTVisitor& _visitor) override;
void accept(ASTConstVisitor& _visitor) const override;
ElementaryTypeName const& keyType() const { return *m_keyType; }
TypeName const& keyType() const { return *m_keyType; }
TypeName const& valueType() const { return *m_valueType; }
private:
ASTPointer<ElementaryTypeName> m_keyType;
ASTPointer<TypeName> m_keyType;
ASTPointer<TypeName> m_valueType;
};
+1 -1
View File
@@ -511,7 +511,7 @@ ASTPointer<Mapping> ASTJsonImporter::createMapping(Json::Value const& _node)
{
return createASTNode<Mapping>(
_node,
createElementaryTypeName(member(_node, "keyType")),
convertJsonToASTNode<TypeName>(member(_node, "keyType")),
convertJsonToASTNode<TypeName>(member(_node, "valueType"))
);
}
+12 -6
View File
@@ -1019,16 +1019,22 @@ ASTPointer<Mapping> Parser::parseMapping()
ASTNodeFactory nodeFactory(*this);
expectToken(Token::Mapping);
expectToken(Token::LParen);
ASTPointer<ElementaryTypeName> keyType;
ASTPointer<TypeName> keyType;
Token token = m_scanner->currentToken();
if (!TokenTraits::isElementaryTypeName(token))
fatalParserError(string("Expected elementary type name for mapping key type"));
unsigned firstSize;
unsigned secondSize;
tie(firstSize, secondSize) = m_scanner->currentTokenInfo();
ElementaryTypeNameToken elemTypeName(token, firstSize, secondSize);
keyType = ASTNodeFactory(*this).createNode<ElementaryTypeName>(elemTypeName);
m_scanner->next();
if (token == Token::Identifier)
keyType = parseUserDefinedTypeName();
else if (TokenTraits::isElementaryTypeName(token))
{
keyType = ASTNodeFactory(*this).createNode<ElementaryTypeName>(
ElementaryTypeNameToken{token, firstSize, secondSize}
);
m_scanner->next();
}
else
fatalParserError(string("Expected elementary type name or identifier for mapping key type"));
expectToken(Token::Arrow);
bool const allowVar = false;
ASTPointer<TypeName> valueType = parseTypeName(allowVar);