Skip to content

Commit

Permalink
Merge pull request #15258 from ethereum/immutable_ast_class
Browse files Browse the repository at this point in the history
Yul: Immutable AST class with top-level block
ekpyron authored Aug 6, 2024

Unverified

This user has not yet uploaded their public signing key.
2 parents 5dbaa13 + 40aec73 commit c92b32f
Showing 67 changed files with 779 additions and 579 deletions.
2 changes: 1 addition & 1 deletion libsolidity/analysis/ControlFlowBuilder.cpp
Original file line number Diff line number Diff line change
@@ -451,7 +451,7 @@ bool ControlFlowBuilder::visit(InlineAssembly const& _inlineAssembly)
solAssert(!!m_currentNode && !m_inlineAssembly, "");

m_inlineAssembly = &_inlineAssembly;
(*this)(_inlineAssembly.operations());
(*this)(_inlineAssembly.operations().root());
m_inlineAssembly = nullptr;

return false;
2 changes: 1 addition & 1 deletion libsolidity/analysis/PostTypeChecker.cpp
Original file line number Diff line number Diff line change
@@ -506,7 +506,7 @@ class LValueChecker: public ASTConstVisitor
return;

YulLValueChecker yulChecker{m_declaration->name()};
yulChecker(_inlineAssembly.operations());
yulChecker(_inlineAssembly.operations().root());
m_willBeWrittenTo = yulChecker.willBeWrittenTo();
}
private:
2 changes: 1 addition & 1 deletion libsolidity/analysis/ReferencesResolver.cpp
Original file line number Diff line number Diff line change
@@ -236,7 +236,7 @@ bool ReferencesResolver::visit(UsingForDirective const& _usingFor)
bool ReferencesResolver::visit(InlineAssembly const& _inlineAssembly)
{
m_yulAnnotation = &_inlineAssembly.annotation();
(*this)(_inlineAssembly.operations());
(*this)(_inlineAssembly.operations().root());
m_yulAnnotation = nullptr;

return false;
2 changes: 1 addition & 1 deletion libsolidity/analysis/SyntaxChecker.cpp
Original file line number Diff line number Diff line change
@@ -354,7 +354,7 @@ bool SyntaxChecker::visit(InlineAssembly const& _inlineAssembly)
if (!m_useYulOptimizer)
return false;

if (yul::MSizeFinder::containsMSize(_inlineAssembly.dialect(), _inlineAssembly.operations()))
if (yul::MSizeFinder::containsMSize(_inlineAssembly.dialect(), _inlineAssembly.operations().root()))
m_errorReporter.syntaxError(
6553_error,
_inlineAssembly.location(),
2 changes: 1 addition & 1 deletion libsolidity/analysis/TypeChecker.cpp
Original file line number Diff line number Diff line change
@@ -940,7 +940,7 @@ bool TypeChecker::visit(InlineAssembly const& _inlineAssembly)
_inlineAssembly.dialect(),
identifierAccess
);
if (!analyzer.analyze(_inlineAssembly.operations()))
if (!analyzer.analyze(_inlineAssembly.operations().root()))
solAssert(m_errorReporter.hasErrors());
_inlineAssembly.annotation().hasMemoryEffects =
lvalueAccessToMemoryVariable ||
2 changes: 1 addition & 1 deletion libsolidity/analysis/ViewPureChecker.cpp
Original file line number Diff line number Diff line change
@@ -226,7 +226,7 @@ void ViewPureChecker::endVisit(InlineAssembly const& _inlineAssembly)
AssemblyViewPureChecker{
_inlineAssembly.dialect(),
[&](StateMutability _mutability, SourceLocation const& _location) { reportMutability(_mutability, _location); }
}(_inlineAssembly.operations());
}(_inlineAssembly.operations().root());
}

void ViewPureChecker::reportMutability(
8 changes: 4 additions & 4 deletions libsolidity/ast/AST.h
Original file line number Diff line number Diff line change
@@ -48,7 +48,7 @@
namespace solidity::yul
{
// Forward-declaration to <yul/AST.h>
struct Block;
class AST;
struct Dialect;
}

@@ -1569,7 +1569,7 @@ class InlineAssembly: public Statement
ASTPointer<ASTString> const& _docString,
yul::Dialect const& _dialect,
ASTPointer<std::vector<ASTPointer<ASTString>>> _flags,
std::shared_ptr<yul::Block> _operations
std::shared_ptr<yul::AST> _operations
):
Statement(_id, _location, _docString),
m_dialect(_dialect),
@@ -1580,15 +1580,15 @@ class InlineAssembly: public Statement
void accept(ASTConstVisitor& _visitor) const override;

yul::Dialect const& dialect() const { return m_dialect; }
yul::Block const& operations() const { return *m_operations; }
yul::AST const& operations() const { return *m_operations; }
ASTPointer<std::vector<ASTPointer<ASTString>>> const& flags() const { return m_flags; }

InlineAssemblyAnnotation& annotation() const override;

private:
yul::Dialect const& m_dialect;
ASTPointer<std::vector<ASTPointer<ASTString>>> m_flags;
std::shared_ptr<yul::Block> m_operations;
std::shared_ptr<yul::AST> m_operations;
};

/**
2 changes: 1 addition & 1 deletion libsolidity/ast/ASTJsonExporter.cpp
Original file line number Diff line number Diff line change
@@ -665,7 +665,7 @@ bool ASTJsonExporter::visit(InlineAssembly const& _node)
externalReferencesJson.emplace_back(std::move(it));

std::vector<std::pair<std::string, Json>> attributes = {
std::make_pair("AST", Json(yul::AsmJsonConverter(sourceIndexFromLocation(_node.location()))(_node.operations()))),
std::make_pair("AST", Json(yul::AsmJsonConverter(sourceIndexFromLocation(_node.location()))(_node.operations().root()))),
std::make_pair("externalReferences", std::move(externalReferencesJson)),
std::make_pair("evmVersion", dynamic_cast<solidity::yul::EVMDialect const&>(_node.dialect()).evmVersion().name())
};
2 changes: 1 addition & 1 deletion libsolidity/ast/ASTJsonImporter.cpp
Original file line number Diff line number Diff line change
@@ -733,7 +733,7 @@ ASTPointer<InlineAssembly> ASTJsonImporter::createInlineAssembly(Json const& _no
flags->emplace_back(std::make_shared<ASTString>(flag.get<std::string>()));
}
}
std::shared_ptr<yul::Block> operations = std::make_shared<yul::Block>(yul::AsmJsonImporter(m_sourceNames).createBlock(member(_node, "AST")));
std::shared_ptr<yul::AST> operations = std::make_shared<yul::AST>(yul::AsmJsonImporter(m_sourceNames).createAST(member(_node, "AST")));
return createASTNode<InlineAssembly>(
_node,
nullOrASTString(_node, "documentation"),
20 changes: 10 additions & 10 deletions libsolidity/codegen/CompilerContext.cpp
Original file line number Diff line number Diff line change
@@ -440,7 +440,7 @@ void CompilerContext::appendInlineAssembly(
std::optional<langutil::SourceLocation> locationOverride;
if (!_system)
locationOverride = m_asm->currentSourceLocation();
std::shared_ptr<yul::Block> parserResult =
std::shared_ptr<yul::AST> parserResult =
yul::Parser(errorReporter, dialect, std::move(locationOverride))
.parse(charStream);
#ifdef SOL_OUTPUT_ASM
@@ -472,17 +472,17 @@ void CompilerContext::appendInlineAssembly(
errorReporter,
dialect,
identifierAccess.resolve
).analyze(*parserResult);
).analyze(parserResult->root());
if (!parserResult || !errorReporter.errors().empty() || !analyzerResult)
reportError("Invalid assembly generated by code generator.");
std::shared_ptr<yul::AST const> toBeAssembledAST = parserResult;

// Several optimizer steps cannot handle externally supplied stack variables,
// so we essentially only optimize the ABI functions.
if (_optimiserSettings.runYulOptimiser && _localVariables.empty())
{
yul::Object obj;
obj.code = parserResult;
obj.analysisInfo = std::make_shared<yul::AsmAnalysisInfo>(analysisInfo);
obj.setCode(parserResult, std::make_shared<yul::AsmAnalysisInfo>(analysisInfo));

solAssert(!dialect.providesObjectAccess());
optimizeYul(obj, dialect, _optimiserSettings, externallyUsedIdentifiers);
@@ -491,15 +491,15 @@ void CompilerContext::appendInlineAssembly(
{
// Store as generated sources, but first re-parse to update the source references.
solAssert(m_generatedYulUtilityCode.empty(), "");
m_generatedYulUtilityCode = yul::AsmPrinter(yul::AsmPrinter::TypePrinting::OmitDefault, dialect)(*obj.code);
std::string code = yul::AsmPrinter{yul::AsmPrinter::TypePrinting::OmitDefault, dialect}(*obj.code);
m_generatedYulUtilityCode = yul::AsmPrinter(yul::AsmPrinter::TypePrinting::OmitDefault, dialect)(obj.code()->root());
std::string code = yul::AsmPrinter{yul::AsmPrinter::TypePrinting::OmitDefault, dialect}(obj.code()->root());
langutil::CharStream charStream(m_generatedYulUtilityCode, _sourceName);
obj.code = yul::Parser(errorReporter, dialect).parse(charStream);
*obj.analysisInfo = yul::AsmAnalyzer::analyzeStrictAssertCorrect(dialect, obj);
obj.setCode(yul::Parser(errorReporter, dialect).parse(charStream));
obj.analysisInfo = std::make_shared<yul::AsmAnalysisInfo>(yul::AsmAnalyzer::analyzeStrictAssertCorrect(dialect, obj));
}

analysisInfo = std::move(*obj.analysisInfo);
parserResult = std::move(obj.code);
toBeAssembledAST = obj.code();

#ifdef SOL_OUTPUT_ASM
cout << "After optimizer:" << endl;
@@ -518,7 +518,7 @@ void CompilerContext::appendInlineAssembly(

solAssert(errorReporter.errors().empty(), "Failed to analyze inline assembly block.");
yul::CodeGenerator::assemble(
*parserResult,
toBeAssembledAST->root(),
analysisInfo,
*m_asm,
m_evmVersion,
8 changes: 4 additions & 4 deletions libsolidity/codegen/ContractCompiler.cpp
Original file line number Diff line number Diff line change
@@ -927,7 +927,7 @@ bool ContractCompiler::visit(InlineAssembly const& _inlineAssembly)
}
};

yul::Block const* code = &_inlineAssembly.operations();
yul::AST const* code = &_inlineAssembly.operations();
yul::AsmAnalysisInfo* analysisInfo = _inlineAssembly.annotation().analysisInfo.get();

// Only used in the scope below, but required to live outside to keep the
@@ -944,17 +944,17 @@ bool ContractCompiler::visit(InlineAssembly const& _inlineAssembly)
solAssert(dialect, "");

// Create a modifiable copy of the code and analysis
object.code = std::make_shared<yul::Block>(yul::ASTCopier().translate(*code));
object.setCode(std::make_shared<yul::AST>(yul::ASTCopier().translate(code->root())));
object.analysisInfo = std::make_shared<yul::AsmAnalysisInfo>(yul::AsmAnalyzer::analyzeStrictAssertCorrect(*dialect, object));

m_context.optimizeYul(object, *dialect, m_optimiserSettings);

code = object.code.get();
code = object.code().get();
analysisInfo = object.analysisInfo.get();
}

yul::CodeGenerator::assemble(
*code,
code->root(),
*analysisInfo,
*m_context.assemblyPtr(),
m_context.evmVersion(),
2 changes: 1 addition & 1 deletion libsolidity/codegen/ir/IRGeneratorForStatements.cpp
Original file line number Diff line number Diff line change
@@ -2252,7 +2252,7 @@ bool IRGeneratorForStatements::visit(InlineAssembly const& _inlineAsm)
m_context.setMemoryUnsafeInlineAssemblySeen();
CopyTranslate bodyCopier{_inlineAsm.dialect(), m_context, _inlineAsm.annotation().externalReferences};

yul::Statement modified = bodyCopier(_inlineAsm.operations());
yul::Statement modified = bodyCopier(_inlineAsm.operations().root());

solAssert(std::holds_alternative<yul::Block>(modified));

2 changes: 1 addition & 1 deletion libsolidity/experimental/analysis/TypeInference.cpp
Original file line number Diff line number Diff line change
@@ -302,7 +302,7 @@ bool TypeInference::visit(InlineAssembly const& _inlineAssembly)
_inlineAssembly.dialect(),
identifierAccess
);
if (!analyzer.analyze(_inlineAssembly.operations()))
if (!analyzer.analyze(_inlineAssembly.operations().root()))
solAssert(m_errorReporter.hasErrors());
return false;
}
Original file line number Diff line number Diff line change
@@ -130,7 +130,7 @@ bool IRGeneratorForStatements::visit(TupleExpression const& _tupleExpression)
bool IRGeneratorForStatements::visit(InlineAssembly const& _assembly)
{
CopyTranslate bodyCopier{m_context, _assembly.dialect(), _assembly.annotation().externalReferences};
yul::Statement modified = bodyCopier(_assembly.operations());
yul::Statement modified = bodyCopier(_assembly.operations().root());
solAssert(std::holds_alternative<yul::Block>(modified));
m_code << yul::AsmPrinter(yul::AsmPrinter::TypePrinting::Full, _assembly.dialect())(std::get<yul::Block>(modified)) << "\n";
return false;
4 changes: 2 additions & 2 deletions libsolidity/formal/SMTEncoder.cpp
Original file line number Diff line number Diff line change
@@ -313,7 +313,7 @@ bool SMTEncoder::visit(InlineAssembly const& _inlineAsm)
{
AssignedExternalsCollector(InlineAssembly const& _inlineAsm): externalReferences(_inlineAsm.annotation().externalReferences)
{
this->operator()(_inlineAsm.operations());
this->operator()(_inlineAsm.operations().root());
}

std::map<yul::Identifier const*, InlineAssemblyAnnotation::ExternalIdentifierInfo> const& externalReferences;
@@ -330,7 +330,7 @@ bool SMTEncoder::visit(InlineAssembly const& _inlineAsm)
}
};

yul::SideEffectsCollector sideEffectsCollector(_inlineAsm.dialect(), _inlineAsm.operations());
yul::SideEffectsCollector sideEffectsCollector(_inlineAsm.dialect(), _inlineAsm.operations().root());
if (sideEffectsCollector.invalidatesMemory())
resetMemoryVariables();
if (sideEffectsCollector.invalidatesStorage())
4 changes: 2 additions & 2 deletions libsolidity/interface/CompilerStack.cpp
Original file line number Diff line number Diff line change
@@ -846,9 +846,9 @@ Json CompilerStack::generatedSources(std::string const& _contractName, bool _run
ErrorReporter errorReporter(errors);
CharStream charStream(source, sourceName);
yul::EVMDialect const& dialect = yul::EVMDialect::strictAssemblyForEVM(m_evmVersion);
std::shared_ptr<yul::Block> parserResult = yul::Parser{errorReporter, dialect}.parse(charStream);
std::shared_ptr<yul::AST> parserResult = yul::Parser{errorReporter, dialect}.parse(charStream);
solAssert(parserResult, "");
sources[0]["ast"] = yul::AsmJsonConverter{sourceIndex}(*parserResult);
sources[0]["ast"] = yul::AsmJsonConverter{sourceIndex}(parserResult->root());
sources[0]["name"] = sourceName;
sources[0]["id"] = sourceIndex;
sources[0]["language"] = "Yul";
8 changes: 4 additions & 4 deletions libsolidity/parsing/Parser.cpp
Original file line number Diff line number Diff line change
@@ -1473,12 +1473,12 @@ ASTPointer<InlineAssembly> Parser::parseInlineAssembly(ASTPointer<ASTString> con
}

yul::Parser asmParser(m_errorReporter, dialect);
std::shared_ptr<yul::Block> block = asmParser.parseInline(m_scanner);
if (block == nullptr)
std::shared_ptr<yul::AST> ast = asmParser.parseInline(m_scanner);
if (ast == nullptr)
BOOST_THROW_EXCEPTION(FatalError());

location.end = nativeLocationOf(*block).end;
return std::make_shared<InlineAssembly>(nextID(), location, _docString, dialect, std::move(flags), block);
location.end = nativeLocationOf(ast->root()).end;
return std::make_shared<InlineAssembly>(nextID(), location, _docString, dialect, std::move(flags), ast);
}

ASTPointer<IfStatement> Parser::parseIfStatement(ASTPointer<ASTString> const& _docString)
12 changes: 12 additions & 0 deletions libyul/AST.h
Original file line number Diff line number Diff line change
@@ -101,6 +101,18 @@ struct Continue { langutil::DebugData::ConstPtr debugData; };
/// Leave statement (valid within function)
struct Leave { langutil::DebugData::ConstPtr debugData; };

/// Immutable AST comprised of its top-level block
class AST
{
public:
explicit AST(Block _root): m_root(std::move(_root)) {}

[[nodiscard]] Block const& root() const { return m_root; }
private:
Block m_root;
};


/// Extracts the IR source location from a Yul node.
template <class T> inline langutil::SourceLocation nativeLocationOf(T const& _node)
{
1 change: 1 addition & 0 deletions libyul/ASTForward.h
Original file line number Diff line number Diff line change
@@ -46,6 +46,7 @@ struct Continue;
struct Leave;
struct ExpressionStatement;
struct Block;
class AST;

struct TypedName;

13 changes: 11 additions & 2 deletions libyul/AsmAnalysis.cpp
Original file line number Diff line number Diff line change
@@ -85,6 +85,15 @@ bool AsmAnalyzer::analyze(Block const& _block)
}

AsmAnalysisInfo AsmAnalyzer::analyzeStrictAssertCorrect(Dialect const& _dialect, Object const& _object)
{
return analyzeStrictAssertCorrect(_dialect, _object.code()->root(), _object.qualifiedDataNames());
}

AsmAnalysisInfo AsmAnalyzer::analyzeStrictAssertCorrect(
Dialect const& _dialect,
Block const& _astRoot,
std::set<std::string> const& _qualifiedDataNames
)
{
ErrorList errorList;
langutil::ErrorReporter errors(errorList);
@@ -94,8 +103,8 @@ AsmAnalysisInfo AsmAnalyzer::analyzeStrictAssertCorrect(Dialect const& _dialect,
errors,
_dialect,
{},
_object.qualifiedDataNames()
).analyze(*_object.code);
_qualifiedDataNames
).analyze(_astRoot);
yulAssert(success && !errors.hasErrors(), "Invalid assembly/yul code.");
return analysisInfo;
}
5 changes: 5 additions & 0 deletions libyul/AsmAnalysis.h
Original file line number Diff line number Diff line change
@@ -78,6 +78,11 @@ class AsmAnalyzer
/// Performs analysis on the outermost code of the given object and returns the analysis info.
/// Asserts on failure.
static AsmAnalysisInfo analyzeStrictAssertCorrect(Dialect const& _dialect, Object const& _object);
static AsmAnalysisInfo analyzeStrictAssertCorrect(
Dialect const& _dialect,
Block const& _astRoot,
std::set<std::string> const& _qualifiedDataNames
);

std::vector<YulName> operator()(Literal const& _literal);
std::vector<YulName> operator()(Identifier const&);
5 changes: 5 additions & 0 deletions libyul/AsmJsonImporter.cpp
Original file line number Diff line number Diff line change
@@ -49,6 +49,11 @@ SourceLocation const AsmJsonImporter::createSourceLocation(Json const& _node)
return solidity::langutil::parseSourceLocation(_node["src"].get<std::string>(), m_sourceNames);
}

AST AsmJsonImporter::createAST(solidity::Json const& _node)
{
return AST(createBlock(_node));
}

template <class T>
T AsmJsonImporter::createAsmNode(Json const& _node)
{
3 changes: 2 additions & 1 deletion libyul/AsmJsonImporter.h
Original file line number Diff line number Diff line change
@@ -41,8 +41,8 @@ class AsmJsonImporter
explicit AsmJsonImporter(std::vector<std::shared_ptr<std::string const>> const& _sourceNames):
m_sourceNames(_sourceNames)
{}
yul::Block createBlock(Json const& _node);

yul::AST createAST(Json const& node);
private:
langutil::SourceLocation const createSourceLocation(Json const& _node);
template <class T>
@@ -51,6 +51,7 @@ class AsmJsonImporter
/// and throw an error if it does not exist
Json member(Json const& _node, std::string const& _name);

yul::Block createBlock(Json const& _node);
yul::Statement createStatement(Json const& _node);
yul::Expression createExpression(Json const& _node);
std::vector<yul::Statement> createStatementVector(Json const& _array);
10 changes: 5 additions & 5 deletions libyul/AsmParser.cpp
Original file line number Diff line number Diff line change
@@ -104,15 +104,15 @@ void Parser::updateLocationEndFrom(
}
}

std::unique_ptr<Block> Parser::parse(CharStream& _charStream)
std::unique_ptr<AST> Parser::parse(CharStream& _charStream)
{
m_scanner = std::make_shared<Scanner>(_charStream);
std::unique_ptr<Block> block = parseInline(m_scanner);
std::unique_ptr<AST> ast = parseInline(m_scanner);
expectToken(Token::EOS);
return block;
return ast;
}

std::unique_ptr<Block> Parser::parseInline(std::shared_ptr<Scanner> const& _scanner)
std::unique_ptr<AST> Parser::parseInline(std::shared_ptr<Scanner> const& _scanner)
{
m_recursionDepth = 0;

@@ -125,7 +125,7 @@ std::unique_ptr<Block> Parser::parseInline(std::shared_ptr<Scanner> const& _scan
m_scanner = _scanner;
if (m_useSourceLocationFrom == UseSourceLocationFrom::Comments)
fetchDebugDataFromComment();
return std::make_unique<Block>(parseBlock());
return std::make_unique<AST>(parseBlock());
}
catch (FatalError const& error)
{
Loading

0 comments on commit c92b32f

Please sign in to comment.