diff options
Diffstat (limited to 'libsolidity/CompilerUtils.cpp')
-rw-r--r-- | libsolidity/CompilerUtils.cpp | 63 |
1 files changed, 57 insertions, 6 deletions
diff --git a/libsolidity/CompilerUtils.cpp b/libsolidity/CompilerUtils.cpp index e1152202..34bb08ba 100644 --- a/libsolidity/CompilerUtils.cpp +++ b/libsolidity/CompilerUtils.cpp @@ -550,6 +550,55 @@ void CompilerUtils::convertType(Type const& _typeOnStack, Type const& _targetTyp } break; } + case Type::Category::Tuple: + { + //@TODO wildcards + TupleType const& sourceTuple = dynamic_cast<TupleType const&>(_typeOnStack); + TupleType const& targetTuple = dynamic_cast<TupleType const&>(_targetType); + solAssert(sourceTuple.components().size() == targetTuple.components().size(), ""); + unsigned depth = sourceTuple.sizeOnStack(); + for (size_t i = 0; i < sourceTuple.components().size(); ++i) + { + TypePointer const& sourceType = sourceTuple.components()[i]; + TypePointer const& targetType = targetTuple.components()[i]; + if (!sourceType) + { + solAssert(!targetType, ""); + continue; + } + unsigned sourceSize = sourceType->sizeOnStack(); + unsigned targetSize = targetType->sizeOnStack(); + if (*sourceType != *targetType || _cleanupNeeded) + { + if (sourceSize > 0) + copyToStackTop(depth, sourceSize); + + convertType(*sourceType, *targetType, _cleanupNeeded); + + if (sourceSize > 0 || targetSize > 0) + { + // Move it back into its place. + for (unsigned j = 0; j < min(sourceSize, targetSize); ++j) + m_context << + eth::swapInstruction(depth + targetSize - sourceSize) << + eth::Instruction::POP; + if (targetSize < sourceSize) + moveToStackTop(sourceSize - targetSize, depth ); + // Value shrank + for (unsigned j = targetSize; j < sourceSize; ++j) + { + moveToStackTop(depth - 1, 1); + m_context << eth::Instruction::POP; + } + // Value grew + if (targetSize > sourceSize) + moveIntoStack(depth + targetSize - sourceSize, targetSize - sourceSize); + } + } + depth -= sourceSize; + } + break; + } default: // All other types should not be convertible to non-equal types. solAssert(_typeOnStack == _targetType, "Invalid type conversion requested."); @@ -631,18 +680,20 @@ void CompilerUtils::copyToStackTop(unsigned _stackDepth, unsigned _itemSize) m_context << eth::dupInstruction(_stackDepth); } -void CompilerUtils::moveToStackTop(unsigned _stackDepth) +void CompilerUtils::moveToStackTop(unsigned _stackDepth, unsigned _itemSize) { solAssert(_stackDepth <= 15, "Stack too deep, try removing local variables."); - for (unsigned i = 0; i < _stackDepth; ++i) - m_context << eth::swapInstruction(1 + i); + for (unsigned j = 0; j < _itemSize; ++j) + for (unsigned i = 0; i < _stackDepth + _itemSize - 1; ++i) + m_context << eth::swapInstruction(1 + i); } -void CompilerUtils::moveIntoStack(unsigned _stackDepth) +void CompilerUtils::moveIntoStack(unsigned _stackDepth, unsigned _itemSize) { solAssert(_stackDepth <= 16, "Stack too deep, try removing local variables."); - for (unsigned i = _stackDepth; i > 0; --i) - m_context << eth::swapInstruction(i); + for (unsigned j = 0; j < _itemSize; ++j) + for (unsigned i = _stackDepth; i > 0; --i) + m_context << eth::swapInstruction(i + _itemSize - 1); } void CompilerUtils::popStackElement(Type const& _type) |