diff --git a/test/libyul/yulInterpreterTests/shadowed_symbol.yul b/test/libyul/yulInterpreterTests/shadowed_symbol.yul new file mode 100644 index 000000000..335f98a02 --- /dev/null +++ b/test/libyul/yulInterpreterTests/shadowed_symbol.yul @@ -0,0 +1,19 @@ +{ + function f() + { + // Variable declaration does not shadow namesake function declaration + // because latter not visible here. + let shadow_id + } + { + // Function named `shadow_id` is in scope now. + f() + function shadow_id() {} + } +} +// ==== +// EVMVersion: >=constantinople +// ---- +// Trace: +// Memory dump: +// Storage dump: diff --git a/test/tools/yulInterpreter/Interpreter.cpp b/test/tools/yulInterpreter/Interpreter.cpp index 7bcd4771e..73c17a6c3 100644 --- a/test/tools/yulInterpreter/Interpreter.cpp +++ b/test/tools/yulInterpreter/Interpreter.cpp @@ -180,14 +180,14 @@ void Interpreter::operator()(Block const& _block) u256 Interpreter::evaluate(Expression const& _expression) { - ExpressionEvaluator ev(m_state, m_dialect, m_variables, m_functions); + ExpressionEvaluator ev(m_state, m_dialect, m_variables, m_functions, m_scopes); ev.visit(_expression); return ev.value(); } vector Interpreter::evaluateMulti(Expression const& _expression) { - ExpressionEvaluator ev(m_state, m_dialect, m_variables, m_functions); + ExpressionEvaluator ev(m_state, m_dialect, m_variables, m_functions, m_scopes); ev.visit(_expression); return ev.values(); } @@ -248,7 +248,7 @@ void ExpressionEvaluator::operator()(FunctionCall const& _funCall) // TODO function name lookup could be a little more efficient, // we have to copy the list here. - Interpreter interpreter(m_state, m_dialect, variables, m_functions); + Interpreter interpreter(m_state, m_dialect, variables, visibleFunctionsFor(fun.name)); interpreter(fun.body); m_values.clear(); @@ -280,3 +280,20 @@ void ExpressionEvaluator::evaluateArgs(vector const& _expr) m_values = std::move(values); std::reverse(m_values.begin(), m_values.end()); } + +std::map ExpressionEvaluator::visibleFunctionsFor(YulString const& _name) +{ + std::map functions; + + for (auto const& scope: m_scopes) + { + for (auto const& symbol: scope) + if (m_functions.count(symbol) > 0) + functions[symbol] = m_functions.at(symbol); + + if (scope.count(_name)) + break; + } + + return functions; +} diff --git a/test/tools/yulInterpreter/Interpreter.h b/test/tools/yulInterpreter/Interpreter.h index 6fc20280a..d7c6b1f76 100644 --- a/test/tools/yulInterpreter/Interpreter.h +++ b/test/tools/yulInterpreter/Interpreter.h @@ -159,12 +159,14 @@ public: InterpreterState& _state, Dialect const& _dialect, std::map const& _variables, - std::map const& _functions + std::map const& _functions, + std::vector> const& _scopes ): m_state(_state), m_dialect(_dialect), m_variables(_variables), - m_functions(_functions) + m_functions(_functions), + m_scopes(_scopes) {} void operator()(Literal const&) override; @@ -184,12 +186,16 @@ private: /// stores it in m_value. void evaluateArgs(std::vector const& _expr); + /// Extracts functions from the earlier scopes that are visible for the given function + std::map visibleFunctionsFor(YulString const& _name); + InterpreterState& m_state; Dialect const& m_dialect; /// Values of variables. std::map const& m_variables; /// Meanings of functions. std::map const& m_functions; + std::vector> const& m_scopes; /// Current value of the expression std::vector m_values; };