Type checking for creating new arrays.

This commit is contained in:
chriseth 2015-11-17 01:47:47 +01:00
parent 30b325fdc1
commit bf55aa6ae2
5 changed files with 67 additions and 7 deletions

View File

@ -37,6 +37,11 @@ bool ReferencesResolver::visit(Return const& _return)
return true; return true;
} }
void ReferencesResolver::endVisit(NewExpression const& _new)
{
typeFor(_new.typeName());
}
bool ReferencesResolver::visit(UserDefinedTypeName const& _typeName) bool ReferencesResolver::visit(UserDefinedTypeName const& _typeName)
{ {
Declaration const* declaration = m_resolver.pathFromCurrentScope(_typeName.namePath()); Declaration const* declaration = m_resolver.pathFromCurrentScope(_typeName.namePath());

View File

@ -64,6 +64,7 @@ private:
virtual bool visit(Identifier const& _identifier) override; virtual bool visit(Identifier const& _identifier) override;
virtual bool visit(UserDefinedTypeName const& _typeName) override; virtual bool visit(UserDefinedTypeName const& _typeName) override;
virtual bool visit(Return const& _return) override; virtual bool visit(Return const& _return) override;
virtual void endVisit(NewExpression const& _new) override;
virtual void endVisit(VariableDeclaration const& _variable) override; virtual void endVisit(VariableDeclaration const& _variable) override;
TypePointer typeFor(TypeName const& _typeName); TypePointer typeFor(TypeName const& _typeName);

View File

@ -1045,6 +1045,9 @@ bool TypeChecker::visit(FunctionCall const& _functionCall)
void TypeChecker::endVisit(NewExpression const& _newExpression) void TypeChecker::endVisit(NewExpression const& _newExpression)
{ {
TypePointer type = _newExpression.typeName().annotation().type;
solAssert(!!type, "Type name not resolved.");
if (auto contractName = dynamic_cast<UserDefinedTypeName const*>(&_newExpression.typeName())) if (auto contractName = dynamic_cast<UserDefinedTypeName const*>(&_newExpression.typeName()))
{ {
auto contract = dynamic_cast<ContractDefinition const*>(&dereference(*contractName)); auto contract = dynamic_cast<ContractDefinition const*>(&dereference(*contractName));
@ -1076,9 +1079,26 @@ void TypeChecker::endVisit(NewExpression const& _newExpression)
FunctionType::Location::Creation FunctionType::Location::Creation
); );
} }
else if (auto arrayTypeName = dynamic_cast<ArrayTypeName const*>(&_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<FunctionType>(
TypePointers{make_shared<IntegerType>(256)},
TypePointers{type},
strings(),
strings(),
FunctionType::Location::ObjectCreation
);
} }
else else
fatalTypeError(_newExpression.location(), "Contract or array type expected."); fatalTypeError(_newExpression.location(), "Contract or array type expected.");

View File

@ -141,9 +141,6 @@ public:
/// Factory functions that convert an AST @ref TypeName to a Type. /// Factory functions that convert an AST @ref TypeName to a Type.
static TypePointer fromElementaryTypeName(Token::Value _typeToken); static TypePointer fromElementaryTypeName(Token::Value _typeToken);
static TypePointer fromElementaryTypeName(std::string const& _name); 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 /// Auto-detect the proper type for a literal. @returns an empty pointer if the literal does
@ -751,7 +748,8 @@ public:
AddMod, ///< ADDMOD AddMod, ///< ADDMOD
MulMod, ///< MULMOD MulMod, ///< MULMOD
ArrayPush, ///< .push() to a dynamically sized array in storage 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; } virtual Category category() const override { return Category::Function; }

View File

@ -2538,7 +2538,7 @@ BOOST_AUTO_TEST_CASE(create_memory_arrays)
} }
contract C { contract C {
function f(uint size) { 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 y = new uint[](20);
var z = new bytes(size); var z = new bytes(size);
} }
@ -2547,6 +2547,42 @@ BOOST_AUTO_TEST_CASE(create_memory_arrays)
BOOST_CHECK(success(text)); 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() BOOST_AUTO_TEST_SUITE_END()
} }