diff options
-rw-r--r-- | libsolidity/analysis/ReferencesResolver.cpp | 1 | ||||
-rw-r--r-- | libsolidity/analysis/TypeChecker.cpp | 67 | ||||
-rw-r--r-- | libsolidity/analysis/TypeChecker.h | 2 | ||||
-rw-r--r-- | libsolidity/ast/AST.h | 11 | ||||
-rw-r--r-- | libsolidity/ast/ASTAnnotations.h | 3 | ||||
-rw-r--r-- | libsolidity/ast/AST_accept.h | 4 | ||||
-rw-r--r-- | libsolidity/parsing/Parser.cpp | 2 | ||||
-rw-r--r-- | test/libsolidity/SolidityEndToEndTest.cpp | 2 | ||||
-rw-r--r-- | test/libsolidity/SolidityNameAndTypeResolution.cpp | 18 |
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() } |