From bf55aa6ae2b9aeec09bb8cf1e3715afd7dd59b7e Mon Sep 17 00:00:00 2001 From: chriseth Date: Tue, 17 Nov 2015 01:47:47 +0100 Subject: [PATCH] Type checking for creating new arrays. --- libsolidity/analysis/ReferencesResolver.cpp | 5 +++ libsolidity/analysis/ReferencesResolver.h | 1 + libsolidity/analysis/TypeChecker.cpp | 24 +++++++++++- libsolidity/ast/Types.h | 6 +-- .../SolidityNameAndTypeResolution.cpp | 38 ++++++++++++++++++- 5 files changed, 67 insertions(+), 7 deletions(-) diff --git a/libsolidity/analysis/ReferencesResolver.cpp b/libsolidity/analysis/ReferencesResolver.cpp index 0e153045e..408212f15 100644 --- a/libsolidity/analysis/ReferencesResolver.cpp +++ b/libsolidity/analysis/ReferencesResolver.cpp @@ -37,6 +37,11 @@ bool ReferencesResolver::visit(Return const& _return) return true; } +void ReferencesResolver::endVisit(NewExpression const& _new) +{ + typeFor(_new.typeName()); +} + bool ReferencesResolver::visit(UserDefinedTypeName const& _typeName) { Declaration const* declaration = m_resolver.pathFromCurrentScope(_typeName.namePath()); diff --git a/libsolidity/analysis/ReferencesResolver.h b/libsolidity/analysis/ReferencesResolver.h index 21cb1d359..621046116 100644 --- a/libsolidity/analysis/ReferencesResolver.h +++ b/libsolidity/analysis/ReferencesResolver.h @@ -64,6 +64,7 @@ private: virtual bool visit(Identifier const& _identifier) override; virtual bool visit(UserDefinedTypeName const& _typeName) override; virtual bool visit(Return const& _return) override; + virtual void endVisit(NewExpression const& _new) override; virtual void endVisit(VariableDeclaration const& _variable) override; TypePointer typeFor(TypeName const& _typeName); diff --git a/libsolidity/analysis/TypeChecker.cpp b/libsolidity/analysis/TypeChecker.cpp index 13c2235a3..5623da376 100644 --- a/libsolidity/analysis/TypeChecker.cpp +++ b/libsolidity/analysis/TypeChecker.cpp @@ -1045,6 +1045,9 @@ bool TypeChecker::visit(FunctionCall const& _functionCall) void TypeChecker::endVisit(NewExpression const& _newExpression) { + TypePointer type = _newExpression.typeName().annotation().type; + solAssert(!!type, "Type name not resolved."); + if (auto contractName = dynamic_cast(&_newExpression.typeName())) { auto contract = dynamic_cast(&dereference(*contractName)); @@ -1076,9 +1079,26 @@ void TypeChecker::endVisit(NewExpression const& _newExpression) FunctionType::Location::Creation ); } - else if (auto arrayTypeName = dynamic_cast(&_newExpression.typeName())) + else if (type->category() == Type::Category::Array) { - solAssert(false, "Not yet implemented."); + if (!type->canLiveOutsideStorage()) + fatalTypeError( + _newExpression.typeName().location(), + "Type cannot live outside storage." + ); + if (!type->isDynamicallySized()) + typeError( + _newExpression.typeName().location(), + "Length has to be placed in parentheses after the array type for new expression." + ); + type = ReferenceType::copyForLocationIfReference(DataLocation::Memory, type); + _newExpression.annotation().type = make_shared( + TypePointers{make_shared(256)}, + TypePointers{type}, + strings(), + strings(), + FunctionType::Location::ObjectCreation + ); } else fatalTypeError(_newExpression.location(), "Contract or array type expected."); diff --git a/libsolidity/ast/Types.h b/libsolidity/ast/Types.h index f5aefa25d..63207a519 100644 --- a/libsolidity/ast/Types.h +++ b/libsolidity/ast/Types.h @@ -141,9 +141,6 @@ public: /// Factory functions that convert an AST @ref TypeName to a Type. static TypePointer fromElementaryTypeName(Token::Value _typeToken); static TypePointer fromElementaryTypeName(std::string const& _name); - static TypePointer fromUserDefinedTypeName(UserDefinedTypeName const& _typeName); - static TypePointer fromMapping(ElementaryTypeName& _keyType, TypeName& _valueType); - static TypePointer fromArrayTypeName(TypeName& _baseTypeName, Expression* _length); /// @} /// Auto-detect the proper type for a literal. @returns an empty pointer if the literal does @@ -751,7 +748,8 @@ public: AddMod, ///< ADDMOD MulMod, ///< MULMOD ArrayPush, ///< .push() to a dynamically sized array in storage - ByteArrayPush ///< .push() to a dynamically sized byte array in storage + ByteArrayPush, ///< .push() to a dynamically sized byte array in storage + ObjectCreation ///< array creation using new }; virtual Category category() const override { return Category::Function; } diff --git a/test/libsolidity/SolidityNameAndTypeResolution.cpp b/test/libsolidity/SolidityNameAndTypeResolution.cpp index 3d9dc5b5f..4f26fa4d6 100644 --- a/test/libsolidity/SolidityNameAndTypeResolution.cpp +++ b/test/libsolidity/SolidityNameAndTypeResolution.cpp @@ -2538,7 +2538,7 @@ BOOST_AUTO_TEST_CASE(create_memory_arrays) } contract C { function f(uint size) { - L.S[][] x = new L.S[][](10); + L.S[][] memory x = new L.S[][](10); var y = new uint[](20); var z = new bytes(size); } @@ -2547,6 +2547,42 @@ BOOST_AUTO_TEST_CASE(create_memory_arrays) BOOST_CHECK(success(text)); } +BOOST_AUTO_TEST_CASE(mapping_in_memory_array) +{ + char const* text = R"( + contract C { + function f(uint size) { + var x = new mapping(uint => uint)[](4); + } + } + )"; + BOOST_CHECK(expectError(text) == Error::Type::TypeError); +} + +BOOST_AUTO_TEST_CASE(new_for_non_array) +{ + char const* text = R"( + contract C { + function f(uint size) { + var x = new uint(7); + } + } + )"; + BOOST_CHECK(expectError(text) == Error::Type::TypeError); +} + +BOOST_AUTO_TEST_CASE(invalid_args_creating_memory_array) +{ + char const* text = R"( + contract C { + function f(uint size) { + var x = new uint[](); + } + } + )"; + BOOST_CHECK(expectError(text) == Error::Type::TypeError); +} + BOOST_AUTO_TEST_SUITE_END() }