Coverage Report

Created: 2026-06-30 07:08

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/solidity/libsolidity/interface/CompilerStack.cpp
Line
Count
Source
1
/*
2
  This file is part of solidity.
3
4
  solidity is free software: you can redistribute it and/or modify
5
  it under the terms of the GNU General Public License as published by
6
  the Free Software Foundation, either version 3 of the License, or
7
  (at your option) any later version.
8
9
  solidity is distributed in the hope that it will be useful,
10
  but WITHOUT ANY WARRANTY; without even the implied warranty of
11
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
  GNU General Public License for more details.
13
14
  You should have received a copy of the GNU General Public License
15
  along with solidity.  If not, see <http://www.gnu.org/licenses/>.
16
*/
17
// SPDX-License-Identifier: GPL-3.0
18
/**
19
 * @author Christian <c@ethdev.com>
20
 * @author Gav Wood <g@ethdev.com>
21
 * @date 2014
22
 * Full-stack compiler that converts a source code string to bytecode.
23
 */
24
25
26
#include <libsolidity/interface/CompilerStack.h>
27
#include <libsolidity/interface/ImportRemapper.h>
28
29
#include <libsolidity/analysis/ControlFlowAnalyzer.h>
30
#include <libsolidity/analysis/ControlFlowGraph.h>
31
#include <libsolidity/analysis/ControlFlowRevertPruner.h>
32
#include <libsolidity/analysis/ContractLevelChecker.h>
33
#include <libsolidity/analysis/DeclarationTypeChecker.h>
34
#include <libsolidity/analysis/DocStringAnalyser.h>
35
#include <libsolidity/analysis/DocStringTagParser.h>
36
#include <libsolidity/analysis/GlobalContext.h>
37
#include <libsolidity/analysis/NameAndTypeResolver.h>
38
#include <libsolidity/analysis/PostTypeChecker.h>
39
#include <libsolidity/analysis/PostTypeContractLevelChecker.h>
40
#include <libsolidity/analysis/StaticAnalyzer.h>
41
#include <libsolidity/analysis/SyntaxChecker.h>
42
#include <libsolidity/analysis/Scoper.h>
43
#include <libsolidity/analysis/TypeChecker.h>
44
#include <libsolidity/analysis/ViewPureChecker.h>
45
#include <libsolidity/analysis/ImmutableValidator.h>
46
47
#include <libsolidity/ast/AST.h>
48
#include <libsolidity/ast/TypeProvider.h>
49
#include <libsolidity/ast/ASTJsonImporter.h>
50
#include <libsolidity/codegen/Compiler.h>
51
#include <libsolidity/formal/ModelChecker.h>
52
#include <libsolidity/interface/ABI.h>
53
#include <libsolidity/interface/Natspec.h>
54
#include <libsolidity/interface/GasEstimator.h>
55
#include <libsolidity/interface/StorageLayout.h>
56
#include <libsolidity/interface/UniversalCallback.h>
57
#include <libsolidity/interface/Version.h>
58
#include <libsolidity/parsing/Parser.h>
59
60
#include <libsolidity/experimental/analysis/Analysis.h>
61
#include <libsolidity/experimental/analysis/FunctionDependencyAnalysis.h>
62
#include <libsolidity/experimental/codegen/IRGenerator.h>
63
64
#include <libsolidity/codegen/ir/Common.h>
65
#include <libsolidity/codegen/ir/IRGenerator.h>
66
67
#include <libstdlib/stdlib.h>
68
69
#include <libyul/YulName.h>
70
#include <libyul/AsmPrinter.h>
71
#include <libyul/AsmJsonConverter.h>
72
#include <libyul/YulStack.h>
73
#include <libyul/AST.h>
74
#include <libyul/AsmParser.h>
75
#include <libyul/optimiser/Suite.h>
76
77
#include <liblangutil/Scanner.h>
78
#include <liblangutil/SemVerHandler.h>
79
#include <liblangutil/SourceReferenceFormatter.h>
80
81
#include <libsolutil/SwarmHash.h>
82
#include <libsolutil/IpfsHash.h>
83
#include <libsolutil/JSON.h>
84
#include <libsolutil/Algorithms.h>
85
#include <libsolutil/FunctionSelector.h>
86
87
#include <libevmasm/Ethdebug.h>
88
89
#include <boost/algorithm/string/replace.hpp>
90
91
#include <range/v3/algorithm/all_of.hpp>
92
#include <range/v3/view/concat.hpp>
93
#include <range/v3/view/map.hpp>
94
95
#include <fmt/format.h>
96
97
#include <utility>
98
#include <map>
99
#include <limits>
100
#include <string>
101
102
using namespace solidity;
103
using namespace solidity::langutil;
104
using namespace solidity::frontend;
105
using namespace solidity::stdlib;
106
using namespace solidity::yul;
107
using namespace std::string_literals;
108
109
using solidity::util::errinfo_comment;
110
111
static int g_compilerStackCounts = 0;
112
113
CompilerStack::CompilerStack(ReadCallback::Callback _readFile):
114
25.5k
  m_readFile{std::move(_readFile)},
115
25.5k
  m_objectOptimizer(std::make_shared<yul::ObjectOptimizer>()),
116
25.5k
  m_errorReporter{m_errorList}
117
25.5k
{
118
  // Because TypeProvider is currently a singleton API, we must ensure that
119
  // no more than one entity is actually using it at a time.
120
25.5k
  solAssert(g_compilerStackCounts == 0, "You shall not have another CompilerStack aside me.");
121
25.5k
  ++g_compilerStackCounts;
122
25.5k
}
123
124
CompilerStack::~CompilerStack()
125
25.5k
{
126
25.5k
  --g_compilerStackCounts;
127
25.5k
  TypeProvider::reset();
128
25.5k
}
129
130
void CompilerStack::createAndAssignCallGraphs()
131
12.6k
{
132
12.6k
  for (Source const* source: m_sourceOrder)
133
14.2k
  {
134
14.2k
    if (!source->ast)
135
0
      continue;
136
137
14.2k
    for (ContractDefinition const* contract: ASTNode::filteredNodes<ContractDefinition>(source->ast->nodes()))
138
14.8k
    {
139
14.8k
      ContractDefinitionAnnotation& annotation =
140
14.8k
        m_contracts.at(contract->fullyQualifiedName()).contract->annotation();
141
142
14.8k
      annotation.creationCallGraph = std::make_unique<CallGraph>(
143
14.8k
        FunctionCallGraphBuilder::buildCreationGraph(*contract)
144
14.8k
      );
145
14.8k
      annotation.deployedCallGraph = std::make_unique<CallGraph>(
146
14.8k
        FunctionCallGraphBuilder::buildDeployedGraph(
147
14.8k
          *contract,
148
14.8k
          **annotation.creationCallGraph
149
14.8k
        )
150
14.8k
      );
151
152
14.8k
      solAssert(annotation.contractDependencies.empty(), "contractDependencies expected to be empty?!");
153
154
14.8k
      annotation.contractDependencies = annotation.creationCallGraph->get()->bytecodeDependency;
155
156
14.8k
      for (auto const& [dependencyContract, referencee]: annotation.deployedCallGraph->get()->bytecodeDependency)
157
216
        annotation.contractDependencies.emplace(dependencyContract, referencee);
158
14.8k
    }
159
14.2k
  }
160
12.6k
}
161
162
void CompilerStack::findAndReportCyclicContractDependencies()
163
12.6k
{
164
  // Cycles we found, used to avoid duplicate reports for the same reference
165
12.6k
  std::set<ASTNode const*, ASTNode::CompareByID> foundCycles;
166
167
12.6k
  for (Source const* source: m_sourceOrder)
168
14.2k
  {
169
14.2k
    if (!source->ast)
170
0
      continue;
171
172
14.2k
    for (ContractDefinition const* contractDefinition: ASTNode::filteredNodes<ContractDefinition>(source->ast->nodes()))
173
14.8k
    {
174
14.8k
      util::CycleDetector<ContractDefinition> cycleDetector{[&](
175
14.8k
        ContractDefinition const& _contract,
176
14.8k
        util::CycleDetector<ContractDefinition>& _cycleDetector,
177
14.8k
        size_t _depth
178
14.8k
      )
179
15.1k
      {
180
        // No specific reason for exactly that number, just a limit we're unlikely to hit.
181
15.1k
        if (_depth >= 256)
182
0
          m_errorReporter.fatalTypeError(
183
0
            7864_error,
184
0
            _contract.location(),
185
0
            "Contract dependencies exhausting cyclic dependency validator"
186
0
          );
187
188
15.1k
        for (auto& [dependencyContract, referencee]: _contract.annotation().contractDependencies)
189
323
          if (_cycleDetector.run(*dependencyContract))
190
73
            return;
191
15.1k
      }};
192
193
14.8k
      ContractDefinition const* cycle = cycleDetector.run(*contractDefinition);
194
195
14.8k
      if (!cycle)
196
14.7k
        continue;
197
198
33
      ASTNode const* referencee = contractDefinition->annotation().contractDependencies.at(cycle);
199
200
33
      if (foundCycles.find(referencee) != foundCycles.end())
201
5
        continue;
202
203
28
      SecondarySourceLocation secondaryLocation{};
204
28
      secondaryLocation.append("Referenced contract is here:"s, cycle->location());
205
206
28
      m_errorReporter.typeError(
207
28
        7813_error,
208
28
        referencee->location(),
209
28
        secondaryLocation,
210
28
        "Circular reference to contract bytecode either via \"new\" or \"type(...).creationCode\" / \"type(...).runtimeCode\"."
211
28
      );
212
213
28
      foundCycles.emplace(referencee);
214
28
    }
215
14.2k
  }
216
12.6k
}
217
218
void CompilerStack::setRemappings(std::vector<ImportRemapper::Remapping> _remappings)
219
0
{
220
0
  solAssert(m_stackState < ParsedAndImported, "Must set remappings before parsing.");
221
0
  for (auto const& remapping: _remappings)
222
0
    solAssert(!remapping.prefix.empty(), "");
223
0
  m_importRemapper.setRemappings(std::move(_remappings));
224
0
}
225
226
void CompilerStack::setViaIR(bool _viaIR)
227
25.5k
{
228
25.5k
  solAssert(m_stackState < ParsedAndImported, "Must set viaIR before parsing.");
229
25.5k
  m_viaIR = _viaIR;
230
25.5k
}
231
232
void CompilerStack::setExperimental(bool _experimental)
233
0
{
234
0
  solAssert(m_stackState < ParsedAndImported, "Must set experimental before parsing.");
235
0
  m_experimental = _experimental;
236
0
}
237
238
void CompilerStack::setViaSSACFG(bool _viaSSACFG)
239
0
{
240
0
  solAssert(m_stackState < CompilationSuccessful, "Must set SSA CFG codegen before compilation.");
241
0
  m_viaSSACFG = _viaSSACFG;
242
0
}
243
244
void CompilerStack::setEVMVersion(langutil::EVMVersion _version)
245
25.5k
{
246
25.5k
  solAssert(m_stackState < ParsedAndImported, "Must set EVM version before parsing.");
247
25.5k
  m_evmVersion = _version;
248
  // GlobalContext depends on evmVersion since the Cancun hardfork.
249
  // Therefore, we reset it whenever we set a new EVM version, ensuring that the context is never reused with a mismatched version.
250
25.5k
  m_globalContext.reset();
251
25.5k
}
252
253
void CompilerStack::setModelCheckerSettings(ModelCheckerSettings _settings)
254
24.8k
{
255
24.8k
  solAssert(m_stackState < ParsedAndImported, "Must set model checking settings before parsing.");
256
24.8k
  m_modelCheckerSettings = _settings;
257
24.8k
}
258
259
void CompilerStack::selectContracts(ContractSelection const& _selectedContracts)
260
0
{
261
0
  solAssert(m_stackState < ParsedAndImported, "Must request outputs before parsing.");
262
0
  m_selectedContracts = _selectedContracts;
263
0
}
264
265
void CompilerStack::setLibraries(std::map<std::string, util::h160> const& _libraries)
266
669
{
267
669
  solAssert(m_stackState < ParsedAndImported, "Must set libraries before parsing.");
268
669
  m_libraries = _libraries;
269
669
}
270
271
void CompilerStack::setOptimiserSettings(bool _optimize, OptimiserSettings::ExecutionCount _runs)
272
0
{
273
0
  OptimiserSettings settings = _optimize ? OptimiserSettings::standard() : OptimiserSettings::minimal();
274
0
  settings.expectedExecutionsPerDeployment = _runs;
275
0
  setOptimiserSettings(std::move(settings));
276
0
}
277
278
void CompilerStack::setOptimiserSettings(OptimiserSettings _settings)
279
25.5k
{
280
25.5k
  solAssert(m_stackState < ParsedAndImported, "Must set optimiser settings before parsing.");
281
25.5k
  m_optimiserSettings = std::move(_settings);
282
25.5k
}
283
284
void CompilerStack::setRevertStringBehaviour(RevertStrings _revertStrings)
285
0
{
286
0
  solAssert(m_stackState < ParsedAndImported, "Must set revert string settings before parsing.");
287
0
  solUnimplementedAssert(_revertStrings != RevertStrings::VerboseDebug);
288
0
  m_revertStrings = _revertStrings;
289
0
}
290
291
void CompilerStack::useMetadataLiteralSources(bool _metadataLiteralSources)
292
0
{
293
0
  solAssert(m_stackState < ParsedAndImported, "Must set use literal sources before parsing.");
294
0
  m_metadataLiteralSources = _metadataLiteralSources;
295
0
}
296
297
void CompilerStack::setMetadataHash(MetadataHash _metadataHash)
298
0
{
299
0
  solAssert(m_stackState < ParsedAndImported, "Must set metadata hash before parsing.");
300
0
  m_metadataHash = _metadataHash;
301
0
}
302
303
void CompilerStack::selectDebugInfo(DebugInfoSelection _debugInfoSelection)
304
0
{
305
0
  solAssert(m_stackState < CompilationSuccessful, "Must select debug info components before compilation.");
306
0
  m_debugInfoSelection = _debugInfoSelection;
307
0
}
308
309
void CompilerStack::addSMTLib2Response(h256 const& _hash, std::string const& _response)
310
0
{
311
0
  solAssert(m_stackState < ParsedAndImported, "Must add SMTLib2 responses before parsing.");
312
0
  m_smtlib2Responses[_hash] = _response;
313
0
}
314
315
void CompilerStack::reset(bool _keepSettings)
316
0
{
317
0
  m_stackState = Empty;
318
0
  m_sources.clear();
319
0
  m_maxAstId.reset();
320
0
  m_smtlib2Responses.clear();
321
0
  m_unhandledSMTLib2Queries.clear();
322
0
  if (!_keepSettings)
323
0
  {
324
0
    m_importRemapper.clear();
325
0
    m_libraries.clear();
326
0
    m_viaIR = false;
327
0
    m_viaSSACFG = false;
328
0
    m_evmVersion = langutil::EVMVersion();
329
0
    m_modelCheckerSettings = ModelCheckerSettings{};
330
0
    m_selectedContracts.clear();
331
0
    m_revertStrings = RevertStrings::Default;
332
0
    m_optimiserSettings = OptimiserSettings::minimal();
333
0
    m_metadataLiteralSources = false;
334
0
    m_metadataFormat = defaultMetadataFormat();
335
0
    m_metadataHash = MetadataHash::IPFS;
336
0
    m_stopAfter = State::CompilationSuccessful;
337
0
    m_compilationSourceType = CompilationSourceType::Solidity;
338
0
  }
339
0
  m_experimentalAnalysis.reset();
340
0
  m_globalContext.reset();
341
0
  m_sourceOrder.clear();
342
0
  m_contracts.clear();
343
0
  m_errorReporter.clear();
344
0
  TypeProvider::reset();
345
0
}
346
347
void CompilerStack::setSources(StringMap _sources)
348
25.5k
{
349
25.5k
  solAssert(m_stackState != SourcesSet, "Cannot change sources once set.");
350
25.5k
  solAssert(m_stackState == Empty, "Must set sources before parsing.");
351
25.5k
  for (auto source: _sources)
352
28.1k
    m_sources[source.first].charStream = std::make_unique<CharStream>(/*content*/std::move(source.second), /*name*/source.first);
353
25.5k
  m_stackState = SourcesSet;
354
25.5k
}
355
356
bool CompilerStack::parse()
357
25.5k
{
358
25.5k
  solAssert(m_stackState == SourcesSet, "Must call parse only after the SourcesSet state.");
359
25.5k
  m_errorReporter.clear();
360
361
25.5k
  if (SemVerVersion{std::string(VersionString)}.isPrerelease())
362
25.5k
    m_errorReporter.warning(3805_error, "This is a pre-release compiler version, please do not use it in production.");
363
364
25.5k
  try
365
25.5k
  {
366
25.5k
    Parser parser{m_errorReporter, m_evmVersion};
367
368
25.5k
    std::vector<std::string> sourcesToParse;
369
25.5k
    for (auto const& s: m_sources)
370
28.1k
      sourcesToParse.push_back(s.first);
371
372
53.7k
    for (size_t i = 0; i < sourcesToParse.size(); ++i)
373
28.1k
    {
374
28.1k
      std::string const path = sourcesToParse[i];
375
28.1k
      Source& source = m_sources[path];
376
28.1k
      source.ast = parser.parse(*source.charStream);
377
28.1k
      if (!source.ast)
378
28.1k
        solAssert(Error::containsErrors(m_errorReporter.errors()), "Parser returned null but did not report error.");
379
23.9k
      else
380
23.9k
      {
381
23.9k
        source.ast->annotation().path = path;
382
383
23.9k
        for (auto const& import: ASTNode::filteredNodes<ImportDirective>(source.ast->nodes()))
384
1.46k
        {
385
1.46k
          solAssert(!import->path().empty(), "Import path cannot be empty.");
386
          // Check whether the import directive is for the standard library,
387
          // and if yes, add specified file to source units to be parsed.
388
1.46k
          auto it = stdlib::sources.find(import->path());
389
1.46k
          if (it != stdlib::sources.end())
390
14
          {
391
14
            auto [name, content] = *it;
392
14
            m_sources[name].charStream = std::make_unique<CharStream>(content, name);
393
14
            sourcesToParse.push_back(name);
394
14
          }
395
396
          // The current value of `path` is the absolute path as seen from this source file.
397
          // We first have to apply remappings before we can store the actual absolute path
398
          // as seen globally.
399
1.46k
          import->annotation().absolutePath = applyRemapping(util::absolutePath(
400
1.46k
            import->path(),
401
1.46k
            path
402
1.46k
          ), path);
403
1.46k
        }
404
405
23.9k
        if (m_stopAfter >= ParsedAndImported)
406
23.9k
          for (auto const& newSource: loadMissingSources(*source.ast))
407
0
          {
408
0
            std::string const& newPath = newSource.first;
409
0
            std::string const& newContents = newSource.second;
410
0
            m_sources[newPath].charStream = std::make_shared<CharStream>(newContents, newPath);
411
0
            sourcesToParse.push_back(newPath);
412
0
          }
413
23.9k
      }
414
28.1k
    }
415
416
25.5k
    if (Error::containsErrors(m_errorReporter.errors()))
417
4.35k
      return false;
418
419
21.2k
    m_stackState = (m_stopAfter <= Parsed ? Parsed : ParsedAndImported);
420
21.2k
    storeContractDefinitions();
421
422
21.2k
    solAssert(!m_maxAstId.has_value());
423
21.2k
    m_maxAstId = parser.maxID();
424
21.2k
  }
425
25.5k
  catch (UnimplementedFeatureError const& _error)
426
25.5k
  {
427
0
    reportUnimplementedFeatureError(_error);
428
0
    return false;
429
0
  }
430
431
21.2k
  return true;
432
25.5k
}
433
434
void CompilerStack::importASTs(std::map<std::string, Json> const& _sources)
435
0
{
436
0
  solAssert(m_stackState == Empty, "Must call importASTs only before the SourcesSet state.");
437
0
  std::map<std::string, ASTPointer<SourceUnit>> reconstructedSources =
438
0
    ASTJsonImporter(m_evmVersion).jsonToSourceUnit(_sources);
439
0
  for (auto& src: reconstructedSources)
440
0
  {
441
0
    solUnimplementedAssert(!src.second->experimentalSolidity());
442
0
    std::string const& path = src.first;
443
0
    Source source;
444
0
    source.ast = src.second;
445
0
    source.charStream = std::make_shared<CharStream>(
446
0
      util::jsonCompactPrint(_sources.at(src.first)),
447
0
      src.first,
448
0
      true // imported from AST
449
0
    );
450
0
    m_sources[path] = std::move(source);
451
0
  }
452
0
  m_stackState = ParsedAndImported;
453
0
  m_compilationSourceType = CompilationSourceType::SolidityAST;
454
455
0
  storeContractDefinitions();
456
0
}
457
458
namespace
459
{
460
461
bool onlySafeExperimentalFeaturesActivated(std::set<ExperimentalFeature> const& _features)
462
28.3k
{
463
28.3k
  for (auto const feature: _features)
464
27.5k
    if (!ExperimentalFeatureWithoutWarning.contains(feature))
465
0
      return false;
466
28.3k
  return true;
467
28.3k
}
468
469
}
470
471
bool CompilerStack::analyze()
472
21.2k
{
473
21.2k
  solAssert(m_stackState == ParsedAndImported, "Must call analyze only after parsing was successful.");
474
475
21.2k
  if (!resolveImports())
476
1
    return false;
477
478
21.2k
  for (Source const* source: m_sourceOrder)
479
23.0k
    if (source->ast)
480
23.0k
      Scoper::assignScopes(*source->ast);
481
482
21.2k
  bool noErrors = true;
483
484
21.2k
  try
485
21.2k
  {
486
21.2k
    bool experimentalSolidity = isExperimentalSolidity();
487
488
21.2k
    SyntaxChecker syntaxChecker(m_errorReporter, m_optimiserSettings.runYulOptimiser, m_experimental);
489
21.2k
    for (Source const* source: m_sourceOrder)
490
23.0k
      if (source->ast && !syntaxChecker.checkSyntax(*source->ast))
491
1.31k
        noErrors = false;
492
493
21.2k
    m_globalContext = std::make_shared<GlobalContext>(m_evmVersion);
494
    // We need to keep the same resolver during the whole process.
495
21.2k
    NameAndTypeResolver resolver(*m_globalContext, m_evmVersion, m_errorReporter, experimentalSolidity);
496
21.2k
    for (Source const* source: m_sourceOrder)
497
23.0k
      if (source->ast && !resolver.registerDeclarations(*source->ast))
498
0
        return false;
499
500
21.2k
    std::map<std::string, SourceUnit const*> sourceUnitsByName;
501
21.2k
    for (auto& source: m_sources)
502
23.0k
      sourceUnitsByName[source.first] = source.second.ast.get();
503
21.2k
    for (Source const* source: m_sourceOrder)
504
23.0k
      if (source->ast && !resolver.performImports(*source->ast, sourceUnitsByName))
505
37
        return false;
506
507
21.1k
    resolver.warnHomonymDeclarations();
508
509
21.1k
    {
510
21.1k
      DocStringTagParser docStringTagParser(m_errorReporter);
511
21.1k
      for (Source const* source: m_sourceOrder)
512
22.9k
        if (source->ast && !docStringTagParser.parseDocStrings(*source->ast))
513
558
          noErrors = false;
514
21.1k
    }
515
516
    // Requires DocStringTagParser
517
21.1k
    for (Source const* source: m_sourceOrder)
518
22.9k
      if (source->ast && !resolver.resolveNamesAndTypes(*source->ast))
519
1.40k
        return false;
520
521
19.7k
    if (experimentalSolidity)
522
55
    {
523
55
      if (!analyzeExperimental())
524
55
        noErrors = false;
525
55
    }
526
19.7k
    else if (!analyzeLegacy(noErrors))
527
6.30k
      noErrors = false;
528
19.7k
  }
529
21.2k
  catch (FatalError const&)
530
21.2k
  {
531
829
    if (!m_errorReporter.hasErrors())
532
0
    {
533
0
      std::cerr << "Unreported fatal error:" << std::endl;
534
0
      std::cerr << boost::current_exception_diagnostic_information() << std::endl;
535
0
      solAssert(false, "Unreported fatal error.");
536
0
    }
537
829
    noErrors = false;
538
829
  }
539
21.2k
  catch (UnimplementedFeatureError const& _error)
540
21.2k
  {
541
0
    reportUnimplementedFeatureError(_error);
542
0
    noErrors = false;
543
0
  }
544
545
19.7k
  if (!noErrors)
546
7.19k
    return false;
547
548
12.5k
  for (Source const* source: m_sourceOrder)
549
14.1k
    if (source->ast && !m_experimental)
550
14.1k
      solAssert(onlySafeExperimentalFeaturesActivated(source->ast->annotation().experimentalFeatures));
551
552
12.5k
  m_stackState = AnalysisSuccessful;
553
12.5k
  return true;
554
19.7k
}
555
556
557
bool CompilerStack::analyzeLegacy(bool _noErrorsSoFar)
558
19.7k
{
559
19.7k
  bool noErrors = _noErrorsSoFar;
560
561
19.7k
  DeclarationTypeChecker declarationTypeChecker(m_errorReporter, m_evmVersion);
562
19.7k
  for (Source const* source: m_sourceOrder)
563
21.4k
    if (source->ast && !declarationTypeChecker.check(*source->ast))
564
2.01k
      return false;
565
566
  // Requires DeclarationTypeChecker to have run
567
17.6k
  DocStringTagParser docStringTagParser(m_errorReporter);
568
17.6k
  for (Source const* source: m_sourceOrder)
569
19.1k
    if (source->ast && !docStringTagParser.validateDocStringsUsingTypes(*source->ast))
570
47
      noErrors = false;
571
572
  // Next, we check inheritance, overrides, function collisions and other things at
573
  // contract or function level.
574
  // This also calculates whether a contract is abstract, which is needed by the
575
  // type checker.
576
17.6k
  ContractLevelChecker contractLevelChecker(m_errorReporter);
577
578
17.6k
  for (Source const* source: m_sourceOrder)
579
19.1k
    if (auto sourceAst = source->ast)
580
19.1k
      noErrors = contractLevelChecker.check(*sourceAst);
581
582
  // Now we run full type checks that go down to the expression level. This
583
  // cannot be done earlier, because we need cross-contract types and information
584
  // about whether a contract is abstract for the `new` expression.
585
  // This populates the `type` annotation for all expressions.
586
  //
587
  // Note: this does not resolve overloaded functions. In order to do that, types of arguments are needed,
588
  // which is only done one step later.
589
17.6k
  TypeChecker typeChecker(m_evmVersion, m_errorReporter);
590
17.6k
  for (Source const* source: m_sourceOrder)
591
19.1k
    if (source->ast && !typeChecker.checkTypeRequirements(*source->ast))
592
4.25k
      noErrors = false;
593
594
17.6k
  if (noErrors)
595
12.7k
  {
596
    // Requires ContractLevelChecker and TypeChecker
597
12.7k
    DocStringAnalyser docStringAnalyser(m_errorReporter);
598
12.7k
    for (Source const* source: m_sourceOrder)
599
14.2k
      if (source->ast && !docStringAnalyser.analyseDocStrings(*source->ast))
600
2
        noErrors = false;
601
12.7k
  }
602
603
17.6k
  if (noErrors)
604
12.7k
  {
605
    // Checks that can only be done when all types of all AST nodes are known.
606
12.7k
    PostTypeChecker postTypeChecker(m_errorReporter);
607
12.7k
    for (Source const* source: m_sourceOrder)
608
14.2k
      if (source->ast && !postTypeChecker.check(*source->ast))
609
17
        noErrors = false;
610
12.7k
    if (!postTypeChecker.finalize())
611
57
      noErrors = false;
612
12.7k
  }
613
614
  // Create & assign callgraphs and check for contract dependency cycles
615
17.6k
  if (noErrors)
616
12.6k
  {
617
12.6k
    createAndAssignCallGraphs();
618
12.6k
    annotateInternalFunctionIDs();
619
12.6k
    findAndReportCyclicContractDependencies();
620
12.6k
  }
621
622
17.6k
  if (noErrors)
623
12.6k
    for (Source const* source: m_sourceOrder)
624
14.2k
      if (source->ast && !PostTypeContractLevelChecker{m_errorReporter}.check(*source->ast))
625
18
        noErrors = false;
626
627
  // Check that immutable variables are never read in c'tors and assigned
628
  // exactly once
629
17.6k
  if (noErrors)
630
12.6k
    for (Source const* source: m_sourceOrder)
631
14.1k
      if (source->ast)
632
14.1k
        for (ASTPointer<ASTNode> const& node: source->ast->nodes())
633
34.3k
          if (ContractDefinition* contract = dynamic_cast<ContractDefinition*>(node.get()))
634
14.7k
            ImmutableValidator(m_errorReporter, *contract).analyze();
635
636
17.6k
  if (noErrors)
637
12.6k
  {
638
    // Control flow graph generator and analyzer. It can check for issues such as
639
    // variable is used before it is assigned to.
640
12.6k
    CFG cfg(m_errorReporter);
641
12.6k
    for (Source const* source: m_sourceOrder)
642
14.1k
      if (source->ast && !cfg.constructFlow(*source->ast))
643
5
        noErrors = false;
644
645
12.6k
    if (noErrors)
646
12.6k
    {
647
12.6k
      ControlFlowRevertPruner pruner(cfg);
648
12.6k
      pruner.run();
649
650
12.6k
      ControlFlowAnalyzer controlFlowAnalyzer(cfg, m_errorReporter);
651
12.6k
      if (!controlFlowAnalyzer.run())
652
18
        noErrors = false;
653
12.6k
    }
654
12.6k
  }
655
656
17.6k
  if (noErrors)
657
12.6k
  {
658
    // Checks for common mistakes. Only generates warnings.
659
12.6k
    StaticAnalyzer staticAnalyzer(m_errorReporter);
660
12.6k
    for (Source const* source: m_sourceOrder)
661
14.1k
      if (source->ast && !staticAnalyzer.analyze(*source->ast))
662
22
        noErrors = false;
663
12.6k
  }
664
665
17.6k
  if (noErrors)
666
12.6k
  {
667
    // Check for state mutability in every function.
668
12.6k
    std::vector<ASTPointer<ASTNode>> ast;
669
12.6k
    for (Source const* source: m_sourceOrder)
670
14.1k
      if (source->ast)
671
14.1k
        ast.push_back(source->ast);
672
673
12.6k
    if (!ViewPureChecker(ast, m_errorReporter).check())
674
27
      noErrors = false;
675
12.6k
  }
676
677
17.6k
  if (noErrors)
678
12.5k
  {
679
    // Run SMTChecker
680
681
14.1k
    auto allSources = util::applyMap(m_sourceOrder, [](Source const* _source) { return _source->ast; });
682
12.5k
    if (ModelChecker::isPragmaPresent(allSources))
683
11.8k
      m_modelCheckerSettings.engine = ModelCheckerEngine::All();
684
685
    // m_modelCheckerSettings is spread to engines and solver interfaces,
686
    // so we need to check whether the enabled ones are available before building the classes.
687
12.5k
    if (m_modelCheckerSettings.engine.any())
688
11.9k
      m_modelCheckerSettings.solvers = ModelChecker::checkRequestedSolvers(m_modelCheckerSettings.solvers, m_errorReporter);
689
690
12.5k
    ModelChecker modelChecker(m_errorReporter, *this, m_smtlib2Responses, m_modelCheckerSettings, m_readFile);
691
12.5k
    modelChecker.checkRequestedSourcesAndContracts(allSources);
692
12.5k
    for (Source const* source: m_sourceOrder)
693
14.1k
      if (source->ast)
694
14.1k
        modelChecker.analyze(*source->ast);
695
12.5k
    m_unhandledSMTLib2Queries += modelChecker.unhandledQueries();
696
12.5k
  }
697
698
17.6k
  return noErrors;
699
19.7k
}
700
701
bool CompilerStack::analyzeExperimental()
702
55
{
703
55
  solAssert(!m_experimentalAnalysis);
704
55
  solAssert(m_maxAstId && *m_maxAstId >= 0);
705
55
  m_experimentalAnalysis = std::make_unique<experimental::Analysis>(m_errorReporter, static_cast<std::uint64_t>(*m_maxAstId));
706
55
  std::vector<std::shared_ptr<SourceUnit const>> sourceAsts;
707
55
  for (Source const* source: m_sourceOrder)
708
60
    if (source->ast)
709
60
      sourceAsts.emplace_back(source->ast);
710
55
  return m_experimentalAnalysis->check(sourceAsts);
711
55
}
712
713
bool CompilerStack::parseAndAnalyze(State _stopAfter)
714
25.5k
{
715
25.5k
  m_stopAfter = _stopAfter;
716
717
25.5k
  bool success = parse();
718
25.5k
  if (m_stackState >= m_stopAfter)
719
0
    return success;
720
25.5k
  if (success)
721
21.2k
    success = analyze();
722
25.5k
  return success;
723
25.5k
}
724
725
bool CompilerStack::isRequestedSource(std::string const& _sourceName) const
726
23.0k
{
727
23.0k
  return
728
23.0k
    m_selectedContracts.empty() ||
729
0
    m_selectedContracts.count("") ||
730
0
    m_selectedContracts.count(_sourceName);
731
23.0k
}
732
733
bool CompilerStack::isRequestedContract(ContractDefinition const& _contract) const
734
14.7k
{
735
  /// In case nothing was specified in selectedContracts.
736
14.7k
  if (m_selectedContracts.empty())
737
14.7k
    return true;
738
739
0
  for (auto const& key: std::vector<std::string>{"", _contract.sourceUnitName()})
740
0
  {
741
0
    auto const& it = m_selectedContracts.find(key);
742
0
    if (it != m_selectedContracts.end())
743
0
      if (it->second.count(_contract.name()) || it->second.count(""))
744
0
        return true;
745
0
  }
746
747
0
  return false;
748
0
}
749
750
CompilerStack::PipelineConfig CompilerStack::requestedPipelineConfig(ContractDefinition const& _contract) const
751
14.7k
{
752
14.7k
  static PipelineConfig constexpr defaultPipelineConfig = PipelineConfig{
753
14.7k
    false, // irCodegen
754
14.7k
    false, // irOptimization
755
14.7k
    true,  // bytecode
756
14.7k
  };
757
758
  // If nothing was explicitly selected, all contracts are selected by default.
759
14.7k
  if (m_selectedContracts.empty())
760
14.7k
    return defaultPipelineConfig;
761
762
0
  PipelineConfig combinedConfig;
763
0
  for (std::string const& sourceUnitName: {""s, _contract.sourceUnitName()})
764
0
    if (m_selectedContracts.count(sourceUnitName) != 0)
765
0
      for (std::string const& contractName: {""s, _contract.name()})
766
0
        if (m_selectedContracts.at(sourceUnitName).count(contractName) != 0)
767
0
          combinedConfig = combinedConfig | m_selectedContracts.at(sourceUnitName).at(contractName);
768
769
0
  return combinedConfig;
770
14.7k
}
771
772
bool CompilerStack::compile(State _stopAfter)
773
25.5k
{
774
25.5k
  m_stopAfter = _stopAfter;
775
776
25.5k
  solAssert(!m_viaSSACFG || m_experimental, "SSA CFG code generation is an experimental feature. It requires experimental mode to be enabled.");
777
778
25.5k
  if (m_stackState < AnalysisSuccessful)
779
25.5k
    if (!parseAndAnalyze(_stopAfter))
780
12.9k
      return false;
781
782
12.5k
  if (m_stackState >= m_stopAfter)
783
0
    return true;
784
785
  // Only compile contracts individually which have been requested.
786
12.5k
  std::map<ContractDefinition const*, std::shared_ptr<Compiler const>> otherCompilers;
787
12.5k
  bool requiresFullCompilation = false;
788
789
12.5k
  for (Source const* source: m_sourceOrder)
790
14.1k
    for (ASTPointer<ASTNode> const& node: source->ast->nodes())
791
34.0k
      if (auto contract = dynamic_cast<ContractDefinition const*>(node.get()))
792
14.7k
        if (isRequestedContract(*contract))
793
14.7k
        {
794
14.7k
          PipelineConfig pipelineConfig = requestedPipelineConfig(*contract);
795
796
14.7k
          try
797
14.7k
          {
798
            // Skip if full compilation is not needed (i.e. no IR/bytecode requested)
799
14.7k
            if (!pipelineConfig.needsFullCompilation())
800
0
              continue;
801
14.7k
            requiresFullCompilation = true;
802
803
14.7k
            if (pipelineConfig.needIR(m_viaIR))
804
3.29k
              generateIR(*contract, pipelineConfig.needIRCodegenOnly(m_viaIR));
805
14.7k
            if (pipelineConfig.needBytecode())
806
14.7k
            {
807
14.7k
              if (m_viaIR)
808
3.29k
                generateEVMFromIR(*contract);
809
11.4k
              else
810
11.4k
              {
811
11.4k
                if (m_experimentalAnalysis)
812
0
                  solThrow(CompilerError, "Legacy codegen after experimental analysis is unsupported.");
813
11.4k
                compileContract(*contract, otherCompilers);
814
11.4k
              }
815
14.7k
            }
816
14.7k
          }
817
14.7k
          catch (Error const& _error)
818
14.7k
          {
819
0
            reportCodeGenerationError(_error, contract);
820
0
          }
821
14.7k
          catch (UnimplementedFeatureError const& _error)
822
14.7k
          {
823
157
            reportUnimplementedFeatureError(_error, contract);
824
157
          }
825
826
14.6k
          if (m_errorReporter.hasErrors())
827
157
            return false;
828
14.6k
        }
829
830
12.4k
  solAssert(!m_errorReporter.hasErrors());
831
12.4k
  m_stackState = CompilationSuccessful;
832
12.4k
  if (requiresFullCompilation)
833
11.6k
    this->link();
834
12.4k
  return true;
835
12.5k
}
836
837
void CompilerStack::link()
838
11.6k
{
839
11.6k
  solAssert(m_stackState >= CompilationSuccessful, "");
840
11.6k
  for (auto& contract: m_contracts)
841
14.5k
  {
842
14.5k
    contract.second.object.link(m_libraries);
843
14.5k
    contract.second.runtimeObject.link(m_libraries);
844
14.5k
  }
845
11.6k
}
846
847
YulStack CompilerStack::loadGeneratedIR(std::string const& _ir) const
848
6.58k
{
849
6.58k
  YulStack stack(
850
6.58k
    m_evmVersion,
851
6.58k
    m_optimiserSettings,
852
6.58k
    m_debugInfoSelection,
853
6.58k
    this, // _soliditySourceProvider
854
6.58k
    m_objectOptimizer
855
6.58k
  );
856
6.58k
  bool yulAnalysisSuccessful = stack.parseAndAnalyze("", _ir);
857
6.58k
  solAssert(
858
6.58k
    yulAnalysisSuccessful,
859
6.58k
    _ir + "\n\n"
860
6.58k
    "Invalid IR generated:\n" +
861
6.58k
    SourceReferenceFormatter::formatErrorInformation(
862
6.58k
      stack.errors(),
863
6.58k
      stack, // _charStreamProvider
864
6.58k
      false, // _colored
865
6.58k
      true   // _withErrorIds
866
6.58k
    ) + "\n"
867
6.58k
  );
868
869
6.58k
  return stack;
870
6.58k
}
871
872
std::vector<std::string> CompilerStack::contractNames() const
873
0
{
874
0
  solAssert(m_stackState >= Parsed, "Parsing was not successful.");
875
0
  std::vector<std::string> contractNames;
876
0
  for (auto const& contract: m_contracts)
877
0
    contractNames.push_back(contract.first);
878
0
  return contractNames;
879
0
}
880
881
std::string const CompilerStack::lastContractName(std::optional<std::string> const& _sourceName) const
882
0
{
883
0
  solAssert(m_stackState >= AnalysisSuccessful, "Parsing was not successful.");
884
  // try to find some user-supplied contract
885
0
  std::string contractName;
886
0
  for (auto const& it: m_sources)
887
0
    if (_sourceName.value_or(it.first) == it.first)
888
0
      for (auto const* contract: ASTNode::filteredNodes<ContractDefinition>(it.second.ast->nodes()))
889
0
        contractName = contract->fullyQualifiedName();
890
0
  return contractName;
891
0
}
892
893
evmasm::AssemblyItems const* CompilerStack::assemblyItems(std::string const& _contractName) const
894
0
{
895
0
  solAssert(m_stackState == CompilationSuccessful, "Compilation was not successful.");
896
897
0
  Contract const& currentContract = contract(_contractName);
898
0
  if (!currentContract.evmAssembly)
899
0
    return nullptr;
900
0
  return &currentContract.evmAssembly->items();
901
0
}
902
903
evmasm::AssemblyItems const* CompilerStack::runtimeAssemblyItems(std::string const& _contractName) const
904
0
{
905
0
  solAssert(m_stackState == CompilationSuccessful, "Compilation was not successful.");
906
907
0
  Contract const& currentContract = contract(_contractName);
908
909
0
  if (!currentContract.evmRuntimeAssembly)
910
0
    return nullptr;
911
0
  return &currentContract.evmRuntimeAssembly->items();
912
0
}
913
914
Json CompilerStack::generatedSources(std::string const& _contractName, bool _runtime) const
915
0
{
916
0
  solAssert(m_stackState == CompilationSuccessful, "Compilation was not successful.");
917
918
0
  Contract const& c = contract(_contractName);
919
0
  Json sources = Json::array();
920
  // If there is no compiler, then no bytecode was generated and thus no
921
  // sources were generated (or we compiled "via IR").
922
0
  if (c.runtimeGeneratedYulUtilityCode.has_value())
923
0
  {
924
0
    solAssert(c.generatedYulUtilityCode.has_value() == c.runtimeGeneratedYulUtilityCode.has_value());
925
0
    solAssert(!m_viaIR);
926
0
    std::string source =
927
0
      _runtime ?
928
0
      *c.runtimeGeneratedYulUtilityCode :
929
0
      *c.generatedYulUtilityCode;
930
0
    if (!source.empty())
931
0
    {
932
0
      std::string sourceName = CompilerContext::yulUtilityFileName();
933
0
      unsigned sourceIndex = sourceIndices()[sourceName];
934
0
      ErrorList errors;
935
0
      ErrorReporter errorReporter(errors);
936
0
      CharStream charStream(source, sourceName);
937
0
      yul::EVMDialect const& dialect = yul::EVMDialect::strictAssemblyForEVM(m_evmVersion);
938
0
      std::shared_ptr<yul::AST> parserResult = yul::Parser{errorReporter, dialect}.parse(charStream);
939
0
      solAssert(parserResult);
940
0
      sources[0]["ast"] = yul::AsmJsonConverter{dialect, sourceIndex}(parserResult->root());
941
0
      sources[0]["name"] = sourceName;
942
0
      sources[0]["id"] = sourceIndex;
943
0
      sources[0]["language"] = "Yul";
944
0
      sources[0]["contents"] = std::move(source);
945
0
    }
946
0
  }
947
0
  return sources;
948
0
}
949
950
std::string const* CompilerStack::sourceMapping(std::string const& _contractName) const
951
0
{
952
0
  solAssert(m_stackState == CompilationSuccessful, "Compilation was not successful.");
953
954
0
  Contract const& c = contract(_contractName);
955
0
  if (!c.sourceMapping)
956
0
  {
957
0
    if (auto items = assemblyItems(_contractName))
958
0
      c.sourceMapping.emplace(evmasm::AssemblyItem::computeSourceMapping(*items, sourceIndices()));
959
0
  }
960
0
  return c.sourceMapping ? &*c.sourceMapping : nullptr;
961
0
}
962
963
std::string const* CompilerStack::runtimeSourceMapping(std::string const& _contractName) const
964
0
{
965
0
  solAssert(m_stackState == CompilationSuccessful, "Compilation was not successful.");
966
967
0
  Contract const& c = contract(_contractName);
968
0
  if (!c.runtimeSourceMapping)
969
0
  {
970
0
    if (auto items = runtimeAssemblyItems(_contractName))
971
0
      c.runtimeSourceMapping.emplace(
972
0
        evmasm::AssemblyItem::computeSourceMapping(*items, sourceIndices())
973
0
      );
974
0
  }
975
0
  return c.runtimeSourceMapping ? &*c.runtimeSourceMapping : nullptr;
976
0
}
977
978
std::string const CompilerStack::filesystemFriendlyName(std::string const& _contractName) const
979
0
{
980
0
  solAssert(m_stackState >= AnalysisSuccessful, "No compiled contracts found.");
981
982
  // Look up the contract (by its fully-qualified name)
983
0
  Contract const& matchContract = m_contracts.at(_contractName);
984
  // Check to see if it could collide on name
985
0
  for (auto const& contract: m_contracts)
986
0
  {
987
0
    if (contract.second.contract->name() == matchContract.contract->name() &&
988
0
        contract.second.contract != matchContract.contract)
989
0
    {
990
      // If it does, then return its fully-qualified name, made fs-friendly
991
0
      std::string friendlyName = boost::algorithm::replace_all_copy(_contractName, "/", "_");
992
0
      boost::algorithm::replace_all(friendlyName, ":", "_");
993
0
      boost::algorithm::replace_all(friendlyName, ".", "_");
994
0
      return friendlyName;
995
0
    }
996
0
  }
997
  // If no collision, return the contract's name
998
0
  return matchContract.contract->name();
999
0
}
1000
1001
std::optional<std::string> const& CompilerStack::yulIR(std::string const& _contractName) const
1002
0
{
1003
0
  solAssert(m_stackState == CompilationSuccessful, "Compilation was not successful.");
1004
0
  return contract(_contractName).yulIR;
1005
0
}
1006
1007
std::optional<Json> CompilerStack::yulIRAst(std::string const& _contractName) const
1008
0
{
1009
0
  solAssert(m_stackState == CompilationSuccessful, "Compilation was not successful.");
1010
0
  solUnimplementedAssert(!isExperimentalSolidity());
1011
1012
  // NOTE: Intentionally not using LazyInit. The artifact can get very large and we don't want to
1013
  // keep it around when compiling a large project containing many contracts.
1014
0
  Contract const& currentContract = contract(_contractName);
1015
0
  yulAssert(currentContract.contract);
1016
0
  yulAssert(currentContract.yulIR.has_value() == currentContract.contract->canBeDeployed());
1017
0
  if (!currentContract.yulIR)
1018
0
    return std::nullopt;
1019
0
  return loadGeneratedIR(*currentContract.yulIR).astJson();
1020
0
}
1021
1022
std::optional<Json> CompilerStack::yulCFGJson(std::string const& _contractName) const
1023
0
{
1024
0
  solAssert(m_stackState == CompilationSuccessful, "Compilation was not successful.");
1025
0
  solUnimplementedAssert(!isExperimentalSolidity());
1026
1027
  // NOTE: Intentionally not using LazyInit. The artifact can get very large and we don't want to
1028
  // keep it around when compiling a large project containing many contracts.
1029
0
  Contract const& currentContract = contract(_contractName);
1030
0
  yulAssert(currentContract.contract);
1031
0
  yulAssert(currentContract.yulIROptimized.has_value() == currentContract.contract->canBeDeployed());
1032
0
  if (!currentContract.yulIROptimized)
1033
0
    return std::nullopt;
1034
0
  return loadGeneratedIR(*currentContract.yulIROptimized).cfgJson();
1035
0
}
1036
1037
std::optional<std::string> const& CompilerStack::yulIROptimized(std::string const& _contractName) const
1038
0
{
1039
0
  solAssert(m_stackState == CompilationSuccessful, "Compilation was not successful.");
1040
0
  return contract(_contractName).yulIROptimized;
1041
0
}
1042
1043
std::optional<Json> CompilerStack::yulIROptimizedAst(std::string const& _contractName) const
1044
0
{
1045
0
  solAssert(m_stackState == CompilationSuccessful, "Compilation was not successful.");
1046
0
  solUnimplementedAssert(!isExperimentalSolidity());
1047
1048
  // NOTE: Intentionally not using LazyInit. The artifact can get very large and we don't want to
1049
  // keep it around when compiling a large project containing many contracts.
1050
0
  Contract const& currentContract = contract(_contractName);
1051
0
  yulAssert(currentContract.contract);
1052
0
  yulAssert(currentContract.yulIROptimized.has_value() == currentContract.contract->canBeDeployed());
1053
0
  if (!currentContract.yulIROptimized)
1054
0
    return std::nullopt;
1055
0
  return loadGeneratedIR(*currentContract.yulIROptimized).astJson();
1056
0
}
1057
1058
evmasm::LinkerObject const& CompilerStack::object(std::string const& _contractName) const
1059
669
{
1060
669
  solAssert(m_stackState == CompilationSuccessful, "Compilation was not successful.");
1061
669
  return contract(_contractName).object;
1062
669
}
1063
1064
evmasm::LinkerObject const& CompilerStack::runtimeObject(std::string const& _contractName) const
1065
0
{
1066
0
  solAssert(m_stackState == CompilationSuccessful, "Compilation was not successful.");
1067
0
  return contract(_contractName).runtimeObject;
1068
0
}
1069
1070
/// TODO: cache this string
1071
std::string CompilerStack::assemblyString(std::string const& _contractName, StringMap const& _sourceCodes) const
1072
0
{
1073
0
  solAssert(m_stackState == CompilationSuccessful, "Compilation was not successful.");
1074
1075
0
  Contract const& currentContract = contract(_contractName);
1076
0
  if (currentContract.evmAssembly)
1077
0
    return currentContract.evmAssembly->assemblyString(m_debugInfoSelection, _sourceCodes);
1078
0
  else
1079
0
    return std::string();
1080
0
}
1081
1082
/// TODO: cache the JSON
1083
Json CompilerStack::assemblyJSON(std::string const& _contractName) const
1084
0
{
1085
0
  solAssert(m_stackState == CompilationSuccessful, "Compilation was not successful.");
1086
0
  solUnimplementedAssert(!isExperimentalSolidity());
1087
1088
0
  Contract const& currentContract = contract(_contractName);
1089
0
  if (currentContract.evmAssembly)
1090
0
    return currentContract.evmAssembly->assemblyJSON(sourceIndices());
1091
0
  else
1092
0
    return Json();
1093
0
}
1094
1095
std::vector<std::string> CompilerStack::sourceNames() const
1096
0
{
1097
0
  return ranges::to<std::vector>(m_sources | ranges::views::keys);
1098
0
}
1099
1100
std::map<std::string, unsigned> CompilerStack::sourceIndices() const
1101
3.29k
{
1102
3.29k
  std::map<std::string, unsigned> indices;
1103
3.29k
  unsigned index = 0;
1104
3.29k
  for (auto const& s: m_sources)
1105
3.39k
    indices[s.first] = index++;
1106
3.29k
  solAssert(!indices.count(CompilerContext::yulUtilityFileName()), "");
1107
3.29k
  indices[CompilerContext::yulUtilityFileName()] = index++;
1108
3.29k
  return indices;
1109
3.29k
}
1110
1111
Json const& CompilerStack::contractABI(std::string const& _contractName) const
1112
0
{
1113
0
  solAssert(m_stackState >= AnalysisSuccessful, "Analysis was not successful.");
1114
0
  return contractABI(contract(_contractName));
1115
0
}
1116
1117
Json const& CompilerStack::contractABI(Contract const& _contract) const
1118
14.2k
{
1119
14.2k
  solAssert(m_stackState >= AnalysisSuccessful, "Analysis was not successful.");
1120
14.2k
  solAssert(_contract.contract);
1121
14.2k
  solUnimplementedAssert(!isExperimentalSolidity());
1122
14.2k
  return _contract.abi.init([&]{ return ABI::generate(*_contract.contract); });
1123
14.2k
}
1124
1125
Json const& CompilerStack::storageLayout(std::string const& _contractName) const
1126
0
{
1127
0
  solAssert(m_stackState >= AnalysisSuccessful, "Analysis was not successful.");
1128
0
  return storageLayout(contract(_contractName));
1129
0
}
1130
1131
Json const& CompilerStack::storageLayout(Contract const& _contract) const
1132
0
{
1133
0
  solAssert(m_stackState >= AnalysisSuccessful, "Analysis was not successful.");
1134
0
  solAssert(_contract.contract);
1135
0
  solUnimplementedAssert(!isExperimentalSolidity());
1136
1137
0
  return _contract.storageLayout.init([&]{ return StorageLayout().generate(*_contract.contract, DataLocation::Storage); });
1138
0
}
1139
1140
Json const& CompilerStack::transientStorageLayout(std::string const& _contractName) const
1141
0
{
1142
0
  solAssert(m_stackState >= AnalysisSuccessful, "Analysis was not successful.");
1143
0
  return transientStorageLayout(contract(_contractName));
1144
0
}
1145
1146
Json const& CompilerStack::transientStorageLayout(Contract const& _contract) const
1147
0
{
1148
0
  solAssert(m_stackState >= AnalysisSuccessful, "Analysis was not successful.");
1149
0
  solAssert(_contract.contract);
1150
0
  solUnimplementedAssert(!isExperimentalSolidity());
1151
1152
0
  return _contract.transientStorageLayout.init([&]{ return StorageLayout().generate(*_contract.contract, DataLocation::Transient); });
1153
0
}
1154
1155
Json const& CompilerStack::natspecUser(std::string const& _contractName) const
1156
0
{
1157
0
  solAssert(m_stackState >= AnalysisSuccessful, "Analysis was not successful.");
1158
0
  return natspecUser(contract(_contractName));
1159
0
}
1160
1161
Json const& CompilerStack::natspecUser(Contract const& _contract) const
1162
14.2k
{
1163
14.2k
  solAssert(m_stackState >= AnalysisSuccessful, "Analysis was not successful.");
1164
14.2k
  solAssert(_contract.contract);
1165
14.2k
  solUnimplementedAssert(!isExperimentalSolidity());
1166
14.2k
  return _contract.userDocumentation.init([&]{ return Natspec::userDocumentation(*_contract.contract); });
1167
14.2k
}
1168
1169
Json const& CompilerStack::natspecDev(std::string const& _contractName) const
1170
0
{
1171
0
  solAssert(m_stackState >= AnalysisSuccessful, "Analysis was not successful.");
1172
0
  return natspecDev(contract(_contractName));
1173
0
}
1174
1175
Json const& CompilerStack::natspecDev(Contract const& _contract) const
1176
14.2k
{
1177
14.2k
  solAssert(m_stackState >= AnalysisSuccessful, "Analysis was not successful.");
1178
14.2k
  solAssert(_contract.contract);
1179
14.2k
  solUnimplementedAssert(!isExperimentalSolidity());
1180
14.2k
  return _contract.devDocumentation.init([&]{ return Natspec::devDocumentation(*_contract.contract); });
1181
14.2k
}
1182
1183
Json CompilerStack::interfaceSymbols(std::string const& _contractName) const
1184
669
{
1185
669
  solAssert(m_stackState >= AnalysisSuccessful, "Analysis was not successful.");
1186
669
  solUnimplementedAssert(!isExperimentalSolidity());
1187
1188
669
  Json interfaceSymbols;
1189
  // Always have a methods object
1190
669
  interfaceSymbols["methods"] = Json::object();
1191
1192
669
  for (auto const& it: contractDefinition(_contractName).interfaceFunctions())
1193
2.35k
    interfaceSymbols["methods"][it.second->externalSignature()] = it.first.hex();
1194
669
  for (ErrorDefinition const* error: contractDefinition(_contractName).interfaceErrors())
1195
0
  {
1196
0
    std::string signature = error->functionType(true)->externalSignature();
1197
0
    interfaceSymbols["errors"][signature] = util::toHex(toCompactBigEndian(util::selectorFromSignatureU32(signature), 4));
1198
0
  }
1199
1200
669
  for (EventDefinition const* event: ranges::concat_view(
1201
669
    contractDefinition(_contractName).definedInterfaceEvents(),
1202
669
    contractDefinition(_contractName).usedInterfaceEvents()
1203
669
  ))
1204
0
    if (!event->isAnonymous())
1205
0
    {
1206
0
      std::string signature = event->functionType(true)->externalSignature();
1207
0
      interfaceSymbols["events"][signature] = toHex(u256(h256::Arith(util::keccak256(signature))));
1208
0
    }
1209
1210
669
  return interfaceSymbols;
1211
669
}
1212
1213
Json CompilerStack::ethdebug() const
1214
0
{
1215
0
  solAssert(m_stackState >= AnalysisSuccessful, "Analysis was not successful.");
1216
0
  return evmasm::ethdebug::resources(ethdebugSources(), VersionString);
1217
0
}
1218
1219
Json CompilerStack::ethdebugCompilation() const
1220
0
{
1221
0
  solAssert(m_stackState >= AnalysisSuccessful, "Analysis was not successful.");
1222
0
  return evmasm::ethdebug::compilation(ethdebugSources(), VersionString);
1223
0
}
1224
1225
std::vector<evmasm::ethdebug::Source> CompilerStack::ethdebugSources() const
1226
0
{
1227
0
  auto const sourceIDs = sourceIndices();
1228
0
  std::vector<evmasm::ethdebug::Source> sources;
1229
0
  sources.reserve(m_sources.size());
1230
0
  for (auto const& [sourceName, source]: m_sources)
1231
0
    sources.push_back({
1232
0
      .id = sourceIDs.at(sourceName),
1233
0
      .path = sourceName,
1234
0
      .contents = source.charStream->source(),
1235
0
      .language = "Solidity"
1236
0
    });
1237
0
  return sources;
1238
0
}
1239
1240
Json CompilerStack::ethdebug(std::string const& _contractName) const
1241
0
{
1242
0
  return ethdebug(contract(_contractName), /* runtime */ false);
1243
0
}
1244
1245
Json CompilerStack::ethdebugRuntime(std::string const& _contractName) const
1246
0
{
1247
0
  return ethdebug(contract(_contractName), /* runtime */ true);
1248
0
}
1249
1250
Json CompilerStack::ethdebug(Contract const& _contract, bool _runtime) const
1251
0
{
1252
0
  solAssert(m_stackState >= AnalysisSuccessful, "Analysis was not successful.");
1253
0
  solAssert(_contract.contract);
1254
0
  solUnimplementedAssert(!isExperimentalSolidity());
1255
0
  evmasm::LinkerObject const& object = _runtime ? _contract.runtimeObject : _contract.object;
1256
0
  std::shared_ptr<evmasm::Assembly> const& assembly = _runtime ? _contract.evmRuntimeAssembly : _contract.evmAssembly;
1257
0
  if (!assembly)
1258
0
    return {};
1259
1260
0
  solAssert(sourceIndices().contains(_contract.contract->sourceUnitName()));
1261
0
  return evmasm::ethdebug::program(_contract.contract->name(), sourceIndices()[_contract.contract->sourceUnitName()], *assembly, object);
1262
0
}
1263
1264
bytes CompilerStack::cborMetadata(std::string const& _contractName, bool _forIR) const
1265
0
{
1266
0
  solAssert(m_stackState >= AnalysisSuccessful, "Analysis was not successful.");
1267
0
  return createCBORMetadata(contract(_contractName), _forIR);
1268
0
}
1269
1270
std::string const& CompilerStack::metadata(Contract const& _contract) const
1271
14.2k
{
1272
14.2k
  solAssert(m_stackState >= AnalysisSuccessful, "Analysis was not successful.");
1273
14.2k
  solAssert(_contract.contract);
1274
14.2k
  solUnimplementedAssert(!isExperimentalSolidity());
1275
14.2k
  return _contract.metadata.init([&]{ return createMetadata(_contract, m_viaIR); });
1276
14.2k
}
1277
1278
CharStream const& CompilerStack::charStream(std::string const& _sourceName) const
1279
433k
{
1280
433k
  solAssert(m_stackState >= SourcesSet, "No sources set.");
1281
433k
  solAssert(source(_sourceName).charStream);
1282
433k
  return *source(_sourceName).charStream;
1283
433k
}
1284
1285
SourceUnit const& CompilerStack::ast(std::string const& _sourceName) const
1286
0
{
1287
0
  solAssert(m_stackState >= Parsed, "Parsing not yet performed.");
1288
0
  solAssert(source(_sourceName).ast, "Parsing was not successful.");
1289
0
  solUnimplementedAssert(!isExperimentalSolidity());
1290
0
  return *source(_sourceName).ast;
1291
0
}
1292
1293
ContractDefinition const& CompilerStack::contractDefinition(std::string const& _contractName) const
1294
2.67k
{
1295
2.67k
  solAssert(m_stackState >= AnalysisSuccessful, "Analysis was not successful.");
1296
1297
2.67k
  return *contract(_contractName).contract;
1298
2.67k
}
1299
1300
size_t CompilerStack::functionEntryPoint(
1301
  std::string const& _contractName,
1302
  FunctionDefinition const& _function
1303
) const
1304
0
{
1305
0
  solAssert(m_stackState == CompilationSuccessful, "Compilation was not successful.");
1306
1307
0
  for (auto&& [name, data]: contract(_contractName).runtimeObject.functionDebugData)
1308
0
    if (data.sourceID == _function.id())
1309
0
      if (data.instructionIndex)
1310
0
        return *data.instructionIndex;
1311
0
  return 0;
1312
0
}
1313
1314
h256 const& CompilerStack::Source::keccak256() const
1315
14.5k
{
1316
14.5k
  if (keccak256HashCached == h256{})
1317
12.0k
    keccak256HashCached = util::keccak256(charStream->source());
1318
14.5k
  return keccak256HashCached;
1319
14.5k
}
1320
1321
h256 const& CompilerStack::Source::swarmHash() const
1322
14.5k
{
1323
14.5k
  if (swarmHashCached == h256{})
1324
12.0k
    swarmHashCached = util::bzzr1Hash(charStream->source());
1325
14.5k
  return swarmHashCached;
1326
14.5k
}
1327
1328
std::string const& CompilerStack::Source::ipfsUrl() const
1329
14.5k
{
1330
14.5k
  if (ipfsUrlCached.empty())
1331
12.0k
    ipfsUrlCached = "dweb:/ipfs/" + util::ipfsHashBase58(charStream->source());
1332
14.5k
  return ipfsUrlCached;
1333
14.5k
}
1334
1335
StringMap CompilerStack::loadMissingSources(SourceUnit const& _ast)
1336
23.9k
{
1337
23.9k
  solAssert(m_stackState < ParsedAndImported, "");
1338
23.9k
  StringMap newSources;
1339
23.9k
  try
1340
23.9k
  {
1341
23.9k
    for (auto const& node: _ast.nodes())
1342
64.7k
      if (ImportDirective const* import = dynamic_cast<ImportDirective*>(node.get()))
1343
1.46k
      {
1344
1.46k
        std::string const& importPath = *import->annotation().absolutePath;
1345
1346
1.46k
        if (m_sources.count(importPath) || newSources.count(importPath))
1347
1.14k
          continue;
1348
1349
323
        ReadCallback::Result result{false, std::string("File not supplied initially.")};
1350
323
        if (m_readFile)
1351
0
          result = m_readFile(ReadCallback::kindString(ReadCallback::Kind::ReadFile), importPath);
1352
1353
323
        if (result.success)
1354
0
          newSources[importPath] = result.responseOrErrorMessage;
1355
323
        else
1356
323
        {
1357
323
          m_errorReporter.parserError(
1358
323
            6275_error,
1359
323
            import->location(),
1360
323
            std::string("Source \"" + importPath + "\" not found: " + result.responseOrErrorMessage)
1361
323
          );
1362
323
          continue;
1363
323
        }
1364
323
      }
1365
23.9k
  }
1366
23.9k
  catch (FatalError const&)
1367
23.9k
  {
1368
0
    if (!m_errorReporter.hasErrors())
1369
0
    {
1370
0
      std::cerr << "Unreported fatal error:" << std::endl;
1371
0
      std::cerr << boost::current_exception_diagnostic_information() << std::endl;
1372
0
      solAssert(false, "Unreported fatal error.");
1373
0
    }
1374
0
  }
1375
23.9k
  return newSources;
1376
23.9k
}
1377
1378
std::string CompilerStack::applyRemapping(std::string const& _path, std::string const& _context)
1379
1.46k
{
1380
1.46k
  solAssert(m_stackState < ParsedAndImported, "");
1381
1.46k
  return m_importRemapper.apply(_path, _context);
1382
1.46k
}
1383
1384
bool CompilerStack::resolveImports()
1385
21.2k
{
1386
21.2k
  solAssert(m_stackState == ParsedAndImported, "");
1387
1388
  // topological sorting (depth first search) of the import graph, cutting potential cycles
1389
21.2k
  std::vector<Source const*> sourceOrder;
1390
21.2k
  std::set<Source const*> sourcesSeen;
1391
1392
21.2k
  std::function<void(Source const*)> toposort = [&](Source const* _source)
1393
24.1k
  {
1394
24.1k
    if (sourcesSeen.count(_source))
1395
1.10k
      return;
1396
23.0k
    sourcesSeen.insert(_source);
1397
23.0k
    solAssert(_source->ast);
1398
23.0k
    for (ASTPointer<ASTNode> const& node: _source->ast->nodes())
1399
63.0k
      if (ImportDirective const* import = dynamic_cast<ImportDirective*>(node.get()))
1400
1.10k
      {
1401
1.10k
        std::string const& path = *import->annotation().absolutePath;
1402
1.10k
        solAssert(m_sources.count(path), "");
1403
1.10k
        import->annotation().sourceUnit = m_sources[path].ast.get();
1404
1.10k
        toposort(&m_sources[path]);
1405
1.10k
      }
1406
23.0k
    sourceOrder.push_back(_source);
1407
23.0k
  };
1408
1409
21.2k
  std::vector<PragmaDirective const*> experimentalPragmaDirectives;
1410
21.2k
  for (auto const& sourcePair: m_sources)
1411
23.0k
  {
1412
23.0k
    if (isRequestedSource(sourcePair.first))
1413
23.0k
      toposort(&sourcePair.second);
1414
23.0k
    if (sourcePair.second.ast && sourcePair.second.ast->experimentalSolidity())
1415
76
      for (ASTPointer<ASTNode> const& node: sourcePair.second.ast->nodes())
1416
122
        if (PragmaDirective const* pragma = dynamic_cast<PragmaDirective*>(node.get()))
1417
122
          if (pragma->literals().size() >=2 && pragma->literals()[0] == "experimental" && pragma->literals()[1] == "solidity")
1418
76
          {
1419
76
            experimentalPragmaDirectives.push_back(pragma);
1420
76
            break;
1421
76
          }
1422
23.0k
  }
1423
1424
21.2k
  if (!experimentalPragmaDirectives.empty() && experimentalPragmaDirectives.size() != m_sources.size())
1425
1
  {
1426
1
    for (auto &&pragma: experimentalPragmaDirectives)
1427
1
      m_errorReporter.parserError(
1428
1
          2141_error,
1429
1
          pragma->location(),
1430
1
          "File declares \"pragma experimental solidity\". If you want to enable the experimental mode, all source units must include the pragma."
1431
1
      );
1432
1
    return false;
1433
1
  }
1434
1435
21.2k
  swap(m_sourceOrder, sourceOrder);
1436
21.2k
  return true;
1437
21.2k
}
1438
1439
void CompilerStack::storeContractDefinitions()
1440
21.2k
{
1441
21.2k
  for (auto const& pair: m_sources)
1442
23.0k
    if (pair.second.ast)
1443
23.0k
      for (
1444
23.0k
        ContractDefinition const* contract:
1445
23.0k
        ASTNode::filteredNodes<ContractDefinition>(pair.second.ast->nodes())
1446
23.0k
      )
1447
22.8k
      {
1448
22.8k
        std::string fullyQualifiedName = *pair.second.ast->annotation().path + ":" + contract->name();
1449
        // Note that we now reference contracts by their fully qualified names, and
1450
        // thus contracts can only conflict if declared in the same source file. This
1451
        // should already cause a double-declaration error elsewhere.
1452
22.8k
        if (!m_contracts.count(fullyQualifiedName))
1453
20.9k
          m_contracts[fullyQualifiedName].contract = contract;
1454
22.8k
      }
1455
21.2k
}
1456
1457
void CompilerStack::annotateInternalFunctionIDs()
1458
12.6k
{
1459
12.6k
  for (Source const* source: m_sourceOrder)
1460
14.2k
  {
1461
14.2k
    if (!source->ast)
1462
0
      continue;
1463
1464
14.2k
    for (ContractDefinition const* contract: ASTNode::filteredNodes<ContractDefinition>(source->ast->nodes()))
1465
14.8k
    {
1466
14.8k
      uint64_t internalFunctionID = 1;
1467
14.8k
      ContractDefinitionAnnotation& annotation = contract->annotation();
1468
1469
14.8k
      if (auto const* deployTimeInternalDispatch = util::valueOrNullptr((*annotation.deployedCallGraph)->edges, CallGraph::SpecialNode::InternalDispatch))
1470
132
        for (auto const& node: *deployTimeInternalDispatch)
1471
200
          if (auto const* callable = std::get_if<CallableDeclaration const*>(&node))
1472
200
            if (auto const* function = dynamic_cast<FunctionDefinition const*>(*callable))
1473
200
            {
1474
200
              solAssert(contract->annotation().internalFunctionIDs.count(function) == 0);
1475
200
              contract->annotation().internalFunctionIDs[function] = internalFunctionID++;
1476
200
            }
1477
14.8k
      if (auto const* creationTimeInternalDispatch = util::valueOrNullptr((*annotation.creationCallGraph)->edges, CallGraph::SpecialNode::InternalDispatch))
1478
41
        for (auto const& node: *creationTimeInternalDispatch)
1479
53
          if (auto const* callable = std::get_if<CallableDeclaration const*>(&node))
1480
53
            if (auto const* function = dynamic_cast<FunctionDefinition const*>(*callable))
1481
              // Make sure the function already got an ID since it also occurs in the deploy-time internal dispatch.
1482
53
              solAssert(contract->annotation().internalFunctionIDs.count(function) != 0);
1483
14.8k
    }
1484
14.2k
  }
1485
12.6k
}
1486
1487
void CompilerStack::assembleYul(
1488
  ContractDefinition const& _contract,
1489
  std::shared_ptr<evmasm::Assembly> _assembly,
1490
  std::shared_ptr<evmasm::Assembly> _runtimeAssembly
1491
)
1492
14.0k
{
1493
14.0k
  solAssert(m_stackState >= AnalysisSuccessful, "");
1494
1495
14.0k
  Contract& compiledContract = m_contracts.at(_contract.fullyQualifiedName());
1496
1497
14.0k
  compiledContract.evmAssembly = _assembly;
1498
14.0k
  solAssert(compiledContract.evmAssembly, "");
1499
14.0k
  try
1500
14.0k
  {
1501
    // Assemble deployment (incl. runtime)  object.
1502
14.0k
    compiledContract.object = compiledContract.evmAssembly->assemble();
1503
14.0k
  }
1504
14.0k
  catch (evmasm::AssemblyException const& error)
1505
14.0k
  {
1506
0
    solAssert(false, "Assembly exception for bytecode: "s + error.what());
1507
0
  }
1508
14.0k
  solAssert(compiledContract.object.immutableReferences.empty(), "Leftover immutables.");
1509
1510
14.0k
  compiledContract.evmRuntimeAssembly = _runtimeAssembly;
1511
14.0k
  solAssert(compiledContract.evmRuntimeAssembly, "");
1512
14.0k
  try
1513
14.0k
  {
1514
    // Assemble runtime object.
1515
14.0k
    compiledContract.runtimeObject = compiledContract.evmRuntimeAssembly->assemble();
1516
14.0k
  }
1517
14.0k
  catch (evmasm::AssemblyException const& error)
1518
14.0k
  {
1519
0
    solAssert(false, "Assembly exception for deployed bytecode"s + error.what());
1520
0
  }
1521
1522
  // Throw a warning if EIP-170 limits are exceeded:
1523
  //   If contract creation returns data with length greater than 0x6000 (2^14 + 2^13) bytes,
1524
  //   contract creation fails with an out of gas error.
1525
14.0k
  if (
1526
14.0k
    m_evmVersion >= langutil::EVMVersion::spuriousDragon() &&
1527
11.8k
    compiledContract.runtimeObject.bytecode.size() > 0x6000
1528
14.0k
  )
1529
128
    m_errorReporter.warning(
1530
128
      5574_error,
1531
128
      _contract.location(),
1532
128
      "Contract code size is "s +
1533
128
      std::to_string(compiledContract.runtimeObject.bytecode.size()) +
1534
128
      " bytes and exceeds 24576 bytes (a limit introduced in Spurious Dragon). "
1535
128
      "This contract may not be deployable on Mainnet. "
1536
128
      "Consider enabling the optimizer (with a low \"runs\" value!), "
1537
128
      "turning off revert strings, or using libraries."
1538
128
    );
1539
1540
  // Throw a warning if EIP-3860 limits are exceeded:
1541
  //   If initcode is larger than 0xC000 bytes (twice the runtime code limit),
1542
  //   then contract creation fails with an out of gas error.
1543
14.0k
  if (
1544
14.0k
    m_evmVersion >= langutil::EVMVersion::shanghai() &&
1545
4.64k
    compiledContract.object.bytecode.size() > 0xC000
1546
14.0k
  )
1547
35
    m_errorReporter.warning(
1548
35
      3860_error,
1549
35
      _contract.location(),
1550
35
      "Contract initcode size is "s +
1551
35
      std::to_string(compiledContract.object.bytecode.size()) +
1552
35
      " bytes and exceeds 49152 bytes (a limit introduced in Shanghai). "
1553
35
      "This contract may not be deployable on Mainnet. "
1554
35
      "Consider enabling the optimizer (with a low \"runs\" value!), "
1555
35
      "turning off revert strings, or using libraries."
1556
35
    );
1557
14.0k
}
1558
1559
void CompilerStack::compileContract(
1560
  ContractDefinition const& _contract,
1561
  std::map<ContractDefinition const*, std::shared_ptr<Compiler const>>& _otherCompilers
1562
)
1563
11.5k
{
1564
11.5k
  solAssert(!m_viaIR, "");
1565
11.5k
  solAssert(m_stackState >= AnalysisSuccessful, "");
1566
1567
11.5k
  if (_otherCompilers.count(&_contract))
1568
171
    return;
1569
1570
11.4k
  for (auto const& [dependency, referencee]: _contract.annotation().contractDependencies)
1571
171
    compileContract(*dependency, _otherCompilers);
1572
1573
11.4k
  if (!_contract.canBeDeployed())
1574
498
    return;
1575
1576
10.9k
  Contract& compiledContract = m_contracts.at(_contract.fullyQualifiedName());
1577
1578
10.9k
  std::shared_ptr<Compiler> compiler = std::make_shared<Compiler>(
1579
10.9k
    m_evmVersion,
1580
10.9k
    m_revertStrings,
1581
10.9k
    m_optimiserSettings
1582
10.9k
  );
1583
1584
10.9k
  solAssert(!m_viaIR, "");
1585
10.9k
  bytes cborEncodedMetadata = createCBORMetadata(compiledContract, /* _forIR */ false);
1586
1587
  // Run optimiser and compile the contract.
1588
10.9k
  compiler->compileContract(_contract, _otherCompilers, cborEncodedMetadata);
1589
10.9k
  compiledContract.generatedYulUtilityCode = compiler->generatedYulUtilityCode();
1590
10.9k
  compiledContract.runtimeGeneratedYulUtilityCode = compiler->runtimeGeneratedYulUtilityCode();
1591
1592
10.9k
  _otherCompilers[compiledContract.contract] = compiler;
1593
1594
10.9k
  assembleYul(_contract, compiler->assemblyPtr(), compiler->runtimeAssemblyPtr());
1595
10.9k
}
1596
1597
void CompilerStack::generateIR(ContractDefinition const& _contract, bool _unoptimizedOnly)
1598
3.36k
{
1599
3.36k
  solAssert(m_stackState >= AnalysisSuccessful, "");
1600
3.36k
  Contract& compiledContract = m_contracts.at(_contract.fullyQualifiedName());
1601
3.36k
  if (compiledContract.yulIR)
1602
75
  {
1603
75
    solAssert(!compiledContract.yulIR->empty());
1604
75
    return;
1605
75
  }
1606
1607
3.29k
  if (!*_contract.sourceUnit().annotation().useABICoderV2)
1608
135
    m_errorReporter.warning(
1609
135
      2066_error,
1610
135
      _contract.location(),
1611
135
      "Contract requests the ABI coder v1, which is incompatible with the IR. "
1612
135
      "Using ABI coder v2 instead."
1613
135
    );
1614
1615
3.29k
  std::string dependenciesSource;
1616
3.29k
  for (auto const& [dependency, referencee]: _contract.annotation().contractDependencies)
1617
75
    generateIR(*dependency, _unoptimizedOnly);
1618
1619
3.29k
  if (!_contract.canBeDeployed())
1620
3
    return;
1621
1622
3.29k
  std::map<ContractDefinition const*, std::string_view const> otherYulSources;
1623
3.29k
  for (auto const& pair: m_contracts)
1624
4.48k
    otherYulSources.emplace(pair.second.contract, pair.second.yulIR ? *pair.second.yulIR : std::string_view{});
1625
1626
3.29k
  if (m_experimentalAnalysis)
1627
0
  {
1628
0
    experimental::IRGenerator generator(
1629
0
      m_evmVersion,
1630
0
      m_revertStrings,
1631
0
      sourceIndices(),
1632
0
      m_debugInfoSelection,
1633
0
      this,
1634
0
      *m_experimentalAnalysis
1635
0
    );
1636
0
    compiledContract.yulIR = generator.run(
1637
0
      _contract,
1638
0
      {}, // TODO: createCBORMetadata(compiledContract, /* _forIR */ true),
1639
0
      otherYulSources
1640
0
    );
1641
0
  }
1642
3.29k
  else
1643
3.29k
  {
1644
3.29k
    IRGenerator generator(
1645
3.29k
      m_evmVersion,
1646
3.29k
      m_revertStrings,
1647
3.29k
      sourceIndices(),
1648
3.29k
      m_debugInfoSelection,
1649
3.29k
      this,
1650
3.29k
      m_optimiserSettings
1651
3.29k
    );
1652
3.29k
    compiledContract.yulIR = generator.run(
1653
3.29k
      _contract,
1654
3.29k
      createCBORMetadata(compiledContract, /* _forIR */ true),
1655
3.29k
      otherYulSources
1656
3.29k
    );
1657
3.29k
  }
1658
1659
3.29k
  yulAssert(compiledContract.yulIR);
1660
3.29k
  YulStack stack = loadGeneratedIR(*compiledContract.yulIR);
1661
3.29k
  if (!_unoptimizedOnly)
1662
3.29k
  {
1663
3.29k
    stack.optimize();
1664
3.29k
    compiledContract.yulIROptimized = stack.print();
1665
3.29k
  }
1666
3.29k
}
1667
1668
void CompilerStack::generateEVMFromIR(ContractDefinition const& _contract)
1669
3.29k
{
1670
3.29k
  solAssert(m_stackState >= AnalysisSuccessful, "");
1671
1672
3.29k
  if (!_contract.canBeDeployed())
1673
3
    return;
1674
1675
3.29k
  Contract& compiledContract = m_contracts.at(_contract.fullyQualifiedName());
1676
3.29k
  solAssert(compiledContract.yulIROptimized);
1677
3.29k
  solAssert(!compiledContract.yulIROptimized->empty());
1678
3.29k
  if (!compiledContract.object.bytecode.empty())
1679
0
    return;
1680
1681
  // Re-parse the Yul IR in EVM dialect
1682
3.29k
  YulStack stack = loadGeneratedIR(*compiledContract.yulIROptimized);
1683
1684
3.29k
  std::string deployedName = IRNames::deployedObject(_contract);
1685
3.29k
  solAssert(!deployedName.empty(), "");
1686
3.29k
  tie(compiledContract.evmAssembly, compiledContract.evmRuntimeAssembly) = stack.assembleEVMWithDeployed(deployedName, m_viaSSACFG);
1687
1688
3.29k
  if (stack.hasErrors())
1689
0
  {
1690
0
    for (std::shared_ptr<Error const> const& error: stack.errors())
1691
0
      reportIRPostAnalysisError(error.get(), compiledContract.contract);
1692
0
    return;
1693
0
  }
1694
1695
3.29k
  assembleYul(_contract, compiledContract.evmAssembly, compiledContract.evmRuntimeAssembly);
1696
3.29k
}
1697
1698
CompilerStack::Contract const& CompilerStack::contract(std::string const& _contractName) const
1699
3.34k
{
1700
3.34k
  solAssert(m_stackState >= AnalysisSuccessful, "");
1701
1702
3.34k
  auto it = m_contracts.find(_contractName);
1703
3.34k
  if (it != m_contracts.end())
1704
0
    return it->second;
1705
1706
  // To provide a measure of backward-compatibility, if a contract is not located by its
1707
  // fully-qualified name, a lookup will be attempted purely on the contract's name to see
1708
  // if anything will satisfy.
1709
3.34k
  if (_contractName.find(':') == std::string::npos)
1710
3.34k
  {
1711
3.34k
    for (auto const& contractEntry: m_contracts)
1712
3.34k
    {
1713
3.34k
      std::stringstream ss;
1714
3.34k
      ss.str(contractEntry.first);
1715
      // All entries are <source>:<contract>
1716
3.34k
      std::string source;
1717
3.34k
      std::string foundName;
1718
3.34k
      getline(ss, source, ':');
1719
3.34k
      getline(ss, foundName, ':');
1720
3.34k
      if (foundName == _contractName)
1721
3.34k
        return contractEntry.second;
1722
3.34k
    }
1723
3.34k
  }
1724
1725
  // If we get here, both lookup methods failed.
1726
0
  solAssert(false, "Contract \"" + _contractName + "\" not found.");
1727
0
}
1728
1729
CompilerStack::Source const& CompilerStack::source(std::string const& _sourceName) const
1730
866k
{
1731
866k
  auto it = m_sources.find(_sourceName);
1732
866k
  solAssert(it != m_sources.end(), "Given source file not found: " + _sourceName);
1733
1734
866k
  return it->second;
1735
866k
}
1736
1737
std::string CompilerStack::createMetadata(Contract const& _contract, bool _forIR) const
1738
14.2k
{
1739
14.2k
  Json meta;
1740
14.2k
  meta["version"] = 1;
1741
14.2k
  std::string sourceType;
1742
14.2k
  switch (m_compilationSourceType)
1743
14.2k
  {
1744
14.2k
  case CompilationSourceType::Solidity:
1745
14.2k
    sourceType = "Solidity";
1746
14.2k
    break;
1747
0
  case CompilationSourceType::SolidityAST:
1748
0
    sourceType = "SolidityAST";
1749
0
    break;
1750
14.2k
  }
1751
14.2k
  meta["language"] = sourceType;
1752
14.2k
  meta["compiler"]["version"] = VersionStringStrict;
1753
1754
  /// All the source files (including self), which should be included in the metadata.
1755
14.2k
  std::set<std::string> referencedSources;
1756
14.2k
  referencedSources.insert(*_contract.contract->sourceUnit().annotation().path);
1757
14.2k
  for (auto const sourceUnit: _contract.contract->sourceUnit().referencedSourceUnits(true))
1758
395
    referencedSources.insert(*sourceUnit->annotation().path);
1759
1760
14.2k
  meta["sources"] = Json::object();
1761
14.2k
  for (auto const& s: m_sources)
1762
16.0k
  {
1763
16.0k
    if (!referencedSources.count(s.first))
1764
1.47k
      continue;
1765
1766
14.5k
    solAssert(s.second.charStream, "Character stream not available");
1767
14.5k
    meta["sources"][s.first]["keccak256"] = "0x" + util::toHex(s.second.keccak256().asBytes());
1768
14.5k
    if (std::optional<std::string> licenseString = s.second.ast->licenseString())
1769
268
      meta["sources"][s.first]["license"] = *licenseString;
1770
14.5k
    if (m_metadataLiteralSources)
1771
0
      meta["sources"][s.first]["content"] = s.second.charStream->source();
1772
14.5k
    else
1773
14.5k
    {
1774
14.5k
      meta["sources"][s.first]["urls"] = Json::array();
1775
14.5k
      meta["sources"][s.first]["urls"].emplace_back("bzz-raw://" + util::toHex(s.second.swarmHash().asBytes()));
1776
14.5k
      meta["sources"][s.first]["urls"].emplace_back(s.second.ipfsUrl());
1777
14.5k
    }
1778
14.5k
  }
1779
1780
14.2k
  static_assert(std::is_same_v<decltype(m_optimiserSettings.expectedExecutionsPerDeployment), Json::number_unsigned_t>);
1781
14.2k
  meta["settings"]["optimizer"]["runs"] = m_optimiserSettings.expectedExecutionsPerDeployment;
1782
1783
  /// Backwards compatibility: If set to one of the default settings, do not provide details.
1784
14.2k
  OptimiserSettings settingsWithoutRuns = m_optimiserSettings;
1785
  // reset to default
1786
14.2k
  settingsWithoutRuns.expectedExecutionsPerDeployment = OptimiserSettings::minimal().expectedExecutionsPerDeployment;
1787
14.2k
  if (settingsWithoutRuns == OptimiserSettings::minimal())
1788
11.8k
    meta["settings"]["optimizer"]["enabled"] = false;
1789
2.37k
  else if (settingsWithoutRuns == OptimiserSettings::standard())
1790
2.37k
    meta["settings"]["optimizer"]["enabled"] = true;
1791
0
  else
1792
0
  {
1793
0
    Json details = Json::object();
1794
1795
0
    details["orderLiterals"] = m_optimiserSettings.runOrderLiterals;
1796
0
    details["inliner"] = m_optimiserSettings.runInliner;
1797
0
    details["jumpdestRemover"] = m_optimiserSettings.runJumpdestRemover;
1798
0
    details["peephole"] = m_optimiserSettings.runPeephole;
1799
0
    details["deduplicate"] = m_optimiserSettings.runDeduplicate;
1800
0
    details["cse"] = m_optimiserSettings.runCSE;
1801
0
    details["constantOptimizer"] = m_optimiserSettings.runConstantOptimiser;
1802
0
    details["simpleCounterForLoopUncheckedIncrement"] = m_optimiserSettings.simpleCounterForLoopUncheckedIncrement;
1803
0
    details["yul"] = m_optimiserSettings.runYulOptimiser;
1804
0
    if (m_optimiserSettings.runYulOptimiser)
1805
0
    {
1806
0
      details["yulDetails"] = Json::object();
1807
0
      details["yulDetails"]["stackAllocation"] = m_optimiserSettings.optimizeStackAllocation;
1808
0
      details["yulDetails"]["optimizerSteps"] = m_optimiserSettings.yulOptimiserSteps + ":" + m_optimiserSettings.yulOptimiserCleanupSteps;
1809
0
    }
1810
0
    else if (OptimiserSuite::isEmptyOptimizerSequence(m_optimiserSettings.yulOptimiserSteps + ":" + m_optimiserSettings.yulOptimiserCleanupSteps))
1811
0
    {
1812
0
      solAssert(m_optimiserSettings.optimizeStackAllocation == false);
1813
0
      details["yulDetails"] = Json::object();
1814
0
      details["yulDetails"]["optimizerSteps"] = ":";
1815
0
    }
1816
0
    else
1817
0
    {
1818
0
      solAssert(m_optimiserSettings.optimizeStackAllocation == false);
1819
0
      solAssert(m_optimiserSettings.yulOptimiserSteps == OptimiserSettings::DefaultYulOptimiserSteps);
1820
0
      solAssert(m_optimiserSettings.yulOptimiserCleanupSteps == OptimiserSettings::DefaultYulOptimiserCleanupSteps);
1821
0
    }
1822
1823
0
    meta["settings"]["optimizer"]["details"] = std::move(details);
1824
0
  }
1825
1826
14.2k
  if (m_revertStrings != RevertStrings::Default)
1827
0
    meta["settings"]["debug"]["revertStrings"] = revertStringsToString(m_revertStrings);
1828
1829
14.2k
  if (m_metadataFormat == MetadataFormat::NoMetadata)
1830
0
    meta["settings"]["metadata"]["appendCBOR"] = false;
1831
1832
14.2k
  if (m_metadataLiteralSources)
1833
0
    meta["settings"]["metadata"]["useLiteralContent"] = true;
1834
1835
14.2k
  static std::vector<std::string> hashes{"ipfs", "bzzr1", "none"};
1836
14.2k
  meta["settings"]["metadata"]["bytecodeHash"] = hashes.at(unsigned(m_metadataHash));
1837
1838
14.2k
  if (_forIR)
1839
3.29k
    meta["settings"]["viaIR"] = _forIR;
1840
14.2k
  meta["settings"]["evmVersion"] = m_evmVersion.name();
1841
14.2k
  if (m_experimental)
1842
0
    meta["settings"]["experimental"] = m_experimental;
1843
14.2k
  if (m_viaSSACFG)
1844
0
    meta["settings"]["viaSSACFG"] = m_viaSSACFG;
1845
14.2k
  meta["settings"]["compilationTarget"][_contract.contract->sourceUnitName()] =
1846
14.2k
    *_contract.contract->annotation().canonicalName;
1847
1848
14.2k
  meta["settings"]["remappings"] = Json::array();
1849
14.2k
  std::set<std::string> remappings;
1850
14.2k
  for (auto const& r: m_importRemapper.remappings())
1851
0
    remappings.insert(r.context + ":" + r.prefix + "=" + r.target);
1852
14.2k
  for (auto const& r: remappings)
1853
0
    meta["settings"]["remappings"].emplace_back(r);
1854
1855
14.2k
  meta["settings"]["libraries"] = Json::object();
1856
14.2k
  for (auto const& library: m_libraries)
1857
0
    meta["settings"]["libraries"][library.first] = "0x" + util::toHex(library.second.asBytes());
1858
1859
14.2k
  meta["output"]["abi"] = contractABI(_contract);
1860
14.2k
  meta["output"]["userdoc"] = natspecUser(_contract);
1861
14.2k
  meta["output"]["devdoc"] = natspecDev(_contract);
1862
1863
14.2k
  return util::jsonCompactPrint(meta);
1864
14.2k
}
1865
1866
class MetadataCBOREncoder
1867
{
1868
public:
1869
  void pushBytes(std::string const& key, bytes const& value)
1870
14.2k
  {
1871
14.2k
    m_entryCount++;
1872
14.2k
    pushTextString(key);
1873
14.2k
    pushByteString(value);
1874
14.2k
  }
1875
1876
  void pushString(std::string const& key, std::string const& value)
1877
14.2k
  {
1878
14.2k
    m_entryCount++;
1879
14.2k
    pushTextString(key);
1880
14.2k
    pushTextString(value);
1881
14.2k
  }
1882
1883
  void pushBool(std::string const& key, bool value)
1884
0
  {
1885
0
    m_entryCount++;
1886
0
    pushTextString(key);
1887
0
    pushBool(value);
1888
0
  }
1889
1890
  bytes serialise() const
1891
14.2k
  {
1892
14.2k
    size_t size = m_data.size() + 1;
1893
14.2k
    solAssert(size <= 0xffff, "Metadata too large.");
1894
14.2k
    solAssert(m_entryCount <= 0x1f, "Too many map entries.");
1895
1896
    // CBOR fixed-length map
1897
14.2k
    bytes ret{static_cast<unsigned char>(0xa0 + m_entryCount)};
1898
    // The already encoded key-value pairs
1899
14.2k
    ret += m_data;
1900
    // 16-bit big endian length
1901
14.2k
    ret += toCompactBigEndian(size, 2);
1902
14.2k
    return ret;
1903
14.2k
  }
1904
1905
private:
1906
  void pushTextString(std::string const& key)
1907
42.6k
  {
1908
42.6k
    size_t length = key.size();
1909
42.6k
    if (length < 24)
1910
28.4k
    {
1911
28.4k
      m_data += bytes{static_cast<unsigned char>(0x60 + length)};
1912
28.4k
      m_data += key;
1913
28.4k
    }
1914
14.2k
    else if (length <= 256)
1915
14.2k
    {
1916
14.2k
      m_data += bytes{0x78, static_cast<unsigned char>(length)};
1917
14.2k
      m_data += key;
1918
14.2k
    }
1919
0
    else
1920
14.2k
      solAssert(false, "Text std::string too large.");
1921
42.6k
  }
1922
  void pushByteString(bytes const& key)
1923
14.2k
  {
1924
14.2k
    size_t length = key.size();
1925
14.2k
    if (length < 24)
1926
0
    {
1927
0
      m_data += bytes{static_cast<unsigned char>(0x40 + length)};
1928
0
      m_data += key;
1929
0
    }
1930
14.2k
    else if (length <= 256)
1931
14.2k
    {
1932
14.2k
      m_data += bytes{0x58, static_cast<unsigned char>(length)};
1933
14.2k
      m_data += key;
1934
14.2k
    }
1935
0
    else
1936
14.2k
      solAssert(false, "Byte std::string too large.");
1937
14.2k
  }
1938
  void pushBool(bool value)
1939
0
  {
1940
0
    if (value)
1941
0
      m_data += bytes{0xf5};
1942
0
    else
1943
0
      m_data += bytes{0xf4};
1944
0
  }
1945
  unsigned m_entryCount = 0;
1946
  bytes m_data;
1947
};
1948
1949
bytes CompilerStack::createCBORMetadata(Contract const& _contract, bool _forIR) const
1950
14.2k
{
1951
14.2k
  if (m_metadataFormat == MetadataFormat::NoMetadata)
1952
0
    return bytes{};
1953
1954
14.2k
  bool const usesExperimentalSyntax = !_contract.contract->sourceUnit().annotation().experimentalFeatures.empty();
1955
14.2k
  bool const onlySafeExperimentalFeatures = onlySafeExperimentalFeaturesActivated(
1956
14.2k
    _contract.contract->sourceUnit().annotation().experimentalFeatures
1957
14.2k
  );
1958
1959
14.2k
  if (usesExperimentalSyntax && !onlySafeExperimentalFeatures)
1960
14.2k
    solAssert(m_experimental, "Experimental mode not enabled");
1961
1962
14.2k
  std::string meta = (_forIR == m_viaIR ? metadata(_contract) : createMetadata(_contract, _forIR));
1963
1964
14.2k
  MetadataCBOREncoder encoder;
1965
1966
14.2k
  if (m_metadataHash == MetadataHash::IPFS)
1967
14.2k
    encoder.pushBytes("ipfs", util::ipfsHash(meta));
1968
0
  else if (m_metadataHash == MetadataHash::Bzzr1)
1969
0
    encoder.pushBytes("bzzr1", util::bzzr1Hash(meta).asBytes());
1970
0
  else
1971
0
    solAssert(m_metadataHash == MetadataHash::None, "Invalid metadata hash");
1972
1973
14.2k
  if (m_experimental)
1974
0
    encoder.pushBool("experimental", true);
1975
14.2k
  if (m_metadataFormat == MetadataFormat::WithReleaseVersionTag)
1976
0
    encoder.pushBytes("solc", VersionCompactBytes);
1977
14.2k
  else
1978
14.2k
  {
1979
14.2k
    solAssert(
1980
14.2k
      m_metadataFormat == MetadataFormat::WithPrereleaseVersionTag,
1981
14.2k
      "Invalid metadata format."
1982
14.2k
    );
1983
14.2k
    encoder.pushString("solc", VersionStringStrict);
1984
14.2k
  }
1985
14.2k
  return encoder.serialise();
1986
14.2k
}
1987
1988
namespace
1989
{
1990
1991
Json gasToJson(GasEstimator::GasConsumption const& _gas)
1992
0
{
1993
0
  if (_gas.isInfinite)
1994
0
    return Json("infinite");
1995
0
  else
1996
0
    return Json(util::toString(_gas.value));
1997
0
}
1998
1999
}
2000
2001
Json CompilerStack::gasEstimates(std::string const& _contractName) const
2002
0
{
2003
0
  solAssert(m_stackState == CompilationSuccessful, "Compilation was not successful.");
2004
0
  solUnimplementedAssert(!isExperimentalSolidity());
2005
2006
0
  if (!assemblyItems(_contractName) && !runtimeAssemblyItems(_contractName))
2007
0
    return Json();
2008
2009
0
  using Gas = GasEstimator::GasConsumption;
2010
0
  GasEstimator gasEstimator(m_evmVersion);
2011
0
  Json output = Json::object();
2012
2013
0
  if (evmasm::AssemblyItems const* items = assemblyItems(_contractName))
2014
0
  {
2015
0
    Gas executionGas = gasEstimator.functionalEstimation(*items);
2016
0
    Gas codeDepositGas{evmasm::GasMeter::dataGas(runtimeObject(_contractName).bytecode, false, m_evmVersion)};
2017
2018
0
    Json creation = Json::object();
2019
0
    creation["codeDepositCost"] = gasToJson(codeDepositGas);
2020
0
    creation["executionCost"] = gasToJson(executionGas);
2021
    /// TODO: implement + overload to avoid the need of +=
2022
0
    executionGas += codeDepositGas;
2023
0
    creation["totalCost"] = gasToJson(executionGas);
2024
0
    output["creation"] = creation;
2025
0
  }
2026
2027
0
  if (evmasm::AssemblyItems const* items = runtimeAssemblyItems(_contractName))
2028
0
  {
2029
    /// External functions
2030
0
    ContractDefinition const& contract = contractDefinition(_contractName);
2031
0
    Json externalFunctions = Json::object();
2032
0
    for (auto it: contract.interfaceFunctions())
2033
0
    {
2034
0
      std::string sig = it.second->externalSignature();
2035
0
      externalFunctions[sig] = gasToJson(gasEstimator.functionalEstimation(*items, sig));
2036
0
    }
2037
2038
0
    if (contract.fallbackFunction())
2039
      /// This needs to be set to an invalid signature in order to trigger the fallback,
2040
      /// without the shortcut (of CALLDATSIZE == 0), and therefore to receive the upper bound.
2041
      /// An empty string ("") would work to trigger the shortcut only.
2042
0
      externalFunctions[""] = gasToJson(gasEstimator.functionalEstimation(*items, "INVALID"));
2043
2044
0
    if (!externalFunctions.empty())
2045
0
      output["external"] = externalFunctions;
2046
2047
    /// Internal functions
2048
0
    Json internalFunctions = Json::object();
2049
0
    for (auto const& it: contract.definedFunctions())
2050
0
    {
2051
      /// Exclude externally visible functions, constructor, fallback and receive ether function
2052
0
      if (it->isPartOfExternalInterface() || !it->isOrdinary())
2053
0
        continue;
2054
2055
0
      size_t entry = functionEntryPoint(_contractName, *it);
2056
0
      GasEstimator::GasConsumption gas = GasEstimator::GasConsumption::infinite();
2057
0
      if (entry > 0)
2058
0
        gas = gasEstimator.functionalEstimation(*items, entry, *it);
2059
2060
      /// TODO: This could move into a method shared with externalSignature()
2061
0
      FunctionType type(*it);
2062
0
      std::string sig = it->name() + "(";
2063
0
      auto paramTypes = type.parameterTypes();
2064
0
      for (auto it = paramTypes.begin(); it != paramTypes.end(); ++it)
2065
0
        sig += (*it)->toString() + (it + 1 == paramTypes.end() ? "" : ",");
2066
0
      sig += ")";
2067
2068
0
      internalFunctions[sig] = gasToJson(gas);
2069
0
    }
2070
2071
0
    if (!internalFunctions.empty())
2072
0
      output["internal"] = internalFunctions;
2073
0
  }
2074
2075
0
  return output;
2076
0
}
2077
2078
bool CompilerStack::isExperimentalSolidity() const
2079
78.6k
{
2080
78.6k
  return
2081
78.6k
    !m_sourceOrder.empty() &&
2082
78.6k
    ranges::all_of(m_sourceOrder, [](auto const* _source) { return _source->ast->experimentalSolidity(); } )
2083
78.6k
  ;
2084
78.6k
}
2085
2086
experimental::Analysis const& CompilerStack::experimentalAnalysis() const
2087
0
{
2088
0
  solAssert(!!m_experimentalAnalysis);
2089
0
  return *m_experimentalAnalysis;
2090
0
}
2091
2092
void CompilerStack::reportUnimplementedFeatureError(
2093
  UnimplementedFeatureError const& _error,
2094
  ContractDefinition const* _contractDefinition
2095
)
2096
157
{
2097
157
  solAssert(_error.comment(), "Errors must include a message for the user.");
2098
157
  if (_error.sourceLocation().sourceName)
2099
157
    solAssert(m_sources.count(*_error.sourceLocation().sourceName) != 0);
2100
2101
157
  m_errorReporter.unimplementedFeatureError(
2102
157
    1834_error,
2103
157
    (_error.sourceLocation().sourceName || !_contractDefinition) ?
2104
0
      _error.sourceLocation() :
2105
157
      _contractDefinition->location(),
2106
157
    *_error.comment()
2107
157
  );
2108
157
}
2109
2110
void CompilerStack::reportCodeGenerationError(Error const& _error, ContractDefinition const* _contractDefinition)
2111
0
{
2112
0
  solAssert(_error.type() == Error::Type::CodeGenerationError);
2113
0
  solAssert(_error.comment(), "Errors must include a message for the user.");
2114
0
  if (_error.sourceLocation() && _error.sourceLocation()->sourceName)
2115
0
    solAssert(m_sources.count(*_error.sourceLocation()->sourceName) != 0);
2116
0
  solAssert(_contractDefinition);
2117
2118
0
  m_errorReporter.codeGenerationError(
2119
0
    _error.errorId(),
2120
0
    (_error.sourceLocation() && _error.sourceLocation()->sourceName) ?
2121
0
      *_error.sourceLocation() :
2122
0
      _contractDefinition->location(),
2123
0
    *_error.comment()
2124
0
  );
2125
0
}
2126
2127
void CompilerStack::reportIRPostAnalysisError(Error const* _error, ContractDefinition const* _contractDefinition)
2128
0
{
2129
0
  solAssert(_error);
2130
0
  solAssert(_error->comment(), "Errors must include a message for the user.");
2131
0
  solAssert(!_error->secondarySourceLocation());
2132
0
  solAssert(_contractDefinition);
2133
2134
  // Do not report Yul warnings and infos. These are only reported in pure Yul compilation.
2135
0
  if (!Error::isError(_error->severity()))
2136
0
    return;
2137
2138
0
  m_errorReporter.error(
2139
0
    _error->errorId(),
2140
0
    _error->type(),
2141
    // Ignore the original location. It's likely missing, but even if not, it points at Yul source.
2142
    // CompilerStack can only point at locations in Solidity sources.
2143
0
    _contractDefinition->location(),
2144
0
    *_error->comment()
2145
0
  );
2146
0
}