mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
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)`
This commit is contained in:
parent
cd94aa978a
commit
30b325fdc1
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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 (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.");
|
||||
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)."
|
||||
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);
|
||||
|
@ -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.
|
||||
|
@ -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;
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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(); }
|
||||
|
@ -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()
|
||||
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user