final changes to typechecker, the expression compiler, and a couple more tests for good measure

This commit is contained in:
RJ Catalano 2016-01-11 14:25:59 -06:00
parent c7df6d0310
commit ac664e7f86
3 changed files with 57 additions and 23 deletions

View File

@ -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,26 +813,34 @@ 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 else
{ {
if (components.size() == 2 && !components[1]) if (components.size() == 1)
types.pop_back(); _tuple.annotation().type = type(*components[0]);
_tuple.annotation().type = make_shared<TupleType>(types); else
{
if (components.size() == 2 && !components[1])
types.pop_back();
_tuple.annotation().type = make_shared<TupleType>(types);
}
} }
} }
return false; return false;
} }

View File

@ -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;

View File

@ -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()
} }