aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--libsolidity/analysis/NameAndTypeResolver.cpp6
-rw-r--r--libsolidity/analysis/ReferencesResolver.cpp9
-rw-r--r--libsolidity/analysis/ReferencesResolver.h1
-rw-r--r--libsolidity/analysis/TypeChecker.cpp87
-rw-r--r--libsolidity/analysis/TypeChecker.h4
-rw-r--r--libsolidity/ast/AST.h11
-rw-r--r--libsolidity/ast/ASTAnnotations.h3
-rw-r--r--libsolidity/ast/AST_accept.h4
-rw-r--r--libsolidity/ast/Types.h6
-rw-r--r--libsolidity/codegen/CompilerUtils.cpp24
-rw-r--r--libsolidity/codegen/CompilerUtils.h5
-rw-r--r--libsolidity/codegen/ExpressionCompiler.cpp47
-rw-r--r--libsolidity/formal/Why3Translator.h2
-rw-r--r--libsolidity/parsing/Parser.cpp4
-rw-r--r--test/libsolidity/SolidityEndToEndTest.cpp46
-rw-r--r--test/libsolidity/SolidityNameAndTypeResolution.cpp54
16 files changed, 258 insertions, 55 deletions
diff --git a/libsolidity/analysis/NameAndTypeResolver.cpp b/libsolidity/analysis/NameAndTypeResolver.cpp
index 806f1322..fa894456 100644
--- a/libsolidity/analysis/NameAndTypeResolver.cpp
+++ b/libsolidity/analysis/NameAndTypeResolver.cpp
@@ -49,7 +49,7 @@ bool NameAndTypeResolver::registerDeclarations(SourceUnit& _sourceUnit)
{
DeclarationRegistrationHelper registrar(m_scopes, _sourceUnit, m_errors);
}
- catch (FatalError const& _e)
+ catch (FatalError const&)
{
if (m_errors.empty())
throw; // Something is weird here, rather throw again.
@@ -146,7 +146,7 @@ bool NameAndTypeResolver::resolveNamesAndTypes(ContractDefinition& _contract)
if (!success)
return false;
}
- catch (FatalError const& _e)
+ catch (FatalError const&)
{
if (m_errors.empty())
throw; // Something is weird here, rather throw again.
@@ -162,7 +162,7 @@ bool NameAndTypeResolver::updateDeclaration(Declaration const& _declaration)
m_scopes[nullptr].registerDeclaration(_declaration, false, true);
solAssert(_declaration.scope() == nullptr, "Updated declaration outside global scope.");
}
- catch (FatalError const& _error)
+ catch (FatalError const&)
{
if (m_errors.empty())
throw; // Something is weird here, rather throw again.
diff --git a/libsolidity/analysis/ReferencesResolver.cpp b/libsolidity/analysis/ReferencesResolver.cpp
index 95643578..f0afc4f9 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());
@@ -44,6 +49,8 @@ bool ReferencesResolver::visit(UserDefinedTypeName const& _typeName)
fatalDeclarationError(_typeName.location(), "Identifier not found or not unique.");
_typeName.annotation().referencedDeclaration = declaration;
+
+ _typeName.annotation().contractScope = m_currentContract;
return true;
}
@@ -53,7 +60,7 @@ bool ReferencesResolver::resolve(ASTNode& _root)
{
_root.accept(*this);
}
- catch (FatalError const& e)
+ catch (FatalError const&)
{
solAssert(m_errorOccurred, "");
}
diff --git a/libsolidity/analysis/ReferencesResolver.h b/libsolidity/analysis/ReferencesResolver.h
index 21cb1d35..62104611 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 0990a9e4..42fdad91 100644
--- a/libsolidity/analysis/TypeChecker.cpp
+++ b/libsolidity/analysis/TypeChecker.cpp
@@ -1045,34 +1045,63 @@ bool TypeChecker::visit(FunctionCall const& _functionCall)
void TypeChecker::endVisit(NewExpression const& _newExpression)
{
- auto contract = dynamic_cast<ContractDefinition const*>(&dereference(_newExpression.contractName()));
+ TypePointer type = _newExpression.typeName().annotation().type;
+ solAssert(!!type, "Type name not resolved.");
- if (!contract)
- fatalTypeError(_newExpression.location(), "Identifier is not a contract.");
- if (!contract->annotation().isFullyImplemented)
- typeError(_newExpression.location(), "Trying to create an instance of an abstract contract.");
-
- auto scopeContract = _newExpression.contractName().annotation().contractScope;
- scopeContract->annotation().contractDependencies.insert(contract);
- solAssert(
- !contract->annotation().linearizedBaseContracts.empty(),
- "Linearized base contracts not yet available."
- );
- if (contractDependenciesAreCyclic(*scopeContract))
- typeError(
- _newExpression.location(),
- "Circular reference for contract creation (cannot create instance of derived or same contract)."
+ if (auto contractName = dynamic_cast<UserDefinedTypeName const*>(&_newExpression.typeName()))
+ {
+ auto contract = dynamic_cast<ContractDefinition const*>(&dereference(*contractName));
+
+ if (!contract)
+ fatalTypeError(_newExpression.location(), "Identifier is not a contract.");
+ if (!contract->annotation().isFullyImplemented)
+ typeError(_newExpression.location(), "Trying to create an instance of an abstract contract.");
+
+ auto scopeContract = contractName->annotation().contractScope;
+ scopeContract->annotation().contractDependencies.insert(contract);
+ solAssert(
+ !contract->annotation().linearizedBaseContracts.empty(),
+ "Linearized base contracts not yet available."
);
+ if (contractDependenciesAreCyclic(*scopeContract))
+ typeError(
+ _newExpression.location(),
+ "Circular reference for contract creation (cannot create instance of derived or same contract)."
+ );
- auto contractType = make_shared<ContractType>(*contract);
- TypePointers const& parameterTypes = contractType->constructorType()->parameterTypes();
- _newExpression.annotation().type = make_shared<FunctionType>(
- parameterTypes,
- TypePointers{contractType},
- strings(),
- strings(),
- FunctionType::Location::Creation
- );
+ auto contractType = make_shared<ContractType>(*contract);
+ TypePointers const& parameterTypes = contractType->constructorType()->parameterTypes();
+ _newExpression.annotation().type = make_shared<FunctionType>(
+ parameterTypes,
+ TypePointers{contractType},
+ strings(),
+ strings(),
+ FunctionType::Location::Creation
+ );
+ }
+ else if (type->category() == Type::Category::Array)
+ {
+ 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
+ fatalTypeError(_newExpression.location(), "Contract or array type expected.");
}
bool TypeChecker::visit(MemberAccess const& _memberAccess)
@@ -1282,12 +1311,18 @@ bool TypeChecker::contractDependenciesAreCyclic(
return false;
}
-Declaration const& TypeChecker::dereference(Identifier const& _identifier)
+Declaration const& TypeChecker::dereference(Identifier const& _identifier) const
{
solAssert(!!_identifier.annotation().referencedDeclaration, "Declaration not stored.");
return *_identifier.annotation().referencedDeclaration;
}
+Declaration const& TypeChecker::dereference(UserDefinedTypeName const& _typeName) const
+{
+ solAssert(!!_typeName.annotation().referencedDeclaration, "Declaration not stored.");
+ return *_typeName.annotation().referencedDeclaration;
+}
+
void TypeChecker::expectType(Expression const& _expression, Type const& _expectedType)
{
_expression.accept(*this);
diff --git a/libsolidity/analysis/TypeChecker.h b/libsolidity/analysis/TypeChecker.h
index f163f47c..2295bc22 100644
--- a/libsolidity/analysis/TypeChecker.h
+++ b/libsolidity/analysis/TypeChecker.h
@@ -107,7 +107,9 @@ private:
) const;
/// @returns the referenced declaration and throws on error.
- Declaration const& dereference(Identifier const& _identifier);
+ Declaration const& dereference(Identifier const& _identifier) const;
+ /// @returns the referenced declaration and throws on error.
+ Declaration const& dereference(UserDefinedTypeName const& _typeName) const;
/// Runs type checks on @a _expression to infer its type and then checks that it is implicitly
/// convertible to @a _expectedType.
diff --git a/libsolidity/ast/AST.h b/libsolidity/ast/AST.h
index 69186cb7..e2ed1853 100644
--- a/libsolidity/ast/AST.h
+++ b/libsolidity/ast/AST.h
@@ -1216,23 +1216,24 @@ private:
};
/**
- * Expression that creates a new contract, e.g. the "new SomeContract" part in "new SomeContract(1, 2)".
+ * Expression that creates a new contract or memory-array,
+ * e.g. the "new SomeContract" part in "new SomeContract(1, 2)".
*/
class NewExpression: public Expression
{
public:
NewExpression(
SourceLocation const& _location,
- ASTPointer<Identifier> const& _contractName
+ ASTPointer<TypeName> const& _typeName
):
- Expression(_location), m_contractName(_contractName) {}
+ Expression(_location), m_typeName(_typeName) {}
virtual void accept(ASTVisitor& _visitor) override;
virtual void accept(ASTConstVisitor& _visitor) const override;
- Identifier const& contractName() const { return *m_contractName; }
+ TypeName const& typeName() const { return *m_typeName; }
private:
- ASTPointer<Identifier> m_contractName;
+ ASTPointer<TypeName> m_typeName;
};
/**
diff --git a/libsolidity/ast/ASTAnnotations.h b/libsolidity/ast/ASTAnnotations.h
index bb59ceae..b9667302 100644
--- a/libsolidity/ast/ASTAnnotations.h
+++ b/libsolidity/ast/ASTAnnotations.h
@@ -111,6 +111,9 @@ struct UserDefinedTypeNameAnnotation: TypeNameAnnotation
{
/// Referenced declaration, set during reference resolution stage.
Declaration const* referencedDeclaration = nullptr;
+ /// Stores a reference to the current contract.
+ /// This is needed because types of base contracts change depending on the context.
+ ContractDefinition const* contractScope = nullptr;
};
struct VariableDeclarationStatementAnnotation: StatementAnnotation
diff --git a/libsolidity/ast/AST_accept.h b/libsolidity/ast/AST_accept.h
index 12a26ea7..99d1bf6a 100644
--- a/libsolidity/ast/AST_accept.h
+++ b/libsolidity/ast/AST_accept.h
@@ -634,14 +634,14 @@ void FunctionCall::accept(ASTConstVisitor& _visitor) const
void NewExpression::accept(ASTVisitor& _visitor)
{
if (_visitor.visit(*this))
- m_contractName->accept(_visitor);
+ m_typeName->accept(_visitor);
_visitor.endVisit(*this);
}
void NewExpression::accept(ASTConstVisitor& _visitor) const
{
if (_visitor.visit(*this))
- m_contractName->accept(_visitor);
+ m_typeName->accept(_visitor);
_visitor.endVisit(*this);
}
diff --git a/libsolidity/ast/Types.h b/libsolidity/ast/Types.h
index f5aefa25..63207a51 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/libsolidity/codegen/CompilerUtils.cpp b/libsolidity/codegen/CompilerUtils.cpp
index 2ebf5b64..357013e6 100644
--- a/libsolidity/codegen/CompilerUtils.cpp
+++ b/libsolidity/codegen/CompilerUtils.cpp
@@ -266,6 +266,19 @@ void CompilerUtils::encodeToMemory(
popStackSlots(argSize + dynPointers + 1);
}
+void CompilerUtils::zeroInitialiseMemoryArray(ArrayType const& _type)
+{
+ auto repeat = m_context.newTag();
+ m_context << repeat;
+ pushZeroValue(*_type.baseType());
+ storeInMemoryDynamic(*_type.baseType());
+ m_context << eth::Instruction::SWAP1 << u256(1) << eth::Instruction::SWAP1;
+ m_context << eth::Instruction::SUB << eth::Instruction::SWAP1;
+ m_context << eth::Instruction::DUP2;
+ m_context.appendConditionalJumpTo(repeat);
+ m_context << eth::Instruction::SWAP1 << eth::Instruction::POP;
+}
+
void CompilerUtils::memoryCopy()
{
// Stack here: size target source
@@ -646,15 +659,8 @@ void CompilerUtils::pushZeroValue(Type const& _type)
{
m_context << arrayType->length() << eth::Instruction::SWAP1;
// stack: items_to_do memory_pos
- auto repeat = m_context.newTag();
- m_context << repeat;
- pushZeroValue(*arrayType->baseType());
- storeInMemoryDynamic(*arrayType->baseType());
- m_context << eth::Instruction::SWAP1 << u256(1) << eth::Instruction::SWAP1;
- m_context << eth::Instruction::SUB << eth::Instruction::SWAP1;
- m_context << eth::Instruction::DUP2;
- m_context.appendConditionalJumpTo(repeat);
- m_context << eth::Instruction::SWAP1 << eth::Instruction::POP;
+ zeroInitialiseMemoryArray(*arrayType);
+ // stack: updated_memory_pos
}
}
else
diff --git a/libsolidity/codegen/CompilerUtils.h b/libsolidity/codegen/CompilerUtils.h
index 6292e5c7..134afd78 100644
--- a/libsolidity/codegen/CompilerUtils.h
+++ b/libsolidity/codegen/CompilerUtils.h
@@ -103,6 +103,11 @@ public:
bool _encodeAsLibraryTypes = false
);
+ /// Zero-initialises (the data part of) an already allocated memory array.
+ /// Stack pre: <length> <memptr>
+ /// Stack post: <updated_memptr>
+ void zeroInitialiseMemoryArray(ArrayType const& _type);
+
/// Uses a CALL to the identity contract to perform a memory-to-memory copy.
/// Stack pre: <size> <target> <source>
/// Stack post:
diff --git a/libsolidity/codegen/ExpressionCompiler.cpp b/libsolidity/codegen/ExpressionCompiler.cpp
index 1a089d63..c94c988b 100644
--- a/libsolidity/codegen/ExpressionCompiler.cpp
+++ b/libsolidity/codegen/ExpressionCompiler.cpp
@@ -703,6 +703,53 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall)
StorageByteArrayElement(m_context).storeValue(*type, _functionCall.location(), true);
break;
}
+ case Location::ObjectCreation:
+ {
+ // Will allocate at the end of memory (MSIZE) and not write at all unless the base
+ // type is dynamically sized.
+ ArrayType const& arrayType = dynamic_cast<ArrayType const&>(*_functionCall.annotation().type);
+ _functionCall.expression().accept(*this);
+ solAssert(arguments.size() == 1, "");
+
+ // Fetch requested length.
+ arguments[0]->accept(*this);
+ utils().convertType(*arguments[0]->annotation().type, IntegerType(256));
+
+ // Stack: requested_length
+ // Allocate at max(MSIZE, freeMemoryPointer)
+ utils().fetchFreeMemoryPointer();
+ m_context << eth::Instruction::DUP1 << eth::Instruction::MSIZE;
+ m_context << eth::Instruction::LT;
+ auto initialise = m_context.appendConditionalJump();
+ // Free memory pointer does not point to empty memory, use MSIZE.
+ m_context << eth::Instruction::POP;
+ m_context << eth::Instruction::MSIZE;
+ m_context << initialise;
+
+ // Stack: requested_length memptr
+ m_context << eth::Instruction::SWAP1;
+ // Stack: memptr requested_length
+ // store length
+ m_context << eth::Instruction::DUP1 << eth::Instruction::DUP3 << eth::Instruction::MSTORE;
+ // Stack: memptr requested_length
+ // update free memory pointer
+ m_context << eth::Instruction::DUP1 << arrayType.baseType()->memoryHeadSize();
+ m_context << eth::Instruction::MUL << u256(32) << eth::Instruction::ADD;
+ m_context << eth::Instruction::DUP3 << eth::Instruction::ADD;
+ utils().storeFreeMemoryPointer();
+ // Stack: memptr requested_length
+
+ // We only have to initialise if the base type is a not a value type.
+ if (dynamic_cast<ReferenceType const*>(arrayType.baseType().get()))
+ {
+ m_context << eth::Instruction::DUP2 << u256(32) << eth::Instruction::ADD;
+ utils().zeroInitialiseMemoryArray(arrayType);
+ m_context << eth::Instruction::POP;
+ }
+ else
+ m_context << eth::Instruction::POP;
+ break;
+ }
default:
BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Invalid function type."));
}
diff --git a/libsolidity/formal/Why3Translator.h b/libsolidity/formal/Why3Translator.h
index 34c6c34f..e5c298b4 100644
--- a/libsolidity/formal/Why3Translator.h
+++ b/libsolidity/formal/Why3Translator.h
@@ -43,7 +43,7 @@ class SourceUnit;
class Why3Translator: private ASTConstVisitor
{
public:
- Why3Translator(ErrorList& _errors): m_lines{{std::string(), 0}}, m_errors(_errors) {}
+ Why3Translator(ErrorList& _errors): m_lines(std::vector<Line>{{std::string(), 0}}), m_errors(_errors) {}
/// Appends formalisation of the given source unit to the output.
/// @returns false on error.
diff --git a/libsolidity/parsing/Parser.cpp b/libsolidity/parsing/Parser.cpp
index d89218bb..2d4ca43e 100644
--- a/libsolidity/parsing/Parser.cpp
+++ b/libsolidity/parsing/Parser.cpp
@@ -88,7 +88,7 @@ ASTPointer<SourceUnit> Parser::parse(shared_ptr<Scanner> const& _scanner)
}
return nodeFactory.createNode<SourceUnit>(nodes);
}
- catch (FatalError const& _error)
+ catch (FatalError const&)
{
if (m_errors.empty())
throw; // Something is weird here, rather throw again.
@@ -939,7 +939,7 @@ ASTPointer<Expression> Parser::parseLeftHandSideExpression(
else if (m_scanner->currentToken() == Token::New)
{
expectToken(Token::New);
- ASTPointer<Identifier> contractName(parseIdentifier());
+ ASTPointer<TypeName> contractName(parseTypeName(false));
nodeFactory.setEndPositionFromNode(contractName);
expression = nodeFactory.createNode<NewExpression>(contractName);
}
diff --git a/test/libsolidity/SolidityEndToEndTest.cpp b/test/libsolidity/SolidityEndToEndTest.cpp
index 93b42c51..0b356145 100644
--- a/test/libsolidity/SolidityEndToEndTest.cpp
+++ b/test/libsolidity/SolidityEndToEndTest.cpp
@@ -1955,7 +1955,7 @@ BOOST_AUTO_TEST_CASE(value_for_constructor)
contract Main {
Helper h;
function Main() {
- h = new Helper.value(10)("abc", true);
+ h = (new Helper).value(10)("abc", true);
}
function getFlag() returns (bool ret) { return h.getFlag(); }
function getName() returns (bytes3 ret) { return h.getName(); }
@@ -5816,6 +5816,50 @@ BOOST_AUTO_TEST_CASE(lone_struct_array_type)
BOOST_CHECK(callContractFunction("f()") == encodeArgs(u256(3)));
}
+BOOST_AUTO_TEST_CASE(create_memory_array)
+{
+ char const* sourceCode = R"(
+ contract C {
+ struct S { uint[2] a; bytes b; }
+ function f() returns (byte, uint, uint, byte) {
+ var x = new bytes(200);
+ x[199] = 'A';
+ var y = new uint[2][](300);
+ y[203][1] = 8;
+ var z = new S[](180);
+ z[170].a[1] = 4;
+ z[170].b = new bytes(102);
+ z[170].b[99] = 'B';
+ return (x[199], y[203][1], z[170].a[1], z[170].b[99]);
+ }
+ }
+ )";
+ compileAndRun(sourceCode);
+ BOOST_CHECK(callContractFunction("f()") == encodeArgs(string("A"), u256(8), u256(4), string("B")));
+}
+
+BOOST_AUTO_TEST_CASE(memory_arrays_of_various_sizes)
+{
+ // Computes binomial coefficients the chinese way
+ char const* sourceCode = R"(
+ contract C {
+ function f(uint n, uint k) returns (uint) {
+ uint[][] memory rows = new uint[][](n + 1);
+ for (uint i = 1; i <= n; i++) {
+ rows[i] = new uint[](i);
+ rows[i][0] = rows[i][rows[i].length - 1] = 1;
+ for (uint j = 1; j < i - 1; j++)
+ rows[i][j] = rows[i - 1][j - 1] + rows[i - 1][j];
+ }
+ return rows[n][k - 1];
+ }
+ }
+ )";
+ compileAndRun(sourceCode);
+ BOOST_CHECK(callContractFunction("f(uint256,uint256)", encodeArgs(u256(3), u256(1))) == encodeArgs(u256(1)));
+ BOOST_CHECK(callContractFunction("f(uint256,uint256)", encodeArgs(u256(9), u256(5))) == encodeArgs(u256(70)));
+}
+
BOOST_AUTO_TEST_CASE(memory_overwrite)
{
char const* sourceCode = R"(
diff --git a/test/libsolidity/SolidityNameAndTypeResolution.cpp b/test/libsolidity/SolidityNameAndTypeResolution.cpp
index e87e47a8..4f26fa4d 100644
--- a/test/libsolidity/SolidityNameAndTypeResolution.cpp
+++ b/test/libsolidity/SolidityNameAndTypeResolution.cpp
@@ -2529,6 +2529,60 @@ BOOST_AUTO_TEST_CASE(member_access_parser_ambiguity)
BOOST_CHECK(success(text));
}
+BOOST_AUTO_TEST_CASE(create_memory_arrays)
+{
+ char const* text = R"(
+ library L {
+ struct R { uint[10][10] y; }
+ struct S { uint a; uint b; uint[20][20][20] c; R d; }
+ }
+ contract C {
+ function f(uint size) {
+ L.S[][] memory x = new L.S[][](10);
+ var y = new uint[](20);
+ var z = new bytes(size);
+ }
+ }
+ )";
+ 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()
}