aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorchriseth <c@ethdev.com>2015-11-17 07:06:57 +0800
committerchriseth <c@ethdev.com>2015-11-26 20:10:12 +0800
commit30b325fdc148d5014f04fd238362e3a1df10310f (patch)
treecd8df0c1f6e5462f2349a07d8f5f7d1fd156b4cc
parentcd94aa978a77ace1296f9978bfae6d8735b5c91d (diff)
downloaddexon-solidity-30b325fdc148d5014f04fd238362e3a1df10310f.tar
dexon-solidity-30b325fdc148d5014f04fd238362e3a1df10310f.tar.gz
dexon-solidity-30b325fdc148d5014f04fd238362e3a1df10310f.tar.bz2
dexon-solidity-30b325fdc148d5014f04fd238362e3a1df10310f.tar.lz
dexon-solidity-30b325fdc148d5014f04fd238362e3a1df10310f.tar.xz
dexon-solidity-30b325fdc148d5014f04fd238362e3a1df10310f.tar.zst
dexon-solidity-30b325fdc148d5014f04fd238362e3a1df10310f.zip
Allow "new expressions" also for general type names.
Breaking change: If you want to send value with a contract creation, you have to use parentheses now: `(new ContractName).value(2 ether)(arg1, arg2)`
-rw-r--r--libsolidity/analysis/ReferencesResolver.cpp1
-rw-r--r--libsolidity/analysis/TypeChecker.cpp67
-rw-r--r--libsolidity/analysis/TypeChecker.h2
-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/parsing/Parser.cpp2
-rw-r--r--test/libsolidity/SolidityEndToEndTest.cpp2
-rw-r--r--test/libsolidity/SolidityNameAndTypeResolution.cpp18
9 files changed, 75 insertions, 35 deletions
diff --git a/libsolidity/analysis/ReferencesResolver.cpp b/libsolidity/analysis/ReferencesResolver.cpp
index 95643578..0e153045 100644
--- a/libsolidity/analysis/ReferencesResolver.cpp
+++ b/libsolidity/analysis/ReferencesResolver.cpp
@@ -44,6 +44,7 @@ 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;
}
diff --git a/libsolidity/analysis/TypeChecker.cpp b/libsolidity/analysis/TypeChecker.cpp
index 0990a9e4..13c2235a 100644
--- a/libsolidity/analysis/TypeChecker.cpp
+++ b/libsolidity/analysis/TypeChecker.cpp
@@ -1045,34 +1045,43 @@ bool TypeChecker::visit(FunctionCall const& _functionCall)
void TypeChecker::endVisit(NewExpression const& _newExpression)
{
- auto contract = dynamic_cast<ContractDefinition const*>(&dereference(_newExpression.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 = _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 (auto arrayTypeName = dynamic_cast<ArrayTypeName const*>(&_newExpression.typeName()))
+ {
+ solAssert(false, "Not yet implemented.");
+ }
+ else
+ fatalTypeError(_newExpression.location(), "Contract or array type expected.");
}
bool TypeChecker::visit(MemberAccess const& _memberAccess)
@@ -1288,6 +1297,12 @@ Declaration const& TypeChecker::dereference(Identifier const& _identifier)
return *_identifier.annotation().referencedDeclaration;
}
+Declaration const& TypeChecker::dereference(UserDefinedTypeName const& _typeName)
+{
+ 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..eb396a8c 100644
--- a/libsolidity/analysis/TypeChecker.h
+++ b/libsolidity/analysis/TypeChecker.h
@@ -108,6 +108,8 @@ private:
/// @returns the referenced declaration and throws on error.
Declaration const& dereference(Identifier const& _identifier);
+ /// @returns the referenced declaration and throws on error.
+ Declaration const& dereference(UserDefinedTypeName const& _typeName);
/// 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/parsing/Parser.cpp b/libsolidity/parsing/Parser.cpp
index d89218bb..c703ef27 100644
--- a/libsolidity/parsing/Parser.cpp
+++ b/libsolidity/parsing/Parser.cpp
@@ -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..681ab107 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(); }
diff --git a/test/libsolidity/SolidityNameAndTypeResolution.cpp b/test/libsolidity/SolidityNameAndTypeResolution.cpp
index e87e47a8..3d9dc5b5 100644
--- a/test/libsolidity/SolidityNameAndTypeResolution.cpp
+++ b/test/libsolidity/SolidityNameAndTypeResolution.cpp
@@ -2529,6 +2529,24 @@ 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[][] x = new L.S[][](10);
+ var y = new uint[](20);
+ var z = new bytes(size);
+ }
+ }
+ )";
+ BOOST_CHECK(success(text));
+}
+
BOOST_AUTO_TEST_SUITE_END()
}