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?
|
||||
===========================================
|
||||
|
||||
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::
|
||||
|
||||
@ -325,6 +326,7 @@ Examples::
|
||||
struct S { uint a; uint b; }
|
||||
S public x = S(1, 2);
|
||||
string name = "Ada";
|
||||
string[4] memory AdaArr = ["This", "is", "an", "array"];
|
||||
}
|
||||
contract D {
|
||||
C c = new C();
|
||||
|
@ -783,10 +783,12 @@ bool TypeChecker::visit(Assignment const& _assignment)
|
||||
bool TypeChecker::visit(TupleExpression const& _tuple)
|
||||
{
|
||||
vector<ASTPointer<Expression>> const& components = _tuple.components();
|
||||
solAssert(!_tuple.isInlineArray(), "Tuple type not properly declared");
|
||||
TypePointers types;
|
||||
|
||||
if (_tuple.annotation().lValueRequested)
|
||||
{
|
||||
if (_tuple.isInlineArray())
|
||||
fatalTypeError(_tuple.location(), "Inline array type cannot be declared as LValue.");
|
||||
for (auto const& component: components)
|
||||
if (component)
|
||||
{
|
||||
@ -804,6 +806,7 @@ bool TypeChecker::visit(TupleExpression const& _tuple)
|
||||
}
|
||||
else
|
||||
{
|
||||
TypePointer inlineArrayType;
|
||||
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,).
|
||||
@ -813,18 +816,34 @@ bool TypeChecker::visit(TupleExpression const& _tuple)
|
||||
{
|
||||
components[i]->accept(*this);
|
||||
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
|
||||
types.push_back(TypePointer());
|
||||
}
|
||||
if (components.size() == 1)
|
||||
_tuple.annotation().type = type(*components[0]);
|
||||
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() == 2 && !components[1])
|
||||
types.pop_back();
|
||||
_tuple.annotation().type = make_shared<TupleType>(types);
|
||||
if (components.size() == 1)
|
||||
_tuple.annotation().type = type(*components[0]);
|
||||
else
|
||||
{
|
||||
if (components.size() == 2 && !components[1])
|
||||
types.pop_back();
|
||||
_tuple.annotation().type = make_shared<TupleType>(types);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
@ -219,25 +219,46 @@ bool ExpressionCompiler::visit(Assignment const& _assignment)
|
||||
|
||||
bool ExpressionCompiler::visit(TupleExpression const& _tuple)
|
||||
{
|
||||
vector<unique_ptr<LValue>> lvalues;
|
||||
for (auto const& component: _tuple.components())
|
||||
if (component)
|
||||
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);
|
||||
if (_tuple.annotation().lValueRequested)
|
||||
{
|
||||
solAssert(!!m_currentLValue, "");
|
||||
lvalues.push_back(move(m_currentLValue));
|
||||
}
|
||||
utils().convertType(*component->annotation().type, *arrayType.baseType(), true);
|
||||
utils().storeInMemoryDynamic(*arrayType.baseType(), true);
|
||||
}
|
||||
else if (_tuple.annotation().lValueRequested)
|
||||
lvalues.push_back(unique_ptr<LValue>());
|
||||
if (_tuple.annotation().lValueRequested)
|
||||
|
||||
m_context << eth::Instruction::POP;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (_tuple.components().size() == 1)
|
||||
m_currentLValue = move(lvalues[0]);
|
||||
else
|
||||
m_currentLValue.reset(new TupleObject(m_context, move(lvalues)));
|
||||
vector<unique_ptr<LValue>> lvalues;
|
||||
for (auto const& component: _tuple.components())
|
||||
if (component)
|
||||
{
|
||||
component->accept(*this);
|
||||
if (_tuple.annotation().lValueRequested)
|
||||
{
|
||||
solAssert(!!m_currentLValue, "");
|
||||
lvalues.push_back(move(m_currentLValue));
|
||||
}
|
||||
}
|
||||
else if (_tuple.annotation().lValueRequested)
|
||||
lvalues.push_back(unique_ptr<LValue>());
|
||||
if (_tuple.annotation().lValueRequested)
|
||||
{
|
||||
if (_tuple.components().size() == 1)
|
||||
m_currentLValue = move(lvalues[0]);
|
||||
else
|
||||
m_currentLValue.reset(new TupleObject(m_context, move(lvalues)));
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@ -774,7 +795,6 @@ bool ExpressionCompiler::visit(NewExpression const&)
|
||||
void ExpressionCompiler::endVisit(MemberAccess const& _memberAccess)
|
||||
{
|
||||
CompilerContext::LocationSetter locationSetter(m_context, _memberAccess);
|
||||
|
||||
// Check whether the member is a bound function.
|
||||
ASTString const& member = _memberAccess.memberName();
|
||||
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);
|
||||
TypePointer type = _literal.annotation().type;
|
||||
|
||||
switch (type->category())
|
||||
{
|
||||
case Type::Category::IntegerConstant:
|
||||
|
@ -6107,6 +6107,119 @@ BOOST_AUTO_TEST_CASE(bound_function_to_string)
|
||||
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()
|
||||
|
||||
}
|
||||
|
@ -2769,15 +2769,98 @@ BOOST_AUTO_TEST_CASE(function_overload_array_type)
|
||||
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"(
|
||||
contract C {
|
||||
function f() returns (uint) {
|
||||
uint8 x = 7;
|
||||
uint16 y = 8;
|
||||
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 {
|
||||
uint[] a;
|
||||
function f() returns (uint, uint) {
|
||||
a = [1,2,3];
|
||||
return (a[3], [3,4][0]);
|
||||
}
|
||||
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"})];
|
||||
}
|
||||
}
|
||||
)";
|
||||
BOOST_CHECK(success(text));
|
||||
@ -2788,12 +2871,37 @@ BOOST_AUTO_TEST_CASE(invalid_types_in_inline_array)
|
||||
char const* text = R"(
|
||||
contract C {
|
||||
function f() {
|
||||
uint[] x = [45, "foo", true];
|
||||
uint[3] x = [45, 'foo', true];
|
||||
}
|
||||
}
|
||||
)";
|
||||
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()
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user