mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
commit
02c1aacd25
@ -317,7 +317,8 @@ by `msg.data`.
|
|||||||
Can state variables be initialized in-line?
|
Can state variables be initialized in-line?
|
||||||
===========================================
|
===========================================
|
||||||
|
|
||||||
Yes, this is possible for most types (even for structs), but not for arrays.
|
Yes, this is possible for all types (even for structs). However, for arrays it
|
||||||
|
should be noted that you must declare them as static memory arrays.
|
||||||
|
|
||||||
Examples::
|
Examples::
|
||||||
|
|
||||||
@ -325,6 +326,7 @@ Examples::
|
|||||||
struct S { uint a; uint b; }
|
struct S { uint a; uint b; }
|
||||||
S public x = S(1, 2);
|
S public x = S(1, 2);
|
||||||
string name = "Ada";
|
string name = "Ada";
|
||||||
|
string[4] memory AdaArr = ["This", "is", "an", "array"];
|
||||||
}
|
}
|
||||||
contract D {
|
contract D {
|
||||||
C c = new C();
|
C c = new C();
|
||||||
|
@ -783,10 +783,12 @@ bool TypeChecker::visit(Assignment const& _assignment)
|
|||||||
bool TypeChecker::visit(TupleExpression const& _tuple)
|
bool TypeChecker::visit(TupleExpression const& _tuple)
|
||||||
{
|
{
|
||||||
vector<ASTPointer<Expression>> const& components = _tuple.components();
|
vector<ASTPointer<Expression>> const& components = _tuple.components();
|
||||||
solAssert(!_tuple.isInlineArray(), "Tuple type not properly declared");
|
|
||||||
TypePointers types;
|
TypePointers types;
|
||||||
|
|
||||||
if (_tuple.annotation().lValueRequested)
|
if (_tuple.annotation().lValueRequested)
|
||||||
{
|
{
|
||||||
|
if (_tuple.isInlineArray())
|
||||||
|
fatalTypeError(_tuple.location(), "Inline array type cannot be declared as LValue.");
|
||||||
for (auto const& component: components)
|
for (auto const& component: components)
|
||||||
if (component)
|
if (component)
|
||||||
{
|
{
|
||||||
@ -804,6 +806,7 @@ bool TypeChecker::visit(TupleExpression const& _tuple)
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
TypePointer inlineArrayType;
|
||||||
for (size_t i = 0; i < components.size(); ++i)
|
for (size_t i = 0; i < components.size(); ++i)
|
||||||
{
|
{
|
||||||
// Outside of an lvalue-context, the only situation where a component can be empty is (x,).
|
// Outside of an lvalue-context, the only situation where a component can be empty is (x,).
|
||||||
@ -813,10 +816,24 @@ bool TypeChecker::visit(TupleExpression const& _tuple)
|
|||||||
{
|
{
|
||||||
components[i]->accept(*this);
|
components[i]->accept(*this);
|
||||||
types.push_back(type(*components[i]));
|
types.push_back(type(*components[i]));
|
||||||
|
if (_tuple.isInlineArray())
|
||||||
|
solAssert(!!types[i], "Inline array cannot have empty components");
|
||||||
|
if (i == 0 && _tuple.isInlineArray())
|
||||||
|
inlineArrayType = types[i]->mobileType();
|
||||||
|
else if (_tuple.isInlineArray() && inlineArrayType)
|
||||||
|
inlineArrayType = Type::commonType(inlineArrayType, types[i]->mobileType());
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
types.push_back(TypePointer());
|
types.push_back(TypePointer());
|
||||||
}
|
}
|
||||||
|
if (_tuple.isInlineArray())
|
||||||
|
{
|
||||||
|
if (!inlineArrayType)
|
||||||
|
fatalTypeError(_tuple.location(), "Unable to deduce common type for array elements.");
|
||||||
|
_tuple.annotation().type = make_shared<ArrayType>(DataLocation::Memory, inlineArrayType, types.size());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
if (components.size() == 1)
|
if (components.size() == 1)
|
||||||
_tuple.annotation().type = type(*components[0]);
|
_tuple.annotation().type = type(*components[0]);
|
||||||
else
|
else
|
||||||
@ -826,6 +843,8 @@ bool TypeChecker::visit(TupleExpression const& _tuple)
|
|||||||
_tuple.annotation().type = make_shared<TupleType>(types);
|
_tuple.annotation().type = make_shared<TupleType>(types);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -219,6 +219,26 @@ bool ExpressionCompiler::visit(Assignment const& _assignment)
|
|||||||
|
|
||||||
bool ExpressionCompiler::visit(TupleExpression const& _tuple)
|
bool ExpressionCompiler::visit(TupleExpression const& _tuple)
|
||||||
{
|
{
|
||||||
|
if (_tuple.isInlineArray())
|
||||||
|
{
|
||||||
|
ArrayType const& arrayType = dynamic_cast<ArrayType const&>(*_tuple.annotation().type);
|
||||||
|
|
||||||
|
solAssert(!arrayType.isDynamicallySized(), "Cannot create dynamically sized inline array.");
|
||||||
|
m_context << max(u256(32u), arrayType.memorySize());
|
||||||
|
utils().allocateMemory();
|
||||||
|
m_context << eth::Instruction::DUP1;
|
||||||
|
|
||||||
|
for (auto const& component: _tuple.components())
|
||||||
|
{
|
||||||
|
component->accept(*this);
|
||||||
|
utils().convertType(*component->annotation().type, *arrayType.baseType(), true);
|
||||||
|
utils().storeInMemoryDynamic(*arrayType.baseType(), true);
|
||||||
|
}
|
||||||
|
|
||||||
|
m_context << eth::Instruction::POP;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
vector<unique_ptr<LValue>> lvalues;
|
vector<unique_ptr<LValue>> lvalues;
|
||||||
for (auto const& component: _tuple.components())
|
for (auto const& component: _tuple.components())
|
||||||
if (component)
|
if (component)
|
||||||
@ -239,6 +259,7 @@ bool ExpressionCompiler::visit(TupleExpression const& _tuple)
|
|||||||
else
|
else
|
||||||
m_currentLValue.reset(new TupleObject(m_context, move(lvalues)));
|
m_currentLValue.reset(new TupleObject(m_context, move(lvalues)));
|
||||||
}
|
}
|
||||||
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -774,7 +795,6 @@ bool ExpressionCompiler::visit(NewExpression const&)
|
|||||||
void ExpressionCompiler::endVisit(MemberAccess const& _memberAccess)
|
void ExpressionCompiler::endVisit(MemberAccess const& _memberAccess)
|
||||||
{
|
{
|
||||||
CompilerContext::LocationSetter locationSetter(m_context, _memberAccess);
|
CompilerContext::LocationSetter locationSetter(m_context, _memberAccess);
|
||||||
|
|
||||||
// Check whether the member is a bound function.
|
// Check whether the member is a bound function.
|
||||||
ASTString const& member = _memberAccess.memberName();
|
ASTString const& member = _memberAccess.memberName();
|
||||||
if (auto funType = dynamic_cast<FunctionType const*>(_memberAccess.annotation().type.get()))
|
if (auto funType = dynamic_cast<FunctionType const*>(_memberAccess.annotation().type.get()))
|
||||||
@ -1123,6 +1143,7 @@ void ExpressionCompiler::endVisit(Literal const& _literal)
|
|||||||
{
|
{
|
||||||
CompilerContext::LocationSetter locationSetter(m_context, _literal);
|
CompilerContext::LocationSetter locationSetter(m_context, _literal);
|
||||||
TypePointer type = _literal.annotation().type;
|
TypePointer type = _literal.annotation().type;
|
||||||
|
|
||||||
switch (type->category())
|
switch (type->category())
|
||||||
{
|
{
|
||||||
case Type::Category::IntegerConstant:
|
case Type::Category::IntegerConstant:
|
||||||
|
@ -6107,6 +6107,119 @@ BOOST_AUTO_TEST_CASE(bound_function_to_string)
|
|||||||
BOOST_CHECK(callContractFunction("g()") == encodeArgs(u256(3)));
|
BOOST_CHECK(callContractFunction("g()") == encodeArgs(u256(3)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
BOOST_AUTO_TEST_CASE(inline_array_storage_to_memory_conversion_strings)
|
||||||
|
{
|
||||||
|
char const* sourceCode = R"(
|
||||||
|
contract C {
|
||||||
|
string s = "doh";
|
||||||
|
function f() returns (string, string) {
|
||||||
|
string memory t = "ray";
|
||||||
|
string[3] memory x = [s, t, "mi"];
|
||||||
|
return (x[1], x[2]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)";
|
||||||
|
compileAndRun(sourceCode);
|
||||||
|
BOOST_CHECK(callContractFunction("f()") == encodeArgs(u256(0x40), u256(0x80), u256(3), string("ray"), u256(2), string("mi")));
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOST_AUTO_TEST_CASE(inline_array_strings_from_document)
|
||||||
|
{
|
||||||
|
char const* sourceCode = R"(
|
||||||
|
contract C {
|
||||||
|
function f(uint i) returns (string) {
|
||||||
|
string[4] memory x = ["This", "is", "an", "array"];
|
||||||
|
return (x[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)";
|
||||||
|
compileAndRun(sourceCode);
|
||||||
|
BOOST_CHECK(callContractFunction("f(uint256)", u256(0)) == encodeArgs(u256(0x20), u256(4), string("This")));
|
||||||
|
BOOST_CHECK(callContractFunction("f(uint256)", u256(1)) == encodeArgs(u256(0x20), u256(2), string("is")));
|
||||||
|
BOOST_CHECK(callContractFunction("f(uint256)", u256(2)) == encodeArgs(u256(0x20), u256(2), string("an")));
|
||||||
|
BOOST_CHECK(callContractFunction("f(uint256)", u256(3)) == encodeArgs(u256(0x20), u256(5), string("array")));
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOST_AUTO_TEST_CASE(inline_array_storage_to_memory_conversion_ints)
|
||||||
|
{
|
||||||
|
char const* sourceCode = R"(
|
||||||
|
contract C {
|
||||||
|
function f() returns (uint x, uint y) {
|
||||||
|
x = 3;
|
||||||
|
y = 6;
|
||||||
|
uint[2] memory z = [x, y];
|
||||||
|
return (z[0], z[1]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)";
|
||||||
|
compileAndRun(sourceCode, 0, "C");
|
||||||
|
BOOST_CHECK(callContractFunction("f()") == encodeArgs(3, 6));
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOST_AUTO_TEST_CASE(inline_array_index_access_ints)
|
||||||
|
{
|
||||||
|
char const* sourceCode = R"(
|
||||||
|
contract C {
|
||||||
|
function f() returns (uint) {
|
||||||
|
return ([1, 2, 3, 4][2]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)";
|
||||||
|
compileAndRun(sourceCode, 0, "C");
|
||||||
|
BOOST_CHECK(callContractFunction("f()") == encodeArgs(3));
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOST_AUTO_TEST_CASE(inline_array_index_access_strings)
|
||||||
|
{
|
||||||
|
char const* sourceCode = R"(
|
||||||
|
contract C {
|
||||||
|
string public tester;
|
||||||
|
function f() returns (string) {
|
||||||
|
return (["abc", "def", "g"][0]);
|
||||||
|
}
|
||||||
|
function test() {
|
||||||
|
tester = f();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)";
|
||||||
|
compileAndRun(sourceCode, 0, "C");
|
||||||
|
BOOST_CHECK(callContractFunction("test()") == encodeArgs());
|
||||||
|
BOOST_CHECK(callContractFunction("tester()") == encodeArgs(u256(0x20), u256(3), string("abc")));
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOST_AUTO_TEST_CASE(inline_array_return)
|
||||||
|
{
|
||||||
|
char const* sourceCode = R"(
|
||||||
|
contract C {
|
||||||
|
uint8[] tester;
|
||||||
|
function f() returns (uint8[5]) {
|
||||||
|
return ([1,2,3,4,5]);
|
||||||
|
}
|
||||||
|
function test() returns (uint8, uint8, uint8, uint8, uint8) {
|
||||||
|
tester = f();
|
||||||
|
return (tester[0], tester[1], tester[2], tester[3], tester[4]);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
)";
|
||||||
|
compileAndRun(sourceCode, 0, "C");
|
||||||
|
BOOST_CHECK(callContractFunction("f()") == encodeArgs(1, 2, 3, 4, 5));
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOST_AUTO_TEST_CASE(inline_long_string_return)
|
||||||
|
{
|
||||||
|
char const* sourceCode = R"(
|
||||||
|
contract C {
|
||||||
|
function f() returns (string) {
|
||||||
|
return (["somethingShort", "0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789001234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678900123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789001234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890"][1]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)";
|
||||||
|
|
||||||
|
string strLong = "0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789001234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678900123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789001234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890";
|
||||||
|
compileAndRun(sourceCode, 0, "C");
|
||||||
|
BOOST_CHECK(callContractFunction("f()") == encodeDyn(strLong));
|
||||||
|
}
|
||||||
BOOST_AUTO_TEST_SUITE_END()
|
BOOST_AUTO_TEST_SUITE_END()
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -2769,14 +2769,97 @@ BOOST_AUTO_TEST_CASE(function_overload_array_type)
|
|||||||
BOOST_CHECK(success(text));
|
BOOST_CHECK(success(text));
|
||||||
}
|
}
|
||||||
|
|
||||||
/*BOOST_AUTO_TEST_CASE(inline_array_declaration_and_passing)
|
BOOST_AUTO_TEST_CASE(inline_array_declaration_and_passing_implicit_conversion)
|
||||||
{
|
{
|
||||||
char const* text = R"(
|
char const* text = R"(
|
||||||
contract C {
|
contract C {
|
||||||
uint[] a;
|
function f() returns (uint) {
|
||||||
function f() returns (uint, uint) {
|
uint8 x = 7;
|
||||||
a = [1,2,3];
|
uint16 y = 8;
|
||||||
return (a[3], [3,4][0]);
|
uint32 z = 9;
|
||||||
|
uint32[3] memory ending = [x, y, z];
|
||||||
|
return (ending[1]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)";
|
||||||
|
BOOST_CHECK(success(text));
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOST_AUTO_TEST_CASE(inline_array_declaration_and_passing_implicit_conversion_strings)
|
||||||
|
{
|
||||||
|
char const* text = R"(
|
||||||
|
contract C {
|
||||||
|
function f() returns (string) {
|
||||||
|
string memory x = "Hello";
|
||||||
|
string memory y = "World";
|
||||||
|
string[2] memory z = [x, y];
|
||||||
|
return (z[0]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)";
|
||||||
|
BOOST_CHECK(success(text));
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOST_AUTO_TEST_CASE(inline_array_declaration_const_int_conversion)
|
||||||
|
{
|
||||||
|
char const* text = R"(
|
||||||
|
contract C {
|
||||||
|
function f() returns (uint) {
|
||||||
|
uint8[4] memory z = [1,2,3,5];
|
||||||
|
return (z[0]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)";
|
||||||
|
BOOST_CHECK(success(text));
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOST_AUTO_TEST_CASE(inline_array_declaration_const_string_conversion)
|
||||||
|
{
|
||||||
|
char const* text = R"(
|
||||||
|
contract C {
|
||||||
|
function f() returns (string) {
|
||||||
|
string[2] memory z = ["Hello", "World"];
|
||||||
|
return (z[0]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)";
|
||||||
|
BOOST_CHECK(success(text));
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOST_AUTO_TEST_CASE(inline_array_declaration_no_type)
|
||||||
|
{
|
||||||
|
char const* text = R"(
|
||||||
|
contract C {
|
||||||
|
function f() returns (uint) {
|
||||||
|
return ([4,5,6][1]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)";
|
||||||
|
BOOST_CHECK(success(text));
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOST_AUTO_TEST_CASE(inline_array_declaration_no_type_strings)
|
||||||
|
{
|
||||||
|
char const* text = R"(
|
||||||
|
contract C {
|
||||||
|
function f() returns (string) {
|
||||||
|
return (["foo", "man", "choo"][1]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)";
|
||||||
|
BOOST_CHECK(success(text));
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOST_AUTO_TEST_CASE(inline_struct_declaration_arrays)
|
||||||
|
{
|
||||||
|
char const* text = R"(
|
||||||
|
contract C {
|
||||||
|
struct S {
|
||||||
|
uint a;
|
||||||
|
string b;
|
||||||
|
}
|
||||||
|
function f() {
|
||||||
|
S[2] memory x = [S({a: 1, b: "fish"}), S({a: 2, b: "fish"})];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
)";
|
)";
|
||||||
@ -2788,12 +2871,37 @@ BOOST_AUTO_TEST_CASE(invalid_types_in_inline_array)
|
|||||||
char const* text = R"(
|
char const* text = R"(
|
||||||
contract C {
|
contract C {
|
||||||
function f() {
|
function f() {
|
||||||
uint[] x = [45, "foo", true];
|
uint[3] x = [45, 'foo', true];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
)";
|
)";
|
||||||
BOOST_CHECK(expectError(text) == Error::Type::TypeError);
|
BOOST_CHECK(expectError(text) == Error::Type::TypeError);
|
||||||
}*/
|
}
|
||||||
|
|
||||||
|
BOOST_AUTO_TEST_CASE(dynamic_inline_array)
|
||||||
|
{
|
||||||
|
char const* text = R"(
|
||||||
|
contract C {
|
||||||
|
function f() {
|
||||||
|
uint8[4][4] memory dyn = [[1, 2, 3, 4], [2, 3, 4, 5], [3, 4, 5, 6], [4, 5, 6, 7]];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)";
|
||||||
|
BOOST_CHECK(success(text));
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOST_AUTO_TEST_CASE(lvalues_as_inline_array)
|
||||||
|
{
|
||||||
|
char const* text = R"(
|
||||||
|
contract C {
|
||||||
|
function f() {
|
||||||
|
[1, 2, 3]++;
|
||||||
|
[1, 2, 3] = [4, 5, 6];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)";
|
||||||
|
BOOST_CHECK(expectError(text) == Error::Type::TypeError);
|
||||||
|
}
|
||||||
|
|
||||||
BOOST_AUTO_TEST_SUITE_END()
|
BOOST_AUTO_TEST_SUITE_END()
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user