From 4908101ad757f0ec6ef54abd6929f7d5cf128992 Mon Sep 17 00:00:00 2001 From: chriseth Date: Thu, 16 Apr 2020 14:21:12 +0200 Subject: [PATCH] Yul IR generation for member access to type types. --- .../codegen/ir/IRGeneratorForStatements.cpp | 125 ++++++++++++++---- .../codegen/ir/IRGeneratorForStatements.h | 5 + ...ract_enums_with_explicit_contract_name.sol | 2 + .../semanticTests/enums/using_enums.sol | 2 + .../enums/using_inherited_enum.sol | 3 +- .../using_inherited_enum_excplicitly.sol | 3 +- .../intheritance/explicit_base_class.sol | 3 +- .../intheritance/inherited_function.sol | 3 +- .../state_variable_local_variable_mixture.sol | 3 +- .../state_variable_under_contract_name.sol | 3 +- 10 files changed, 117 insertions(+), 35 deletions(-) diff --git a/libsolidity/codegen/ir/IRGeneratorForStatements.cpp b/libsolidity/codegen/ir/IRGeneratorForStatements.cpp index c1b4c8b21..e375739d0 100644 --- a/libsolidity/codegen/ir/IRGeneratorForStatements.cpp +++ b/libsolidity/codegen/ir/IRGeneratorForStatements.cpp @@ -985,12 +985,74 @@ void IRGeneratorForStatements::endVisit(MemberAccess const& _memberAccess) } case Type::Category::TypeType: { - TypeType const& type = dynamic_cast(*_memberAccess.expression().annotation().type); - solUnimplementedAssert(type.actualType()->category() == Type::Category::Contract, ""); - FunctionType const* funType = dynamic_cast(_memberAccess.annotation().type); - solUnimplementedAssert(funType, ""); - solUnimplementedAssert(funType->kind() == FunctionType::Kind::Declaration, ""); - // Nothing to do for declaration. + Type const& actualType = *dynamic_cast( + *_memberAccess.expression().annotation().type + ).actualType(); + + if (actualType.category() == Type::Category::Contract) + { + if (auto const* variable = dynamic_cast(_memberAccess.annotation().referencedDeclaration)) + handleVariableReference(*variable, _memberAccess); + else if (auto const* funType = dynamic_cast(_memberAccess.annotation().type)) + { + switch (funType->kind()) + { + case FunctionType::Kind::Declaration: + break; + case FunctionType::Kind::Internal: + if (auto const* function = dynamic_cast(_memberAccess.annotation().referencedDeclaration)) + define(_memberAccess) << to_string(function->id()) << "\n"; + else + solAssert(false, "Function not found in member access"); + break; + case FunctionType::Kind::Event: + solAssert( + dynamic_cast(_memberAccess.annotation().referencedDeclaration), + "Event not found" + ); + // the call will do the resolving + break; + case FunctionType::Kind::DelegateCall: + define(IRVariable(_memberAccess).part("address"), _memberAccess.expression()); + define(IRVariable(_memberAccess).part("functionIdentifier")) << formatNumber(funType->externalIdentifier()) << "\n"; + break; + case FunctionType::Kind::External: + case FunctionType::Kind::Creation: + case FunctionType::Kind::Send: + case FunctionType::Kind::BareCall: + case FunctionType::Kind::BareCallCode: + case FunctionType::Kind::BareDelegateCall: + case FunctionType::Kind::BareStaticCall: + case FunctionType::Kind::Transfer: + case FunctionType::Kind::Log0: + case FunctionType::Kind::Log1: + case FunctionType::Kind::Log2: + case FunctionType::Kind::Log3: + case FunctionType::Kind::Log4: + case FunctionType::Kind::ECRecover: + case FunctionType::Kind::SHA256: + case FunctionType::Kind::RIPEMD160: + default: + solAssert(false, "unsupported member function"); + } + } + else if (dynamic_cast(_memberAccess.annotation().type)) + { + // no-op + } + else + // The old code generator had a generic "else" case here + // without any specific code being generated, + // but it would still be better to have an exhaustive list. + solAssert(false, ""); + } + else if (EnumType const* enumType = dynamic_cast(&actualType)) + define(_memberAccess) << to_string(enumType->memberValue(_memberAccess.memberName())) << "\n"; + else + // The old code generator had a generic "else" case here + // without any specific code being generated, + // but it would still be better to have an exhaustive list. + solAssert(false, ""); break; } default: @@ -1208,28 +1270,7 @@ void IRGeneratorForStatements::endVisit(Identifier const& _identifier) else if (FunctionDefinition const* functionDef = dynamic_cast(declaration)) define(_identifier) << to_string(functionDef->resolveVirtual(m_context.mostDerivedContract()).id()) << "\n"; else if (VariableDeclaration const* varDecl = dynamic_cast(declaration)) - { - // TODO for the constant case, we have to be careful: - // If the value is visited twice, `defineExpression` is called twice on - // the same expression. - solUnimplementedAssert(!varDecl->isConstant(), ""); - solUnimplementedAssert(!varDecl->immutable(), ""); - if (m_context.isLocalVariable(*varDecl)) - setLValue(_identifier, IRLValue{ - *varDecl->annotation().type, - IRLValue::Stack{m_context.localVariable(*varDecl)} - }); - else if (m_context.isStateVariable(*varDecl)) - setLValue(_identifier, IRLValue{ - *varDecl->annotation().type, - IRLValue::Storage{ - toCompactHexWithPrefix(m_context.storageLocationOfVariable(*varDecl).first), - m_context.storageLocationOfVariable(*varDecl).second - } - }); - else - solAssert(false, "Invalid variable kind."); - } + handleVariableReference(*varDecl, _identifier); else if (auto contract = dynamic_cast(declaration)) { solUnimplementedAssert(!contract->isLibrary(), "Libraries not yet supported."); @@ -1271,6 +1312,33 @@ bool IRGeneratorForStatements::visit(Literal const& _literal) return false; } +void IRGeneratorForStatements::handleVariableReference( + VariableDeclaration const& _variable, + Expression const& _referencingExpression +) +{ + // TODO for the constant case, we have to be careful: + // If the value is visited twice, `defineExpression` is called twice on + // the same expression. + solUnimplementedAssert(!_variable.isConstant(), ""); + solUnimplementedAssert(!_variable.immutable(), ""); + if (m_context.isLocalVariable(_variable)) + setLValue(_referencingExpression, IRLValue{ + *_variable.annotation().type, + IRLValue::Stack{m_context.localVariable(_variable)} + }); + else if (m_context.isStateVariable(_variable)) + setLValue(_referencingExpression, IRLValue{ + *_variable.annotation().type, + IRLValue::Storage{ + toCompactHexWithPrefix(m_context.storageLocationOfVariable(_variable).first), + m_context.storageLocationOfVariable(_variable).second + } + }); + else + solAssert(false, "Invalid variable kind."); +} + void IRGeneratorForStatements::appendExternalFunctionCall( FunctionCall const& _functionCall, vector> const& _arguments @@ -1890,4 +1958,3 @@ bool IRGeneratorForStatements::visit(TryCatchClause const& _clause) _clause.block().accept(*this); return false; } - diff --git a/libsolidity/codegen/ir/IRGeneratorForStatements.h b/libsolidity/codegen/ir/IRGeneratorForStatements.h index 810087a2d..c0cf11ba0 100644 --- a/libsolidity/codegen/ir/IRGeneratorForStatements.h +++ b/libsolidity/codegen/ir/IRGeneratorForStatements.h @@ -87,6 +87,11 @@ private: /// Generates code to rethrow an exception. void rethrow(); + void handleVariableReference( + VariableDeclaration const& _variable, + Expression const& _referencingExpression + ); + /// Appends code to call an external function with the given arguments. /// All involved expressions have already been visited. void appendExternalFunctionCall( diff --git a/test/libsolidity/semanticTests/enums/using_contract_enums_with_explicit_contract_name.sol b/test/libsolidity/semanticTests/enums/using_contract_enums_with_explicit_contract_name.sol index 5d60a7466..c6830abf8 100644 --- a/test/libsolidity/semanticTests/enums/using_contract_enums_with_explicit_contract_name.sol +++ b/test/libsolidity/semanticTests/enums/using_contract_enums_with_explicit_contract_name.sol @@ -6,5 +6,7 @@ contract test { } } +// ==== +// compileViaYul: also // ---- // answer() -> 1 diff --git a/test/libsolidity/semanticTests/enums/using_enums.sol b/test/libsolidity/semanticTests/enums/using_enums.sol index ae497f409..883726f7c 100644 --- a/test/libsolidity/semanticTests/enums/using_enums.sol +++ b/test/libsolidity/semanticTests/enums/using_enums.sol @@ -12,5 +12,7 @@ contract test { ActionChoices choices; } +// ==== +// compileViaYul: also // ---- // getChoice() -> 2 diff --git a/test/libsolidity/semanticTests/enums/using_inherited_enum.sol b/test/libsolidity/semanticTests/enums/using_inherited_enum.sol index c39bfe064..187ec962e 100644 --- a/test/libsolidity/semanticTests/enums/using_inherited_enum.sol +++ b/test/libsolidity/semanticTests/enums/using_inherited_enum.sol @@ -8,6 +8,7 @@ contract test is base { _ret = Choice.B; } } - +// ==== +// compileViaYul: also // ---- // answer() -> 1 diff --git a/test/libsolidity/semanticTests/enums/using_inherited_enum_excplicitly.sol b/test/libsolidity/semanticTests/enums/using_inherited_enum_excplicitly.sol index 0be3f80d4..3bd2b0cea 100644 --- a/test/libsolidity/semanticTests/enums/using_inherited_enum_excplicitly.sol +++ b/test/libsolidity/semanticTests/enums/using_inherited_enum_excplicitly.sol @@ -8,6 +8,7 @@ contract test is base { _ret = base.Choice.B; } } - +// ==== +// compileViaYul: also // ---- // answer() -> 1 diff --git a/test/libsolidity/semanticTests/intheritance/explicit_base_class.sol b/test/libsolidity/semanticTests/intheritance/explicit_base_class.sol index 44553b3f1..7481a0441 100644 --- a/test/libsolidity/semanticTests/intheritance/explicit_base_class.sol +++ b/test/libsolidity/semanticTests/intheritance/explicit_base_class.sol @@ -21,7 +21,8 @@ contract Derived is Base { return 3; } } - +// ==== +// compileViaYul: also // ---- // g() -> 3 // f() -> 1 diff --git a/test/libsolidity/semanticTests/intheritance/inherited_function.sol b/test/libsolidity/semanticTests/intheritance/inherited_function.sol index 23f9bee37..fc01100de 100644 --- a/test/libsolidity/semanticTests/intheritance/inherited_function.sol +++ b/test/libsolidity/semanticTests/intheritance/inherited_function.sol @@ -14,6 +14,7 @@ contract B is A { return A.f(); } } - +// ==== +// compileViaYul: also // ---- // g() -> 1 diff --git a/test/libsolidity/semanticTests/various/state_variable_local_variable_mixture.sol b/test/libsolidity/semanticTests/various/state_variable_local_variable_mixture.sol index 585914c80..6f712839c 100644 --- a/test/libsolidity/semanticTests/various/state_variable_local_variable_mixture.sol +++ b/test/libsolidity/semanticTests/various/state_variable_local_variable_mixture.sol @@ -6,6 +6,7 @@ contract A { x = A.y; } } - +// ==== +// compileViaYul: also // ---- // a() -> 2 diff --git a/test/libsolidity/semanticTests/various/state_variable_under_contract_name.sol b/test/libsolidity/semanticTests/various/state_variable_under_contract_name.sol index 6bef6f85a..2a2c9b975 100644 --- a/test/libsolidity/semanticTests/various/state_variable_under_contract_name.sol +++ b/test/libsolidity/semanticTests/various/state_variable_under_contract_name.sol @@ -5,6 +5,7 @@ contract Scope { stateVar = Scope.stateVar; } } - +// ==== +// compileViaYul: also // ---- // getStateVar() -> 42