From 944ac6fb6d7a1400a24db4c436119544a93e4e76 Mon Sep 17 00:00:00 2001 From: Mathias Baumann Date: Mon, 15 Apr 2019 18:10:36 +0200 Subject: [PATCH 1/3] Sol -> Yul Generation: Implicit conversions --- .../codegen/ir/IRGeneratorForStatements.cpp | 44 ++++++++++++------- .../codegen/ir/IRGeneratorForStatements.h | 4 ++ .../viaYul/implicit_cast_assignment.sol | 14 ++++++ .../viaYul/implicit_cast_function_call.sol | 17 +++++++ .../viaYul/implicit_cast_local_assignment.sol | 13 ++++++ 5 files changed, 76 insertions(+), 16 deletions(-) create mode 100644 test/libsolidity/semanticTests/viaYul/implicit_cast_assignment.sol create mode 100644 test/libsolidity/semanticTests/viaYul/implicit_cast_function_call.sol create mode 100644 test/libsolidity/semanticTests/viaYul/implicit_cast_local_assignment.sol diff --git a/libsolidity/codegen/ir/IRGeneratorForStatements.cpp b/libsolidity/codegen/ir/IRGeneratorForStatements.cpp index 1c2563771..b95430eb7 100644 --- a/libsolidity/codegen/ir/IRGeneratorForStatements.cpp +++ b/libsolidity/codegen/ir/IRGeneratorForStatements.cpp @@ -90,15 +90,12 @@ bool IRGeneratorForStatements::visit(VariableDeclarationStatement const& _varDec expression->accept(*this); - solUnimplementedAssert( - *expression->annotation().type == *_varDeclStatement.declarations().front()->type(), - "Type conversion not yet implemented" - ); + VariableDeclaration const& varDecl = *_varDeclStatement.declarations().front(); m_code << "let " << - m_context.variableName(*_varDeclStatement.declarations().front()) << + m_context.variableName(varDecl) << " := " << - m_context.variable(*expression) << + expressionAsType(*expression, *varDecl.type()) << "\n"; } else @@ -115,15 +112,17 @@ bool IRGeneratorForStatements::visit(Assignment const& _assignment) _assignment.rightHandSide().accept(*this); -// solUnimplementedAssert( -// *_assignment.rightHandSide().annotation().type == *_assignment.leftHandSide().annotation().type, -// "Type conversion not yet implemented" -// ); // TODO proper lvalue handling - auto const& identifier = dynamic_cast(_assignment.leftHandSide()); - string varName = m_context.variableName(dynamic_cast(*identifier.annotation().referencedDeclaration)); - m_code << varName << " := " << m_context.variable(_assignment.rightHandSide()) << "\n"; + auto const& lvalue = dynamic_cast(_assignment.leftHandSide()); + string varName = m_context.variableName(dynamic_cast(*lvalue.annotation().referencedDeclaration)); + + m_code << + varName << + " := " << + expressionAsType(_assignment.rightHandSide(), *lvalue.annotation().type) << + "\n"; m_code << "let " << m_context.variable(_assignment) << " := " << varName << "\n"; + return false; } @@ -185,9 +184,11 @@ bool IRGeneratorForStatements::visit(FunctionCall const& _functionCall) for (unsigned i = 0; i < arguments.size(); ++i) { arguments[i]->accept(*this); - // TODO convert - //utils().convertType(*arguments[i]->annotation().type, *function.parameterTypes()[i]); - args.emplace_back(m_context.variable(*arguments[i])); + + if (functionType->takesArbitraryParameters()) + args.emplace_back(m_context.variable(*arguments[i])); + else + args.emplace_back(expressionAsType(*arguments[i], *parameterTypes[i])); } if (auto identifier = dynamic_cast(&_functionCall.expression())) @@ -273,3 +274,14 @@ bool IRGeneratorForStatements::visit(Literal const& _literal) } return false; } + +string IRGeneratorForStatements::expressionAsType(Expression const& _expression, Type const& _to) +{ + Type const& from = *_expression.annotation().type; + string varName = m_context.variable(_expression); + + if (from == _to) + return varName; + else + return m_utils.conversionFunction(from, _to) + "(" + std::move(varName) + ")"; +} diff --git a/libsolidity/codegen/ir/IRGeneratorForStatements.h b/libsolidity/codegen/ir/IRGeneratorForStatements.h index c90f2f0bf..75caa4f85 100644 --- a/libsolidity/codegen/ir/IRGeneratorForStatements.h +++ b/libsolidity/codegen/ir/IRGeneratorForStatements.h @@ -53,6 +53,10 @@ public: bool visit(Literal const& _literal) override; private: + /// @returns a Yul expression representing the current value of @a _expression, + /// converted to type @a _to if it does not yet have that type. + std::string expressionAsType(Expression const& _expression, Type const& _to); + std::ostringstream m_code; IRGenerationContext& m_context; YulUtilFunctions& m_utils; diff --git a/test/libsolidity/semanticTests/viaYul/implicit_cast_assignment.sol b/test/libsolidity/semanticTests/viaYul/implicit_cast_assignment.sol new file mode 100644 index 000000000..d6bba1bf5 --- /dev/null +++ b/test/libsolidity/semanticTests/viaYul/implicit_cast_assignment.sol @@ -0,0 +1,14 @@ +// Tests IRGeneratorForStatements::visit(Assignment const& _assignment) +contract C { + function f() public pure returns (uint16 x) { + uint8 y; + assembly { + y := 0x12345678 + } + x = y; + } +} +// ==== +// compileViaYul: true +// ---- +// f() -> 0x78 diff --git a/test/libsolidity/semanticTests/viaYul/implicit_cast_function_call.sol b/test/libsolidity/semanticTests/viaYul/implicit_cast_function_call.sol new file mode 100644 index 000000000..47a9b1cea --- /dev/null +++ b/test/libsolidity/semanticTests/viaYul/implicit_cast_function_call.sol @@ -0,0 +1,17 @@ +// IRGeneratorForStatements::visit(FunctionCall const& _functionCall) +contract C { + function f(uint b) public pure returns (uint x) { + x = b; + } + function g() public pure returns (uint x) { + uint8 a; + assembly { + a := 0x12345678 + } + x = f(a); + } +} +// ==== +// compileViaYul: true +// ---- +// g() -> 0x78 diff --git a/test/libsolidity/semanticTests/viaYul/implicit_cast_local_assignment.sol b/test/libsolidity/semanticTests/viaYul/implicit_cast_local_assignment.sol new file mode 100644 index 000000000..c99b50969 --- /dev/null +++ b/test/libsolidity/semanticTests/viaYul/implicit_cast_local_assignment.sol @@ -0,0 +1,13 @@ +// IRGeneratorForStatements::visit(VariableDeclarationStatement const& _varDeclStatement) +contract C { + function f() public pure returns (uint y) { + uint8 a; + assembly { a := 0x12345678 } + uint z = a; + y = z; + } +} +// ==== +// compileViaYul: true +// ---- +// f() -> 0x78 From 441369d5f1fb096f3d2eba9dbc9ccc90d797f774 Mon Sep 17 00:00:00 2001 From: Mathias Baumann Date: Mon, 15 Apr 2019 18:11:05 +0200 Subject: [PATCH 2/3] Sol -> Yul Generator: Mark "return" as unimplemented --- libsolidity/codegen/ir/IRGeneratorForStatements.cpp | 5 +++++ libsolidity/codegen/ir/IRGeneratorForStatements.h | 1 + 2 files changed, 6 insertions(+) diff --git a/libsolidity/codegen/ir/IRGeneratorForStatements.cpp b/libsolidity/codegen/ir/IRGeneratorForStatements.cpp index b95430eb7..06e9367de 100644 --- a/libsolidity/codegen/ir/IRGeneratorForStatements.cpp +++ b/libsolidity/codegen/ir/IRGeneratorForStatements.cpp @@ -126,6 +126,11 @@ bool IRGeneratorForStatements::visit(Assignment const& _assignment) return false; } +bool IRGeneratorForStatements::visit(Return const&) +{ + solUnimplemented("Return not yet implemented in yul code generation"); +} + void IRGeneratorForStatements::endVisit(BinaryOperation const& _binOp) { solUnimplementedAssert(_binOp.getOperator() == Token::Add, ""); diff --git a/libsolidity/codegen/ir/IRGeneratorForStatements.h b/libsolidity/codegen/ir/IRGeneratorForStatements.h index 75caa4f85..b40d50ff4 100644 --- a/libsolidity/codegen/ir/IRGeneratorForStatements.h +++ b/libsolidity/codegen/ir/IRGeneratorForStatements.h @@ -46,6 +46,7 @@ public: bool visit(VariableDeclarationStatement const& _variableDeclaration) override; bool visit(Assignment const& _assignment) override; + bool visit(Return const& _return) override; void endVisit(BinaryOperation const& _binOp) override; bool visit(FunctionCall const& _funCall) override; bool visit(InlineAssembly const& _inlineAsm) override; From 1ef213cc152e6767cd9f523c8eb496e7aefda14f Mon Sep 17 00:00:00 2001 From: Mathias Baumann Date: Tue, 16 Apr 2019 12:25:30 +0200 Subject: [PATCH 3/3] Sol -> Yul: Implement explicit cast --- .../codegen/ir/IRGeneratorForStatements.cpp | 27 +++++++++++++++++-- .../viaYul/explicit_cast_assignment.sol | 10 +++++++ .../viaYul/explicit_cast_function_call.sol | 12 +++++++++ .../viaYul/explicit_cast_local_assignment.sol | 10 +++++++ 4 files changed, 57 insertions(+), 2 deletions(-) create mode 100644 test/libsolidity/semanticTests/viaYul/explicit_cast_assignment.sol create mode 100644 test/libsolidity/semanticTests/viaYul/explicit_cast_function_call.sol create mode 100644 test/libsolidity/semanticTests/viaYul/explicit_cast_local_assignment.sol diff --git a/libsolidity/codegen/ir/IRGeneratorForStatements.cpp b/libsolidity/codegen/ir/IRGeneratorForStatements.cpp index 06e9367de..42d92fbd5 100644 --- a/libsolidity/codegen/ir/IRGeneratorForStatements.cpp +++ b/libsolidity/codegen/ir/IRGeneratorForStatements.cpp @@ -155,8 +155,31 @@ void IRGeneratorForStatements::endVisit(BinaryOperation const& _binOp) bool IRGeneratorForStatements::visit(FunctionCall const& _functionCall) { - solUnimplementedAssert(_functionCall.annotation().kind == FunctionCallKind::FunctionCall, ""); - FunctionTypePointer functionType = dynamic_cast(_functionCall.expression().annotation().type); + solUnimplementedAssert( + _functionCall.annotation().kind == FunctionCallKind::FunctionCall || + _functionCall.annotation().kind == FunctionCallKind::TypeConversion, + "This type of function call is not yet implemented" + ); + + TypePointer const funcType = _functionCall.expression().annotation().type; + + if (_functionCall.annotation().kind == FunctionCallKind::TypeConversion) + { + solAssert(funcType->category() == Type::Category::TypeType, "Expected category to be TypeType"); + solAssert(_functionCall.arguments().size() == 1, "Expected one argument for type conversion"); + _functionCall.arguments().front()->accept(*this); + + m_code << + "let " << + m_context.variable(_functionCall) << + " := " << + expressionAsType(*_functionCall.arguments().front(), *_functionCall.annotation().type) << + "\n"; + + return false; + } + + FunctionTypePointer functionType = dynamic_cast(funcType); TypePointers parameterTypes = functionType->parameterTypes(); vector> const& callArguments = _functionCall.arguments(); diff --git a/test/libsolidity/semanticTests/viaYul/explicit_cast_assignment.sol b/test/libsolidity/semanticTests/viaYul/explicit_cast_assignment.sol new file mode 100644 index 000000000..6a9291c32 --- /dev/null +++ b/test/libsolidity/semanticTests/viaYul/explicit_cast_assignment.sol @@ -0,0 +1,10 @@ +contract C { + function f() public pure returns (uint16 x) { + uint8 y = uint8(0x12345678); + x = y; + } +} +// ==== +// compileViaYul: true +// ---- +// f() -> 0x78 diff --git a/test/libsolidity/semanticTests/viaYul/explicit_cast_function_call.sol b/test/libsolidity/semanticTests/viaYul/explicit_cast_function_call.sol new file mode 100644 index 000000000..c239b07e4 --- /dev/null +++ b/test/libsolidity/semanticTests/viaYul/explicit_cast_function_call.sol @@ -0,0 +1,12 @@ +contract C { + function f(bytes32 b) public pure returns (bytes32 x) { + x = b; + } + function g() public pure returns (bytes32 x) { + x = f(bytes4(uint32(0x12345678))); + } +} +// ==== +// compileViaYul: true +// ---- +// g() -> 0x1234567800000000000000000000000000000000000000000000000000000000 diff --git a/test/libsolidity/semanticTests/viaYul/explicit_cast_local_assignment.sol b/test/libsolidity/semanticTests/viaYul/explicit_cast_local_assignment.sol new file mode 100644 index 000000000..22bb1f7ea --- /dev/null +++ b/test/libsolidity/semanticTests/viaYul/explicit_cast_local_assignment.sol @@ -0,0 +1,10 @@ +contract C { + function f(uint a) public pure returns (uint8 x) { + uint8 b = uint8(a); + x = b; + } +} +// ==== +// compileViaYul: true +// ---- +// f(uint256): 0x12345678 -> 0x78