From 2bfa3a7c97724a2dbccafc1a9186b43b404bc5ff Mon Sep 17 00:00:00 2001 From: Leonardo Alt Date: Sun, 24 Nov 2019 18:46:43 +0100 Subject: [PATCH] Rewrite GenericVisitor --- libdevcore/Visitor.h | 128 +++++---------------- libyul/AsmAnalysis.cpp | 8 +- libyul/AsmScope.h | 2 - libyul/backends/evm/EVMCodeTransform.cpp | 16 +-- libyul/optimiser/ControlFlowSimplifier.cpp | 6 +- libyul/optimiser/FullInliner.cpp | 13 ++- libyul/optimiser/StructuralSimplifier.cpp | 5 +- libyul/optimiser/VarDeclInitializer.cpp | 4 +- 8 files changed, 59 insertions(+), 123 deletions(-) diff --git a/libdevcore/Visitor.h b/libdevcore/Visitor.h index c7f117d38..b8d0708d4 100644 --- a/libdevcore/Visitor.h +++ b/libdevcore/Visitor.h @@ -20,109 +20,41 @@ #pragma once -#include -#include - namespace dev { -/// Generic visitor used as follows: -/// std::visit(GenericVisitor( -/// [](Class1& _c) { _c.f(); }, -/// [](Class2& _c) { _c.g(); } -/// ), variant); -/// This one does not have a fallback and will fail at -/// compile-time if you do not specify all variants. +/** + * Generic visitor used as follows: + * std::visit(GenericVisitor{ + * [](Class1& _c) { _c.f(); }, + * [](Class2& _c) { _c.g(); } + * }, variant); + * This one does not have a fallback and will fail at + * compile-time if you do not specify all variants. + * + * Fallback with no return: + * std::visit(GenericVisitor{ + * VisitorFallback<>{}, + * [](Class1& _c) { _c.f(); }, + * [](Class2& _c) { _c.g(); } + * }, variant); + * + * Fallback with return type R: + * std::visit(GenericVisitor{ + * VisitorFallback{}, + * [](Class1& _c) { _c.f(); }, + * [](Class2& _c) { _c.g(); } + * }, variant); + */ -template -struct GenericVisitor{}; +template struct VisitorFallback; -template -struct GenericVisitor: public GenericVisitor -{ - using GenericVisitor::operator (); - explicit GenericVisitor( - std::function _visitor, - std::function... _otherVisitors - ): - GenericVisitor(std::move(_otherVisitors)...), - m_visitor(std::move(_visitor)) - {} +template +struct VisitorFallback { template R operator()(T&&) const { return {}; } }; - void operator()(Visitable& _v) const { m_visitor(_v); } - - std::function m_visitor; -}; -template <> -struct GenericVisitor<>: public boost::static_visitor<> { - void operator()() const {} -}; - -/// Generic visitor with fallback: -/// std::visit(GenericFallbackVisitor( -/// [](Class1& _c) { _c.f(); }, -/// [](Class2& _c) { _c.g(); } -/// ), variant); -/// This one DOES have a fallback and will NOT fail at -/// compile-time if you do not specify all variants. - -template -struct GenericFallbackVisitor{}; - -template -struct GenericFallbackVisitor: public GenericFallbackVisitor -{ - explicit GenericFallbackVisitor( - std::function _visitor, - std::function... _otherVisitors - ): - GenericFallbackVisitor(std::move(_otherVisitors)...), - m_visitor(std::move(_visitor)) - {} - - using GenericFallbackVisitor::operator (); - void operator()(Visitable& _v) const { m_visitor(_v); } - - std::function m_visitor; -}; -template <> -struct GenericFallbackVisitor<>: public boost::static_visitor<> { - template - void operator()(T&) const { } -}; - -/// Generic visitor with fallback that can return a value: -/// std::visit(GenericFallbackReturnsVisitor( -/// [](Class1& _c) { return _c.f(); }, -/// [](Class2& _c) { return _c.g(); } -/// ), variant); -/// This one DOES have a fallback and will NOT fail at -/// compile-time if you do not specify all variants. -/// The fallback {}-constructs the return value. - -template -struct GenericFallbackReturnsVisitor{}; - -template -struct GenericFallbackReturnsVisitor: public GenericFallbackReturnsVisitor -{ - explicit GenericFallbackReturnsVisitor( - std::function _visitor, - std::function... _otherVisitors - ): - GenericFallbackReturnsVisitor(std::move(_otherVisitors)...), - m_visitor(std::move(_visitor)) - {} - - using GenericFallbackReturnsVisitor::operator (); - R operator()(Visitable& _v) const { return m_visitor(_v); } - - std::function m_visitor; -}; -template -struct GenericFallbackReturnsVisitor: public boost::static_visitor { - template - R operator()(T&) const { return {}; } -}; +template<> +struct VisitorFallback<> { template void operator()(T&&) const {} }; +template struct GenericVisitor: Visitors... { using Visitors::operator()...; }; +template GenericVisitor(Visitors...) -> GenericVisitor; } diff --git a/libyul/AsmAnalysis.cpp b/libyul/AsmAnalysis.cpp index 35e933cd1..80a39f386 100644 --- a/libyul/AsmAnalysis.cpp +++ b/libyul/AsmAnalysis.cpp @@ -146,7 +146,7 @@ bool AsmAnalyzer::operator()(Identifier const& _identifier) solAssert(!_identifier.name.empty(), ""); size_t numErrorsBefore = m_errorReporter.errors().size(); bool success = true; - if (m_currentScope->lookup(_identifier.name, Scope::Visitor( + if (m_currentScope->lookup(_identifier.name, GenericVisitor{ [&](Scope::Variable const& _var) { if (!m_activeVariables.count(&_var)) @@ -171,7 +171,7 @@ bool AsmAnalyzer::operator()(Identifier const& _identifier) ); success = false; } - ))) + })) { } else @@ -341,7 +341,7 @@ bool AsmAnalyzer::operator()(FunctionCall const& _funCall) if (f->literalArguments) needsLiteralArguments = true; } - else if (!m_currentScope->lookup(_funCall.functionName.name, Scope::Visitor( + else if (!m_currentScope->lookup(_funCall.functionName.name, GenericVisitor{ [&](Scope::Variable const&) { m_errorReporter.typeError( @@ -364,7 +364,7 @@ bool AsmAnalyzer::operator()(FunctionCall const& _funCall) parameters = _fun.arguments.size(); returns = _fun.returns.size(); } - ))) + })) { m_errorReporter.declarationError(_funCall.functionName.location, "Function not found."); success = false; diff --git a/libyul/AsmScope.h b/libyul/AsmScope.h index e8cd6ef64..9e3a74d03 100644 --- a/libyul/AsmScope.h +++ b/libyul/AsmScope.h @@ -48,8 +48,6 @@ struct Scope }; using Identifier = std::variant; - using Visitor = dev::GenericVisitor; - using NonconstVisitor = dev::GenericVisitor; bool registerVariable(YulString _name, YulType const& _type); bool registerLabel(YulString _name); diff --git a/libyul/backends/evm/EVMCodeTransform.cpp b/libyul/backends/evm/EVMCodeTransform.cpp index ee564ed6b..8e04969c1 100644 --- a/libyul/backends/evm/EVMCodeTransform.cpp +++ b/libyul/backends/evm/EVMCodeTransform.cpp @@ -82,14 +82,14 @@ void VariableReferenceCounter::operator()(Block const& _block) void VariableReferenceCounter::increaseRefIfFound(YulString _variableName) { - m_scope->lookup(_variableName, Scope::Visitor( + m_scope->lookup(_variableName, GenericVisitor{ [=](Scope::Variable const& _var) { ++m_context.variableReferences[&_var]; }, [=](Scope::Label const&) { }, [=](Scope::Function const&) { } - )); + }); } CodeTransform::CodeTransform( @@ -302,11 +302,11 @@ void CodeTransform::operator()(FunctionCall const& _call) } Scope::Function* function = nullptr; - solAssert(m_scope->lookup(_call.functionName.name, Scope::NonconstVisitor( + solAssert(m_scope->lookup(_call.functionName.name, GenericVisitor{ [=](Scope::Variable&) { solAssert(false, "Expected function name."); }, [=](Scope::Label&) { solAssert(false, "Expected function name."); }, [&](Scope::Function& _function) { function = &_function; } - )), "Function name not found."); + }), "Function name not found."); solAssert(function, ""); solAssert(function->arguments.size() == _call.arguments.size(), ""); for (auto const& arg: _call.arguments | boost::adaptors::reversed) @@ -363,7 +363,7 @@ void CodeTransform::operator()(Identifier const& _identifier) m_assembly.setSourceLocation(_identifier.location); // First search internals, then externals. solAssert(m_scope, ""); - if (m_scope->lookup(_identifier.name, Scope::NonconstVisitor( + if (m_scope->lookup(_identifier.name, GenericVisitor{ [=](Scope::Variable& _var) { // TODO: opportunity for optimization: Do not DUP if this is the last reference @@ -383,7 +383,7 @@ void CodeTransform::operator()(Identifier const& _identifier) { solAssert(false, "Function not removed during desugaring."); } - ))) + })) { return; } @@ -682,14 +682,14 @@ void CodeTransform::operator()(Block const& _block) AbstractAssembly::LabelID CodeTransform::labelFromIdentifier(Identifier const& _identifier) { AbstractAssembly::LabelID label = AbstractAssembly::LabelID(-1); - if (!m_scope->lookup(_identifier.name, Scope::NonconstVisitor( + if (!m_scope->lookup(_identifier.name, GenericVisitor{ [=](Scope::Variable&) { solAssert(false, "Expected label"); }, [&](Scope::Label& _label) { label = labelID(_label); }, [=](Scope::Function&) { solAssert(false, "Expected label"); } - ))) + })) { solAssert(false, "Identifier not found."); } diff --git a/libyul/optimiser/ControlFlowSimplifier.cpp b/libyul/optimiser/ControlFlowSimplifier.cpp index 65da3e8fb..4ebb35871 100644 --- a/libyul/optimiser/ControlFlowSimplifier.cpp +++ b/libyul/optimiser/ControlFlowSimplifier.cpp @@ -180,7 +180,8 @@ void ControlFlowSimplifier::visit(Statement& _st) void ControlFlowSimplifier::simplify(std::vector& _statements) { - GenericFallbackReturnsVisitor const visitor( + GenericVisitor visitor{ + VisitorFallback{}, [&](If& _ifStmt) -> OptionalStatements { if (_ifStmt.body.statements.empty() && m_dialect.discardFunction()) { @@ -205,8 +206,7 @@ void ControlFlowSimplifier::simplify(std::vector& _statements) return {}; } - ); - + }; iterateReplacing( _statements, [&](Statement& _stmt) -> OptionalStatements diff --git a/libyul/optimiser/FullInliner.cpp b/libyul/optimiser/FullInliner.cpp index 54c8555d2..75bbb49c3 100644 --- a/libyul/optimiser/FullInliner.cpp +++ b/libyul/optimiser/FullInliner.cpp @@ -157,17 +157,19 @@ void InlineModifier::operator()(Block& _block) std::optional> InlineModifier::tryInlineStatement(Statement& _statement) { // Only inline for expression statements, assignments and variable declarations. - Expression* e = std::visit(GenericFallbackReturnsVisitor( + Expression* e = std::visit(GenericVisitor{ + VisitorFallback{}, [](ExpressionStatement& _s) { return &_s.expression; }, [](Assignment& _s) { return _s.value.get(); }, [](VariableDeclaration& _s) { return _s.value.get(); } - ), _statement); + }, _statement); if (e) { // Only inline direct function calls. - FunctionCall* funCall = std::visit(GenericFallbackReturnsVisitor( + FunctionCall* funCall = std::visit(GenericVisitor{ + VisitorFallback{}, [](FunctionCall& _e) { return &_e; } - ), *e); + }, *e); if (funCall && m_driver.shallInline(*funCall, m_currentFunction)) return performInline(_statement, *funCall); } @@ -205,7 +207,8 @@ vector InlineModifier::performInline(Statement& _statement, FunctionC Statement newBody = BodyCopier(m_nameDispenser, variableReplacements)(function->body); newStatements += std::move(std::get(newBody).statements); - std::visit(GenericFallbackVisitor{ + std::visit(GenericVisitor{ + VisitorFallback<>{}, [&](Assignment& _assignment) { for (size_t i = 0; i < _assignment.variableNames.size(); ++i) diff --git a/libyul/optimiser/StructuralSimplifier.cpp b/libyul/optimiser/StructuralSimplifier.cpp index 424caf575..fb97e22a8 100644 --- a/libyul/optimiser/StructuralSimplifier.cpp +++ b/libyul/optimiser/StructuralSimplifier.cpp @@ -71,7 +71,8 @@ void StructuralSimplifier::operator()(Block& _block) void StructuralSimplifier::simplify(std::vector& _statements) { - GenericFallbackReturnsVisitor const visitor( + GenericVisitor visitor{ + VisitorFallback{}, [&](If& _ifStmt) -> OptionalStatements { if (expressionAlwaysTrue(*_ifStmt.condition)) return {std::move(_ifStmt.body.statements)}; @@ -89,7 +90,7 @@ void StructuralSimplifier::simplify(std::vector& _statements) return {std::move(_forLoop.pre.statements)}; return {}; } - ); + }; iterateReplacing( _statements, diff --git a/libyul/optimiser/VarDeclInitializer.cpp b/libyul/optimiser/VarDeclInitializer.cpp index d6f07bc1e..abedfe069 100644 --- a/libyul/optimiser/VarDeclInitializer.cpp +++ b/libyul/optimiser/VarDeclInitializer.cpp @@ -30,7 +30,8 @@ void VarDeclInitializer::operator()(Block& _block) ASTModifier::operator()(_block); using OptionalStatements = std::optional>; - GenericFallbackReturnsVisitor visitor{ + GenericVisitor visitor{ + VisitorFallback{}, [](VariableDeclaration& _varDecl) -> OptionalStatements { if (_varDecl.value) @@ -51,5 +52,6 @@ void VarDeclInitializer::operator()(Block& _block) } } }; + iterateReplacing(_block.statements, [&](auto&& _statement) { return std::visit(visitor, _statement); }); }