mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
final changes to typechecker, the expression compiler, and a couple more tests for good measure
This commit is contained in:
parent
c7df6d0310
commit
ac664e7f86
@ -781,10 +781,12 @@ bool TypeChecker::visit(TupleExpression const& _tuple)
|
|||||||
{
|
{
|
||||||
vector<ASTPointer<Expression>> const& components = _tuple.components();
|
vector<ASTPointer<Expression>> const& components = _tuple.components();
|
||||||
TypePointers types;
|
TypePointers types;
|
||||||
TypePointer internalArrayType;
|
TypePointer inlineArrayType;
|
||||||
bool isArray = _tuple.isInlineArray();
|
|
||||||
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)
|
||||||
{
|
{
|
||||||
@ -811,20 +813,26 @@ 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 (i == 0 && isArray)
|
if (_tuple.isInlineArray())
|
||||||
internalArrayType = types[i]->mobileType();
|
solAssert(!!types[i], "Inline array cannot have empty components");
|
||||||
else if (isArray && internalArrayType && types[i]->mobileType())
|
if (i == 0 && _tuple.isInlineArray())
|
||||||
internalArrayType = Type::commonType(internalArrayType, types[i]->mobileType());
|
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 (components.size() == 1 && !isArray)
|
if (_tuple.isInlineArray())
|
||||||
_tuple.annotation().type = type(*components[0]);
|
{
|
||||||
else if (!internalArrayType && isArray)
|
if (!inlineArrayType)
|
||||||
fatalTypeError(_tuple.location(), "Unable to deduce common type for array elements.");
|
fatalTypeError(_tuple.location(), "Unable to deduce common type for array elements.");
|
||||||
else if (isArray)
|
_tuple.annotation().type = make_shared<ArrayType>(DataLocation::Memory, inlineArrayType, types.size());
|
||||||
_tuple.annotation().type = make_shared<ArrayType>(DataLocation::Memory, internalArrayType, types.size());
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (components.size() == 1)
|
||||||
|
_tuple.annotation().type = type(*components[0]);
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (components.size() == 2 && !components[1])
|
if (components.size() == 2 && !components[1])
|
||||||
@ -832,6 +840,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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -222,18 +222,17 @@ bool ExpressionCompiler::visit(TupleExpression const& _tuple)
|
|||||||
if (_tuple.isInlineArray())
|
if (_tuple.isInlineArray())
|
||||||
{
|
{
|
||||||
ArrayType const& arrayType = dynamic_cast<ArrayType const&>(*_tuple.annotation().type);
|
ArrayType const& arrayType = dynamic_cast<ArrayType const&>(*_tuple.annotation().type);
|
||||||
auto components = _tuple.components();
|
|
||||||
|
|
||||||
|
solAssert(!arrayType.isDynamicallySized(), "Cannot create dynamically sized inline array.");
|
||||||
m_context << max(u256(32u), arrayType.memorySize());
|
m_context << max(u256(32u), arrayType.memorySize());
|
||||||
utils().allocateMemory();
|
utils().allocateMemory();
|
||||||
m_context << eth::Instruction::DUP1;
|
m_context << eth::Instruction::DUP1;
|
||||||
|
|
||||||
for (unsigned i = 0; i < components.size(); ++i)
|
for (auto const& component: _tuple.components())
|
||||||
{
|
{
|
||||||
components[i]->accept(*this);
|
component->accept(*this);
|
||||||
utils().convertType(*components[i]->annotation().type, *arrayType.baseType(), true);
|
utils().convertType(*component->annotation().type, *arrayType.baseType(), true);
|
||||||
components[i]->annotation().type = arrayType.baseType(); //force conversion
|
utils().storeInMemoryDynamic(*arrayType.baseType(), true);
|
||||||
utils().storeInMemoryDynamic(*components[i]->annotation().type, true);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
m_context << eth::Instruction::POP;
|
m_context << eth::Instruction::POP;
|
||||||
|
@ -2862,6 +2862,31 @@ BOOST_AUTO_TEST_CASE(invalid_types_in_inline_array)
|
|||||||
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() {
|
||||||
|
uint[4][4] memory dyn = [[1, 2, 3, 4], [2, 3, 4, 5], [3, 4, 5, 6], [4, 5, 6, 7]];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)";
|
||||||
|
BOOST_CHECK(expectError(text) == Error::Type::TypeError);
|
||||||
|
}
|
||||||
|
|
||||||
|
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