diff --git a/libsolidity/codegen/YulUtilFunctions.cpp b/libsolidity/codegen/YulUtilFunctions.cpp index 8786ff6c2..f61a76d32 100644 --- a/libsolidity/codegen/YulUtilFunctions.cpp +++ b/libsolidity/codegen/YulUtilFunctions.cpp @@ -35,6 +35,16 @@ using namespace solidity; using namespace solidity::util; using namespace solidity::frontend; +string YulUtilFunctions::identityFunction() +{ + string functionName = "identity"; + return m_functionCollector.createFunction("identity", [&](vector& _args, vector& _rets) { + _args.push_back("value"); + _rets.push_back("ret"); + return "ret := value"; + }); +} + string YulUtilFunctions::combineExternalFunctionIdFunction() { string functionName = "combine_external_function_id"; @@ -3272,48 +3282,38 @@ string YulUtilFunctions::conversionFunction(Type const& _from, Type const& _to) if (rational->isFractional()) solAssert(toCategory == Type::Category::FixedPoint, ""); - if (toCategory == Type::Category::FixedBytes) - { - FixedBytesType const& toBytesType = dynamic_cast(_to); - body = - Whiskers("converted := ((value))") - ("shiftLeft", shiftLeftFunction(256 - toBytesType.numBytes() * 8)) - ("clean", cleanupFunction(_from)) - .render(); - } - else if (toCategory == Type::Category::Enum) - body = - Whiskers("converted := ((value))") - ("cleanEnum", cleanupFunction(_to)) - ("cleanInt", cleanupFunction(_from)) - .render(); - else if (toCategory == Type::Category::FixedPoint) - solUnimplemented("Not yet implemented - FixedPointType."); - else if (toCategory == Type::Category::Address || toCategory == Type::Category::Contract) + if (toCategory == Type::Category::Address || toCategory == Type::Category::Contract) body = Whiskers("converted := (value)") ("convert", conversionFunction(_from, IntegerType(160))) .render(); - else if (toCategory == Type::Category::Integer) - { - IntegerType const& to = dynamic_cast(_to); - - // Clean according to the "to" type, except if this is - // a widening conversion. - IntegerType const* cleanupType = &to; - if (fromCategory == Type::Category::Integer) - { - IntegerType const& from = dynamic_cast(_from); - if (to.numBits() > from.numBits()) - cleanupType = &from; - } - body = - Whiskers("converted := (value)") - ("cleanInt", cleanupFunction(*cleanupType)) - .render(); - } else - solAssert(false, ""); + { + Whiskers bodyTemplate("converted := (((value)))"); + bodyTemplate("cleanInput", cleanupFunction(_from)); + bodyTemplate("cleanOutput", cleanupFunction(_to)); + string convert; + + if (auto const* toFixedBytes = dynamic_cast(&_to)) + convert = shiftLeftFunction(256 - toFixedBytes->numBytes() * 8); + else if (dynamic_cast(&_to)) + solUnimplementedAssert(false, ""); + else if (dynamic_cast(&_to)) + { + solUnimplementedAssert(fromCategory != Type::Category::FixedPoint, ""); + convert = identityFunction(); + } + else if (toCategory == Type::Category::Enum) + { + solAssert(fromCategory != Type::Category::FixedPoint, ""); + convert = identityFunction(); + } + else + solAssert(false, ""); + solAssert(!convert.empty(), ""); + bodyTemplate("convert", convert); + body = bodyTemplate.render(); + } break; } case Type::Category::Bool: diff --git a/libsolidity/codegen/YulUtilFunctions.h b/libsolidity/codegen/YulUtilFunctions.h index 6b7aa1545..a03ee75c2 100644 --- a/libsolidity/codegen/YulUtilFunctions.h +++ b/libsolidity/codegen/YulUtilFunctions.h @@ -59,6 +59,10 @@ public: m_functionCollector(_functionCollector) {} + /// @returns the name of a function that returns its argument. + /// Sometimes needed to satisfy templates. + std::string identityFunction(); + /// @returns a function that combines the address and selector to a single value /// for use in the ABI. std::string combineExternalFunctionIdFunction();