diff options
-rw-r--r-- | libsolidity/analysis/TypeChecker.cpp | 40 | ||||
-rw-r--r-- | libsolidity/codegen/ExpressionCompiler.cpp | 15 | ||||
-rw-r--r-- | test/libsolidity/SolidityNameAndTypeResolution.cpp | 25 |
3 files changed, 57 insertions, 23 deletions
diff --git a/libsolidity/analysis/TypeChecker.cpp b/libsolidity/analysis/TypeChecker.cpp index 20b3ad6c..75a9632e 100644 --- a/libsolidity/analysis/TypeChecker.cpp +++ b/libsolidity/analysis/TypeChecker.cpp @@ -781,10 +781,12 @@ bool TypeChecker::visit(TupleExpression const& _tuple) { vector<ASTPointer<Expression>> const& components = _tuple.components(); TypePointers types; - TypePointer internalArrayType; - bool isArray = _tuple.isInlineArray(); + TypePointer inlineArrayType; + 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) { @@ -811,26 +813,34 @@ bool TypeChecker::visit(TupleExpression const& _tuple) { components[i]->accept(*this); types.push_back(type(*components[i])); - if (i == 0 && isArray) - internalArrayType = types[i]->mobileType(); - else if (isArray && internalArrayType && types[i]->mobileType()) - internalArrayType = Type::commonType(internalArrayType, types[i]->mobileType()); + 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 && !isArray) - _tuple.annotation().type = type(*components[0]); - else if (!internalArrayType && isArray) - fatalTypeError(_tuple.location(), "Unable to deduce common type for array elements."); - else if (isArray) - _tuple.annotation().type = make_shared<ArrayType>(DataLocation::Memory, internalArrayType, types.size()); + 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; } diff --git a/libsolidity/codegen/ExpressionCompiler.cpp b/libsolidity/codegen/ExpressionCompiler.cpp index c5f0f97e..f0dab41a 100644 --- a/libsolidity/codegen/ExpressionCompiler.cpp +++ b/libsolidity/codegen/ExpressionCompiler.cpp @@ -186,7 +186,7 @@ bool ExpressionCompiler::visit(Assignment const& _assignment) _assignment.leftHandSide().annotation().type ); utils().convertType(*_assignment.rightHandSide().annotation().type, *type); - + _assignment.leftHandSide().accept(*this); solAssert(!!m_currentLValue, "LValue not retrieved."); @@ -222,18 +222,17 @@ bool ExpressionCompiler::visit(TupleExpression const& _tuple) if (_tuple.isInlineArray()) { 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()); utils().allocateMemory(); m_context << eth::Instruction::DUP1; - for (unsigned i = 0; i < components.size(); ++i) + for (auto const& component: _tuple.components()) { - components[i]->accept(*this); - utils().convertType(*components[i]->annotation().type, *arrayType.baseType(), true); - components[i]->annotation().type = arrayType.baseType(); //force conversion - utils().storeInMemoryDynamic(*components[i]->annotation().type, true); + component->accept(*this); + utils().convertType(*component->annotation().type, *arrayType.baseType(), true); + utils().storeInMemoryDynamic(*arrayType.baseType(), true); } m_context << eth::Instruction::POP; @@ -1155,7 +1154,7 @@ void ExpressionCompiler::endVisit(Literal const& _literal) break; // will be done during conversion default: BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Only integer, boolean and string literals implemented for now.")); - } + } } void ExpressionCompiler::appendAndOrOperatorCode(BinaryOperation const& _binaryOperation) diff --git a/test/libsolidity/SolidityNameAndTypeResolution.cpp b/test/libsolidity/SolidityNameAndTypeResolution.cpp index c63d8297..3909fc6c 100644 --- a/test/libsolidity/SolidityNameAndTypeResolution.cpp +++ b/test/libsolidity/SolidityNameAndTypeResolution.cpp @@ -2862,6 +2862,31 @@ BOOST_AUTO_TEST_CASE(invalid_types_in_inline_array) 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() } |